diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..e69de29 diff --git a/.gitignore b/.gitignore index 15e9211..f031a21 100644 --- a/.gitignore +++ b/.gitignore @@ -4,3 +4,5 @@ sandag_rsm/__pycache__ .ipynb_checkpoints sandag_rsm.egg-info _version.py +.DS_Store +test/data/* diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 35cc926..333916f 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -1,7 +1,7 @@ repos: - repo: https://github.com/pre-commit/pre-commit-hooks - rev: v4.1.0 + rev: v4.3.0 hooks: - id: check-yaml - id: end-of-file-fixer @@ -9,7 +9,7 @@ repos: - id: trailing-whitespace - repo: https://github.com/kynan/nbstripout - rev: 0.5.0 + rev: 0.6.1 hooks: - id: nbstripout @@ -20,11 +20,11 @@ repos: args: ["--profile", "black", "--filter-files"] - repo: https://github.com/psf/black - rev: 21.12b0 + rev: 22.10.0 hooks: - id: black - repo: https://github.com/PyCQA/flake8 - rev: 4.0.1 + rev: 5.0.4 hooks: - id: flake8 diff --git a/README.md b/README.md index 673e61b..c4d9257 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,16 @@ # RSM Rapid Strategic Model for the San Diego Association of Governments +## Source Code Access + +The source code for the RSM is stored in this repository. You can access it +via GitHub, or check out the repository using Git. Some larger files (especially +for testing) are stored using [git-lfs](https://git-lfs.github.com/) (large file +storage). This is mostly transparent, but for best results you do need to make +sure that the LFS extension is installed before you clone the repository. Visit +[git-lfs](https://git-lfs.github.com/) for platform-specific instructions. + + ## Installing To install, activate the python or conda environment you want to use, @@ -10,6 +20,13 @@ the cd into the repository directory and run: python -m pip install -e . ``` +This will make the `sandag_rsm` package available, so you can `import sandag_rsm` +to access the functions in this tool, without regard for the current working +directory or pointing the python path to the right place(s). Using the `-e` flag +installs in `editable` mode, so if you make changes or pull updates from GitHub, +those updates will be available to Python without re-installing. + + ## Code Formatting This repo use several tools to ensure a consistent code format throughout the project: @@ -34,7 +51,8 @@ with `git commit --no-verify`. ## Developing with Docker -To build the docker container, change into the repository root and run: +This project uses [Docker](https://www.docker.com/). For development, to build +the docker container, change into the repository root and run: ```shell docker build --tag sandag_rsm . @@ -42,11 +60,19 @@ docker build --tag sandag_rsm . ### Jupyter Notebook for Development -On the host machine, run: +On the host machine, on linux or macOS run: ```shell docker run -v $(pwd):/home/mambauser/sandag_rsm -p 8899:8899 \ - -it sandag_rsm jupyter notebook --ip 0.0.0.0 --no-browser --allow-root \ + -it --rm sandag_rsm jupyter notebook --ip 0.0.0.0 --no-browser --allow-root \ + --port 8899 --notebook-dir=/home/mambauser +``` + +or in `cwd` on Windows, run: + +```shell +docker run -v %cd%:/home/mambauser/sandag_rsm -p 8899:8899 ^ + -it --rm sandag_rsm jupyter notebook --ip 0.0.0.0 --no-browser --allow-root ^ --port 8899 --notebook-dir=/home/mambauser ``` diff --git a/environment.yaml b/environment.yaml index 2a01ecd..5799404 100644 --- a/environment.yaml +++ b/environment.yaml @@ -10,12 +10,15 @@ dependencies: - numpy>=1.19 - geopandas - git + - git-lfs - jupyter - libpysal - networkx - notebook + - openmatrix - pandas - plotly + - pyarrow - pyproj - requests=2.25.1 - scikit-learn diff --git a/notebooks/TranslateDemand.ipynb b/notebooks/TranslateDemand.ipynb new file mode 100644 index 0000000..822302d --- /dev/null +++ b/notebooks/TranslateDemand.ipynb @@ -0,0 +1,329 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 18, + "id": "4fc00298", + "metadata": {}, + "outputs": [], + "source": [ + "import os\n", + "import requests\n", + "import openmatrix as omx\n", + "\n", + "from sandag_rsm.translate import translate_demand" + ] + }, + { + "cell_type": "markdown", + "id": "de5861aa", + "metadata": {}, + "source": [ + "## Remote I/O" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "1d4896bb", + "metadata": {}, + "outputs": [], + "source": [ + "data_dir = './data-dl/'\n", + "\n", + "os.makedirs(data_dir, exist_ok=True)\n", + "\n", + "resource_url = 'https://media.githubusercontent.com/media/wsp-sag/client_sandag_rsm_resources/main/original_omx/'\n", + "\n", + "download_files_vector = [\n", + " 'trip_EA.omx',\n", + " 'trip_AM.omx',\n", + " 'trip_MD.omx',\n", + " 'trip_PM.omx',\n", + " 'trip_EV.omx',\n", + "]\n", + "\n", + "# for download_file in download_files_vector:\n", + "# r = requests.get((resource_url+download_file), allow_redirects=True)\n", + "# open((data_dir+download_file), 'w').write(r.content)" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "e09fa2ee", + "metadata": {}, + "outputs": [], + "source": [ + "input_dir = './data-dl/'\n", + "output_dir = './data-dl/export/'\n", + "matrix_names = ['trip_EA.omx', 'trip_AM.omx', 'trip_MD.omx', 'trip_PM.omx', 'trip_EV.omx']\n", + "agg_zone_mapping = './../test/data/taz_crosswalk.csv'" + ] + }, + { + "cell_type": "code", + "execution_count": 14, + "id": "b23b92f9", + "metadata": {}, + "outputs": [], + "source": [ + "os.makedirs(output_dir, exist_ok=True)" + ] + }, + { + "cell_type": "markdown", + "id": "fe41ea9a", + "metadata": {}, + "source": [ + "## Aggregate Matrices" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "458ad160-33cf-4149-94ca-b436c2a5aafb", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[04:47.70] INFO: Agregating Matrix: trip_EA.omx ...\n", + "[06:23.38] INFO: Agregating Matrix: trip_AM.omx ...\n", + "[08:00.64] INFO: Agregating Matrix: trip_MD.omx ...\n", + "[09:39.43] INFO: Agregating Matrix: trip_PM.omx ...\n", + "[11:16.33] INFO: Agregating Matrix: trip_EV.omx ...\n" + ] + } + ], + "source": [ + "translate_demand(\n", + " matrix_names,\n", + " agg_zone_mapping,\n", + " input_dir,\n", + " output_dir\n", + ")" + ] + }, + { + "cell_type": "markdown", + "id": "62a0c438", + "metadata": {}, + "source": [ + "## Compare Original and Aggregated Matrices" + ] + }, + { + "cell_type": "code", + "execution_count": 16, + "id": "cd5d0436", + "metadata": {}, + "outputs": [], + "source": [ + "matrix_name = 'trip_AM.omx'" + ] + }, + { + "cell_type": "code", + "execution_count": 20, + "id": "eb4bcad1-fe01-405c-8da7-96ac040a10d6", + "metadata": {}, + "outputs": [], + "source": [ + "input_matrix = omx.open_file(os.path.join(input_dir, matrix_name), mode=\"r\") \n", + "output_matrix = omx.open_file(os.path.join(output_dir, matrix_name), mode=\"r\")" + ] + }, + { + "cell_type": "code", + "execution_count": 21, + "id": "692ecce3-946b-4ca1-ac01-b8610991b8bc", + "metadata": {}, + "outputs": [], + "source": [ + "matrix_cores = input_matrix.list_matrices()" + ] + }, + { + "cell_type": "code", + "execution_count": 22, + "id": "c3030557-03f4-402c-8da2-306c0b4f268c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(4996, 4996)" + ] + }, + "execution_count": 22, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "input_matrix.shape()" + ] + }, + { + "cell_type": "code", + "execution_count": 23, + "id": "650baf9b-569f-424b-a703-5cb7c75110d4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(2012, 2012)" + ] + }, + "execution_count": 23, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "output_matrix.shape()" + ] + }, + { + "cell_type": "code", + "execution_count": 24, + "id": "a9552989-8251-445f-a3b1-4070d66c06fa", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "Core: AM_HOV2_H\n", + "Input Sum: 90,480\n", + "Output Sum: 90,480\n", + "\n", + "Core: AM_HOV2_L\n", + "Input Sum: 101,330\n", + "Output Sum: 101,330\n", + "\n", + "Core: AM_HOV2_M\n", + "Input Sum: 229,308\n", + "Output Sum: 229,308\n", + "\n", + "Core: AM_HOV3_H\n", + "Input Sum: 81,707\n", + "Output Sum: 81,707\n", + "\n", + "Core: AM_HOV3_L\n", + "Input Sum: 38,662\n", + "Output Sum: 38,662\n", + "\n", + "Core: AM_HOV3_M\n", + "Input Sum: 98,403\n", + "Output Sum: 98,403\n", + "\n", + "Core: AM_SOV_NT_H\n", + "Input Sum: 222,616\n", + "Output Sum: 222,616\n", + "\n", + "Core: AM_SOV_NT_L\n", + "Input Sum: 535,342\n", + "Output Sum: 535,342\n", + "\n", + "Core: AM_SOV_NT_M\n", + "Input Sum: 426,238\n", + "Output Sum: 426,238\n", + "\n", + "Core: AM_SOV_TR_H\n", + "Input Sum: 185,345\n", + "Output Sum: 185,345\n", + "\n", + "Core: AM_SOV_TR_L\n", + "Input Sum: 21,590\n", + "Output Sum: 21,590\n", + "\n", + "Core: AM_SOV_TR_M\n", + "Input Sum: 16,563\n", + "Output Sum: 16,563\n", + "\n", + "Core: AM_TRK_H\n", + "Input Sum: 58,381\n", + "Output Sum: 58,381\n", + "\n", + "Core: AM_TRK_L\n", + "Input Sum: 32,998\n", + "Output Sum: 32,998\n", + "\n", + "Core: AM_TRK_M\n", + "Input Sum: 14,039\n", + "Output Sum: 14,039\n", + "\n" + ] + } + ], + "source": [ + "for core in matrix_cores:\n", + " input_core = input_matrix[core].read()\n", + " output_core = output_matrix[core].read()\n", + " \n", + " input_mtx_sum = input_core.sum().sum()\n", + " output_mtx_sum = input_core.sum().sum()\n", + " \n", + " print(f'Core: {core}')\n", + " print(f'Input Sum: {input_mtx_sum:,.0f}')\n", + " print(f'Output Sum: {output_mtx_sum:,.0f}\\n')\n", + " \n", + " assert output_mtx_sum == input_mtx_sum" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "da9761de-2fec-4ba5-a5c1-f0f276398195", + "metadata": {}, + "outputs": [], + "source": [ + "input_matrix.close()\n", + "output_matrix.close()" + ] + } + ], + "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" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + }, + "vscode": { + "interpreter": { + "hash": "6969d5340a2324284ea9e82958789f0af31a889f2a17dbf954a94cd3bfb1e1ef" + } + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/ZoneAggDemo.ipynb b/notebooks/ZoneAggDemo.ipynb new file mode 100644 index 0000000..310db9d --- /dev/null +++ b/notebooks/ZoneAggDemo.ipynb @@ -0,0 +1,555 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": null, + "id": "a845c147", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "import os\n", + "\n", + "from sandag_rsm.data_load.zones import load_mgra_data\n", + "from sandag_rsm.data_load.triplist import load_trip_list, trip_mode_shares_by_mgra, \\\n", + " trip_mode_shares_by_taz\n", + "from sandag_rsm.poi import poi_taz_mgra, attach_poi_taz_skims\n", + "from sandag_rsm.zone_agg import aggregate_zones, viewer, viewer2, \\\n", + " aggregate_zones_within_districts, merge_zone_data, make_crosswalk, \\\n", + " mark_centroids" + ] + }, + { + "cell_type": "markdown", + "id": "73a4f97c", + "metadata": { + "pycharm": { + "name": "#%% md\n" + } + }, + "source": [ + "## Remote I/O" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "542ccfa1", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "from sandag_rsm.data_load import get_test_file\n", + "data_dir = \"./data-dl/\"\n", + "\n", + "mgra_filename = \"mgra13_based_input2016.csv.gz\"\n", + "skim_filename = \"traffic_skims_AM_mini.omx\"\n", + "trips_filename = \"trips_sample.pq\"\n", + "\n", + "get_test_file([\n", + " mgra_filename, \n", + " trips_filename, \n", + " skim_filename, \n", + "], data_dir)" + ] + }, + { + "cell_type": "markdown", + "id": "4b5e3239", + "metadata": {}, + "source": [ + "## Demo" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b8dc27e3", + "metadata": {}, + "outputs": [], + "source": [ + "mgra = load_mgra_data(data_dir=data_dir, simplify_tolerance=10, topo=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ae5d7f1c", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "mgra['taz20'] = mgra.taz % 20" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e6d1c5ef", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "trips = load_trip_list(\"trips_sample.pq\", data_dir=data_dir)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4bb2cb35", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "tazs = merge_zone_data(mgra, cluster_id=\"taz\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f3593b1c", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "trip_mode_shares = trip_mode_shares_by_taz(trips, tazs=tazs.index, mgra_gdf=mgra)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e64f7a0b", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "tazs = tazs.join(trip_mode_shares.add_prefix(\"modeshare_\"), on='taz')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "65c404fa", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "poi = poi_taz_mgra(mgra)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "569cfadc", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "poi" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2c974741", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "cluster_factors={'popden':1, 'empden':1, 'modeshare_NM':100, 'modeshare_WT':100}" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6cd4cee2", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "tazs, cluster_factors = attach_poi_taz_skims(\n", + " tazs,\n", + " \"traffic_skims_AM_mini.omx\",\n", + " names='AM_SOV_TR_M_TIME',\n", + " poi=poi,\n", + " data_dir=data_dir,\n", + " cluster_factors=cluster_factors,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "772c319e", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "explicit_agg=[\n", + "# 571, 588, 606, \n", + "# [143, 270, 15],\n", + "]\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "2f7c2125", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "d1 = tazs.query(\"district27 == 1\")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a93bd34a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "viewer(d1, color='popden', marker_line_width=0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "073d0c19", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "viewer(d1, color='outside_pendleton_gate_AM_SOV_TR_M_TIME', marker_line_width=0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f66915c5", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "viewer(d1, color='modeshare_WT', marker_line_width=0)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "61b2c6c7", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "cluster_factors" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3234d883", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "kmeans1 = aggregate_zones(\n", + " d1, \n", + " cluster_factors=cluster_factors, \n", + " n_zones=100,\n", + " explicit_agg=explicit_agg,\n", + " explicit_col='taz',\n", + " use_xy=1e-6,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b50a4bc3", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "viewer2(edges=kmeans1, colors=d1, color_col='empden')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "872ac31b", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "from sandag_rsm.zone_agg import aggregate_zones_within_districts\n", + "\n", + "kmeans = aggregate_zones_within_districts(\n", + " tazs, \n", + " cluster_factors=cluster_factors, \n", + " n_zones=1000,\n", + " use_xy=1e-6,\n", + " explicit_agg=explicit_agg,\n", + " explicit_col='taz',\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f5d6cd56", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "kmeans = kmeans.reset_index(drop=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e7b56ea", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "viewer2(edges=kmeans, colors=kmeans, color_col='empden')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "aa31c88d", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "agglom3full = aggregate_zones(\n", + " tazs, \n", + " cluster_factors=cluster_factors, \n", + " n_zones=2000,\n", + " method='agglom_adj', \n", + " use_xy=1e-4,\n", + " explicit_agg=explicit_agg,\n", + " explicit_col='taz',\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "7e8cec6a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "taz_crosswalk = make_crosswalk(agglom3full, tazs, old_index='taz').sort_values('taz')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "736eac0a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "mgra_crosswalk = make_crosswalk(agglom3full, mgra, old_index='MGRA').sort_values('MGRA')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "71956608", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "agglom3full = mark_centroids(agglom3full)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a11469a8", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "mgra_crosswalk.to_csv(\"mgra_crosswalk.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "00c3e83e", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "taz_crosswalk.to_csv(\"taz_crosswalk.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ecdfc521", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "agglom3full.to_csv(\"cluster_zones.csv\", index=False)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "18d6902a", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "viewer2(edges=agglom3full, colors=agglom3full, color_col='empden')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "391a94af", + "metadata": { + "pycharm": { + "name": "#%%\n" + } + }, + "outputs": [], + "source": [ + "viewer2(edges=agglom3full, colors=agglom3full, color_col='popden')" + ] + } + ], + "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.10.6" + }, + "toc": { + "base_numbering": 1, + "nav_menu": {}, + "number_sections": false, + "sideBar": true, + "skip_h1_title": false, + "title_cell": "Table of Contents", + "title_sidebar": "Contents", + "toc_cell": false, + "toc_position": {}, + "toc_section_display": true, + "toc_window_display": false + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/notebooks/data-dl/.gitignore b/notebooks/data-dl/.gitignore new file mode 100644 index 0000000..928939a --- /dev/null +++ b/notebooks/data-dl/.gitignore @@ -0,0 +1,5 @@ +*.csv +*.csv.gz +*.gpkg +*.omx +*.pq diff --git a/sandag_abm/src/main/emme/init_emme_project.py b/sandag_abm/src/main/emme/init_emme_project.py new file mode 100644 index 0000000..2809405 --- /dev/null +++ b/sandag_abm/src/main/emme/init_emme_project.py @@ -0,0 +1,97 @@ +#/////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2019. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// init_emme_project.py /// +#//// /// +#//// Usage: init_emme_project.py [-r root] [-t title] /// +#//// /// +#//// [-r root]: Specifies the root directory in which to create /// +#//// the Emme project. /// +#//// If omitted, defaults to the current working directory /// +#//// [-t title]: The title of the Emme project and Emme database. /// +#//// If omitted, defaults to SANDAG empty database. /// +#//// [-v emmeversion]: Emme version to use to create the project. /// +#//// If omitted, defaults to 4.3.7. /// +#//// /// +#//// /// +#//// /// +#//// /// +#/////////////////////////////////////////////////////////////////////////////// + +import inro.emme.desktop.app as _app +import inro.emme.desktop.types as _ws_types +import inro.emme.database.emmebank as _eb +import argparse +import os + +WKT_PROJECTION = 'PROJCS["NAD_1983_NSRS2007_StatePlane_California_VI_FIPS_0406_Ft_US",GEOGCS["GCS_NAD_1983_NSRS2007",DATUM["D_NAD_1983_NSRS2007",SPHEROID["GRS_1980",6378137.0,298.257222101]],PRIMEM["Greenwich",0.0],UNIT["Degree",0.0174532925199433]],PROJECTION["Lambert_Conformal_Conic"],PARAMETER["False_Easting",6561666.666666666],PARAMETER["False_Northing",1640416.666666667],PARAMETER["Central_Meridian",-116.25],PARAMETER["Standard_Parallel_1",32.78333333333333],PARAMETER["Standard_Parallel_2",33.88333333333333],PARAMETER["Latitude_Of_Origin",32.16666666666666],UNIT["Foot_US",0.3048006096012192]];-118608900 -91259500 3048.00609601219;-100000 10000;-100000 10000;3.28083333333333E-03;0.001;0.001;IsHighPrecision' + +def init_emme_project(root, title, emmeversion): + project_path = _app.create_project(root, "emme_project") + desktop = _app.start_dedicated( + project=project_path, user_initials="WS", visible=False) + project = desktop.project + project.name = "SANDAG Emme project" + prj_file_path = os.path.join(os.path.dirname(project_path), 'NAD 1983 NSRS2007 StatePlane California VI FIPS 0406 (US Feet).prj') + with open(prj_file_path, 'w') as f: + f.write(WKT_PROJECTION) + project.spatial_reference_file = prj_file_path + project.initial_view = _ws_types.Box(6.18187e+06, 1.75917e+06, 6.42519e+06, 1.89371e+06) + project_root = os.path.dirname(project_path) + dimensions = { + 'scalar_matrices': 9999, + 'destination_matrices': 999, + 'origin_matrices': 999, + 'full_matrices': 1600, + + 'scenarios': 10, + 'centroids': 5000, + 'regular_nodes': 29999, + 'links': 90000, + 'turn_entries': 13000, + 'transit_vehicles': 200, + 'transit_lines': 450, + 'transit_segments': 40000, + 'extra_attribute_values': 28000000, + + 'functions': 99, + 'operators': 5000 + } + + # for Emme version > 4.3.7, add the sola_analyses dimension + if emmeversion != '4.3.7': + dimensions['sola_analyses'] = 240 + + os.mkdir(os.path.join(project_root, "Database")) + emmebank = _eb.create(os.path.join(project_root, "Database", "emmebank"), dimensions) + emmebank.title = title + emmebank.coord_unit_length = 0.000189394 # feet to miles + emmebank.unit_of_length = "mi" + emmebank.unit_of_cost = "$" + emmebank.unit_of_energy = "MJ" + emmebank.node_number_digits = 6 + emmebank.use_engineering_notation = True + scenario = emmebank.create_scenario(100) + scenario.title = "Empty scenario" + emmebank.dispose() + + desktop.data_explorer().add_database(emmebank.path) + desktop.add_modeller_toolbox("%<$ProjectPath>%/scripts/sandag_toolbox.mtbx") + desktop.add_modeller_toolbox("%<$ProjectPath>%/scripts/solutions.mtbx") + project.save() + + +if __name__ == "__main__": + parser = argparse.ArgumentParser(description="Create a new empty Emme project and database with Sandag defaults.") + parser.add_argument('-r', '--root', help="path to the root ABM folder, default is the working folder", + default=os.path.abspath(os.getcwd())) + parser.add_argument('-t', '--title', help="the Emmebank title", + default="SANDAG empty database") + parser.add_argument('-v', '--emmeversion', help='the Emme version', default='4.3.7') + args = parser.parse_args() + + init_emme_project(args.root, args.title, args.emmeversion) diff --git a/sandag_abm/src/main/emme/python_virtualenv.pth b/sandag_abm/src/main/emme/python_virtualenv.pth new file mode 100644 index 0000000..c169252 --- /dev/null +++ b/sandag_abm/src/main/emme/python_virtualenv.pth @@ -0,0 +1,3 @@ +# Inserts defined python_virtualenv site-packages into the python module search path if defined +# +import sys, os; r=os.environ.get("PYTHON_VIRTUALENV"); t = 1 if r is None else sys.path.insert(0, os.path.join(r, "Lib\site-packages")); \ No newline at end of file diff --git a/sandag_abm/src/main/emme/solutions.mtbx b/sandag_abm/src/main/emme/solutions.mtbx new file mode 100644 index 0000000..10d5345 Binary files /dev/null and b/sandag_abm/src/main/emme/solutions.mtbx differ diff --git a/sandag_abm/src/main/emme/solutions_unconsolidated.mtbx b/sandag_abm/src/main/emme/solutions_unconsolidated.mtbx new file mode 100644 index 0000000..0674c2b Binary files /dev/null and b/sandag_abm/src/main/emme/solutions_unconsolidated.mtbx differ diff --git a/sandag_abm/src/main/emme/toolbox/assignment/build_transit_scenario.py b/sandag_abm/src/main/emme/toolbox/assignment/build_transit_scenario.py new file mode 100644 index 0000000..ec8d4a9 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/assignment/build_transit_scenario.py @@ -0,0 +1,679 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// build_transit_scenario.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# The build transit scenario tool generates a new scenario in the Transit +# database (under the Database_transit directory) as a copy of a scenario in +# the base (traffic assignment) database. The base traffic scenario should have +# valid results from a traffic assignment for the travel times on links to be +# available for transit lines in mixed traffic operation. +# +# +# Inputs: +# period: the corresponding period for the scenario +# base_scenario_id: the base traffic assignment scenario in the main Emme database +# scenario_id: the ID to use for the new scenario in the Transit Emme database +# scenario_title: the title for the new scenario +# data_table_name: the root name for the source data table for the timed transfer +# line pairs and the day and regional pass costs. +# Usually the ScenarioYear +# overwrite: overwrite the scenario if it already exists. +# +# +# Script example: +""" +import inro.modeller as _m +import os +modeller = _m.Modeller() +desktop = modeller.desktop + +build_transit_scen = modeller.tool("sandag.assignment.build_transit_scenario") +transit_assign = modeller.tool("sandag.assignment.transit_assignment") +load_properties = modeller.tool('sandag.utilities.properties') + +project_dir = os.path.dirname(desktop.project_path()) +main_directory = os.path.dirname(project_dir) +props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) +main_emmebank = os.path.join(project_dir, "Database", "emmebank") +scenario_id = 100 +base_scenario = main_emmebank.scenario(scenario_id) + +transit_emmebank = os.path.join(project_dir, "Database_transit", "emmebank") + +periods = ["EA", "AM", "MD", "PM", "EV"] +period_ids = list(enumerate(periods, start=int(scenario_id) + 1)) +num_processors = "MAX-1" +scenarioYear = str(props["scenarioYear"]) + +for number, period in period_ids: + src_period_scenario = main_emmebank.scenario(number) + transit_assign_scen = build_transit_scen( + period=period, base_scenario=src_period_scenario, + transit_emmebank=transit_emmebank, + scenario_id=src_period_scenario.id, + scenario_title="%s %s transit assign" % (base_scenario.title, period), + data_table_name=scenarioYear, overwrite=True) + transit_assign(period, transit_assign_scen, data_table_name=scenarioYear, + skims_only=True, num_processors=num_processors) +""" + + + +TOOLBOX_ORDER = 21 + + +import inro.modeller as _m +import inro.emme.core.exception as _except +import inro.emme.database.emmebank as _eb +import traceback as _traceback +from copy import deepcopy as _copy +from collections import defaultdict as _defaultdict +import contextlib as _context + +import os +import sys +import math + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + + +class BuildTransitNetwork(_m.Tool(), gen_utils.Snapshot): + + period = _m.Attribute(unicode) + scenario_id = _m.Attribute(int) + base_scenario_id = _m.Attribute(str) + + data_table_name = _m.Attribute(unicode) + scenario_title = _m.Attribute(unicode) + overwrite = _m.Attribute(bool) + + tool_run_msg = "" + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self.data_table_name = None + self.base_scenario = _m.Modeller().scenario + self.scenario_id = 100 + self.scenario_title = "" + self.overwrite = False + self.attributes = [ + "period", "scenario_id", "base_scenario_id", + "data_table_name", "scenario_title", "overwrite"] + + def page(self): + if not self.data_table_name: + load_properties = _m.Modeller().tool('sandag.utilities.properties') + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + main_directory = os.path.dirname(project_dir) + props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) + self.data_table_name = props["scenarioYear"] + + pb = _m.ToolPageBuilder(self) + pb.title = "Build transit network" + pb.description = """ + Builds the transit network for the specified period based + on existing base (traffic + transit) scenario.""" + pb.branding_text = "- SANDAG - " + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + options = [("EA", "Early AM"), + ("AM", "AM peak"), + ("MD", "Mid-day"), + ("PM", "PM peak"), + ("EV", "Evening")] + pb.add_select("period", options, title="Period:") + + root_dir = os.path.dirname(_m.Modeller().desktop.project.path) + main_emmebank = _eb.Emmebank(os.path.join(root_dir, "Database", "emmebank")) + options = [(scen.id, "%s - %s" % (scen.id, scen.title)) for scen in main_emmebank.scenarios()] + pb.add_select("base_scenario_id", options, + title="Base scenario (with traffic and transit data):", + note="With period traffic results from main (traffic assignment) database at:
%s" % main_emmebank.path) + + pb.add_text_box("scenario_id", title="ID for transit assignment scenario:") + pb.add_text_box("scenario_title", title="Scenario title:", size=80) + pb.add_text_box("data_table_name", title="Data table prefix name:", note="Default is the ScenarioYear") + pb.add_checkbox("overwrite", title=" ", label="Overwrite existing scenario") + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + root_dir = os.path.dirname(_m.Modeller().desktop.project.path) + main_emmebank = _eb.Emmebank(os.path.join(root_dir, "Database", "emmebank")) + base_scenario = main_emmebank.scenario(self.base_scenario_id) + transit_emmebank = _eb.Emmebank(os.path.join(root_dir, "Database_transit", "emmebank")) + results = self( + self.period, base_scenario, transit_emmebank, + self.scenario_id, self.scenario_title, + self.data_table_name, self.overwrite) + run_msg = "Transit scenario created" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, period, base_scenario, transit_emmebank, scenario_id, scenario_title, + data_table_name, overwrite=False): + modeller = _m.Modeller() + attrs = { + "period": period, + "base_scenario_id": base_scenario.id, + "transit_emmebank": transit_emmebank.path, + "scenario_id": scenario_id, + "scenario_title": scenario_title, + "data_table_name": data_table_name, + "overwrite": overwrite, + "self": str(self) + } + with _m.logbook_trace("Build transit network for period %s" % period, attributes=attrs): + gen_utils.log_snapshot("Build transit network", str(self), attrs) + copy_scenario = modeller.tool( + "inro.emme.data.scenario.copy_scenario") + periods = ["EA", "AM", "MD", "PM", "EV"] + if not period in periods: + raise Exception( + 'period: unknown value - specify one of %s' % periods) + + transit_assignment = modeller.tool( + "sandag.assignment.transit_assignment") + if transit_emmebank.scenario(scenario_id): + if overwrite: + transit_emmebank.delete_scenario(scenario_id) + else: + raise Exception("scenario_id: scenario %s already exists" % scenario_id) + + scenario = transit_emmebank.create_scenario(scenario_id) + scenario.title = scenario_title[:80] + scenario.has_traffic_results = base_scenario.has_traffic_results + scenario.has_transit_results = base_scenario.has_transit_results + for attr in sorted(base_scenario.extra_attributes(), key=lambda x: x._id): + dst_attr = scenario.create_extra_attribute(attr.type, attr.name, attr.default_value) + dst_attr.description = attr.description + for field in base_scenario.network_fields(): + scenario.create_network_field(field.type, field.name, field.atype, field.description) + network = base_scenario.get_network() + new_attrs = [ + ("TRANSIT_LINE", "@xfer_from_day", "Fare for xfer from daypass/trolley"), + ("TRANSIT_LINE", "@xfer_from_premium", "Fare for first xfer from premium"), + ("TRANSIT_LINE", "@xfer_from_coaster", "Fare for first xfer from coaster"), + ("TRANSIT_LINE", "@xfer_regional_pass", "0-fare for regional pass"), + ("TRANSIT_SEGMENT", "@xfer_from_bus", "Fare for first xfer from bus"), + ("TRANSIT_SEGMENT", "@headway_seg", "Headway adj for special xfers"), + ("TRANSIT_SEGMENT", "@transfer_penalty_s", "Xfer pen adj for special xfers"), + ("TRANSIT_SEGMENT", "@layover_board", "Boarding cost adj for special xfers"), + ("NODE", "@network_adj", "Model: 1=TAP adj, 2=circle, 3=timedxfer"), + ("NODE", "@network_adj_src", "Orig src node for timedxfer splits"), + ] + for elem, name, desc in new_attrs: + attr = scenario.create_extra_attribute(elem, name) + attr.description = desc + network.create_attribute(elem, name) + network.create_attribute("TRANSIT_LINE", "xfer_from_bus") + self._init_node_id(network) + + transit_passes = gen_utils.DataTableProc("%s_transit_passes" % data_table_name) + transit_passes = {row["pass_type"]: row["cost"] for row in transit_passes} + day_pass = float(transit_passes["day_pass"]) / 2.0 + regional_pass = float(transit_passes["regional_pass"]) / 2.0 + params = transit_assignment.get_perception_parameters(period) + mode_groups = transit_assignment.group_modes_by_fare(network, day_pass) + + bus_fares = {} + for mode_id, fares in mode_groups["bus"]: + for fare, count in fares.items(): + bus_fares[fare] = bus_fares.get(fare, 0) + count + # set nominal bus fare as unweighted average of two most frequent fares + bus_fares = sorted(bus_fares.items(), key=lambda x: x[1], reverse=True) + + if len(bus_fares) >= 2: + bus_fare = (bus_fares[0][0] + bus_fares[1][0]) / 2 + elif len(bus_fares) == 1: # unless there is only one fare value, in which case use that one + bus_fare = bus_fares[0][0] + else: + bus_fare = 0 + # find max premium mode fare + premium_fare = 0 + for mode_id, fares in mode_groups["premium"]: + for fare in fares.keys(): + premium_fare = max(premium_fare, fare) + # find max coaster_fare by checking the cumulative fare along each line + coaster_fare = 0 + for line in network.transit_lines(): + if line.mode.id != "c": + continue + segments = line.segments() + first = segments.next() + fare = first["@coaster_fare_board"] + for seg in segments: + fare += seg["@coaster_fare_inveh"] + coaster_fare = max(coaster_fare, fare) + + bus_fare_modes = [x[0] for x in mode_groups["bus"]] # have a bus fare, less than the day pass + day_pass_modes = [x[0] for x in mode_groups["day_pass"]] # boarding fare is the same as the day pass + premium_fare_modes = ["c"] + [x[0] for x in mode_groups["premium"]] # special premium services not covered by day pass + + for line in list(network.transit_lines()): + # remove the "unavailable" lines in this period + if line[params["xfer_headway"]] == 0: + network.delete_transit_line(line) + continue + # Adjust fare perception by VOT + line[params["fare"]] = line[params["fare"]] / params["vot"] + # set the fare increments for transfer combinations with day pass / regional pass + if line.mode.id in bus_fare_modes: + line["xfer_from_bus"] = max(min(day_pass - line["@fare"], line["@fare"]), 0) + line["@xfer_from_day"] = 0.0 + line["@xfer_from_premium"] = max(min(regional_pass - premium_fare, line["@fare"]), 0) + line["@xfer_from_coaster"] = max(min(regional_pass - coaster_fare, line["@fare"]), 0) + elif line.mode.id in day_pass_modes: + line["xfer_from_bus"] = max(day_pass - bus_fare, 0.0) + line["@xfer_from_day"] = 0.0 + line["@xfer_from_premium"] = max(min(regional_pass - premium_fare, line["@fare"]), 0) + line["@xfer_from_coaster"] = max(min(regional_pass - coaster_fare, line["@fare"]), 0) + elif line.mode.id in premium_fare_modes: + if line["@fare"] > day_pass or line.mode.id == "c": + # increment from bus to regional + line["xfer_from_bus"] = max(regional_pass - bus_fare, 0) + line["@xfer_from_day"] = max(regional_pass - day_pass, 0) + else: + # some "premium" modes lines are really regular fare + # increment from bus to day pass + line["xfer_from_bus"] = max(day_pass - bus_fare, 0) + line["@xfer_from_day"] = 0.0 + line["@xfer_from_premium"] = max(regional_pass - premium_fare, 0) + line["@xfer_from_coaster"] = max(min(regional_pass - coaster_fare, line["@fare"]), 0) + + for segment in network.transit_segments(): + line = segment.line + segment["@headway_seg"] = line[params["xfer_headway"]] + segment["@transfer_penalty_s"] = line["@transfer_penalty"] + segment["@xfer_from_bus"] = line["xfer_from_bus"] + network.delete_attribute("TRANSIT_LINE", "xfer_from_bus") + + self.taps_to_centroids(network) + # changed to allow timed xfers for different periods + timed_transfers_with_walk = list(gen_utils.DataTableProc("%s_timed_xfer_%s" % (data_table_name,period))) + self.timed_transfers(network, timed_transfers_with_walk, period) + #self.connect_circle_lines(network) + self.duplicate_tap_adajcent_stops(network) + # The fixed guideway travel times are stored in "@trtime_link_xx" + # and copied to data2 (ul2) for the ttf + # The congested auto times for mixed traffic are in "@auto_time" + # (output from traffic assignment) which needs to be copied to auto_time (a.k.a. timau) + # (The auto_time attribute is generated from the VDF values which include reliability factor) + src_attrs = [params["fixed_link_time"]] + dst_attrs = ["data2"] + if scenario.has_traffic_results and "@auto_time" in scenario.attributes("LINK"): + src_attrs.append("@auto_time") + dst_attrs.append("auto_time") + values = network.get_attribute_values("LINK", src_attrs) + network.set_attribute_values("LINK", dst_attrs, values) + scenario.publish_network(network) + + return scenario + + @_m.logbook_trace("Convert TAP nodes to centroids") + def taps_to_centroids(self, network): + # delete existing traffic centroids + for centroid in list(network.centroids()): + network.delete_node(centroid, cascade=True) + + node_attrs = network.attributes("NODE") + link_attrs = network.attributes("LINK") + for node in list(network.nodes()): + if node["@tap_id"] > 0: + centroid = network.create_node(node["@tap_id"], is_centroid=True) + for attr in node_attrs: + centroid[attr] = node[attr] + for link in node.outgoing_links(): + connector = network.create_link(centroid, link.j_node, link.modes) + connector.vertices = link.vertices + for attr in link_attrs: + connector[attr] = link[attr] + for link in node.incoming_links(): + connector = network.create_link(link.i_node, centroid, link.modes) + connector.vertices = link.vertices + for attr in link_attrs: + connector[attr] = link[attr] + network.delete_node(node, cascade=True) + + @_m.logbook_trace("Duplicate TAP access and transfer access stops") + def duplicate_tap_adajcent_stops(self, network): + # Expand network by duplicating TAP adjacent stops + network.create_attribute("NODE", "tap_stop", False) + all_transit_modes = set([mode for mode in network.modes() if mode.type == "TRANSIT"]) + access_mode = set([network.mode("a")]) + transfer_mode = network.mode("x") + walk_mode = network.mode("w") + + # Mark TAP adjacent stops and split TAP connectors + for centroid in network.centroids(): + out_links = list(centroid.outgoing_links()) + in_links = list(centroid.incoming_links()) + for link in out_links + in_links: + link.length = 0.0005 # setting length so that connector access time = 0.01 + for link in out_links: + real_stop = link.j_node + has_adjacent_transfer_links = False + has_adjacent_walk_links = False + for stop_link in real_stop.outgoing_links(): + if stop_link == link.reverse_link: + continue + if transfer_mode in stop_link.modes : + has_adjacent_transfer_links = True + if walk_mode in stop_link.modes : + has_adjacent_walk_links = True + + if has_adjacent_transfer_links or has_adjacent_walk_links: + length = link.length + tap_stop = network.split_link(centroid, real_stop, self._get_node_id(), include_reverse=True) + tap_stop["@network_adj"] = 1 + real_stop.tap_stop = tap_stop + transit_access_link = network.link(real_stop, tap_stop) + for link in transit_access_link, transit_access_link.reverse_link: + link.modes = all_transit_modes + link.length = 0 + for p in ["ea", "am", "md", "pm", "ev"]: + link["@time_link_" + p] = 0 + access_link = network.link(tap_stop, centroid) + access_link.modes = access_mode + access_link.reverse_link.modes = access_mode + access_link.length = length + access_link.reverse_link.length = length + + line_attributes = network.attributes("TRANSIT_LINE") + seg_attributes = network.attributes("TRANSIT_SEGMENT") + + # re-route the transit lines through the new TAP-stops + for line in network.transit_lines(): + # store line and segment data for re-routing + line_data = dict((k, line[k]) for k in line_attributes) + line_data["id"] = line.id + line_data["vehicle"] = line.vehicle + + seg_data = {} + itinerary = [] + tap_adjacent_stops = [] + + for seg in line.segments(include_hidden=True): + seg_data[(seg.i_node, seg.j_node, seg.loop_index)] = \ + dict((k, seg[k]) for k in seg_attributes) + itinerary.append(seg.i_node.number) + if seg.i_node.tap_stop and seg.allow_boardings: + # insert tap_stop, real_stop loop after tap_stop + real_stop = seg.i_node + tap_stop = real_stop.tap_stop + itinerary.extend([tap_stop.number, real_stop.number]) + tap_adjacent_stops.append(len(itinerary) - 1) # index of "real" stop in itinerary + + if tap_adjacent_stops: + network.delete_transit_line(line) + new_line = network.create_transit_line( + line_data.pop("id"), + line_data.pop("vehicle"), + itinerary) + for k, v in line_data.iteritems(): + new_line[k] = v + + for seg in new_line.segments(include_hidden=True): + data = seg_data.get((seg.i_node, seg.j_node, seg.loop_index), {}) + for k, v in data.iteritems(): + seg[k] = v + for index in tap_adjacent_stops: + access_seg = new_line.segment(index - 2) + egress_seg = new_line.segment(index - 1) + real_seg = new_line.segment(index) + for k in seg_attributes: + access_seg[k] = egress_seg[k] = real_seg[k] + access_seg.allow_boardings = False + access_seg.allow_alightings = True + access_seg.transit_time_func = 3 + access_seg.dwell_time = real_seg.dwell_time + egress_seg.allow_boardings = True + egress_seg.allow_alightings = True + egress_seg.transit_time_func = 3 + egress_seg.dwell_time = 0 + real_seg.allow_boardings = True + real_seg.allow_alightings = False + real_seg.dwell_time = 0 + + network.delete_attribute("NODE", "tap_stop") + + @_m.logbook_trace("Add timed-transfer links", save_arguments=True) + def timed_transfers(self, network, timed_transfers_with_walk, period): + no_walk_link_error = "no walk link from line %s to %s" + node_not_found_error = "node %s not found in itinerary for line %s; "\ + "the to_line may end at the transfer stop" + + def find_walk_link(from_line, to_line): + to_nodes = set([s.i_node for s in to_line.segments(True) + if s.allow_boardings]) + link_candidates = [] + for seg in from_line.segments(True): + if not s.allow_alightings: + continue + for link in seg.i_node.outgoing_links(): + if link.j_node in to_nodes: + link_candidates.append(link) + if not link_candidates: + raise Exception(no_walk_link_error % (from_line, to_line)) + # if there are multiple connecting links take the shortest one + return sorted(link_candidates, key=lambda x: x.length)[0] + + def link_on_line(line, node, near_side_stop): + node = network.node(node) + if near_side_stop: + for seg in line.segments(): + if seg.j_node == node: + return seg.link + else: + for seg in line.segments(): + if seg.i_node == node: + return seg.link + raise Exception(node_not_found_error % (node, line)) + + # Group parallel transfers together (same pair of alighting-boarding nodes from the same line) + walk_transfers = _defaultdict(lambda: []) + for i, transfer in enumerate(timed_transfers_with_walk, start=1): + try: + from_line = network.transit_line(transfer["from_line"]) + if not from_line: + raise Exception("from_line %s does not exist" % transfer["from_line"]) + to_line = network.transit_line(transfer["to_line"]) + if not to_line: + raise Exception("to_line %s does not exist" % transfer["to_line"]) + walk_link = find_walk_link(from_line, to_line) + from_link = link_on_line(from_line, walk_link.i_node, near_side_stop=True) + to_link = link_on_line(to_line, walk_link.j_node, near_side_stop=False) + walk_transfers[(from_link, to_link)].append({ + "to_line": to_line, + "from_line": from_line, + "walk_link": walk_link, + "wait": transfer["wait_time"], + }) + except Exception as error: + new_message = "Timed transfer[%s]: %s" % (i, error.message) + raise type(error), type(error)(new_message), sys.exc_info()[2] + + # If there is only one transfer at the location (redundant case) + # OR all transfers are from the same line (can have different waits) + # OR all transfers are to the same line and have the same wait + # Merge all transfers onto the same transfer node + network_transfers = [] + for (from_link, to_link), transfers in walk_transfers.iteritems(): + walk_links = set([t["walk_link"] for t in transfers]) + from_lines = set([t["from_line"] for t in transfers]) + to_lines = set([t["to_line"] for t in transfers]) + waits = set(t["wait"] for t in transfers) + if len(transfers) == 1 or len(from_lines) == 1 or (len(to_lines) == 1 and len(waits) == 1): + network_transfers.append({ + "from_link": from_link, + "to_link": to_link, + "to_lines": list(to_lines), + "from_lines": list(from_lines), + "walk_link": walk_links.pop(), + "wait": dict((t["to_line"], t["wait"]) for t in transfers)}) + else: + for transfer in transfers: + network_transfers.append({ + "from_link": from_link, + "to_link": to_link, + "to_lines": [transfer["to_line"]], + "from_lines": [transfer["from_line"]], + "walk_link": transfer["walk_link"], + "wait": {transfer["to_line"]: transfer["wait"]}}) + + def split_link(link, node_id, lines, split_links, stop_attr, waits=None): + near_side_stop = (stop_attr == "allow_alightings") + orig_link = link + if link in split_links: + link = split_links[link] + i_node, j_node = link.i_node, link.j_node + length = link.length + proportion = min(0.006 / length, 0.2) + if near_side_stop: + proportion = 1 - proportion + new_node = network.split_link(i_node, j_node, node_id, False, proportion) + new_node["@network_adj"] = 3 + new_node["@network_adj_src"] = orig_link.j_node.number if near_side_stop else orig_link.i_node.number + in_link = network.link(i_node, new_node) + out_link = network.link(new_node, j_node) + split_links[orig_link] = in_link if near_side_stop else out_link + if near_side_stop: + in_link.length = length + out_link.length = 0 + for p in ["ea", "am", "md", "pm", "ev"]: + out_link["@trtime_link_" + p] = 0 + else: + out_link.length = length + in_link.length = 0 + for p in ["ea", "am", "md", "pm", "ev"]: + in_link["@trtime_link_" + p] = 0 + + for seg in in_link.segments(): + if not near_side_stop: + seg.transit_time_func = 3 + seg["@coaster_fare_inveh"] = 0 + for seg in out_link.segments(): + if near_side_stop: + seg.transit_time_func = 3 + seg.allow_alightings = seg.allow_boardings = False + seg.dwell_time = 0 + if seg.line in lines: + seg[stop_attr] = True + if stop_attr == "allow_boardings": + seg["@headway_seg"] = float(waits[seg.line]) * 2 + return new_node + + # process the transfer points, split links and set attributes + split_links = {} + for transfer in network_transfers: + new_alight_node = split_link( + transfer["from_link"], self._get_node_id(), transfer["from_lines"], + split_links, "allow_alightings") + new_board_node = split_link( + transfer["to_link"], self._get_node_id(), transfer["to_lines"], + split_links, "allow_boardings", waits=transfer["wait"]) + walk_link = transfer["walk_link"] + transfer_link = network.create_link( + new_alight_node, new_board_node, [network.mode("x")]) + for attr in network.attributes("LINK"): + transfer_link[attr] = walk_link[attr] + + @_m.logbook_trace("Add circle line free layover transfers") + def connect_circle_lines(self, network): + network.create_attribute("NODE", "circle_lines") + line_attributes = network.attributes("TRANSIT_LINE") + seg_attributes = network.attributes("TRANSIT_SEGMENT") + + def offset_coords(node): + rho = math.sqrt(5000) + phi = 3 * math.pi / 4 + node.circle_lines * math.pi / 12 + x = node.x + rho * math.cos(phi) + y = node.y + rho * math.sin(phi) + node.circle_lines += 1 + return(x, y) + + transit_lines = list(network.transit_lines()) + for line in transit_lines: + first_seg = line.segment(0) + last_seg = line.segment(-1) + if first_seg.i_node == last_seg.i_node: + # Add new node, offset from existing node + start_node = line.segment(0).i_node + xfer_node = network.create_node(self._get_node_id(), False) + xfer_node["@network_adj"] = 2 + xfer_node.x, xfer_node.y = offset_coords(start_node) + network.create_link(start_node, xfer_node, [line.vehicle.mode]) + network.create_link(xfer_node, start_node, [line.vehicle.mode]) + + # copy transit line data, re-route itinerary to and from new node + line_data = dict((k, line[k]) for k in line_attributes) + line_data["id"] = line.id + line_data["vehicle"] = line.vehicle + first_seg.allow_boardings = True + first_seg.allow_alightings = False + first_seg_data = dict((k, first_seg[k]) for k in seg_attributes) + first_seg_data.update({ + "@headway_seg": 0.01, "dwell_time": 0, "transit_time_func": 3, + "@transfer_penalty_s": 0, "@xfer_from_bus": 0, "@layover_board": 1 + }) + last_seg.allow_boardings = False + last_seg.allow_alightings = True + last_seg_data = dict((k, last_seg[k]) for k in seg_attributes) + last_seg_data.update({ + "@headway_seg": 0.01, "dwell_time": 5.0, "transit_time_func": 3 + # incremental dwell time for layover of 5 min + # Note: some lines seem to have a layover of 0, most of 5 mins + }) + seg_data = { + (xfer_node, start_node, 1): first_seg_data, + (xfer_node, None, 1): last_seg_data} + itinerary = [xfer_node.number] + for seg in line.segments(): + seg_data[(seg.i_node, seg.j_node, seg.loop_index)] = dict((k, seg[k]) for k in seg_attributes) + itinerary.append(seg.i_node.number) + last_seg = line.segment(-1) + seg_data[(last_seg.i_node, xfer_node, 1)] = dict((k, last_seg[k]) for k in seg_attributes) + seg_data[(last_seg.i_node, xfer_node, 1)]["transit_time_func"] = 3 + itinerary.extend([last_seg.i_node.number, xfer_node.number]) + + network.delete_transit_line(line) + new_line = network.create_transit_line( + line_data.pop("id"), line_data.pop("vehicle"), itinerary) + for k, v in line_data.iteritems(): + new_line[k] = v + for seg in new_line.segments(include_hidden=True): + data = seg_data.get((seg.i_node, seg.j_node, seg.loop_index), {}) + for k, v in data.iteritems(): + seg[k] = v + + network.delete_attribute("NODE", "circle_lines") + + def _init_node_id(self, network): + new_node_id = max(n.number for n in network.nodes()) + self._new_node_id = math.ceil(new_node_id / 10000.0) * 10000 + + def _get_node_id(self): + self._new_node_id += 1 + return self._new_node_id diff --git a/sandag_abm/src/main/emme/toolbox/assignment/traffic_assignment.py b/sandag_abm/src/main/emme/toolbox/assignment/traffic_assignment.py new file mode 100644 index 0000000..cdf652e --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/assignment/traffic_assignment.py @@ -0,0 +1,1087 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// traffic_assignment.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# The Traffic assignment tool runs the traffic assignment and skims per +# period on the current primary scenario. +# +# The traffic assignment is a 15-class assignment with generalized cost on +# links and BPR-type volume-delay functions which include capacities on links +# and at intersection approaches. The assignment is run using the +# fast-converging Second-Order Linear Approximation (SOLA) method in Emme to +# a relative gap of 5x10-4. The per-link fixed costs include toll values and +# operating costs which vary by class of demand. +# Assignment matrices and resulting network flows are always in PCE. +# +# Inputs: +# period: the time-of-day period, one of EA, AM, MD, PM, EV. +# msa_iteration: global iteration number. If greater than 1, existing flow +# values must be present and the resulting flows on links and turns will +# be the weighted average of this assignment and the existing values. +# relative_gap: minimum relative stopping criteria. +# max_iterations: maximum iterations stopping criteria. +# num_processors: number of processors to use for the traffic assignments. +# select_link: specify one or more select link analysis setups as a list of +# specifications with three keys: +# "expression": selection expression to identify the link(s) of interest. +# "suffix": the suffix to use in the naming of per-class result +# attributes and matrices, up to 6 characters. +# "threshold": the minimum number of links which must be encountered +# for the path selection. +# Example: +# select_link = [ +# {"expression": "@tov_id=4578 or @tcov_id=9203", "suffix": "fwy", "threshold": "1"} +# ] +# raise_zero_dist: if checked, the distance skim for the SOVGP is checked for +# any zero values, which would indicate a disconnected zone, in which case +# an error is raised and the model run is halted. +# +# Matrices: +# All traffic demand and skim matrices. +# See list of classes under __call__ method, or matrix list under report method. +# +# Script example: +""" +import inro.modeller as _m +import os +import inro.emme.database.emmebank as _eb + +modeller = _m.Modeller() +desktop = modeller.desktop +traffic_assign = modeller.tool("sandag.assignment.traffic_assignment") +export_traffic_skims = modeller.tool("sandag.export.export_traffic_skims") +load_properties = modeller.tool('sandag.utilities.properties') +project_dir = os.path.dirname(_m.Modeller().desktop.project.path) +main_directory = os.path.dirname(project_dir) +output_dir = os.path.join(main_directory, "output") +props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) + + +main_emmebank = os.path.join(project_dir, "Database", "emmebank") +scenario_id = 100 +base_scenario = main_emmebank.scenario(scenario_id) + +periods = ["EA", "AM", "MD", "PM", "EV"] +period_ids = list(enumerate(periods, start=int(scenario_id) + 1)) + +msa_iteration = 1 +relative_gap = 0.0005 +max_assign_iterations = 100 +num_processors = "MAX-1" +select_link = None # Optional select link specification + +for number, period in period_ids: + period_scenario = main_emmebank.scenario(number) + traffic_assign(period, msa_iteration, relative_gap, max_assign_iterations, + num_processors, period_scenario, select_link) + omx_file = _join(output_dir, "traffic_skims_%s.omx" % period) + if msa_iteration < 4: + export_traffic_skims(period, omx_file, base_scenario) +""" + + +TOOLBOX_ORDER = 20 + + +import inro.modeller as _m +import inro.emme.core.exception as _except +import traceback as _traceback +from contextlib import contextmanager as _context +import numpy +import array +import os +import json as _json + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + + +class TrafficAssignment(_m.Tool(), gen_utils.Snapshot): + + period = _m.Attribute(unicode) + msa_iteration = _m.Attribute(int) + relative_gap = _m.Attribute(float) + max_iterations = _m.Attribute(int) + num_processors = _m.Attribute(str) + select_link = _m.Attribute(unicode) + raise_zero_dist = _m.Attribute(bool) + stochastic = _m.Attribute(bool) + input_directory = _m.Attribute(str) + + tool_run_msg = "" + + def __init__(self): + self.msa_iteration = 1 + self.relative_gap = 0.0005 + self.max_iterations = 100 + self.num_processors = "MAX-1" + self.raise_zero_dist = True + self.select_link = '[]' + self.stochastic = False + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.attributes = ["period", "msa_iteration", "relative_gap", "max_iterations", + "num_processors", "select_link", "raise_zero_dist", "stochastic", "input_directory"] + version = os.environ.get("EMMEPATH", "") + self._version = version[-5:] if version else "" + self._skim_classes_separately = True # Used for debugging only + self._stats = {} + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Traffic assignment" + pb.description = """ +The Traffic assignment tool runs the traffic assignment and skims per +period on the current primary scenario. +
+The traffic assignment is a 15-class assignment with generalized cost on +links and BPR-type volume-delay functions which include capacities on links +and at intersection approaches. The assignment is run using the +fast-converging Second-Order Linear Approximation (SOLA) method in Emme to +a relative gap of 5x10-4. The per-link fixed costs include toll values and +operating costs which vary by class of demand. +Assignment matrices and resulting network flows are always in PCE. +""" + pb.branding_text = "- SANDAG - Assignment" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + options = [("EA","Early AM"), + ("AM","AM peak"), + ("MD","Mid-day"), + ("PM","PM peak"), + ("EV","Evening")] + pb.add_select("period", options, title="Period:") + pb.add_text_box("msa_iteration", title="MSA iteration:", note="If >1 will apply MSA to flows.") + pb.add_text_box("relative_gap", title="Relative gap:") + pb.add_text_box("max_iterations", title="Max iterations:") + dem_utils.add_select_processors("num_processors", pb, self) + pb.add_checkbox("raise_zero_dist", title=" ", label="Raise on zero distance value", + note="Check for and raise an exception if a zero value is found in the SOVGP_DIST matrix.") + pb.add_checkbox( + 'stochastic', + title=" ", + label="Run as a stochastic assignment", + note="If the current MSA iteration is the last (4th) one, the SOLA traffic assignment is replaced with a stochastic traffic assignment." + ) + pb.add_select_file('input_directory', 'directory', title='Select input directory') + self._add_select_link_interface(pb) + return pb.render() + + + def _add_select_link_interface(self, pb): + pb.add_html(""" +""") + pb.add_text_box("select_link", multi_line=True) + pb.wrap_html(title="Select link(s):", + body=""" + + + +
+ +
+
+ Click for help +
+
+

+ Expression: Emme selection expression to identify the link(s) of interest. + Examples and available attributes below. +

+

+ Result suffix: the suffix to use in the naming of per-class result + attributes and matrices, up to 6 characters. + Should be unique (existing attributes / matrices will be overwritten). +

+

+ Threshold: the minimum number of links which must be encountered + for the path selection. + The default value of 1 indicates an "any" link selection. +

+

+ Expression selection help: use one (or more) selection criteria of the form + attribute=value or attribute=min,max. + Multiple criteria may be combined with 'and' ('&'), 'or' ('|'), and + 'xor' ('^'). Use 'not' ('!') in front or a criteria to negate it.
+ + More help on selection expressions + +

+

+

+ Result link and turn flows will be saved in extra attributes + @sel_XX_NAME_SUFFIX, where XX is the period, NAME is + the class name, and SUFFIX is the specified result suffix. + The selected O-D demand will be saved in SELDEM_XX_NAME_SUFFIX. +

+
+
+
+
+ Click for available attributes +
+
+ +
+
""") + pb.add_html(""" +""" % {"tool_proxy_tag": pb.tool_proxy_tag, }) + + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + results = self(self.period, self.msa_iteration, self.relative_gap, self.max_iterations, + self.num_processors, scenario, self.select_link, self.raise_zero_dist, + self.stochastic, self.input_directory) + run_msg = "Traffic assignment completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, period, msa_iteration, relative_gap, max_iterations, num_processors, scenario, + select_link=[], raise_zero_dist=True, stochastic=False, input_directory=None): + select_link = _json.loads(select_link) if isinstance(select_link, basestring) else select_link + attrs = { + "period": period, + "msa_iteration": msa_iteration, + "relative_gap": relative_gap, + "max_iterations": max_iterations, + "num_processors": num_processors, + "scenario": scenario.id, + "select_link": _json.dumps(select_link), + "raise_zero_dist": raise_zero_dist, + "stochastic": stochastic, + "input_directory": input_directory, + "self": str(self) + } + self._stats = {} + with _m.logbook_trace("Traffic assignment for period %s" % period, attributes=attrs): + gen_utils.log_snapshot("Traffic assignment", str(self), attrs) + periods = ["EA", "AM", "MD", "PM", "EV"] + if not period in periods: + raise _except.ArgumentError( + 'period: unknown value - specify one of %s' % periods) + num_processors = dem_utils.parse_num_processors(num_processors) + # Main list of assignment classes + classes = [ + { # 0 + "name": 'SOV_NT_L', "mode": 's', "PCE": 1, "VOT": 8.81, "cost": '@cost_auto', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.SOV", "TOLLDIST"] + }, + { # 1 + "name": 'SOV_TR_L', "mode": 'S', "PCE": 1, "VOT": 8.81, "cost": '@cost_auto', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.SOV", "TOLLDIST"] + }, + { # 2 + "name": 'HOV2_L', "mode": 'H', "PCE": 1, "VOT": 8.81, "cost": '@cost_hov2', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.HOV2", "TOLLDIST.HOV2", "HOVDIST"] + }, + { # 3 + "name": 'HOV3_L', "mode": 'I', "PCE": 1, "VOT": 8.81, "cost": '@cost_hov3', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.HOV3", "TOLLDIST.HOV3", "HOVDIST"] + }, + { # 4 + "name": 'SOV_NT_M', "mode": 's', "PCE": 1, "VOT": 18.0, "cost": '@cost_auto', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.SOV", "TOLLDIST"] + }, + { # 5 + "name": 'SOV_TR_M', "mode": 'S', "PCE": 1, "VOT": 18.0, "cost": '@cost_auto', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.SOV", "TOLLDIST"] + }, + { # 6 + "name": 'HOV2_M', "mode": 'H', "PCE": 1, "VOT": 18.0, "cost": '@cost_hov2', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.HOV2", "TOLLDIST.HOV2", "HOVDIST"] + }, + { # 7 + "name": 'HOV3_M', "mode": 'I', "PCE": 1, "VOT": 18.0, "cost": '@cost_hov3', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.HOV3", "TOLLDIST.HOV3", "HOVDIST"] + }, + { # 8 + "name": 'SOV_NT_H', "mode": 's', "PCE": 1, "VOT": 85., "cost": '@cost_auto', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.SOV", "TOLLDIST"] + }, + { # 9 + "name": 'SOV_TR_H', "mode": 'S', "PCE": 1, "VOT": 85., "cost": '@cost_auto', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.SOV", "TOLLDIST"] + }, + { # 10 + "name": 'HOV2_H', "mode": 'H', "PCE": 1, "VOT": 85., "cost": '@cost_hov2', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.HOV2", "TOLLDIST.HOV2", "HOVDIST"] + }, + { # 11 + "name": 'HOV3_H', "mode": 'I', "PCE": 1, "VOT": 85., "cost": '@cost_hov3', + "skims": ["TIME", "DIST", "REL", "TOLLCOST.HOV3", "TOLLDIST.HOV3", "HOVDIST"] + }, + { # 12 + "name": 'TRK_L', "mode": 'T', "PCE": 1.3, "VOT": 67., "cost": '@cost_lgt_truck', + "skims": ["TIME", "DIST", "TOLLCOST.TRK_L"] + }, + { # 13 + "name": 'TRK_M', "mode": 'M', "PCE": 1.5, "VOT": 68., "cost": '@cost_med_truck', + "skims": ["TIME", "DIST", "TOLLCOST.TRK_M"] + }, + { # 14 + "name": 'TRK_H', "mode": 'V', "PCE": 2.5, "VOT": 89., "cost": '@cost_hvy_truck', + "skims": ["TIME", "DIST", "TOLLCOST.TRK_H"] + }, + ] + + # change mode to allow sovntp on SR125 + # TODO: incorporate this into import_network instead + # also, consider updating mode definitions + self.change_mode_sovntp(scenario) + + if period == "MD" and (msa_iteration == 1 or not scenario.mode('D')): + self.prepare_midday_generic_truck(scenario) + + if 1 < msa_iteration < 4: + # Link and turn flows + link_attrs = ["auto_volume"] + turn_attrs = ["auto_volume"] + for traffic_class in classes: + link_attrs.append("@%s" % (traffic_class["name"].lower())) + turn_attrs.append("@p%s" % (traffic_class["name"].lower())) + msa_link_flows = scenario.get_attribute_values("LINK", link_attrs)[1:] + msa_turn_flows = scenario.get_attribute_values("TURN", turn_attrs)[1:] + + if stochastic: + self.run_stochastic_assignment( + period, + relative_gap, + max_iterations, + num_processors, + scenario, + classes, + input_directory + ) + else: + self.run_assignment(period, relative_gap, max_iterations, num_processors, scenario, classes, select_link) + + + if 1 < msa_iteration < 4: + link_flows = scenario.get_attribute_values("LINK", link_attrs) + values = [link_flows.pop(0)] + for msa_array, flow_array in zip(msa_link_flows, link_flows): + msa_vals = numpy.frombuffer(msa_array, dtype='float32') + flow_vals = numpy.frombuffer(flow_array, dtype='float32') + result = msa_vals + (1.0 / msa_iteration) * (flow_vals - msa_vals) + result_array = array.array('f') + result_array.fromstring(result.tostring()) + values.append(result_array) + scenario.set_attribute_values("LINK", link_attrs, values) + + turn_flows = scenario.get_attribute_values("TURN", turn_attrs) + values = [turn_flows.pop(0)] + for msa_array, flow_array in zip(msa_turn_flows, turn_flows): + msa_vals = numpy.frombuffer(msa_array, dtype='float32') + flow_vals = numpy.frombuffer(flow_array, dtype='float32') + result = msa_vals + (1.0 / msa_iteration) * (flow_vals - msa_vals) + result_array = array.array('f') + result_array.fromstring(result.tostring()) + values.append(result_array) + scenario.set_attribute_values("TURN", turn_attrs, values) + + self.calc_network_results(period, num_processors, scenario) + + if msa_iteration <= 4: + self.run_skims(period, num_processors, scenario, classes) + self.report(period, scenario, classes) + # Check that the distance matrix is valid (no disconnected zones) + # Using SOVGPL class as representative + if raise_zero_dist: + name = "%s_SOV_TR_H_DIST" % period + dist_stats = self._stats[name] + if dist_stats[1] == 0: + zones = scenario.zone_numbers + matrix = scenario.emmebank.matrix(name) + data = matrix.get_numpy_data(scenario) + row, col = numpy.unravel_index(data.argmin(), data.shape) + row, col = zones[row], zones[col] + raise Exception("Disconnected zone error: 0 value found in matrix %s from zone %s to %s" % (name, row, col)) + + def run_assignment(self, period, relative_gap, max_iterations, num_processors, scenario, classes, select_link): + emmebank = scenario.emmebank + + modeller = _m.Modeller() + set_extra_function_para = modeller.tool( + "inro.emme.traffic_assignment.set_extra_function_parameters") + create_attribute = modeller.tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + traffic_assign = modeller.tool( + "inro.emme.traffic_assignment.sola_traffic_assignment") + net_calc = gen_utils.NetworkCalculator(scenario) + + if period in ["AM", "PM"]: + # For freeway links in AM and PM periods, convert VDF to type 25 + net_calc("vdf", "25", "vdf=10") + + p = period.lower() + assign_spec = self.base_assignment_spec( + relative_gap, max_iterations, num_processors) + with _m.logbook_trace("Prepare traffic data for period %s" % period): + with _m.logbook_trace("Input link attributes"): + # set extra attributes for the period for VDF + # ul1 = @time_link (period) + # ul2 = transit flow -> volad (for assignment only) + # ul3 = @capacity_link (period) + el1 = "@green_to_cycle" + el2 = "@sta_reliability" + el3 = "@capacity_inter" + set_extra_function_para(el1, el2, el3, emmebank=emmebank) + + # set green to cycle to el1=@green_to_cycle for VDF + att_name = "@green_to_cycle_%s" % p + att = scenario.extra_attribute(att_name) + new_att_name = "@green_to_cycle" + create_attribute("LINK", new_att_name, att.description, + 0, overwrite=True, scenario=scenario) + net_calc(new_att_name, att_name, "modes=d") + # set static reliability to el2=@sta_reliability for VDF + att_name = "@sta_reliability_%s" % p + att = scenario.extra_attribute(att_name) + new_att_name = "@sta_reliability" + create_attribute("LINK", new_att_name, att.description, + 0, overwrite=True, scenario=scenario) + net_calc(new_att_name, att_name, "modes=d") + # set capacity_inter to el3=@capacity_inter for VDF + att_name = "@capacity_inter_%s" % p + att = scenario.extra_attribute(att_name) + new_att_name = "@capacity_inter" + create_attribute("LINK", new_att_name, att.description, + 0, overwrite=True, scenario=scenario) + net_calc(new_att_name, att_name, "modes=d") + # set link time + net_calc("ul1", "@time_link_%s" % p, "modes=d") + net_calc("ul3", "@capacity_link_%s" % p, "modes=d") + # set number of lanes (not used in VDF, just for reference) + net_calc("lanes", "@lane_%s" % p, "modes=d") + if period in ["EA", "MD", "EV"]: + # For links with signals inactive in the off-peak periods, convert VDF to type 11 + net_calc("vdf", "11", "modes=d and @green_to_cycle=0 and @traffic_control=4,5 and vdf=24") + # # Set HOV2 cost attribute + # create_attribute("LINK", "@cost_hov2_%s" % p, "toll (non-mngd) + cost for HOV2", + # 0, overwrite=True, scenario=scenario) + # net_calc("@cost_hov2_%s" % p, "@cost_hov_%s" % p, "modes=d") + # net_calc("@cost_hov2_%s" % p, "@cost_auto_%s" % p, "@lane_restriction=3") + + with _m.logbook_trace("Transit line headway and background traffic"): + # set headway for the period + hdw = {"ea": "@headway_op", + "am": "@headway_am", + "md": "@headway_op", + "pm": "@headway_pm", + "ev": "@headway_op"} + net_calc("hdw", hdw[p], {"transit_line": "all"}) + + # transit vehicle as background flow with periods + period_hours = {'ea': 3, 'am': 3, 'md': 6.5, 'pm': 3.5, 'ev': 5} + expression = "(60 / hdw) * vauteq * %s" % (period_hours[p]) + net_calc("ul2", "0", "modes=d") + net_calc("ul2", expression, + selections={"link": "modes=d", "transit_line": "hdw=0.02,9999"}, + aggregation="+") + + with _m.logbook_trace("Per-class flow attributes"): + for traffic_class in classes: + demand = 'mf"%s_%s"' % (period, traffic_class["name"]) + link_cost = "%s_%s" % (traffic_class["cost"], p) if traffic_class["cost"] else "@cost_operating" + + att_name = "@%s" % (traffic_class["name"].lower()) + att_des = "%s %s link volume" % (period, traffic_class["name"]) + link_flow = create_attribute("LINK", att_name, att_des, 0, overwrite=True, scenario=scenario) + att_name = "@p%s" % (traffic_class["name"].lower()) + att_des = "%s %s turn volume" % (period, traffic_class["name"]) + turn_flow = create_attribute("TURN", att_name, att_des, 0, overwrite=True, scenario=scenario) + + class_spec = { + "mode": traffic_class["mode"], + "demand": demand, + "generalized_cost": { + "link_costs": link_cost, "perception_factor": 1.0 / traffic_class["VOT"] + }, + "results": { + "link_volumes": link_flow.id, "turn_volumes": turn_flow.id, + "od_travel_times": None + } + } + assign_spec["classes"].append(class_spec) + if select_link: + for class_spec in assign_spec["classes"]: + class_spec["path_analyses"] = [] + for sub_spec in select_link: + expr = sub_spec["expression"] + suffix = sub_spec["suffix"] + threshold = sub_spec["threshold"] + if not expr and not suffix: + continue + with _m.logbook_trace("Prepare for select link analysis '%s' - %s" % (expr, suffix)): + slink = create_attribute("LINK", "@slink_%s" % suffix, "selected link for %s" % suffix, 0, + overwrite=True, scenario=scenario) + net_calc(slink.id, "1", expr) + with _m.logbook_trace("Initialize result matrices and extra attributes"): + for traffic_class, class_spec in zip(classes, assign_spec["classes"]): + att_name = "@sl_%s_%s" % (traffic_class["name"].lower(), suffix) + att_des = "%s %s '%s' sel link flow"% (period, traffic_class["name"], suffix) + link_flow = create_attribute("LINK", att_name, att_des, 0, overwrite=True, scenario=scenario) + att_name = "@psl_%s_%s" % (traffic_class["name"].lower(), suffix) + att_des = "%s %s '%s' sel turn flow" % (period, traffic_class["name"], suffix) + turn_flow = create_attribute("TURN", att_name, att_des, 0, overwrite=True, scenario=scenario) + + name = "SELDEM_%s_%s_%s" % (period, traffic_class["name"], suffix) + desc = "Selected demand for %s %s %s" % (period, traffic_class["name"], suffix) + seldem = dem_utils.create_full_matrix(name, desc, scenario=scenario) + + # add select link analysis + class_spec["path_analyses"].append({ + "link_component": slink.id, + "turn_component": None, + "operator": "+", + "selection_threshold": { "lower": threshold, "upper": 999999}, + "path_to_od_composition": { + "considered_paths": "SELECTED", + "multiply_path_proportions_by": {"analyzed_demand": True, "path_value": False} + }, + "analyzed_demand": None, + "results": { + "selected_link_volumes": link_flow.id, + "selected_turn_volumes": turn_flow.id, + "od_values": seldem.named_id + } + }) + # Run assignment + traffic_assign(assign_spec, scenario, chart_log_interval=2) + return + + def run_stochastic_assignment( + self, period, relative_gap, max_iterations, num_processors, scenario, + classes, input_directory): + load_properties = _m.Modeller().tool('sandag.utilities.properties') + main_directory = os.path.dirname(input_directory) + props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) + distribution_type = props['stochasticHighwayAssignment.distributionType'] + replications = props['stochasticHighwayAssignment.replications'] + a_parameter = props['stochasticHighwayAssignment.aParameter'] + b_parameter = props['stochasticHighwayAssignment.bParameter'] + seed = props['stochasticHighwayAssignment.seed'] + + emmebank = scenario.emmebank + + modeller = _m.Modeller() + set_extra_function_para = modeller.tool( + "inro.emme.traffic_assignment.set_extra_function_parameters") + create_attribute = modeller.tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + traffic_assign = modeller.tool( + "solutions.stochastic_traffic_assignment") + net_calc = gen_utils.NetworkCalculator(scenario) + + if period in ["AM", "PM"]: + # For freeway links in AM and PM periods, convert VDF to type 25 + net_calc("vdf", "25", "vdf=10") + + p = period.lower() + assign_spec = self.base_assignment_spec( + relative_gap, max_iterations, num_processors) + assign_spec['background_traffic'] = { + "link_component": None, + "turn_component": None, + "add_transit_vehicles": True + } + with _m.logbook_trace("Prepare traffic data for period %s" % period): + with _m.logbook_trace("Input link attributes"): + # set extra attributes for the period for VDF + # ul1 = @time_link (period) + # ul2 = transit flow -> volad (for assignment only) + # ul3 = @capacity_link (period) + el1 = "@green_to_cycle" + el2 = "@sta_reliability" + el3 = "@capacity_inter" + set_extra_function_para(el1, el2, el3, emmebank=emmebank) + + # set green to cycle to el1=@green_to_cycle for VDF + att_name = "@green_to_cycle_%s" % p + att = scenario.extra_attribute(att_name) + new_att_name = "@green_to_cycle" + create_attribute("LINK", new_att_name, att.description, + 0, overwrite=True, scenario=scenario) + net_calc(new_att_name, att_name, "modes=d") + # set static reliability to el2=@sta_reliability for VDF + att_name = "@sta_reliability_%s" % p + att = scenario.extra_attribute(att_name) + new_att_name = "@sta_reliability" + create_attribute("LINK", new_att_name, att.description, + 0, overwrite=True, scenario=scenario) + net_calc(new_att_name, att_name, "modes=d") + # set capacity_inter to el3=@capacity_inter for VDF + att_name = "@capacity_inter_%s" % p + att = scenario.extra_attribute(att_name) + new_att_name = "@capacity_inter" + create_attribute("LINK", new_att_name, att.description, + 0, overwrite=True, scenario=scenario) + net_calc(new_att_name, att_name, "modes=d") + # set link time + net_calc("ul1", "@time_link_%s" % p, "modes=d") + net_calc("ul3", "@capacity_link_%s" % p, "modes=d") + # set number of lanes (not used in VDF, just for reference) + net_calc("lanes", "@lane_%s" % p, "modes=d") + if period in ["EA", "MD", "EV"]: + # For links with signals inactive in the off-peak periods, convert VDF to type 11 + net_calc("vdf", "11", "modes=d and @green_to_cycle=0 and @traffic_control=4,5 and vdf=24") + # # Set HOV2 cost attribute + # create_attribute("LINK", "@cost_hov2_%s" % p, "toll (non-mngd) + cost for HOV2", + # 0, overwrite=True, scenario=scenario) + # net_calc("@cost_hov2_%s" % p, "@cost_hov_%s" % p, "modes=d") + # net_calc("@cost_hov2_%s" % p, "@cost_auto_%s" % p, "@lane_restriction=3") + + with _m.logbook_trace("Transit line headway and background traffic"): + # set headway for the period: format is (attribute_name, period duration in hours) + hdw = {"ea": ("@headway_op", 3), + "am": ("@headway_am", 3), + "md": ("@headway_op", 6.5), + "pm": ("@headway_pm", 3.5), + "ev": ("@headway_op", 5)} + net_calc('ul2', '0', {'link': 'all'}) + net_calc('hdw', '9999.99', {'transit_line': 'all'}) + net_calc( + 'hdw', "{hdw} / {p} ".format(hdw=hdw[p][0], p=hdw[p][1]), + {"transit_line": "%s=0.02,9999" % hdw[p][0]} + ) + + with _m.logbook_trace("Per-class flow attributes"): + for traffic_class in classes: + demand = 'mf"%s_%s"' % (period, traffic_class["name"]) + link_cost = "%s_%s" % (traffic_class["cost"], p) if traffic_class["cost"] else "@cost_operating" + + att_name = "@%s" % (traffic_class["name"].lower()) + att_des = "%s %s link volume" % (period, traffic_class["name"]) + link_flow = create_attribute("LINK", att_name, att_des, 0, overwrite=True, scenario=scenario) + att_name = "@p%s" % (traffic_class["name"].lower()) + att_des = "%s %s turn volume" % (period, traffic_class["name"]) + turn_flow = create_attribute("TURN", att_name, att_des, 0, overwrite=True, scenario=scenario) + + class_spec = { + "mode": traffic_class["mode"], + "demand": demand, + "generalized_cost": { + "link_costs": link_cost, "perception_factor": 1.0 / traffic_class["VOT"] + }, + "results": { + "link_volumes": link_flow.id, "turn_volumes": turn_flow.id, + "od_travel_times": None + } + } + assign_spec["classes"].append(class_spec) + + # Run assignment + traffic_assign( + assign_spec, + dist_par={'type': distribution_type, 'A': a_parameter, 'B': b_parameter}, + replications=replications, + seed=seed, + orig_func=False, + random_term='ul2', + compute_travel_times=False, + scenario=scenario + ) + + with _m.logbook_trace("Reset transit line headways"): + # set headway for the period + hdw = {"ea": "@headway_op", + "am": "@headway_am", + "md": "@headway_op", + "pm": "@headway_pm", + "ev": "@headway_op"} + net_calc("hdw", hdw[p], {"transit_line": "all"}) + return + + def calc_network_results(self, period, num_processors, scenario): + modeller = _m.Modeller() + create_attribute = modeller.tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + net_calc = gen_utils.NetworkCalculator(scenario) + emmebank = scenario.emmebank + p = period.lower() + # ul2 is the total flow (volau + volad) in the skim assignment + with _m.logbook_trace("Calculation of attributes for skims"): + link_attributes = [ + ("@hovdist", "distance for HOV"), + ("@tollcost", "Toll cost for SOV autos"), + ("@h2tollcost", "Toll cost for hov2"), + ("@h3tollcost", "Toll cost for hov3"), + ("@trk_ltollcost", "Toll cost for light trucks"), + ("@trk_mtollcost", "Toll cost for medium trucks"), + ("@trk_htollcost", "Toll cost for heavy trucks"), + ("@mlcost", "Manage lane cost in cents"), + ("@tolldist", "Toll distance"), + ("@h2tolldist", "Toll distance for hov2"), + ("@h3tolldist", "Toll distance for hov3"), + ("@reliability", "Reliability factor"), + ("@reliability_sq", "Reliability factor squared"), + ("@auto_volume", "traffic link volume (volau)"), + ("@auto_time", "traffic link time (timau)"), + ] + for name, description in link_attributes: + create_attribute("LINK", name, description, + 0, overwrite=True, scenario=scenario) + create_attribute("TURN", "@auto_time_turn", "traffic turn time (ptimau)", + overwrite=True, scenario=scenario) + + net_calc("@hovdist", "length", {"link": "@lane_restriction=2,3"}) + net_calc("@tollcost", "@cost_auto_%s - @cost_operating" % p) + net_calc("@h2tollcost", "@cost_hov2_%s - @cost_operating" % p, {"link": "@lane_restriction=3,4"}) + net_calc("@h3tollcost", "@cost_hov3_%s - @cost_operating" % p, {"link": "@lane_restriction=4"}) + net_calc("@trk_ltollcost", "@cost_lgt_truck_%s - @cost_operating" % p) + net_calc("@trk_mtollcost", "@cost_med_truck_%s - @cost_operating" % p) + net_calc("@trk_htollcost", "@cost_hvy_truck_%s - @cost_operating" % p) + net_calc("@mlcost", "@toll_%s" % p, {"link": "not @lane_restriction=4"}) + net_calc("@tolldist", "length", {"link": "@lane_restriction=2,4"}) + net_calc("@h2tolldist", "length", {"link": "@lane_restriction=3,4"}) + net_calc("@h3tolldist", "length", {"link": "@lane_restriction=4"}) + net_calc("@auto_volume", "volau", {"link": "modes=d"}) + net_calc("ul2", "volau+volad", {"link": "modes=d"}) + vdfs = [f for f in emmebank.functions() if f.type == "VOLUME_DELAY"] + exf_pars = emmebank.extra_function_parameters + for function in vdfs: + expression = function.expression + for exf_par in ["el1", "el2", "el3"]: + expression = expression.replace(exf_par, getattr(exf_pars, exf_par)) + # split function into time component and reliability component + time_expr, reliability_expr = expression.split("*(1+@sta_reliability+") + net_calc("@auto_time", time_expr, {"link": "vdf=%s" % function.id[2:]}) + net_calc("@reliability", "(@sta_reliability+" + reliability_expr, + {"link": "vdf=%s" % function.id[2:]}) + + net_calc("@reliability_sq", "@reliability**2", {"link": "modes=d"}) + net_calc("@auto_time_turn", "ptimau*(ptimau.gt.0)", + {"incoming_link": "all", "outgoing_link": "all"}) + + def run_skims(self, period, num_processors, scenario, classes): + modeller = _m.Modeller() + traffic_assign = modeller.tool( + "inro.emme.traffic_assignment.sola_traffic_assignment") + emmebank = scenario.emmebank + p = period.lower() + analysis_link = { + "TIME": "@auto_time", + "DIST": "length", + "HOVDIST": "@hovdist", + "TOLLCOST.SOV": "@tollcost", + "TOLLCOST.HOV2": "@h2tollcost", + "TOLLCOST.HOV3": "@h3tollcost", + "TOLLCOST.TRK_L": "@trk_ltollcost", + "TOLLCOST.TRK_M": "@trk_mtollcost", + "TOLLCOST.TRK_H": "@trk_htollcost", + "MLCOST": "@mlcost", + "TOLLDIST": "@tolldist", + "TOLLDIST.HOV2": "@h2tolldist", + "TOLLDIST.HOV3": "@h3tolldist", + "REL": "@reliability_sq" + } + analysis_turn = {"TIME": "@auto_time_turn"} + with self.setup_skims(period, scenario): + if period == "MD": + gen_truck_mode = 'D' + classes.append({ + "name": 'TRK', "mode": gen_truck_mode, "PCE": 1, "VOT": 67., "cost": '', + "skims": ["TIME"] + }) + skim_spec = self.base_assignment_spec(0, 0, num_processors, background_traffic=False) + for traffic_class in classes: + if not traffic_class["skims"]: + continue + class_analysis = [] + if "GENCOST" in traffic_class["skims"]: + od_travel_times = 'mf"%s_%s_%s"' % (period, traffic_class["name"], "GENCOST") + traffic_class["skims"].remove("GENCOST") + else: + od_travel_times = None + for skim_type in traffic_class["skims"]: + skim_name = skim_type.split(".")[0] + class_analysis.append({ + "link_component": analysis_link.get(skim_type), + "turn_component": analysis_turn.get(skim_type), + "operator": "+", + "selection_threshold": {"lower": None, "upper": None}, + "path_to_od_composition": { + "considered_paths": "ALL", + "multiply_path_proportions_by": + {"analyzed_demand": False, "path_value": True} + }, + "results": { + "od_values": 'mf"%s_%s_%s"' % (period, traffic_class["name"], skim_name), + "selected_link_volumes": None, + "selected_turn_volumes": None + } + }) + if traffic_class["cost"]: + link_cost = "%s_%s" % (traffic_class["cost"], p) + else: + link_cost = "@cost_operating" + skim_spec["classes"].append({ + "mode": traffic_class["mode"], + "demand": 'ms"zero"', # 0 demand for skim with 0 iteration and fix flow in ul2 in vdf + "generalized_cost": { + "link_costs": link_cost, "perception_factor": 1.0 / traffic_class["VOT"] + }, + "results": { + "link_volumes": None, "turn_volumes": None, + "od_travel_times": {"shortest_paths": od_travel_times} + }, + "path_analyses": class_analysis, + }) + + # skim assignment + if self._skim_classes_separately: + # Debugging check + skim_classes = skim_spec["classes"][:] + for kls in skim_classes: + skim_spec["classes"] = [kls] + traffic_assign(skim_spec, scenario) + else: + traffic_assign(skim_spec, scenario) + + # compute diagonal value for TIME and DIST + with _m.logbook_trace("Compute diagonal values for period %s" % period): + num_cells = len(scenario.zone_numbers) ** 2 + for traffic_class in classes: + class_name = traffic_class["name"] + skims = traffic_class["skims"] + with _m.logbook_trace("Class %s" % class_name): + for skim_type in skims: + skim_name = skim_type.split(".")[0] + name = '%s_%s_%s' % (period, class_name, skim_name) + matrix = emmebank.matrix(name) + data = matrix.get_numpy_data(scenario) + if skim_name == "TIME" or skim_name == "DIST": + numpy.fill_diagonal(data, 999999999.0) + data[numpy.diag_indices_from(data)] = 0.5 * numpy.nanmin(data[::,12::], 1) + internal_data = data[12::, 12::] # Exclude the first 12 zones, external zones + self._stats[name] = (name, internal_data.min(), internal_data.max(), internal_data.mean(), internal_data.sum(), 0) + elif skim_name == "REL": + data = numpy.sqrt(data) + else: + self._stats[name] = (name, data.min(), data.max(), data.mean(), data.sum(), 0) + numpy.fill_diagonal(data, 0.0) + matrix.set_numpy_data(data, scenario) + return + + def base_assignment_spec(self, relative_gap, max_iterations, num_processors, background_traffic=True): + base_spec = { + "type": "SOLA_TRAFFIC_ASSIGNMENT", + "background_traffic": None, + "classes": [], + "stopping_criteria": { + "max_iterations": int(max_iterations), "best_relative_gap": 0.0, + "relative_gap": float(relative_gap), "normalized_gap": 0.0 + }, + "performance_settings": {"number_of_processors": num_processors}, + } + if background_traffic: + base_spec["background_traffic"] = { + "link_component": "ul2", # ul2 = transit flow of the period + "turn_component": None, + "add_transit_vehicles": False + } + return base_spec + + @_context + def setup_skims(self, period, scenario): + emmebank = scenario.emmebank + with _m.logbook_trace("Extract skims for period %s" % period): + # temp_functions converts to skim-type VDFs + with temp_functions(emmebank): + backup_attributes = {"LINK": ["data2", "auto_volume", "auto_time", "additional_volume"]} + with gen_utils.backup_and_restore(scenario, backup_attributes): + yield + + def prepare_midday_generic_truck(self, scenario): + modeller = _m.Modeller() + create_mode = modeller.tool( + "inro.emme.data.network.mode.create_mode") + delete_mode = modeller.tool( + "inro.emme.data.network.mode.delete_mode") + change_link_modes = modeller.tool( + "inro.emme.data.network.base.change_link_modes") + with _m.logbook_trace("Preparation for generic truck skim"): + gen_truck_mode = 'D' + truck_mode = scenario.mode(gen_truck_mode) + if not truck_mode: + truck_mode = create_mode( + mode_type="AUX_AUTO", mode_id=gen_truck_mode, + mode_description="all trucks", scenario=scenario) + change_link_modes(modes=[truck_mode], action="ADD", + selection="modes=vVmMtT", scenario=scenario) + + #added by RSG (nagendra.dhakar@rsginc.com) for collapsed assignment classes testing + #this adds non-transponder SOV mode to SR-125 links + # TODO: move this to the network_import step for consistency and foward-compatibility + def change_mode_sovntp(self, scenario): + modeller = _m.Modeller() + change_link_modes = modeller.tool( + "inro.emme.data.network.base.change_link_modes") + with _m.logbook_trace("Preparation for sov ntp assignment"): + gen_sov_mode = 's' + sov_mode = scenario.mode(gen_sov_mode) + change_link_modes(modes=[sov_mode], action="ADD", + selection="@lane_restriction=4", scenario=scenario) + + def report(self, period, scenario, classes): + emmebank = scenario.emmebank + text = ['
'] + matrices = [] + for traffic_class in classes: + matrices.extend(["%s_%s" % (traffic_class["name"], s.split(".")[0]) for s in traffic_class["skims"]]) + num_zones = len(scenario.zone_numbers) + num_cells = num_zones ** 2 + text.append(""" + Number of zones: %s. Number of O-D pairs: %s. + Values outside -9999999, 9999999 are masked in summaries.
""" % (num_zones, num_cells)) + text.append("%-25s %9s %9s %9s %13s %9s" % ("name", "min", "max", "mean", "sum", "mask num")) + for name in matrices: + name = period + "_" + name + matrix = emmebank.matrix(name) + stats = self._stats.get(name) + if stats is None: + data = matrix.get_numpy_data(scenario) + data = numpy.ma.masked_outside(data, -9999999, 9999999, copy=False) + stats = (name, data.min(), data.max(), data.mean(), data.sum(), num_cells-data.count()) + text.append("%-25s %9.4g %9.4g %9.4g %13.7g %9d" % stats) + text.append("
") + title = 'Traffic impedance summary for period %s' % period + report = _m.PageBuilder(title) + report.wrap_html('Matrix details', "
".join(text)) + _m.logbook_write(title, report.render()) + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg + + @_m.method(return_type=unicode) + def get_link_attributes(self): + export_utils = _m.Modeller().module("inro.emme.utility.export_utilities") + return export_utils.get_link_attributes(_m.Modeller().scenario) + + +@_context +def temp_functions(emmebank): + change_function = _m.Modeller().tool( + "inro.emme.data.function.change_function") + orig_expression = {} + with _m.logbook_trace("Set functions to skim parameter"): + for func in emmebank.functions(): + if func.prefix=="fd": + exp = func.expression + orig_expression[func] = exp + if "volau+volad" in exp: + exp = exp.replace("volau+volad", "ul2") + change_function(func, exp, emmebank) + try: + yield + finally: + with _m.logbook_trace("Reset functions to assignment parameters"): + for func, expression in orig_expression.iteritems(): + change_function(func, expression, emmebank) + diff --git a/sandag_abm/src/main/emme/toolbox/assignment/transit_assignment.py b/sandag_abm/src/main/emme/toolbox/assignment/transit_assignment.py new file mode 100644 index 0000000..cd23ba6 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/assignment/transit_assignment.py @@ -0,0 +1,785 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// transit_assignment.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# The Transit assignment tool runs the transit assignment and skims for each +# period on the current primary scenario. +# +# The Build transit network tool must be run first to prepare the scenario for +# assignment. Note that this tool must be run with the Transit database +# (under the Database_transit directory) open (as the active database in the +# Emme desktop). +# +# +# Inputs: +# period: the time-of-day period, one of EA, AM, MD, PM, EV. +# scenario: Transit assignment scenario +# skims_only: Only run assignment for skim matrices, if True only two assignments +# are run to generate the skim matrices for the BUS and ALL skim classes. +# Otherwise, all 15 assignments are run to generate the total network flows. +# num_processors: number of processors to use for the traffic assignments. +# +# Matrices: +# All transit demand and skim matrices. +# See list of matrices under report method. +# +# Script example: +""" +import inro.modeller as _m +import os +modeller = _m.Modeller() +desktop = modeller.desktop + +build_transit_scen = modeller.tool("sandag.assignment.build_transit_scenario") +transit_assign = modeller.tool("sandag.assignment.transit_assignment") +load_properties = modeller.tool('sandag.utilities.properties') + +project_dir = os.path.dirname(desktop.project_path()) +main_directory = os.path.dirname(project_dir) +props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) +main_emmebank = os.path.join(project_dir, "Database", "emmebank") +scenario_id = 100 +base_scenario = main_emmebank.scenario(scenario_id) + +transit_emmebank = os.path.join(project_dir, "Database_transit", "emmebank") + +periods = ["EA", "AM", "MD", "PM", "EV"] +period_ids = list(enumerate(periods, start=int(scenario_id) + 1)) +num_processors = "MAX-1" +scenarioYear = str(props["scenarioYear"]) + +for number, period in period_ids: + src_period_scenario = main_emmebank.scenario(number) + transit_assign_scen = build_transit_scen( + period=period, base_scenario=src_period_scenario, + transit_emmebank=transit_emmebank, + scenario_id=src_period_scenario.id, + scenario_title="%s %s transit assign" % (base_scenario.title, period), + data_table_name=scenarioYear, overwrite=True) + transit_assign(period, transit_assign_scen, data_table_name=scenarioYear, + skims_only=True, num_processors=num_processors) + +omx_file = os.path.join(output_dir, "transit_skims.omx") +export_transit_skims(omx_file, periods, transit_scenario) +""" + + +TOOLBOX_ORDER = 21 + + +import inro.modeller as _m +import inro.emme.core.exception as _except +import traceback as _traceback +from copy import deepcopy as _copy +from collections import defaultdict as _defaultdict, OrderedDict +import contextlib as _context +import numpy + +import os +import sys +import math + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + + +class TransitAssignment(_m.Tool(), gen_utils.Snapshot): + + period = _m.Attribute(unicode) + scenario = _m.Attribute(_m.InstanceType) + data_table_name = _m.Attribute(unicode) + assignment_only = _m.Attribute(bool) + skims_only = _m.Attribute(bool) + num_processors = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self.assignment_only = False + self.skims_only = False + self.scenario = _m.Modeller().scenario + self.num_processors = "MAX-1" + self.attributes = [ + "period", "scenario", "data_table_name", "assignment_only", "skims_only", "num_processors"] + self._dt_db = _m.Modeller().desktop.project.data_tables() + self._matrix_cache = {} # used to hold data for reporting and post-processing of skims + + def from_snapshot(self, snapshot): + super(TransitAssignment, self).from_snapshot(snapshot) + # custom from_snapshot to load scenario and database objects + self.scenario = _m.Modeller().emmebank.scenario(self.scenario) + return self + + def page(self): + if not self.data_table_name: + load_properties = _m.Modeller().tool('sandag.utilities.properties') + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + main_directory = os.path.dirname(project_dir) + props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) + self.data_table_name = props["scenarioYear"] + + pb = _m.ToolPageBuilder(self) + pb.title = "Transit assignment" + pb.description = """Assign transit demand for the selected time period.""" + pb.branding_text = "- SANDAG - " + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + options = [("EA", "Early AM"), + ("AM", "AM peak"), + ("MD", "Mid-day"), + ("PM", "PM peak"), + ("EV", "Evening")] + pb.add_select("period", options, title="Period:") + pb.add_select_scenario("scenario", + title="Transit assignment scenario:") + pb.add_text_box("data_table_name", title="Data table prefix name:", note="Default is the ScenarioYear") + pb.add_checkbox("assignment_only", title=" ", label="Only assign trips (no skims)") + pb.add_checkbox("skims_only", title=" ", label="Only run assignments relevant for skims") + dem_utils.add_select_processors("num_processors", pb, self) + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + results = self( + self.period, self.scenario, self.data_table_name, + self.assignment_only, self.skims_only, self.num_processors) + run_msg = "Transit assignment completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, period, scenario, data_table_name, assignment_only=False, skims_only=False, + num_processors="MAX-1"): + attrs = { + "period": period, + "scenario": scenario.id, + "data_table_name": data_table_name, + "assignment_only": assignment_only, + "skims_only": skims_only, + "num_processors": num_processors, + "self": str(self) + } + self.scenario = scenario + if not scenario.has_traffic_results: + raise Exception("missing traffic assignment results for period %s scenario %s" % (period, scenario)) + emmebank = scenario.emmebank + with self.setup(attrs): + gen_utils.log_snapshot("Transit assignment", str(self), attrs) + periods = ["EA", "AM", "MD", "PM", "EV"] + if not period in periods: + raise Exception('period: unknown value - specify one of %s' % periods) + num_processors = dem_utils.parse_num_processors(num_processors) + params = self.get_perception_parameters(period) + network = scenario.get_partial_network( + element_types=["TRANSIT_LINE"], include_attributes=True) + coaster_mode = network.mode("c") + params["coaster_fare_percep"] = 0 + for line in list(network.transit_lines()): + # get the coaster fare perception for use in journey levels + if line.mode == coaster_mode: + params["coaster_fare_percep"] = line[params["fare"]] + break + + transit_passes = gen_utils.DataTableProc("%s_transit_passes" % data_table_name) + transit_passes = {row["pass_type"]: row["cost"] for row in transit_passes} + day_pass = float(transit_passes["day_pass"]) / 2.0 + regional_pass = float(transit_passes["regional_pass"]) / 2.0 + + self.run_assignment(period, params, network, day_pass, skims_only, num_processors) + + if not assignment_only: + # max_fare = day_pass for local bus and regional_pass for premium modes + self.run_skims("BUS", period, params, day_pass, num_processors, network) + self.run_skims("PREM", period, params, regional_pass, num_processors, network) + self.run_skims("ALLPEN", period, params, regional_pass, num_processors, network) + self.mask_allpen(period) + self.report(period) + + @_context.contextmanager + def setup(self, attrs): + self._matrix_cache = {} # initialize cache at beginning of run + emmebank = self.scenario.emmebank + period = attrs["period"] + with _m.logbook_trace("Transit assignment for period %s" % period, attributes=attrs): + with gen_utils.temp_matrices(emmebank, "FULL", 3) as matrices: + matrices[0].name = "TEMP_IN_VEHICLE_COST" + matrices[1].name = "TEMP_LAYOVER_BOARD" + matrices[2].name = "TEMP_PERCEIVED_FARE" + try: + yield + finally: + self._matrix_cache = {} # clear cache at end of run + + def get_perception_parameters(self, period): + perception_parameters = { + "EA": { + "vot": 0.27, + "init_wait": 1.5, + "xfer_wait": 3.0, + "walk": 2.0, + "init_headway": "@headway_rev_op", + "xfer_headway": "@headway_op", + "fare": "@fare_per_op", + "in_vehicle": "@vehicle_per_op", + "fixed_link_time": "@trtime_link_ea" + }, + "AM": { + "vot": 0.27, + "init_wait": 1.5, + "xfer_wait": 3.0, + "walk": 2.0, + "init_headway": "@headway_rev_am", + "xfer_headway": "@headway_am", + "fare": "@fare_per_pk", + "in_vehicle": "@vehicle_per_pk", + "fixed_link_time": "@trtime_link_am" + }, + "MD": { + "vot": 0.27, + "init_wait": 1.5, + "xfer_wait": 3.0, + "walk": 2.0, + "init_headway": "@headway_rev_op", + "xfer_headway": "@headway_op", + "fare": "@fare_per_op", + "in_vehicle": "@vehicle_per_op", + "fixed_link_time": "@trtime_link_md" + }, + "PM": { + "vot": 0.27, + "init_wait": 1.5, + "xfer_wait": 3.0, + "walk": 2.0, + "init_headway": "@headway_rev_pm", + "xfer_headway": "@headway_pm", + "fare": "@fare_per_pk", + "in_vehicle": "@vehicle_per_pk", + "fixed_link_time": "@trtime_link_pm" + }, + "EV": { + "vot": 0.27, + "init_wait": 1.5, + "xfer_wait": 3.0, + "walk": 2.0, + "init_headway": "@headway_rev_op", + "xfer_headway": "@headway_op", + "fare": "@fare_per_op", + "in_vehicle": "@vehicle_per_op", + "fixed_link_time": "@trtime_link_ev" + } + } + return perception_parameters[period] + + def group_modes_by_fare(self, network, day_pass_cost): + # Identify all the unique boarding fare values + fare_set = {mode.id: _defaultdict(lambda:0) + for mode in network.modes() + if mode.type == "TRANSIT"} + for line in network.transit_lines(): + fare_set[line.mode.id][line["@fare"]] += 1 + del fare_set['c'] # remove coaster mode, this fare is handled separately + # group the modes relative to day_pass + mode_groups = { + "bus": [], # have a bus fare, less than 1/2 day pass + "day_pass": [], # boarding fare is the same as 1/2 day pass + "premium": [] # special premium services not covered by day pass + } + for mode_id, fares in fare_set.items(): + try: + max_fare = max(fares.keys()) + except ValueError: + continue # an empty set means this mode is unused in this period + if numpy.isclose(max_fare, day_pass_cost, rtol=0.0001): + mode_groups["day_pass"].append((mode_id, fares)) + elif max_fare < day_pass_cost: + mode_groups["bus"].append((mode_id, fares)) + else: + mode_groups["premium"].append((mode_id, fares)) + return mode_groups + + def all_modes_journey_levels(self, params, network, day_pass_cost): + transfer_penalty = {"on_segments": {"penalty": "@transfer_penalty_s", "perception_factor": 5.0}} + transfer_wait = { + "effective_headways": "@headway_seg", + "headway_fraction": 0.5, + "perception_factor": params["xfer_wait"], + "spread_factor": 1.0 + } + mode_groups = self.group_modes_by_fare(network, day_pass_cost) + + def get_transition_rules(next_level): + rules = [] + for name, group in mode_groups.items(): + for mode_id, fares in group: + rules.append({"mode": mode_id, "next_journey_level": next_level[name]}) + rules.append({"mode": "c", "next_journey_level": next_level["coaster"]}) + return rules + + journey_levels = [ + { + "description": "base", + "destinations_reachable": False, + "transition_rules": get_transition_rules({"bus": 1, "day_pass": 2, "premium": 3, "coaster": 4}), + "boarding_time": {"global": {"penalty": 0, "perception_factor": 1}}, + "waiting_time": { + "effective_headways": params["init_headway"], "headway_fraction": 0.5, + "perception_factor": params["init_wait"], "spread_factor": 1.0 + }, + "boarding_cost": { + "on_lines": {"penalty": "@fare", "perception_factor": params["fare"]}, + "on_segments": {"penalty": "@coaster_fare_board", "perception_factor": params["coaster_fare_percep"]}, + }, + }, + { + "description": "boarded_bus", + "destinations_reachable": True, + "transition_rules": get_transition_rules({"bus": 2, "day_pass": 2, "premium": 5, "coaster": 5}), + "boarding_time": transfer_penalty, + "waiting_time": transfer_wait, + "boarding_cost": { + # xfer from bus fare is on segments so circle lines get free transfer + "on_segments": {"penalty": "@xfer_from_bus", "perception_factor": params["fare"]}, + }, + }, + { + "description": "day_pass", + "destinations_reachable": True, + "transition_rules": get_transition_rules({"bus": 2, "day_pass": 2, "premium": 5, "coaster": 5}), + "boarding_time": transfer_penalty, + "waiting_time": transfer_wait, + "boarding_cost": { + "on_lines": {"penalty": "@xfer_from_day", "perception_factor": params["fare"]}, + }, + }, + { + "description": "boarded_premium", + "destinations_reachable": True, + "transition_rules": get_transition_rules({"bus": 5, "day_pass": 5, "premium": 5, "coaster": 5}), + "boarding_time": transfer_penalty, + "waiting_time": transfer_wait, + "boarding_cost": { + "on_lines": {"penalty": "@xfer_from_premium", "perception_factor": params["fare"]}, + }, + }, + { + "description": "boarded_coaster", + "destinations_reachable": True, + "transition_rules": get_transition_rules({"bus": 5, "day_pass": 5, "premium": 5, "coaster": 5}), + "boarding_time": transfer_penalty, + "waiting_time": transfer_wait, + "boarding_cost": { + "on_lines": {"penalty": "@xfer_from_coaster", "perception_factor": params["fare"]}, + }, + }, + { + "description": "regional_pass", + "destinations_reachable": True, + "transition_rules": get_transition_rules({"bus": 5, "day_pass": 5, "premium": 5, "coaster": 5}), + "boarding_time": transfer_penalty, + "waiting_time": transfer_wait, + "boarding_cost": { + "on_lines": {"penalty": "@xfer_regional_pass", "perception_factor": params["fare"]}, + }, + } + ] + return journey_levels + + def filter_journey_levels_by_mode(self, modes, journey_levels): + # remove rules for unused modes from provided journey_levels + # (restrict to provided modes) + journey_levels = _copy(journey_levels) + for level in journey_levels: + rules = level["transition_rules"] + rules = [r for r in rules if r["mode"] in modes] + level["transition_rules"] = rules + # count level transition rules references to find unused levels + num_levels = len(journey_levels) + level_count = [0] * len(journey_levels) + + def follow_rule(next_level): + level_count[next_level] += 1 + if level_count[next_level] > 1: + return + for rule in journey_levels[next_level]["transition_rules"]: + follow_rule(rule["next_journey_level"]) + + follow_rule(0) + # remove unreachable levels + # and find new index for transition rules for remaining levels + level_map = {i:i for i in range(num_levels)} + for level_id, count in reversed(list(enumerate(level_count))): + if count == 0: + for index in range(level_id, num_levels): + level_map[index] -= 1 + del journey_levels[level_id] + # re-index remaining journey_levels + for level in journey_levels: + for rule in level["transition_rules"]: + next_level = rule["next_journey_level"] + rule["next_journey_level"] = level_map[next_level] + return journey_levels + + @_m.logbook_trace("Transit assignment by demand set", save_arguments=True) + def run_assignment(self, period, params, network, day_pass_cost, skims_only, num_processors): + modeller = _m.Modeller() + scenario = self.scenario + emmebank = scenario.emmebank + assign_transit = modeller.tool( + "inro.emme.transit_assignment.extended_transit_assignment") + + walk_modes = ["a", "w", "x"] + local_bus_mode = ["b"] + premium_modes = ["c", "l", "e", "p", "r", "y", "o"] + + # get the generic all-modes journey levels table + journey_levels = self.all_modes_journey_levels(params, network, day_pass_cost) + local_bus_journey_levels = self.filter_journey_levels_by_mode(local_bus_mode, journey_levels) + premium_modes_journey_levels = self.filter_journey_levels_by_mode(premium_modes, journey_levels) + # All modes transfer penalty assignment uses penalty of 15 minutes + for level in journey_levels[1:]: + level["boarding_time"] = {"global": {"penalty": 15, "perception_factor": 1}} + + base_spec = { + "type": "EXTENDED_TRANSIT_ASSIGNMENT", + "modes": [], + "demand": "", + "waiting_time": { + "effective_headways": params["init_headway"], "headway_fraction": 0.5, + "perception_factor": params["init_wait"], "spread_factor": 1.0 + }, + # Fare attributes + "boarding_cost": {"global": {"penalty": 0, "perception_factor": 1}}, + "boarding_time": {"global": {"penalty": 0, "perception_factor": 1}}, + "in_vehicle_cost": {"penalty": "@coaster_fare_inveh", + "perception_factor": params["coaster_fare_percep"]}, + "in_vehicle_time": {"perception_factor": params["in_vehicle"]}, + "aux_transit_time": {"perception_factor": params["walk"]}, + "aux_transit_cost": None, + "journey_levels": [], + "flow_distribution_between_lines": {"consider_total_impedance": False}, + "flow_distribution_at_origins": { + "fixed_proportions_on_connectors": None, + "choices_at_origins": "OPTIMAL_STRATEGY" + }, + "flow_distribution_at_regular_nodes_with_aux_transit_choices": { + "choices_at_regular_nodes": "OPTIMAL_STRATEGY" + }, + #"circular_lines": { + # "stay": True + #}, + "connector_to_connector_path_prohibition": None, + "od_results": {"total_impedance": None}, + "performance_settings": {"number_of_processors": num_processors} + } + + skim_parameters = OrderedDict([ + ("BUS", { + "modes": walk_modes + local_bus_mode, + "journey_levels": local_bus_journey_levels + }), + ("PREM", { + "modes": walk_modes + premium_modes, + "journey_levels": premium_modes_journey_levels + }), + ("ALLPEN", { + "modes": walk_modes + local_bus_mode + premium_modes, + "journey_levels": journey_levels + }), + ]) + + if skims_only: + access_modes = ["WLK"] + else: + access_modes = ["WLK", "PNR", "KNR"] + add_volumes = False + for a_name in access_modes: + for mode_name, parameters in skim_parameters.iteritems(): + spec = _copy(base_spec) + name = "%s_%s%s" % (period, a_name, mode_name) + spec["modes"] = parameters["modes"] + spec["demand"] = 'mf"%s"' % name + spec["journey_levels"] = parameters["journey_levels"] + assign_transit(spec, class_name=name, add_volumes=add_volumes, scenario=self.scenario) + add_volumes = True + + @_m.logbook_trace("Extract skims", save_arguments=True) + def run_skims(self, name, period, params, max_fare, num_processors, network): + modeller = _m.Modeller() + scenario = self.scenario + emmebank = scenario.emmebank + matrix_calc = modeller.tool( + "inro.emme.matrix_calculation.matrix_calculator") + network_calc = modeller.tool( + "inro.emme.network_calculation.network_calculator") + matrix_results = modeller.tool( + "inro.emme.transit_assignment.extended.matrix_results") + path_analysis = modeller.tool( + "inro.emme.transit_assignment.extended.path_based_analysis") + strategy_analysis = modeller.tool( + "inro.emme.transit_assignment.extended.strategy_based_analysis") + + class_name = "%s_WLK%s" % (period, name) + skim_name = "%s_%s" % (period, name) + self.run_skims.logbook_cursor.write(name="Extract skims for %s, using assignment class %s" % (name, class_name)) + + with _m.logbook_trace("First and total wait time, number of boardings, fares, total walk time, in-vehicle time"): + # First and total wait time, number of boardings, fares, total walk time, in-vehicle time + spec = { + "type": "EXTENDED_TRANSIT_MATRIX_RESULTS", + "actual_first_waiting_times": 'mf"%s_FIRSTWAIT"' % skim_name, + "actual_total_waiting_times": 'mf"%s_TOTALWAIT"' % skim_name, + "total_impedance": 'mf"%s_GENCOST"' % skim_name, + "by_mode_subset": { + "modes": [mode.id for mode in network.modes() if mode.type == "TRANSIT" or mode.type == "AUX_TRANSIT"], + "avg_boardings": 'mf"%s_XFERS"' % skim_name, + "actual_in_vehicle_times": 'mf"%s_TOTALIVTT"' % skim_name, + "actual_in_vehicle_costs": 'mf"TEMP_IN_VEHICLE_COST"', + "actual_total_boarding_costs": 'mf"%s_FARE"' % skim_name, + "perceived_total_boarding_costs": 'mf"TEMP_PERCEIVED_FARE"', + "actual_aux_transit_times": 'mf"%s_TOTALWALK"' % skim_name, + }, + } + matrix_results(spec, class_name=class_name, scenario=scenario, num_processors=num_processors) + with _m.logbook_trace("Distance and in-vehicle time by mode"): + mode_combinations = [ + ("BUS", ["b"], ["IVTT", "DIST"]), + ("LRT", ["l"], ["IVTT", "DIST"]), + ("CMR", ["c"], ["IVTT", "DIST"]), + ("EXP", ["e", "p"], ["IVTT", "DIST"]), + ("BRT", ["r", "y"], ["DIST"]), + ("BRTRED", ["r"], ["IVTT"]), + ("BRTYEL", ["y"], ["IVTT"]), + ("TIER1", ["o"], ["IVTT", "DIST"]), + ] + for mode_name, modes, skim_types in mode_combinations: + dist = 'mf"%s_%sDIST"' % (skim_name, mode_name) if "DIST" in skim_types else None + ivtt = 'mf"%s_%sIVTT"' % (skim_name, mode_name) if "IVTT" in skim_types else None + spec = { + "type": "EXTENDED_TRANSIT_MATRIX_RESULTS", + "by_mode_subset": { + "modes": modes, + "distance": dist, + "actual_in_vehicle_times": ivtt, + }, + } + matrix_results(spec, class_name=class_name, scenario=scenario, num_processors=num_processors) + # Sum total distance + spec = { + "type": "MATRIX_CALCULATION", + "constraint": None, + "result": 'mf"%s_TOTDIST"' % skim_name, + "expression": ('mf"{0}_BUSDIST" + mf"{0}_LRTDIST" + mf"{0}_CMRDIST"' + ' + mf"{0}_EXPDIST" + mf"{0}_BRTDIST" + mf"{0}_TIER1DIST"').format(skim_name), + } + matrix_calc(spec, scenario=scenario, num_processors=num_processors) + + # convert number of boardings to number of transfers + # and subtract transfers to the same line at layover points + with _m.logbook_trace("Number of transfers and total fare"): + spec = { + "trip_components": {"boarding": "@layover_board"}, + "sub_path_combination_operator": "+", + "sub_strategy_combination_operator": "average", + "selected_demand_and_transit_volumes": { + "sub_strategies_to_retain": "ALL", + "selection_threshold": {"lower": -999999, "upper": 999999} + }, + "results": { + "strategy_values": 'TEMP_LAYOVER_BOARD', + }, + "type": "EXTENDED_TRANSIT_STRATEGY_ANALYSIS" + } + strategy_analysis(spec, class_name=class_name, scenario=scenario, num_processors=num_processors) + spec = { + "type": "MATRIX_CALCULATION", + "constraint":{ + "by_value": { + "od_values": 'mf"%s_XFERS"' % skim_name, + "interval_min": 1, "interval_max": 9999999, + "condition": "INCLUDE"}, + }, + "result": 'mf"%s_XFERS"' % skim_name, + "expression": '(%s_XFERS - 1 - TEMP_LAYOVER_BOARD).max.0' % skim_name, + } + matrix_calc(spec, scenario=scenario, num_processors=num_processors) + + # sum in-vehicle cost and boarding cost to get the fare paid + spec = { + "type": "MATRIX_CALCULATION", + "constraint": None, + "result": 'mf"%s_FARE"' % skim_name, + "expression": '(%s_FARE + TEMP_IN_VEHICLE_COST).min.%s' % (skim_name, max_fare), + } + matrix_calc(spec, scenario=scenario, num_processors=num_processors) + + # walk access time - get distance and convert to time with 3 miles / hr + with _m.logbook_trace("Walk time access, egress and xfer"): + path_spec = { + "portion_of_path": "ORIGIN_TO_INITIAL_BOARDING", + "trip_components": {"aux_transit": "length",}, + "path_operator": "+", + "path_selection_threshold": {"lower": 0, "upper": 999999 }, + "path_to_od_aggregation": { + "operator": "average", + "aggregated_path_values": 'mf"%s_ACCWALK"' % skim_name, + }, + "type": "EXTENDED_TRANSIT_PATH_ANALYSIS" + } + path_analysis(path_spec, class_name=class_name, scenario=scenario, num_processors=num_processors) + + # walk egress time - get distance and convert to time with 3 miles/ hr + path_spec = { + "portion_of_path": "FINAL_ALIGHTING_TO_DESTINATION", + "trip_components": {"aux_transit": "length",}, + "path_operator": "+", + "path_selection_threshold": {"lower": 0, "upper": 999999 }, + "path_to_od_aggregation": { + "operator": "average", + "aggregated_path_values": 'mf"%s_EGRWALK"' % skim_name + }, + "type": "EXTENDED_TRANSIT_PATH_ANALYSIS" + } + path_analysis(path_spec, class_name=class_name, scenario=scenario, num_processors=num_processors) + + spec_list = [ + { # walk access time - convert to time with 3 miles/ hr + "type": "MATRIX_CALCULATION", + "constraint": None, + "result": 'mf"%s_ACCWALK"' % skim_name, + "expression": '60.0 * %s_ACCWALK / 3.0' % skim_name, + }, + { # walk egress time - convert to time with 3 miles/ hr + "type": "MATRIX_CALCULATION", + "constraint": None, + "result": 'mf"%s_EGRWALK"' % skim_name, + "expression": '60.0 * %s_EGRWALK / 3.0' % skim_name, + }, + { # transfer walk time = total - access - egress + "type": "MATRIX_CALCULATION", + "constraint": None, + "result": 'mf"%s_XFERWALK"' % skim_name, + "expression": '({name}_TOTALWALK - {name}_ACCWALK - {name}_EGRWALK).max.0'.format(name=skim_name), + }] + matrix_calc(spec_list, scenario=scenario, num_processors=num_processors) + + # transfer wait time + with _m.logbook_trace("Wait time - xfer"): + spec = { + "type": "MATRIX_CALCULATION", + "constraint":{ + "by_value": { + "od_values": 'mf"%s_TOTALWAIT"' % skim_name, + "interval_min": 0, "interval_max": 9999999, + "condition": "INCLUDE"}, + }, + "result": 'mf"%s_XFERWAIT"' % skim_name, + "expression": '({name}_TOTALWAIT - {name}_FIRSTWAIT).max.0'.format(name=skim_name), + } + matrix_calc(spec, scenario=scenario, num_processors=num_processors) + + with _m.logbook_trace("Calculate dwell time"): + with gen_utils.temp_attrs(scenario, "TRANSIT_SEGMENT", ["@dwt_for_analysis"]): + values = scenario.get_attribute_values("TRANSIT_SEGMENT", ["dwell_time"]) + scenario.set_attribute_values("TRANSIT_SEGMENT", ["@dwt_for_analysis"], values) + + spec = { + "trip_components": {"in_vehicle": "@dwt_for_analysis"}, + "sub_path_combination_operator": "+", + "sub_strategy_combination_operator": "average", + "selected_demand_and_transit_volumes": { + "sub_strategies_to_retain": "ALL", + "selection_threshold": {"lower": -999999, "upper": 999999} + }, + "results": { + "strategy_values": 'mf"%s_DWELLTIME"' % skim_name, + }, + "type": "EXTENDED_TRANSIT_STRATEGY_ANALYSIS" + } + strategy_analysis(spec, class_name=class_name, scenario=scenario, num_processors=num_processors) + + expr_params = _copy(params) + expr_params["xfers"] = 15.0 + expr_params["name"] = skim_name + spec = { + "type": "MATRIX_CALCULATION", + "constraint": None, + "result": 'mf"%s_GENCOST"' % skim_name, + "expression": ("{xfer_wait} * {name}_TOTALWAIT " + "- ({xfer_wait} - {init_wait}) * {name}_FIRSTWAIT " + "+ 1.0 * {name}_TOTALIVTT + 0.5 * {name}_BUSIVTT" + "+ (1 / {vot}) * (TEMP_PERCEIVED_FARE + {coaster_fare_percep} * TEMP_IN_VEHICLE_COST)" + "+ {xfers} *({name}_XFERS.max.0) " + "+ {walk} * {name}_TOTALWALK").format(**expr_params) + } + matrix_calc(spec, scenario=scenario, num_processors=num_processors) + return + + def mask_allpen(self, period): + # Reset skims to 0 if not both local and premium + skims = [ + "FIRSTWAIT", "TOTALWAIT", "DWELLTIME", "BUSIVTT", "XFERS", "TOTALWALK", + "LRTIVTT", "CMRIVTT", "EXPIVTT", "LTDEXPIVTT", "BRTREDIVTT", "BRTYELIVTT", "TIER1IVTT", + "GENCOST", "XFERWAIT", "FARE", + "ACCWALK", "XFERWALK", "EGRWALK", "TOTALIVTT", + "BUSDIST", "LRTDIST", "CMRDIST", "EXPDIST", "BRTDIST" , "TIER1DIST"] + localivt_skim = self.get_matrix_data(period + "_ALLPEN_BUSIVTT") + totalivt_skim = self.get_matrix_data(period + "_ALLPEN_TOTALIVTT") + has_premium = numpy.greater((totalivt_skim - localivt_skim), 0) + has_both = numpy.greater(localivt_skim, 0) * has_premium + for skim in skims: + mat_name = period + "_ALLPEN_" + skim + data = self.get_matrix_data(mat_name) + self.set_matrix_data(mat_name, data * has_both) + + def get_matrix_data(self, name): + data = self._matrix_cache.get(name) + if data is None: + matrix = self.scenario.emmebank.matrix(name) + data = matrix.get_numpy_data(self.scenario) + self._matrix_cache[name] = data + return data + + def set_matrix_data(self, name, data): + matrix = self.scenario.emmebank.matrix(name) + self._matrix_cache[name] = data + matrix.set_numpy_data(data, self.scenario) + + def report(self, period): + text = ['
'] + init_matrices = _m.Modeller().tool("sandag.initialize.initialize_matrices") + matrices = init_matrices.get_matrix_names("transit_skims", [period], self.scenario) + num_zones = len(self.scenario.zone_numbers) + num_cells = num_zones ** 2 + text.append( + "Number of zones: %s. Number of O-D pairs: %s. " + "Values outside -9999999, 9999999 are masked in summaries.
" % (num_zones, num_cells)) + text.append("%-25s %9s %9s %9s %13s %9s" % ("name", "min", "max", "mean", "sum", "mask num")) + for name in matrices: + data = self.get_matrix_data(name) + data = numpy.ma.masked_outside(data, -9999999, 9999999, copy=False) + stats = (name, data.min(), data.max(), data.mean(), data.sum(), num_cells-data.count()) + text.append("%-25s %9.4g %9.4g %9.4g %13.7g %9d" % stats) + text.append("
") + title = 'Transit impedance summary for period %s' % period + report = _m.PageBuilder(title) + report.wrap_html('Matrix details', "
".join(text)) + _m.logbook_write(title, report.render()) diff --git a/sandag_abm/src/main/emme/toolbox/assignment/transit_select_analysis.py b/sandag_abm/src/main/emme/toolbox/assignment/transit_select_analysis.py new file mode 100644 index 0000000..8f4b387 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/assignment/transit_select_analysis.py @@ -0,0 +1,217 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// transit_select_analysis.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# This tool runs select type network analysis on the results of one or more +# transit assignments. It is run as a post-process tool after the assignment +# tools are complete, using the saved transit strategies. Any number of +# analyses can be run without needing to rerun the assignments. +# +# +# Inputs: +# Trip components for selection: pick one or more extra attributes which +# identify the network elements of interest by trip component: +# in_vehicle +# aux_transit +# initial_boarding +# transfer_boarding +# transfer_alighting +# final_alighting +# Result suffix: the suffix to use in the naming of per-class result +# attributes and matrices, up to 6 characters. +# Threshold: the minimum number of elements which must be encountered +# for the path selection. +# Scenario: the scenario to analyse. +# +# +# Script example: +""" +import inro.modeller as _m +import os +modeller = _m.Modeller() +desktop = modeller.desktop + +select_link = modeller.tool("sandag.assignment.transit_select_link") + +project_dir = os.path.dirname(desktop.project_path()) +main_directory = os.path.dirname(project_dir) + +transit_emmebank = os.path.join(project_dir, "Database_transit", "emmebank") + +periods = ["EA", "AM", "MD", "PM", "EV"] +period_ids = list(enumerate(periods, start=int(scenario_id) + 1)) + +suffix = "LRT" +threshold = 1 +num_processors = "MAX-1" +selection = { + "in_vehicle": None, + "aux_transit": None, + "initial_boarding": "@selected_line", + "transfer_boarding": None, + "transfer_alighting": None, + "final_alighting": None, +} + +for number, period in period_ids: + scenario = transit_emmebank.scenario(number) + select_link(selection, suffix, threshold, scenario, num_processors) +""" + +TOOLBOX_ORDER = 25 + + +import inro.modeller as _m +import inro.emme.core.exception as _except +import traceback as _traceback + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + + +class TransitSelectAnalysis(_m.Tool(), gen_utils.Snapshot): + + in_vehicle = _m.Attribute(_m.InstanceType) + aux_transit = _m.Attribute(_m.InstanceType) + initial_boarding = _m.Attribute(_m.InstanceType) + transfer_boarding = _m.Attribute(_m.InstanceType) + transfer_alighting = _m.Attribute(_m.InstanceType) + final_alighting = _m.Attribute(_m.InstanceType) + + suffix = _m.Attribute(str) + threshold = _m.Attribute(int) + num_processors = _m.Attribute(str) + + tool_run_msg = "" + + def __init__(self): + self.threshold = 1 + self.num_processors = "MAX-1" + self.attributes = [ + "in_vehicle", "aux_transit", "initial_boarding", "transfer_boarding", + "transfer_alighting", "final_alighting", "suffix", "threshold", + "num_processors"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Transit select analysis" + pb.description = """ + Run select type of analysis (select link, select node, select line ...) on + the results of the transit assignment(s) using a path-based analysis. + Can be used after a transit assignment has been completed.""" + pb.branding_text = "- SANDAG - Assignment" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + with pb.section("Trip components for selection:"): + domains = ["LINK", "NODE", "TRANSIT_SEGMENT", "TRANSIT_LINE"] + pb.add_select_extra_attribute("in_vehicle", title="In-vehicle", filter=domains, allow_none=True) + pb.add_select_extra_attribute("aux_transit", title="Auxilary transit", filter=domains, allow_none=True) + pb.add_select_extra_attribute("initial_boarding", title="Initial boarding", filter=domains, allow_none=True) + pb.add_select_extra_attribute("transfer_boarding", title="Transfer boarding", filter=domains, allow_none=True) + pb.add_select_extra_attribute("transfer_alighting", title="Transfer alighting", filter=domains, allow_none=True) + pb.add_select_extra_attribute("final_alighting", title="Final alighting", filter=domains, allow_none=True) + + pb.add_text_box("suffix", title="Suffix for results (matrices and attributes):", size=6, + note="The suffix to use in the naming of per-class result attributes and matrices, up to 6 characters. " + "Should be unique (existing attributes / matrices will be overwritten).") + pb.add_text_box("threshold", title="Threshold for selection:", + note="The minimum number of links which must be encountered for the path selection. " + "The default value of 1 indicates an 'any' link selection.") + dem_utils.add_select_processors("num_processors", pb, self) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + selection = { + "in_vehicle": self.in_vehicle, + "aux_transit": self.aux_transit, + "initial_boarding": self.initial_boarding, + "transfer_boarding": self.transfer_boarding, + "transfer_alighting": self.transfer_alighting, + "final_alighting": self.final_alighting, + } + scenario = _m.Modeller().scenario + results = self(selection, self.suffix, self.threshold, scenario, self.num_processors) + run_msg = "Traffic assignment completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, selection, suffix, threshold, scenario, num_processors): + attrs = { + "selection": selection, + "suffix": suffix, + "threshold": threshold, + "scenario": scenario.id, + "num_processors": num_processors + } + with _m.logbook_trace("Transit select analysis %s" % suffix, attributes=attrs): + attrs.update(dict((k,v) for k,v in attrs["selection"].iteritems())) + gen_utils.log_snapshot("Transit select analysis", str(self), attrs) + + path_analysis = _m.Modeller().tool( + "inro.emme.transit_assignment.extended.path_based_analysis") + create_attribute = _m.Modeller().tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + + spec = { + "portion_of_path": "COMPLETE", + "trip_components": selection, + "path_operator": "+", + "path_selection_threshold": {"lower": threshold, "upper": 999999}, + "path_to_od_aggregation": None, + "constraint": None, + "analyzed_demand": None, + "results_from_retained_paths": None, + "path_to_od_statistics": None, + "path_details": None, + "type": "EXTENDED_TRANSIT_PATH_ANALYSIS" + } + strategies = scenario.transit_strategies + classes = [x.name for x in strategies.strat_files()] + if not classes: + raise Exception("Results for multi-class transit assignment not available") + + for class_name in classes: + with _m.logbook_trace("Analysis for class %s" % class_name): + seldem_name = "SELDEM_%s_%s" % (class_name, suffix) + desc = "Selected demand for %s %s" % (class_name, suffix) + seldem = dem_utils.create_full_matrix(seldem_name, desc, scenario=scenario) + results_from_retained_paths = { + "paths_to_retain": "SELECTED", + "demand": seldem.named_id, + } + attributes = [ + ("transit_volumes", "TRANSIT_SEGMENT", "@seltr_%s_%s", "%s '%s' sel segment flow"), + ("aux_transit_volumes", "LINK", "@selax_%s_%s", "%s '%s' sel aux transit flow"), + ("total_boardings", "TRANSIT_SEGMENT", "@selbr_%s_%s", "%s '%s' sel boardings"), + ("total_alightings", "TRANSIT_SEGMENT", "@selal_%s_%s", "%s '%s' sel alightings"), + ] + mode_name = class_name.lower()[3:] + for key, domain, name, desc in attributes: + attr = create_attribute(domain, name % (mode_name, suffix), desc % (class_name, suffix), + 0, overwrite=True, scenario=scenario) + results_from_retained_paths[key] = attr.id + spec["results_from_retained_paths"] = results_from_retained_paths + path_analysis(spec, class_name=class_name, scenario=scenario, num_processors=num_processors) + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg diff --git a/sandag_abm/src/main/emme/toolbox/build_toolbox.py b/sandag_abm/src/main/emme/toolbox/build_toolbox.py new file mode 100644 index 0000000..1a9d1b7 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/build_toolbox.py @@ -0,0 +1,411 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// build_toolbox.py /// +#//// /// +#//// Generates an mtbx (Emme Modeller Toolbox), based on the structure /// +#//// of the Python source tree. /// +#//// /// +#//// Usage: build_toolbox.py [-s source_folder] [-p toolbox_path] /// +#//// /// +#//// [-p toolbox_path]: Specifies the name of the MTBX file. /// +#//// If omitted,defaults to "sandag_toolbox.mtbx" /// +#//// [-s source_folder]: The location of the source code folder. /// +#//// If omitted, defaults to the working directory. /// +#//// [-l] [--link] Build the toolbox with references to the files /// +#//// Use with developing or debugging scripts, changes to the /// +#//// scripts can be used with a "Refresh" of the toolbox /// +#//// [-c] [--consolidate] Build the toolbox with copies of the /// +#//// scripts included inside the toolbox. /// +#//// Use to have a "frozen" version of the scripts with node /// +#//// changes available. /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Example: +# python "T:\projects\sr13\develop\emme_conversion\git\sandag_abm\ABM_EMME\src\main\emme\toolbox\build_toolbox.py" --link +# -p "T:\projects\sr14\abm2_test\abm_runs\14_2_0\2035D_Hyperloop\emme_project\Scripts\sandag_toolbox.mtbx" +# -s T:\projects\sr13\develop\emme_conversion\git\sandag_abm\ABM_EMME\src\main\emme\toolbox + + +import os +import re +from datetime import datetime +import subprocess +import sqlite3.dbapi2 as sqllib +import base64 +import pickle + + +def check_namespace(ns): + if not re.match("^[a-zA-Z][a-zA-Z0-9_]*$", ns): + raise Exception("Namespace '%s' is invalid" % ns) + + +def get_emme_version(): + emme_process = subprocess.Popen(['Emme', '-V'], stdout=subprocess.PIPE, stderr=subprocess.PIPE) + output = emme_process.communicate()[0] + return output.split(',')[0] + + +def usc_transform(value): + try: + return unicode(value) + except Exception: + return unicode(str(value), encoding="raw-unicode-escape") + + +class BaseNode(object): + def __init__(self, namespace, title): + check_namespace(namespace) + self.namespace = namespace + self.title = title + self.element_id = None + self.parent = None + self.root = None + self.children = [] + + def add_folder(self, namespace): + node = FolderNode(namespace, parent=self) + self.children.append(node) + return node + + def add_tool(self, script_path, namespace): + try: + node = ToolNode(namespace, script_path, parent=self) + self.children.append(node) + with open(script_path, 'r') as f: + for line in f: + if line.startswith("TOOLBOX_ORDER"): + node.order = int(line.split("=")[1]) + if line.startswith("TOOLBOX_TITLE"): + title = line.split("=")[1].strip() + node.title = title[1:-1] # exclude first and last quotes + except Exception, e: + print script_path, namespace + print type(e), str(e) + return None + return node + + def consolidate(self): + for child in self.children: + child.consolidate() + + def set_toolbox_order(self): + self.element_id = self.root.next_id() + self.children.sort(key=lambda x: x.order) + for child in self.children: + child.set_toolbox_order() + + +class ElementTree(BaseNode): + + def __init__(self, namespace, title): + super(ElementTree, self).__init__(namespace, title) + self.next_element_id = 0 + self.begin = str(datetime.now()) + self.version = "Emme %s" % get_emme_version() + self.root = self + + def next_id(self): + self.next_element_id += 1 + return self.next_element_id + + +class FolderNode(BaseNode): + + def __init__(self, namespace, parent): + title = namespace.replace("_", " ").capitalize() + super(FolderNode, self).__init__(namespace, title) + self.parent = parent + self.root = parent.root + self.element_id = None + + @property + def order(self): + child_order = [child.order for child in self.children if child.order is not None] + if child_order: + return min(child_order) + return None + + +class ToolNode(): + + def __init__(self, namespace, script_path, parent): + check_namespace(namespace) + self.namespace = namespace + self.title = namespace.replace("_", " ").capitalize() + + self.root = parent.root + self.parent = parent + self.element_id = None + self.order = None + + self.script = script_path + self.extension = '.py' + self.code = '' + + def consolidate(self): + with open(self.script, 'r') as f: + code = f.read() + self.code = usc_transform(base64.b64encode(pickle.dumps(code))) + self.script = '' + + def set_toolbox_order(self): + self.element_id = self.root.next_id() + +class MTBXDatabase(): + FORMAT_MAGIC_NUMBER = 'B8C224F6_7C94_4E6F_8C2C_5CC06F145271' + TOOLBOX_MAGIC_NUMBER = 'TOOLBOX_C6809332_CD61_45B3_9060_411D825669F8' + CATEGORY_MAGIC_NUMBER = 'CATEGORY_984876A0_3350_4374_B47C_6D9C5A47BBC8' + TOOL_MAGIC_NUMBER = 'TOOL_1AC06B56_6A54_431A_9515_0BF77013646F' + + def __init__(self, filepath, title): + if os.path.exists(filepath): + os.remove(filepath) + + self.db = sqllib.connect(filepath) + + self._create_attribute_table() + self._create_element_table() + self._create_document_table() + self._create_triggers() + + self._initialize_documents_table(title) + + def _create_attribute_table(self): + sql = """CREATE TABLE attributes( + element_id INTEGER REFERENCES elements(element_id), + name VARCHAR, + value VARCHAR, + PRIMARY KEY(element_id, name));""" + + self.db.execute(sql) + + def _create_element_table(self): + sql = """CREATE TABLE elements( + element_id INTEGER PRIMARY KEY AUTOINCREMENT, + parent_id INTEGER REFERENCES elements(element_id), + document_id INTEGER REFERENCES documents(document_id), + tag VARCHAR, + text VARCHAR, + tail VARCHAR);""" + + self.db.execute(sql) + + def _create_document_table(self): + sql = """CREATE TABLE documents( + document_id INTEGER PRIMARY KEY AUTOINCREMENT, + title VARCHAR);""" + + self.db.execute(sql) + + def _create_triggers(self): + sql = """CREATE TRIGGER documents_delete + BEFORE DELETE on documents + FOR EACH ROW BEGIN + DELETE FROM elements WHERE document_id = OLD.document_id; + END""" + + self.db.execute(sql) + + sql = """CREATE TRIGGER elements_delete + BEFORE DELETE on elements + FOR EACH ROW BEGIN + DELETE FROM attributes WHERE element_id = OLD.element_id; + END""" + + self.db.execute(sql) + + def _initialize_documents_table(self, title): + sql = """INSERT INTO documents (document_id, title) + VALUES (1, '%s');""" % title + + self.db.execute(sql) + self.db.commit() + + def populate_tables_from_tree(self, tree): + + #Insert into the elements table + column_string = "element_id, document_id, tag, text, tail" + value_string = "{id}, 1, '{title}', '', ''".format( + id=tree.element_id, title=tree.title) + sql = """INSERT INTO elements (%s) + VALUES (%s);""" % (column_string, value_string) + self.db.execute(sql) + + #Insert into the attributes table + column_string = "element_id, name, value" + atts = {'major': '', + 'format': MTBXDatabase.FORMAT_MAGIC_NUMBER, + 'begin': tree.begin, + 'version': tree.version, + 'maintenance': '', + 'minor': '', + 'name': tree.title, + 'description': '', + 'namespace': tree.namespace, + MTBXDatabase.TOOLBOX_MAGIC_NUMBER: 'True'} + for key, val in atts.iteritems(): + value_string = "{id}, '{name}', '{value}'".format( + id=tree.element_id, name=key, value=val) + sql = """INSERT INTO attributes (%s) + VALUES (%s);""" % (column_string, value_string) + self.db.execute(sql) + + self.db.commit() + + #Handle children nodes + for child in tree.children: + if isinstance(child, ToolNode): + self._insert_tool(child) + else: + self._insert_folder(child) + + def _insert_folder(self, node): + #Insert into the elements table + column_string = "element_id, parent_id, document_id, tag, text, tail" + value_string = "{id}, {parent}, 1, '{title}', '', ''".format( + id=node.element_id, parent=node.parent.element_id, title=node.title) + sql = """INSERT INTO elements (%s) + VALUES (%s);""" % (column_string, value_string) + self.db.execute(sql) + + #Insert into the attributes table + column_string = "element_id, name, value" + atts = {'namespace': node.namespace, + 'description': '', + 'name': node.title, + 'children': [c.element_id for c in node.children], + MTBXDatabase.CATEGORY_MAGIC_NUMBER: 'True'} + for key, val in atts.iteritems(): + value_string = "{id}, '{name}', '{value}'".format( + id=node.element_id, name=key, value=val) + sql = """INSERT INTO attributes (%s) + VALUES (%s);""" % (column_string, value_string) + self.db.execute(sql) + + self.db.commit() + + #Handle children nodes + for child in node.children: + if isinstance(child, ToolNode): + self._insert_tool(child) + else: + self._insert_folder(child) + + def _insert_tool(self, node): + #Insert into the elements table + column_string = "element_id, parent_id, document_id, tag, text, tail" + value_string = "{id}, {parent}, 1, '{title}', '', ''".format( + id=node.element_id, parent=node.parent.element_id, title=node.title) + + sql = """INSERT INTO elements (%s) + VALUES (%s);""" % (column_string, value_string) + self.db.execute(sql) + + #Insert into the attributes table + column_string = "element_id, name, value" + atts = {'code': node.code, + 'description': '', + 'script': node.script, + 'namespace': node.namespace, + 'python_suffix': node.extension, + 'name': node.title, + MTBXDatabase.TOOL_MAGIC_NUMBER: 'True'} + for key, val in atts.iteritems(): + value_string = "{id}, '{name}', '{value!s}'".format( + id=node.element_id, name=key, value=val) + sql = """INSERT INTO attributes (%s) + VALUES (?, ?, ?);""" % column_string + self.db.execute(sql, (node.element_id, key, val)) + + self.db.commit() + + +def build_toolbox(toolbox_file, source_folder, title, namespace, consolidate): + print "------------------------" + print " Build Toolbox Utility" + print "------------------------" + print "" + print "toolbox: %s" % toolbox_file + print "source folder: %s" % source_folder + print "title: %s" % title + print "namespace: %s" % namespace + print "" + + print "Loading toolbox structure" + tree = ElementTree(namespace, title) + explore_source_folder(source_folder, tree) + tree.set_toolbox_order() + print "Done. Found %s elements." % (tree.next_element_id) + if consolidate: + print "Consolidating code..." + tree.consolidate() + print "Consolidate done" + + print "" + print "Building MTBX file..." + mtbx = MTBXDatabase(toolbox_file, title) + mtbx.populate_tables_from_tree(tree) + print "Build MTBX file done." + + +def explore_source_folder(root_folder_path, parent_node): + folders = [] + files = [] + for item in os.listdir(root_folder_path): + itempath = os.path.join(root_folder_path, item) + if os.path.isfile(itempath): + name, extension = os.path.splitext(item) + if extension != '.py': + continue # skip non-Python files + if os.path.normpath(itempath) == os.path.normpath(os.path.abspath(__file__)): + continue # skip this file + files.append((name, extension)) + else: + folders.append(item) + + for foldername in folders: + folderpath = os.path.join(root_folder_path, foldername) + folder_node = parent_node.add_folder(namespace=foldername) + explore_source_folder(folderpath, folder_node) + + for filename, ext in files: + script_path = os.path.join(root_folder_path, filename + ext) + parent_node.add_tool(script_path, namespace=filename) + + +if __name__ == "__main__": + ''' + Usage: build_toolbox.py [-p toolbox_path] [-s source_folder] [-l] [-c] + ''' + + import argparse + parser = argparse.ArgumentParser() + parser.add_argument('-s', '--src', help= "Path to the source code folder. Default is the working folder.") + parser.add_argument('-p', '--path', help= "Output file path. Default is 'sandag_toolbox.mtbx' in the source code folder.") + parser.add_argument('-l', '--link', help= "Link the python source files from their current location (instead of consolidate (compile) the toolbox).", action= 'store_true') + parser.add_argument('-c', '--consolidate', help= "Consolidate (compile) the toolbox (default option).", action= 'store_true') + + args = parser.parse_args() + + source_folder = args.src or os.path.dirname(os.path.abspath(__file__)) + folder_name = os.path.split(source_folder)[1] + toolbox_file = args.path or "sandag_toolbox.mtbx" + title = "SANDAG toolbox" + namespace = "sandag" + consolidate = args.consolidate + link = args.link + if consolidate and link: + raise Exception("-l and -c (--link and --consolidate) are mutually exclusive options") + if not consolidate and not link: + consolidate = True # default if neither is specified + + build_toolbox(toolbox_file, source_folder, title, namespace, consolidate) diff --git a/sandag_abm/src/main/emme/toolbox/diagnostic/mode_choice_diagnostic.py b/sandag_abm/src/main/emme/toolbox/diagnostic/mode_choice_diagnostic.py new file mode 100644 index 0000000..f9f1ab1 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/diagnostic/mode_choice_diagnostic.py @@ -0,0 +1,669 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright RSG, 2019-2020. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/mode_choice_diagnostic.py /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Diagnostic tool for the SANDAG activity-based travel model mode choice results. +# This script first generates synthetic population files for target markets. +# Users may input target market parameters via the "syn_pop_attributes.yaml" file. +# Users must additionally input origin and destination MAZs (i.e. MGRAs) via the +# "origin_mgra.csv" and "destination_mgra.csv" files. +# +# Once all synthetic population files have been created, the script creates a copy of +# the "sandag_abm.properties" file and modifies specific property parameters so that +# it is compatible with a the mode choice diagnostic tool. The modified properties +# file is renamed as "sandag_abm_mcd.properties" +# +# Finally, the mode choice diagnostic tool is run via "runSandagAbm_MCDiagnostic.cmd" +# The mode choice diagnostic tool uses the synthetic population files as inputs and +# outputs a tour file with utilities and probabilities for each tour mode. +# +# Files referenced: +# input\mcd\destination_mgra.csv +# input\mcd\origin_mgra.csv +# input\mcd\syn_pop_attributes.yaml +# output\mcd\mcd_households.csv +# output\mcd\mcd_persons.csv +# output\mcd\mcd_output_households.csv +# output\mcd\mcd_output_persons.csv +# output\mcd\mcd_work_location.csv +# output\mcd\mcd_tour_file.csv +# conf\sandag_abm.properties +# bin\runSandagAbm_MCDiagnostic.cmd + +import inro.modeller as _m + +import pandas as pd +import collections, os +import shutil as _shutil +import yaml +import warnings +import traceback as _traceback +import tempfile as _tempfile +import subprocess as _subprocess + +warnings.filterwarnings("ignore") + +_join = os.path.join +_dir = os.path.dirname + +class mode_choice_diagnostic(_m.Tool()): + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = _dir(_m.Modeller().desktop.project.path) + self.main_directory = _dir(project_dir) + self.properties_path = _join(_dir(project_dir), "conf") + self.mcd_out_path = _join(_dir(project_dir), "output", "mcd") + self.syn_pop_attributes_path = _join(_dir(project_dir), "input", "mcd", "syn_pop_attributes.yaml") + self.origin_mgra_path = _join(_dir(project_dir), "input", "mcd", "origin_mgra.csv") + self.destination_mgra_path = _join(_dir(project_dir), "input", "mcd", "destination_mgra.csv") + self.household_df = pd.DataFrame() + self.household_out_df = pd.DataFrame() + self.person_df = pd.DataFrame() + self.person_out_df = pd.DataFrame() + self.work_location_df = pd.DataFrame() + self.tour_df = pd.DataFrame() + self.household_attributes = {} + self.person_attributes = {} + self.tour_attributes = {} + self._log_level = "ENABLED" + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Mode Choice Diagnostic Tool" + pb.description = """ + Diagnostic tool for the activity-based travel model mode choice results.
+
+
+ This tool first generates synthetic population files for specified target markets. + Users may edit target market attributes via a configuration file. + Users may additionally select origin and destination MAZs (i.e. MGRAs) of interest via + input CSV files.

+ The configuration file and MAZ selection CSV files are read from the following locations:
+ + The synthetic population generator outputs the following files:
+ + Once all synthetic population files have been created, the script creates a copy of + the "sandag_abm.properties" file and modifies specific property parameters so that + it is compatible with the mode choice diagnostic tool. The modified properties + file is renamed and output as "conf\sandag_abm_mcd.properties"
+
+ Finally, the mode choice diagnostic tool is run via runSandagAbm_MCDiagnostic.cmd + The mode choice diagnostic tool uses the synthetic population files as inputs and + outputs a tour file with utilities and probabilities for each tour mode. The tour file + is output as "output\mcd\indivTourData_5.csv" +
+ """ + pb.branding_text = "SANDAG - Mode Choice Diagnostic Tool" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self() + run_msg = "Mode Choice Diagnostic Complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self): + _m.logbook_write("Started running mode choice diagnostic...") + + # check if transit shapefiles are present in mcd input directory + # if present, will move to mcd output directory + _m.logbook_write("Checking for transit shapefiles...") + self.check_shp() + + # run synthetic population generator + _m.logbook_write("Creating synthetic population...") + self.syn_pop() + + # copy and edit properties file + _m.logbook_write("Copying and editing properties file...") + mcd_props = self.copy_edit_props() + + self.set_global_logbook_level(mcd_props) + + drive, path_no_drive = os.path.splitdrive(self.main_directory) + + # run matrix manager + _m.logbook_write("Running matrix manager...") + self.run_proc("runMtxMgr.cmd", [drive, drive + path_no_drive], "Start matrix manager") + + # run driver + _m.logbook_write("Running JPPF driver...") + self.run_proc("runDriver.cmd", [drive, drive + path_no_drive], "Start JPPF driver") + + # run household manager + _m.logbook_write("Running household manager, JPPF driver, and nodes...") + self.run_proc("StartHHAndNodes.cmd", [drive, path_no_drive], "Start household manager, JPPF driver, and nodes") + + # run diagnostic tool + _m.logbook_write("Running mode choice diagnostic tool...") + path_forward_slash = path_no_drive.replace("\\", "/") + self.run_proc( + "runSandagAbm_MCDiagnostic.cmd", + [drive, drive + path_forward_slash, 1.0, 5], + "Java-Run Mode Choice Diagnostic Tool", capture_output=True) + + # move final output mcd files to the mcd output directory + self.move_mcd_files() + + def syn_pop(self): + # Creates sample synthetic population files for desired target market. Files will in turn + # be used as inputs to the mode choice diagnostic tool + + load_properties = _m.Modeller().tool("sandag.utilities.properties") + props = load_properties(self.properties_path) + + mgra_data_path = _join(self.main_directory, props["mgra.socec.file"]) + + file_paths = [self.syn_pop_attributes_path, self.origin_mgra_path, self.destination_mgra_path, mgra_data_path] + + for path in file_paths: + if not os.path.exists(path): + raise Exception("missing file '%s'" % (path)) + + # create output directory if it donesn't already exist + if not os.path.exists(self.mcd_out_path): + os.makedirs(self.mcd_out_path) + + # read inputs + mgra_data = pd.read_csv(mgra_data_path)[['mgra', 'taz']] + origin_mgra_data = list(set(pd.read_csv(self.origin_mgra_path)['MGRA'])) + destination_mgra_data = list(set(pd.read_csv(self.destination_mgra_path)['MGRA'])) + + # read synthetic population attributes + with open (self.syn_pop_attributes_path) as file: + syn_pop_attributes = yaml.load(file, Loader = yaml.Loader) + + self.household_attributes = syn_pop_attributes["household"] + self.person_attributes = syn_pop_attributes["person"] + self.tour_attributes = syn_pop_attributes["tour"] + + # create households input file + self.household_in(origin_mgra_data, mgra_data) + + # create households output file + self.household_out() + + # create persons input file + self.person_in() + + # create persons output file + self.person_out() + + # create output work location file + self.work_location(destination_mgra_data) + + # create individual tour file + self.tour() + + def household_in(self, origin_mgra_data, mgra_data): + # Creates the input household file + + # fixed household attributes + household = collections.OrderedDict([ + ('hworkers', [1]), # number of hh workers: one worker per household + ('persons', [2]), # number of hh persons: two persons per household + ('version', [0]), # synthetic population version + ]) + + household_df = pd.DataFrame.from_dict(household) + household_df = self.replicate_df_for_variable(household_df, 'mgra', origin_mgra_data) + for key, values in self.household_attributes.items(): + household_df = self.replicate_df_for_variable(household_df, key, self.maybe_list(values)) + household_df['hinccat1'] = household_df.apply(lambda hh_row: self.hinccat(hh_row), axis = 1) + household_df = self.replicate_df_for_variable(household_df, 'poverty', [1]) + household_df = pd.merge(left = household_df, right = mgra_data, on = 'mgra') + household_df = household_df.reset_index(drop = True) + household_df['hhid'] = household_df.index + 1 + household_df['household_serial_no'] = 0 + + # reorder columns + household_df = household_df[['hhid', 'household_serial_no', 'taz', 'mgra', 'hinccat1', 'hinc', 'hworkers', + 'veh','persons', 'hht', 'bldgsz', 'unittype', 'version', 'poverty']] + + self.household_df = household_df + + # print + household_df.to_csv(_join(self.mcd_out_path, 'mcd_households.csv'), index = False) + + def household_out(self): + # Creates the output household file + + household_out_df = self.household_df.copy() + household_out_df = household_out_df[['hhid', 'mgra', 'hinc', 'veh']] + household_out_df['transponder'] = 1 + household_out_df['cdap_pattern'] = 'MNj' + household_out_df['out_escort_choice'] = 0 + household_out_df['inb_escort_choice'] = 0 + household_out_df['jtf_choice'] = 0 + if self.tour_attributes['av_avail']: + household_out_df['AVs'] = household_out_df['veh'] + household_out_df['veh'] = 0 + else: + household_out_df['AVs'] = 0 + + # rename columns + household_out_df.rename(columns = {'hhid':'hh_id', 'mgra':'home_mgra', 'hinc':'income', 'veh':'HVs'}, + inplace = True) + + self.household_out_df = household_out_df + + # print + household_out_df.to_csv(_join(self.mcd_out_path, 'mcd_output_households.csv'), index = False) + + def person_in(self): + # Creates the input person file + + # fixed person attributes + persons = collections.OrderedDict([ + ('pnum', [1, 2]), # person number: two per household + ('pemploy', [1, 3]), # employment status: full-time employee and unemployed + ('ptype', [1, 4]), # person type: full-time worker and non-working adult + ('occen5', [0, 0]), # occupation + ('occsoc5', ['11-1021', '00-0000']), # occupation code# + ('indcen', [0, 0]), # industry code + ('weeks', [1, 0]), # weeks worked + ('hours', [35, 0]), # hours worked + ('race1p', [9, 9]), # race + ('hisp', [1, 1]), # hispanic flag + ('version', [9, 9]), # synthetic population run version: 9 is new for disaggregate population + ('timeFactorWork', [1, 1]), # work travel time factor: 1 is the mean + ('timeFactorNonWork', [1, 1]), # non work travel time factor: 2 is the mean + ('DAP', ['M', 'N']) # daily activity pattern: M (Mandatory), N (Non-Mandatory) + ]) + + persons.update(self.person_attributes) + person_df = pd.DataFrame.from_dict(persons) + person_df['join_key'] = 1 + self.household_df['join_key'] = 1 + person_df = pd.merge(left = person_df, right = self.household_df[['hhid','household_serial_no', 'join_key']]).\ + drop(columns = ['join_key']) + person_df['pstudent'] = person_df.apply(lambda person_row: self.pstudent(person_row), axis = 1) + person_df = person_df.sort_values(by = 'hhid') + person_df = person_df.reset_index(drop = True) + person_df['perid'] = person_df.index + 1 + + # reorder columns + person_df = person_df[['hhid', 'perid', 'household_serial_no', 'pnum', 'age', 'sex', 'miltary', 'pemploy', + 'pstudent', 'ptype', 'educ', 'grade', 'occen5', 'occsoc5', 'indcen', 'weeks', 'hours', + 'race1p', 'hisp', 'version', 'timeFactorWork', 'timeFactorNonWork', 'DAP']] + + self.person_df = person_df + + # print + person_df.to_csv(_join(self.mcd_out_path, 'mcd_persons.csv'), index = False) + + def person_out(self): + # Creates the output person file + + person_out_df = self.person_df.copy() + person_out_df = person_out_df[['hhid', 'perid', 'pnum', 'age', 'sex', 'ptype', 'DAP', + 'timeFactorWork', 'timeFactorNonWork']] + person_out_df['gender'] = person_out_df['sex'].apply(lambda x: 'male' if x == 1 else 'female') + person_out_df['type'] = person_out_df.apply(lambda person_row: self.p_type(person_row), axis = 1) + person_out_df['value_of_time'] = 0 + person_out_df['imf_choice'] = person_out_df['pnum'].apply(lambda x: 1 if x == 1 else 0) + person_out_df['inmf_choice'] = person_out_df['pnum'].apply(lambda x: 0 if x == 1 else 36) + person_out_df['fp_choice'] = person_out_df['pnum'].apply(lambda x: 2 if x == 1 else -1) + person_out_df['reimb_pct'] = 0 + person_out_df['tele_choice'] = person_out_df['pnum'].apply(lambda x: 1 if x == 1 else -1) + person_out_df['ie_choice'] = 1 + + # drop columns not required + person_out_df.drop(columns = ['sex', 'ptype'], inplace = True) + + # rename columns + person_out_df.rename(columns = {'hhid':'hh_id', 'perid':'person_id', + 'pnum':'person_num', 'DAP':'activity_pattern'}, + inplace = True) + + # reorder columns + person_out_df = person_out_df[['hh_id', 'person_id', 'person_num', 'age', 'gender', 'type', 'value_of_time', + 'activity_pattern', 'imf_choice', 'inmf_choice', 'fp_choice', 'reimb_pct', + 'tele_choice', 'ie_choice', 'timeFactorWork', 'timeFactorNonWork']] + + self.person_out_df = person_out_df + + # print + person_out_df.to_csv(_join(self.mcd_out_path, 'mcd_output_persons.csv'), index = False) + + def work_location(self, destination_mgra_data): + # Creates the output work location file + + # create copies and subset household and person dataframes + household_subset_df = self.household_df.copy() + person_subset_df = self.person_df.copy() + household_subset_df = household_subset_df[['hhid', 'mgra', 'hinc']] + person_subset_df = person_subset_df[['hhid', 'perid', 'pnum', 'ptype', 'age', 'pemploy', 'pstudent']] + + # merge to create work location dataframe + work_location_df = pd.merge(left = household_subset_df, right = person_subset_df, on = 'hhid') + work_location_df['WorkSegment'] = work_location_df['pnum'].apply(lambda x: 0 if x == 1 else -1) + work_location_df['SchoolSegment'] = -1 + work_location_df = self.replicate_df_for_variable(work_location_df, 'WorkLocation', self.maybe_list(destination_mgra_data)) + work_location_df['WorkLocationDistance'] = 0 + work_location_df['WorkLocationLogsum'] = 0 + work_location_df['SchoolLocation'] = -1 + work_location_df['SchoolLocationDistance'] = 0 + work_location_df['SchoolLocationLogsum'] = 0 + + # rename columns + work_location_df.rename(columns = {'hhid':'HHID', 'mgra':'homeMGRA', 'hinc':'income', 'perid':'personID', + 'pnum':'personNum', 'ptype':'personType', 'age':'personAge', + 'pemploy':'Employment Category', 'pstudent':'StudentCategory'}, + inplace = True) + + # reorder columns + work_location_df = work_location_df[['HHID', 'homeMGRA', 'income', 'personID', 'personNum', 'personType', + 'personAge', 'Employment Category', 'StudentCategory', 'WorkSegment', + 'SchoolSegment', 'WorkLocation', 'WorkLocationDistance', 'WorkLocationLogsum', + 'SchoolLocation', 'SchoolLocationDistance', 'SchoolLocationLogsum']] + + self.work_location_df = work_location_df + + # print + work_location_df.to_csv(_join(self.mcd_out_path, 'mcd_work_location.csv'), index = False) + + def tour(self): + # Creates the individual tour file + + tour_df = self.work_location_df.copy() + tour_df = tour_df[['HHID', 'personID', 'personNum', 'personType', 'homeMGRA', 'WorkLocation']] + tour_df = tour_df.sort_values(by = list(tour_df.columns), ascending = True) + tour_df['tour_id'] = tour_df.groupby(['HHID', 'personID']).cumcount() + tour_df['tour_category'] = tour_df['personNum'].\ + apply(lambda x: 'INDIVIDUAL_MANDATORY' if x == 1 else 'INDIVIDUAL_NON_MANDATORY') + tour_df['tour_purpose'] = tour_df['personNum'].apply(lambda x: 'Work' if x == 1 else 'Shop') + tour_df['start_period'] = tour_df['personNum'].apply(lambda x: self.tour_attributes['start_period'][0] if x == 1 else self.tour_attributes['start_period'][1]) + tour_df['end_period'] = tour_df['personNum'].apply(lambda x: self.tour_attributes['end_period'][0] if x == 1 else self.tour_attributes['end_period'][1]) + tour_df['tour_mode'] = 0 + if self.tour_attributes['av_avail']: + tour_df['av_avail'] = 1 + else: + tour_df['av_avail'] = 0 + tour_df['tour_distance'] = 0 + tour_df['atwork_freq'] = tour_df['personNum'].apply(lambda x: 1 if x == 1 else 0) + tour_df['num_ob_stops'] = 0 + tour_df['num_ib_stops'] = 0 + tour_df['valueOfTime'] = 0 + tour_df['escort_type_out'] = 0 + tour_df['escort_type_in'] = 0 + tour_df['driver_num_out'] = 0 + tour_df['driver_num_in'] = 0 + + # utilities 1 through 13 + util_cols = [] + for x in range(1, 14, 1): + col_name = 'util_{}'.format(x) + tour_df[col_name] = 0 + util_cols.append(col_name) + + # probabilities 1 through 13 + prob_cols = [] + for x in range(1, 14, 1): + col_name = 'prob_{}'.format(x) + tour_df[col_name] = 0 + prob_cols.append(col_name) + + # rename columns + tour_df.rename(columns = {'HHID':'hh_id', 'personID':'person_id', 'personNum':'person_num', + 'personType':'person_type', 'homeMGRA':'orig_mgra', 'WorkLocation':'dest_mgra'}, + inplace = True) + + # reorder columns + tour_df = tour_df[['hh_id', 'person_id', 'person_num', 'person_type', 'tour_id', 'tour_category', + 'tour_purpose', 'orig_mgra', 'dest_mgra', 'start_period', 'end_period', + 'tour_mode', 'av_avail', 'tour_distance', 'atwork_freq', 'num_ob_stops', + 'num_ib_stops', 'valueOfTime', 'escort_type_out', 'escort_type_in', + 'driver_num_out', 'driver_num_in'] + util_cols + prob_cols] + + self.tour_df = tour_df + + # print + tour_df.to_csv(_join(self.mcd_out_path, 'mcd_tour_file.csv'), index = False) + + def replicate_df_for_variable(self, df, var_name, var_values): + new_var_df = pd.DataFrame({var_name: var_values}) + new_var_df['join_key'] = 1 + df['join_key'] = 1 + + ret_df = pd.merge(left = df, right = new_var_df, how = 'outer').drop(columns=['join_key']) + return ret_df + + def maybe_list(self, values): + if (type(values) is not list) and (type(values) is not int): + raise Exception('Attribute values may only be of type list or int.') + if type(values) is not list: + return [values] + else: + return values + + def hinccat(self, hh_row): + if hh_row['hinc'] < 30000: + return 1 + if hh_row['hinc'] >= 30000 and hh_row['hinc'] < 60000: + return 2 + if hh_row['hinc'] >= 60000 and hh_row['hinc'] < 100000: + return 3 + if hh_row['hinc'] >= 100000 and hh_row['hinc'] < 150000: + return 4 + if hh_row['hinc'] >= 150000: + return 5 + + def pstudent(self, person_row): + if person_row['grade'] == 0: + return 3 + if person_row['grade'] == 1: + return 1 + if person_row['grade'] == 2: + return 1 + if person_row['grade'] == 3: + return 1 + if person_row['grade'] == 4: + return 1 + if person_row['grade'] == 5: + return 1 + if person_row['grade'] == 6: + return 2 + if person_row['grade'] == 7: + return 2 + + def p_type(self, person_row): + if person_row['ptype'] == 1: + return 'Full-time worker' + if person_row['ptype'] == 2: + return 'Part-time worker' + if person_row['ptype'] == 3: + return 'University student' + if person_row['ptype'] == 4: + return 'Non-worker' + if person_row['ptype'] == 5: + return 'Retired' + if person_row['ptype'] == 6: + return 'Student of driving age' + if person_row['ptype'] == 7: + return 'Student of non-driving age' + if person_row['ptype'] == 8: + return 'Child too young for school' + + def copy_edit_props(self): + # Copy and edit properties file tokens to be compatible with the mode choice diagnostic tool + + load_properties = _m.Modeller().tool("sandag.utilities.properties") + mcd_props = load_properties(_join(self.properties_path, "sandag_abm.properties")) + + # update properties + + # PopSyn inputs + mcd_props["RunModel.MandatoryTourModeChoice"] = "true" + mcd_props["RunModel.IndividualNonMandatoryTourModeChoice"] = "true" + + # data file paths + mcd_props["PopulationSynthesizer.InputToCTRAMP.HouseholdFile"] = "output/mcd/mcd_households.csv" + mcd_props["PopulationSynthesizer.InputToCTRAMP.PersonFile"] = "output/mcd/mcd_persons.csv" + mcd_props["Accessibilities.HouseholdDataFile"] = "output/mcd/mcd_output_households.csv" + mcd_props["Accessibilities.PersonDataFile"] = "output/mcd/mcd_output_persons.csv" + mcd_props["Accessibilities.IndivTourDataFile"] = "output/mcd/mcd_tour_file.csv" + mcd_props["Accessibilities.JointTourDataFile"] = "" + mcd_props["Accessibilities.IndivTripDataFile"] = "" + mcd_props["Accessibilities.JointTripDataFile"] = "" + + # model component run flags + mcd_props["RunModel.PreAutoOwnership"] = "false" + mcd_props["RunModel.UsualWorkAndSchoolLocationChoice"] = "false" + mcd_props["RunModel.AutoOwnership"] = "false" + mcd_props["RunModel.TransponderChoice"] = "false" + mcd_props["RunModel.FreeParking"] = "false" + mcd_props["RunModel.CoordinatedDailyActivityPattern"] = "false" + mcd_props["RunModel.IndividualMandatoryTourFrequency"] = "false" + mcd_props["RunModel.MandatoryTourModeChoice"] = "true" + mcd_props["RunModel.MandatoryTourDepartureTimeAndDuration"] = "false" + mcd_props["RunModel.SchoolEscortModel"] = "false" + mcd_props["RunModel.JointTourFrequency"] = "false" + mcd_props["RunModel.JointTourLocationChoice"] = "false" + mcd_props["RunModel.JointTourDepartureTimeAndDuration"] = "false" + mcd_props["RunModel.JointTourModeChoice"] = "true" + mcd_props["RunModel.IndividualNonMandatoryTourFrequency"] = "false" + mcd_props["RunModel.IndividualNonMandatoryTourLocationChoice"] = "false" + mcd_props["RunModel.IndividualNonMandatoryTourDepartureTimeAndDuration"] = "false" + mcd_props["RunModel.IndividualNonMandatoryTourModeChoice"] = "true" + mcd_props["RunModel.AtWorkSubTourFrequency"] = "false" + mcd_props["RunModel.AtWorkSubTourLocationChoice"] = "false" + mcd_props["RunModel.AtWorkSubTourDepartureTimeAndDuration"] = "false" + mcd_props["RunModel.AtWorkSubTourModeChoice"] = "true" + mcd_props["RunModel.StopFrequency"] = "false" + mcd_props["RunModel.StopLocation"] = "false" + + mcd_props.save(_join(self.properties_path, "sandag_abm_mcd.properties")) + + return(mcd_props) + + def run_proc(self, name, arguments, log_message, capture_output=False): + path = _join(self.main_directory, "bin", name) + if not os.path.exists(path): + raise Exception("No command / batch file '%s'" % path) + command = path + " " + " ".join([str(x) for x in arguments]) + attrs = {"command": command, "name": name, "arguments": arguments} + with _m.logbook_trace(log_message, attributes=attrs): + if capture_output and self._log_level != "NO_EXTERNAL_REPORTS": + report = _m.PageBuilder(title="Process run %s" % name) + report.add_html('Command:

%s

' % command) + # temporary file to capture output error messages generated by Java + err_file_ref, err_file_path = _tempfile.mkstemp(suffix='.log') + err_file = os.fdopen(err_file_ref, "w") + try: + output = _subprocess.check_output(command, stderr=err_file, cwd=self.main_directory, shell=True) + report.add_html('Output:

%s
' % output) + except _subprocess.CalledProcessError as error: + report.add_html('Output:

%s
' % error.output) + raise + finally: + err_file.close() + with open(err_file_path, 'r') as f: + error_msg = f.read() + os.remove(err_file_path) + if error_msg: + report.add_html('Error message(s):

%s
' % error_msg) + try: + # No raise on writing report error + # due to observed issue with runs generating reports which cause + # errors when logged + _m.logbook_write("Process run %s report" % name, report.render()) + except Exception as error: + print _time.strftime("%Y-%M-%d %H:%m:%S") + print "Error writing report '%s' to logbook" % name + print error + print _traceback.format_exc(error) + if self._log_level == "DISABLE_ON_ERROR": + _m.logbook_level(_m.LogbookLevel.NONE) + else: + _subprocess.check_call(command, cwd=self.main_directory, shell=True) + + def set_global_logbook_level(self, props): + self._log_level = props.get("RunModel.LogbookLevel", "ENABLED") + log_all = _m.LogbookLevel.ATTRIBUTE | _m.LogbookLevel.VALUE | _m.LogbookLevel.COOKIE | _m.LogbookLevel.TRACE | _m.LogbookLevel.LOG + log_states = { + "ENABLED": log_all, + "DISABLE_ON_ERROR": log_all, + "NO_EXTERNAL_REPORTS": log_all, + "NO_REPORTS": _m.LogbookLevel.ATTRIBUTE | _m.LogbookLevel.COOKIE | _m.LogbookLevel.TRACE | _m.LogbookLevel.LOG, + "TITLES_ONLY": _m.LogbookLevel.TRACE | _m.LogbookLevel.LOG, + "DISABLED": _m.LogbookLevel.NONE, + } + _m.logbook_write("Setting logbook level to %s" % self._log_level) + try: + _m.logbook_level(log_states[self._log_level]) + except KeyError: + raise Exception("properties.RunModel.LogLevel: value must be one of %s" % ",".join(log_states.keys())) + + def move_mcd_files(self): + + out_directory = _join(self.main_directory, "output") + + hh_data = "householdData_5.csv" + ind_tour = "indivTourData_5.csv" + ind_trip = "indivTripData_5.csv" + joint_tour = "jointTourData_5.csv" + joint_trip = "jointTripData_5.csv" + per_data = "personData_5.csv" + mgra_park = "mgraParkingCost.csv" + + files = [hh_data, ind_tour, ind_trip, joint_tour, joint_trip, per_data, mgra_park] + + for file in files: + src = _join(out_directory, file) + if not os.path.exists(src): + raise Exception("missing output file '%s'" % (src)) + dst = _join(self.mcd_out_path, file) + _shutil.move(src, dst) + + def check_shp(self): + + in_directory = _join(self.main_directory, "input", "mcd") + out_directory = self.mcd_out_path + + shp_names = ["tapcov", "rtcov"] + + for shp in shp_names: + + files_to_move = [f for f in os.listdir(in_directory) if shp in f] + + for file in files_to_move: + + src = _join(in_directory, file) + dst = _join(out_directory, file) + if not os.path.exists(src): + raise Exception("missing shapefile '%s'" % (src)) + _shutil.move(src, dst) \ No newline at end of file diff --git a/sandag_abm/src/main/emme/toolbox/export/export_data_loader_matrices.py b/sandag_abm/src/main/emme/toolbox/export/export_data_loader_matrices.py new file mode 100644 index 0000000..c0df738 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/export/export_data_loader_matrices.py @@ -0,0 +1,302 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// export/export_data_loader_matrices.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Exports the matrix results to OMX and csv files for use by the Java Data +# export process and the Data loader to the reporting database. +# +# +# Inputs: +# output_dir: the output directory for the created files +# base_scenario_id: scenario ID for the base scenario (same used in the Import network tool) +# transit_scenario_id: scenario ID for the base transit scenario +# +# Files created: +# CSV format files +# ../report/trucktrip.csv +# ../report/eetrip.csv +# ../report/eitrip.csv +# OMX format files +# trip_pp.omx +# +# +# Script example: +""" + import os + import inro.emme.database.emmebank as _eb + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + main_emmebank = _eb.Emmebank(os.path.join(main_directory, "emme_project", "Database", "emmebank")) + transit_emmebank = _eb.Emmebank(os.path.join(main_directory, "emme_project", "Database", "emmebank")) + output_dir = os.path.join(main_directory, "output") + num_processors = "MAX-1" + export_data_loader_matrices = modeller.tool( + "sandag.export.export_data_loader_matrices") + export_data_loader_matrices(output_dir, 100, main_emmebank, transit_emmebank, num_processors) +""" +TOOLBOX_ORDER = 74 + + +import inro.modeller as _m +import inro.emme.database.emmebank as _eb +import traceback as _traceback +from collections import OrderedDict +import os +import numpy +import warnings +import tables + + +warnings.filterwarnings('ignore', category=tables.NaturalNameWarning) +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + +_join = os.path.join +_dir = os.path.dirname + +class ExportDataLoaderMatrices(_m.Tool(), gen_utils.Snapshot): + + output_dir = _m.Attribute(str) + base_scenario_id = _m.Attribute(int) + transit_scenario_id = _m.Attribute(int) + + tool_run_msg = "" + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.output_dir = os.path.join(os.path.dirname(project_dir), "output") + self.base_scenario_id = 100 + self.transit_scenario_id = 100 + self.periods = ["EA", "AM", "MD", "PM", "EV"] + self.attributes = ["main_directory", "base_scenario_id", "transit_scenario_id"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Export matrices for Data Loader" + pb.description = """ + Export model results to OMX files for export by Data Exporter + to CSV format for load in SQL Data loader.""" + pb.branding_text = "- SANDAG - Export" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('output_dir', 'directory', + title='Select output directory') + + pb.add_text_box('base_scenario_id', title="Base scenario ID:", size=10) + pb.add_text_box('transit_scenario_id', title="Transit scenario ID:", size=10) + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + base_emmebank = _eb.Emmebank(os.path.join(project_dir, "Database", "emmebank")) + transit_emmebank = _eb.Emmebank(os.path.join(project_dir, "Database_transit", "emmebank")) + base_scenario = base_emmebank.scenario(self.base_scenario_id) + transit_scenario = transit_emmebank.scenario(self.transit_scenario_id) + + results = self(self.output_dir, base_scenario, transit_scenario) + run_msg = "Export completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Export matrices for Data Loader", save_arguments=True) + def __call__(self, output_dir, base_scenario, transit_scenario): + attrs = { + "output_dir": output_dir, + "base_scenario_id": base_scenario.id, + "transit_scenario_id": transit_scenario.id, + "self": str(self) + } + gen_utils.log_snapshot("Export Matrices for Data Loader", str(self), attrs) + self.output_dir = output_dir + self.base_scenario = base_scenario + self.transit_scenario = transit_scenario + + self.truck_demand() + self.external_demand() + self.total_demand() + + @_m.logbook_trace("Export truck demand") + def truck_demand(self): + name_mapping = [ + # ("lhdn", "TRKLGP", 1.3), + # ("mhdn", "TRKMGP", 1.5), + # ("hhdn", "TRKHGP", 2.5), + ("lhdt", "TRK_L", 1.3), + ("mhdt", "TRK_M", 1.5), + ("hhdt", "TRK_H", 2.5), + ] + scenario = self.base_scenario + emmebank = scenario.emmebank + zones = scenario.zone_numbers + formater = lambda x: ("%.5f" % x).rstrip('0').rstrip(".") + truck_trip_path = os.path.join(os.path.dirname(self.output_dir), "report", "trucktrip.csv") + + # get auto operating cost + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(_dir(self.output_dir), "conf", "sandag_abm.properties")) + try: + aoc = float(props["aoc.fuel"]) + float(props["aoc.maintenance"]) + except ValueError: + raise Exception("Error during float conversion for aoc.fuel or aoc.maintenance from sandag_abm.properties file") + + with open(truck_trip_path, 'w') as f: + f.write("OTAZ,DTAZ,TOD,MODE,TRIPS,TIME,DIST,AOC,TOLLCOST\n") + for period in self.periods: + for key, name, pce in name_mapping: + matrix_data = emmebank.matrix(period + "_" + name + "_VEH").get_data(scenario) + matrix_data_time = emmebank.matrix(period + "_" + name + "_TIME").get_data(scenario) + matrix_data_dist = emmebank.matrix(period + "_" + name + "_DIST").get_data(scenario) + matrix_data_tollcost = emmebank.matrix(period + "_" + name + "_TOLLCOST").get_data(scenario) + rounded_demand = 0 + for orig in zones: + for dest in zones: + value = matrix_data.get(orig, dest) + # skip trips less than 0.00001 to avoid 0 trips records in database + if value < 0.00001: + rounded_demand += value + continue + time = matrix_data_time.get(orig, dest) + distance = matrix_data_dist.get(orig, dest) + tollcost = matrix_data_tollcost.get(orig, dest) + od_aoc = distance * aoc + f.write(",".join([str(orig), str(dest), period, key, formater(value), formater(time), formater(distance), formater(od_aoc), formater(tollcost)])) + f.write("\n") + if rounded_demand > 0: + print period + "_" + name + "_VEH", "rounded_demand", rounded_demand + + def external_demand(self): + #get auto operating cost + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(_dir(self.output_dir), "conf", "sandag_abm.properties")) + try: + aoc = float(props["aoc.fuel"]) + float(props["aoc.maintenance"]) + except ValueError: + raise Exception("Error during float conversion for aoc.fuel or aoc.maintenance from sandag_abm.properties file") + + # EXTERNAL-EXTERNAL TRIP TABLE (toll-eligible) + name_mapping = [ + ("DA", "SOV"), + ("S2", "HOV2"), + ("S3", "HOV3"), + ] + scenario = self.base_scenario + emmebank = scenario.emmebank + zones = scenario.zone_numbers + formater = lambda x: ("%.5f" % x).rstrip('0').rstrip(".") + ee_trip_path = os.path.join(os.path.dirname(self.output_dir), "report", "eetrip.csv") + with _m.logbook_trace("Export external-external demand"): + with open(ee_trip_path, 'w') as f: + f.write("OTAZ,DTAZ,TOD,MODE,TRIPS,TIME,DIST,AOC,TOLLCOST\n") + for period in self.periods: + matrix_data_time = emmebank.matrix(period + "_SOV_NT_M_TIME").get_data(scenario) + matrix_data_dist = emmebank.matrix(period + "_SOV_NT_M_DIST").get_data(scenario) + matrix_data_tollcost = emmebank.matrix(period + "_SOV_NT_M_TOLLCOST").get_data(scenario) + for key, name in name_mapping: + matrix_data = emmebank.matrix(period + "_" + name + "_EETRIPS").get_data(scenario) + rounded_demand = 0 + for orig in zones: + for dest in zones: + value = matrix_data.get(orig, dest) + # skip trips less than 0.00001 to avoid 0 trips records in database + if value < 0.00001: + rounded_demand += value + continue + time = matrix_data_time.get(orig, dest) + distance = matrix_data_dist.get(orig, dest) + tollcost = 0 + tollcost = matrix_data_tollcost.get(orig, dest) + od_aoc = distance * aoc + f.write(",".join( + [str(orig), str(dest), period, key, formater(value), formater(time), + formater(distance), formater(od_aoc), formater(tollcost)])) + f.write("\n") + if rounded_demand > 0: + print period + "_" + name + "_EETRIPS", "rounded_demand", rounded_demand + + # EXTERNAL-INTERNAL TRIP TABLE + name_mapping = [ + ("DAN", "SOVGP"), + ("DAT", "SOVTOLL"), + ("S2N", "HOV2HOV"), + ("S2T", "HOV2TOLL"), + ("S3N", "HOV3HOV"), + ("S3T", "HOV3TOLL"), + ] + ei_trip_path = os.path.join(os.path.dirname(self.output_dir), "report", "eitrip.csv") + + with _m.logbook_trace("Export external-internal demand"): + with open(ei_trip_path, 'w') as f: + f.write("OTAZ,DTAZ,TOD,MODE,PURPOSE,TRIPS,TIME,DIST,AOC,TOLLCOST\n") + for period in self.periods: + matrix_data_time = emmebank.matrix(period + "_SOV_TR_M_TIME").get_data(scenario) + matrix_data_dist = emmebank.matrix(period + "_SOV_TR_M_DIST").get_data(scenario) + if "TOLL" in name: + matrix_data_tollcost = emmebank.matrix(period + "_SOV_NT_M_TOLLCOST").get_data(scenario) + for purpose in ["WORK", "NONWORK"]: + for key, name in name_mapping: + matrix_data = emmebank.matrix(period + "_" + name + "_EI" + purpose).get_data(scenario) + rounded_demand = 0 + for orig in zones: + for dest in zones: + value = matrix_data.get(orig, dest) + # skip trips less than 0.00001 to avoid 0 trips records in database + if value < 0.00001: + rounded_demand += value + continue + time = matrix_data_time.get(orig, dest) + distance = matrix_data_dist.get(orig, dest) + tollcost = 0 + if "TOLL" in name: + tollcost = matrix_data_tollcost.get(orig, dest) + od_aoc = distance * aoc + f.write(",".join( + [str(orig), str(dest), period, key, purpose, formater(value), formater(time), + formater(distance), formater(od_aoc), formater(tollcost)])) + f.write("\n") + if rounded_demand > 0: + print period + "_" + name + "_EI" + purpose, "rounded_demand", rounded_demand + + @_m.logbook_trace("Export total auto and truck demand to OMX") + def total_demand(self): + for period in self.periods: + matrices = { + "%s_SOV_NT_L": 'mf"%s_SOV_NT_L"', + "%s_SOV_TR_L": 'mf"%s_SOV_TR_L"', + "%s_HOV2_L": 'mf"%s_HOV2_L"', + "%s_HOV3_L": 'mf"%s_HOV3_L"', + "%s_SOV_NT_M": 'mf"%s_SOV_NT_M"', + "%s_SOV_TR_M": 'mf"%s_SOV_TR_M"', + "%s_HOV2_M": 'mf"%s_HOV2_M"', + "%s_HOV3_M": 'mf"%s_HOV3_M"', + "%s_SOV_NT_H": 'mf"%s_SOV_NT_H"', + "%s_SOV_TR_H": 'mf"%s_SOV_TR_H"', + "%s_HOV2_H": 'mf"%s_HOV2_H"', + "%s_HOV3_H": 'mf"%s_HOV3_H"', + "%s_TRK_H": 'mf"%s_TRK_H"', + "%s_TRK_L": 'mf"%s_TRK_L"', + "%s_TRK_M": 'mf"%s_TRK_M"', + } + matrices = dict((k % period, v % period) for k, v in matrices.iteritems()) + omx_file = os.path.join(self.output_dir, "trip_%s.omx" % period) + with gen_utils.ExportOMX(omx_file, self.base_scenario) as exporter: + exporter.write_matrices(matrices) + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg diff --git a/sandag_abm/src/main/emme/toolbox/export/export_data_loader_network.py b/sandag_abm/src/main/emme/toolbox/export/export_data_loader_network.py new file mode 100644 index 0000000..ec38ed3 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/export/export_data_loader_network.py @@ -0,0 +1,1203 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// export_data_loader_network.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Exports the network results to csv file for use by the Java Data export process +# and the Data loader to the reporting database. +# +# +# Inputs: +# main_directory: main ABM directory +# base_scenario_id: scenario ID for the base scenario (same used in the Import network tool) +# traffic_emmebank: the base, traffic, Emme database +# transit_emmebank: the transit database +# num_processors: number of processors to use in the transit analysis calculations +# +# Files created: +# report/hwyload_pp.csv +# report/hwy_tcad.csv rename to hwyTcad.csv +# report/transit_aggflow.csv +# report/transit_flow.csv +# report/transit_onoff.csv +# report/trrt.csv rename to transitRoute.csv +# report/trstop.csv renmae to transitStop.csv +# report/transitTap.csv +# report/transitLink.csv +# +# Script example: +""" + import os + import inro.emme.database.emmebank as _eb + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + main_emmebank = _eb.Emmebank(os.path.join(main_directory, "emme_project", "Database", "emmebank")) + transit_emmebank = _eb.Emmebank(os.path.join(main_directory, "emme_project", "Database_transit", "emmebank")) + num_processors = "MAX-1" + export_data_loader_network = modeller.tool( + "sandag.export.export_data_loader_network") + export_data_loader_network(main_directory, 100, main_emmebank, transit_emmebank, num_processors) +""" + +TOOLBOX_ORDER = 73 + + +import inro.modeller as _m +import traceback as _traceback +import inro.emme.database.emmebank as _eb +import inro.emme.desktop.worksheet as _ws +import inro.emme.datatable as _dt +import inro.emme.core.exception as _except +from contextlib import contextmanager as _context +from collections import OrderedDict +from itertools import chain as _chain +import math +import os +import pandas as pd +import numpy as _np + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + +format = lambda x: ("%.6f" % x).rstrip('0').rstrip(".") +id_format = lambda x: str(int(x)) + +class ExportDataLoaderNetwork(_m.Tool(), gen_utils.Snapshot): + + main_directory = _m.Attribute(str) + base_scenario_id = _m.Attribute(int) + traffic_emmebank = _m.Attribute(str) + transit_emmebank = _m.Attribute(str) + num_processors = _m.Attribute(str) + + tool_run_msg = "" + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.main_directory = os.path.dirname(project_dir) + self.base_scenario_id = 100 + self.traffic_emmebank = os.path.join(project_dir, "Database", "emmebank") + self.transit_emmebank = os.path.join(project_dir, "Database_transit", "emmebank") + self.num_processors = "MAX-1" + self.attributes = ["main_directory", "base_scenario_id", "traffic_emmebank", "transit_emmebank", "num_processors"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Export network for Data Loader" + pb.description = """ +Export network results to csv files for SQL data loader.""" + pb.branding_text = "- SANDAG - Export" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('main_directory', 'directory', + title='Select main directory') + + pb.add_text_box('base_scenario_id', title="Base scenario ID:", size=10) + pb.add_select_file('traffic_emmebank', 'file', + title='Select traffic emmebank') + pb.add_select_file('transit_emmebank', 'file', + title='Select transit emmebank') + + dem_utils.add_select_processors("num_processors", pb, self) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + results = self(self.main_directory, self.base_scenario_id, + self.traffic_emmebank, self.transit_emmebank, + self.num_processors) + run_msg = "Export completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Export network results for Data Loader", save_arguments=True) + def __call__(self, main_directory, base_scenario_id, traffic_emmebank, transit_emmebank, num_processors): + attrs = { + "traffic_emmebank": str(traffic_emmebank), + "transit_emmebank": str(transit_emmebank), + "main_directory": main_directory, + "base_scenario_id": base_scenario_id, + "self": str(self) + } + gen_utils.log_snapshot("Export network results", str(self), attrs) + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) + + traffic_emmebank = _eb.Emmebank(traffic_emmebank) + transit_emmebank = _eb.Emmebank(transit_emmebank) + export_path = os.path.join(main_directory, "report") + input_path = os.path.join(main_directory,"input") + num_processors = dem_utils.parse_num_processors(num_processors) + + periods = ["EA", "AM", "MD", "PM", "EV"] + period_scenario_ids = OrderedDict((v, i) for i, v in enumerate(periods, start=base_scenario_id + 1)) + + base_scenario = traffic_emmebank.scenario(base_scenario_id) + + self.export_traffic_attribute(base_scenario, export_path, traffic_emmebank, period_scenario_ids, props) + self.export_traffic_load_by_period(export_path, traffic_emmebank, period_scenario_ids) + self.export_transit_results(export_path, input_path, transit_emmebank, period_scenario_ids, num_processors) + self.export_geometry(export_path, traffic_emmebank) + + @_m.logbook_trace("Export traffic attribute data") + def export_traffic_attribute(self, base_scenario, export_path, traffic_emmebank, period_scenario_ids, props): + # Several column names are legacy from the original network files + # and data loader process, and are populated with zeros. + # items are ("column name", "attribute name") or ("column name", ("attribute name", default)) + hwylink_attrs = [ + ("ID", "@tcov_id"), + ("Length", "length"), + ("Dir", "is_one_way"), + ("hwycov-id:1", "@tcov_id"), + ("ID:1", "@tcov_id"), + ("Length:1", "length_feet"), + ("QID", "zero"), + ("CCSTYLE", "zero"), + ("UVOL", "zero"), + ("AVOL", "zero"), + ("TMP1", "zero"), + ("TMP2", "zero"), + ("PLOT", "zero"), + ("SPHERE", "@sphere"), + ("RTNO", "zero"), + ("LKNO", "zero"), + ("NM", "#name"), + ("FXNM", "#name_from"), + ("TXNM", "#name_to"), + ("AN", "i"), + ("BN", "j"), + ("COJUR", "zero"), + ("COSTAT", "zero"), + ("COLOC", "zero"), + ("RLOOP", "zero"), + ("ADTLK", "zero"), + ("ADTVL", "zero"), + ("PKPCT", "zero"), + ("TRPCT", "zero"), + ("SECNO", "zero"), + ("DIR:1", "zero"), + ("FFC", "type"), + ("CLASS", "zero"), + ("ASPD", "@speed_adjusted"), + ("IYR", "@year_open_traffic"), + ("IPROJ", "@project_code"), + ("IJUR", "@jurisdiction_type"), + ("IFC", "type"), + ("IHOV", "@lane_restriction"), + ("ITRUCK", "@truck_restriction"), + ("ISPD", "@speed_posted"), + ("ITSPD", "zero"), + ("IWAY", "iway"), + ("IMED", "@median"), + ("COST", "@cost_operating"), + ("ITOLLO", "@toll_md"), + ("ITOLLA", "@toll_am"), + ("ITOLLP", "@toll_pm"), + ] + directional_attrs = [ + ("ABLNO", "@lane_md", "0"), + ("ABLNA", "@lane_am", "0"), + ("ABLNP", "@lane_pm", "0"), + ("ABAU", "@lane_auxiliary", "0"), + ("ABPCT", "zero", "0"), + ("ABPHF", "zero", "0"), + ("ABCNT", "@traffic_control", "0"), + ("ABTL", "@turn_thru", "0"), + ("ABRL", "@turn_right", "0"), + ("ABLL", "@turn_left", "0"), + ("ABTLB", "zero", "0"), + ("ABRLB", "zero", "0"), + ("ABLLB", "zero", "0"), + ("ABGC", "@green_to_cycle_init", "0"), + ("ABPLC", "per_lane_capacity", "1900"), + ("ABCPO", "@capacity_link_md", "999999"), + ("ABCPA", "@capacity_link_am", "999999"), + ("ABCPP", "@capacity_link_pm", "999999"), + ("ABCXO", "@capacity_inter_md", "999999"), + ("ABCXA", "@capacity_inter_am", "999999"), + ("ABCXP", "@capacity_inter_pm", "999999"), + ("ABCHO", "@capacity_hourly_op", "0"), + ("ABCHA", "@capacity_hourly_am", "0"), + ("ABCHP", "@capacity_hourly_pm", "0"), + ("ABTMO", "@time_link_md", "999"), + ("ABTMA", "@time_link_am", "999"), + ("ABTMP", "@time_link_pm", "999"), + ("ABTXO", "@time_inter_md", "0"), + ("ABTXA", "@time_inter_am", "0"), + ("ABTXP", "@time_inter_pm", "0"), + ("ABCST", "zero", "999.999"), + ("ABVLA", "zero", "0"), + ("ABVLP", "zero", "0"), + ("ABLOS", "zero", "0"), + ] + for key, name, default in directional_attrs: + hwylink_attrs.append((key, name)) + for key, name, default in directional_attrs: + hwylink_attrs.append(("BA" + key[2:], (name, default))) + hwylink_attrs.append(("relifac", "relifac")) + + time_period_atts = [ + ("ITOLL2", "@toll"), + ("ITOLL3", "@cost_auto"), + ("ITOLL4", "@cost_med_truck"), + ("ITOLL5", "@cost_hvy_truck"), + ("ITOLL", "toll_hov"), + ("ABCP", "@capacity_link", "999999"), + ("ABCX", "@capacity_inter", "999999"), + ("ABTM", "@time_link", "999"), + ("ABTX", "@time_inter", "0"), + ("ABLN", "@lane", "0"), + ("ABSCST", "sov_total_gencost", ""), + ("ABH2CST", "hov2_total_gencost", ""), + ("ABH3CST", "hov3_total_gencost", ""), + ("ABSTM", "auto_time", ""), + ("ABHTM", "auto_time", ""), + ] + periods = ["_ea", "_am", "_md", "_pm", "_ev"] + for column in time_period_atts: + for period in periods: + key = column[0] + period.upper() + name = column[1] + period + hwylink_attrs.append((key, name)) + if key.startswith("AB"): + for period in periods: + key = column[0] + period.upper() + name = column[1] + period + default = column[2] + hwylink_attrs.append(("BA" + key[2:], (name, default))) + for period in periods: + key = "ABPRELOAD" + period.upper() + name = "additional_volume" + period + default = "0" + hwylink_attrs.append((key, name)) + hwylink_attrs.append(("BA" + key[2:], (name, default))) + + vdf_attrs = [ + ("AB_GCRatio", "@green_to_cycle", ""), + ("AB_Cycle", "@cycle", ""), + ("AB_PF", "progression_factor", ""), + ("ALPHA1", "alpha1", "0.8"), + ("BETA1", "beta1", "4"), + ("ALPHA2", "alpha2", "4.5"), + ("BETA2", "beta2", "2"), + ] + for key, name, default in vdf_attrs: + name = name + "_am" if name.startswith("@") else name + hwylink_attrs.append((key, name)) + if key.startswith("AB"): + hwylink_attrs.append(("BA" + key[2:], (name, default))) + for period in periods: + for key, name, default in vdf_attrs: + name = name + period if name.startswith("@") else name + default = default or "0" + hwylink_attrs.append((key + period.upper(), name)) + if key.startswith("AB"): + hwylink_attrs.append(("BA" + key[2:] + period.upper(), (name, default))) + + network = base_scenario.get_partial_network(["LINK"], include_attributes=True) + + #copy assignment from period scenarios + for period, scenario_id in period_scenario_ids.iteritems(): + from_scenario = traffic_emmebank.scenario(scenario_id) + src_attrs = ["@auto_time", "additional_volume"] + dst_attrs = ["auto_time_" + period.lower(), + "additional_volume_" + period.lower()] + for dst_attr in dst_attrs: + network.create_attribute("LINK", dst_attr) + values = from_scenario.get_attribute_values("LINK", src_attrs) + network.set_attribute_values("LINK", dst_attrs, values) + # add in and calculate additional columns + new_attrs = [ + ("zero", 0), ("is_one_way", 0), ("iway", 2), ("length_feet", 0), + ("toll_hov", 0), ("per_lane_capacity", 1900), + ("progression_factor", 1.0), ("alpha1", 0.8), ("beta1", 4.0), + ("alpha2", 4.5), ("beta2", 2.0), ("relifac", 1.0), + ] + for name, default in new_attrs: + network.create_attribute("LINK", name, default) + for period in periods: + network.create_attribute("LINK", "toll_hov" + period, 0) + network.create_attribute("LINK", "sov_total_gencost" + period, 0) + network.create_attribute("LINK", "hov2_total_gencost" + period, 0) + network.create_attribute("LINK", "hov3_total_gencost" + period, 0) + for link in network.links(): + link.is_one_way = 1 if link.reverse_link else 0 + link.iway = 2 if link.reverse_link else 1 + link.length_feet = link.length * 5280 + for period in periods: + link["toll_hov" + period] = link["@cost_hov2" + period] - link["@cost_operating"] + link["sov_total_gencost" + period] = link["auto_time" + period] + link["@cost_auto" + period] + link["hov2_total_gencost" + period] = link["auto_time" + period] + link["@cost_hov2" + period] + link["hov3_total_gencost" + period] = link["auto_time" + period] + link["@cost_hov3" + period] + if link.volume_delay_func == 24: + link.alpha2 = 6.0 + link.per_lane_capacity = max([(link["@capacity_link" + p] / link["@lane" + p]) + for p in periods if link["@lane" + p] > 0] + [0]) + + hwylink_atts_file = os.path.join(export_path, "hwy_tcad.csv") + busPCE = props["transit.bus.pceveh"] + self.export_traffic_to_csv(hwylink_atts_file, hwylink_attrs, network, busPCE) + + @_m.logbook_trace("Export traffic load data by period") + def export_traffic_load_by_period(self, export_path, traffic_emmebank, period_scenario_ids): + create_attribute = _m.Modeller().tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + net_calculator = _m.Modeller().tool( + "inro.emme.network_calculation.network_calculator") + hwyload_attrs = [("ID1", "@tcov_id")] + + dir_atts = [ + ("AB_Flow_PCE", "@pce_flow"), # sum of pce flow + ("AB_Time", "@auto_time"), # computed vdf based on pce flow + ("AB_VOC", "@voc"), + ("AB_V_Dist_T", "length"), + ("AB_VHT", "@vht"), + ("AB_Speed", "@speed"), + ("AB_VDF", "@msa_time"), + ("AB_MSA_Flow", "@msa_flow"), + ("AB_MSA_Time", "@msa_time"), + ("AB_Flow_SOV_NTPL", "@sov_nt_l"), + ("AB_Flow_SOV_TPL", "@sov_tr_l"), + ("AB_Flow_SR2L", "@hov2_l"), + ("AB_Flow_SR3L", "@hov3_l"), + ("AB_Flow_SOV_NTPM", "@sov_nt_m"), + ("AB_Flow_SOV_TPM", "@sov_tr_m"), + ("AB_Flow_SR2M", "@hov2_m"), + ("AB_Flow_SR3M", "@hov3_m"), + ("AB_Flow_SOV_NTPH", "@sov_nt_h"), + ("AB_Flow_SOV_TPH", "@sov_tr_h"), + ("AB_Flow_SR2H", "@hov2_h"), + ("AB_Flow_SR3H", "@hov3_h"), + ("AB_Flow_lhd", "@trk_l_non_pce"), + ("AB_Flow_mhd", "@trk_m_non_pce"), + ("AB_Flow_hhd", "@trk_h_non_pce"), + ("AB_Flow", "@non_pce_flow"), + ] + + for key, attr in dir_atts: + hwyload_attrs.append((key, attr)) + hwyload_attrs.append((key.replace("AB_", "BA_"), (attr, ""))) # default for BA on one-way links is blank + for p, scen_id in period_scenario_ids.iteritems(): + scenario = traffic_emmebank.scenario(scen_id) + new_atts = [ + ("@speed", "link travel speed", "length*60/@auto_time"), + ("@sov_nt_all", "total number of SOV GP vehicles", + "@sov_nt_l+@sov_nt_m+@sov_nt_h" ), + ("@sov_tr_all", "total number of SOV TOLL vehicles", + "@sov_tr_l+@sov_tr_m+@sov_tr_h" ), + ("@hov2_all", "total number of HOV2 HOV vehicles", + "@hov2_l+@hov2_m+@hov2_h" ), + ("@hov3_all", "total number of HOV3 HOV vehicles", + "@hov3_l+@hov3_m+@hov3_h" ), + ("@trk_l_non_pce", "total number of light trucks in non-Pce", + "(@trk_l)/1.3" ), + ("@trk_m_non_pce", "total medium trucks in non-Pce", + "(@trk_m)/1.5" ), + ("@trk_h_non_pce", "total heavy trucks in non-Pce", + "(@trk_h)/2.5" ), + ("@pce_flow", "total number of vehicles in Pce", + "@sov_nt_all+@sov_tr_all+ \ + @hov2_all+ \ + @hov3_all+ \ + (@trk_l) + (@trk_m) + \ + (@trk_h) + volad" ), + ("@non_pce_flow", "total number of vehicles in non-Pce", + "@sov_nt_all+@sov_tr_all+ \ + @hov2_all+ \ + @hov3_all+ \ + (@trk_l)/1.3 + (@trk_m)/1.5 + \ + (@trk_h)/2.5 + volad/3" ), #volad includes bus flow - pce factor is 3 + ("@msa_flow", "MSA flow", "@non_pce_flow"), #flow from final assignment + ("@msa_time", "MSA time", "timau"), #skim assignment time on msa flow + ("@voc", "volume over capacity", "@pce_flow/ul3"), #pce flow over road capacity + ("@vht", "vehicle hours travelled", "@non_pce_flow*@auto_time/60") #vehicle flow (non-pce)*time + ] + + for name, des, formula in new_atts: + att = scenario.extra_attribute(name) + if not att: + att = create_attribute("LINK", name, des, 0, overwrite=True, scenario=scenario) + cal_spec = {"result": att.id, + "expression": formula, + "aggregation": None, + "selections": {"link": "mode=d"}, + "type": "NETWORK_CALCULATION" + } + net_calculator(cal_spec, scenario=scenario) + file_path = os.path.join(export_path, "hwyload_%s.csv" % p) + network = self.get_partial_network(scenario, {"LINK": ["@tcov_id"] + [a[1] for a in dir_atts]}) + self.export_traffic_to_csv(file_path, hwyload_attrs, network) + + def export_traffic_to_csv(self, filename, att_list, network, busPCE = None): + auto_mode = network.mode("d") + # only the original forward direction links and auto links only + links = [l for l in network.links() + if l["@tcov_id"] > 0 and + (auto_mode in l.modes or (l.reverse_link and auto_mode in l.reverse_link.modes)) + ] + links.sort(key=lambda l: l["@tcov_id"]) + with open(filename, 'w') as fout: + fout.write(",".join(['"%s"' % x[0] for x in att_list])) + fout.write("\n") + for link in links: + key, att = att_list[0] # expected to be the link id + values = [id_format(link[att])] + reverse_link = link.reverse_link + for key, att in att_list[1:]: + if key == "AN": + values.append(link.i_node.id) + elif key == "BN": + values.append(link.j_node.id) + elif key.startswith("BA"): + name, default = att + if reverse_link and (abs(link["@tcov_id"]) == abs(reverse_link["@tcov_id"])): + if "additional_volume" in name: + values.append(format(float(reverse_link[name]) / busPCE)) + else: + values.append(format(reverse_link[name])) + else: + values.append(default) + + #values.append(format(reverse_link[name]) if reverse_link else default) + elif att.startswith("#"): + values.append('"%s"' % link[att]) + else: + if "additional_volume" in att: + values.append(format(float(link[att]) / busPCE)) + else: + values.append(format(link[att])) + fout.write(",".join(values)) + fout.write("\n") + + @_m.logbook_trace("Export transit results") + def export_transit_results(self, export_path, input_path, transit_emmebank, period_scenario_ids, num_processors): + # Note: Node analysis for transfers is VERY time consuming + # this implementation will be replaced when new Emme version is available + + trrt_atts = ["Route_ID","Route_Name","Mode","AM_Headway","PM_Headway","OP_Headway","Night_Headway","Night_Hours","Config","Fare"] + trstop_atts = ["Stop_ID","Route_ID","Link_ID","Pass_Count","Milepost","Longitude","Latitude","NearNode","FareZone","StopName"] + + #transit route file + trrt_infile = os.path.join(input_path, "trrt.csv") + trrt = pd.read_csv(trrt_infile) + trrt = trrt.rename(columns=lambda x:x.strip()) + trrt_out = trrt[trrt_atts] + trrt_outfile = os.path.join(export_path, "trrt.csv") + trrt_out.to_csv(trrt_outfile, index=False) + + #transit stop file + trstop_infile = os.path.join(input_path, "trstop.csv") + trstop = pd.read_csv(trstop_infile) + trstop = trstop.rename(columns={"HwyNode":"NearNode"}) + trstop = trstop.rename(columns=lambda x:x.strip()) + trstop_out = trstop[trstop_atts] + trstop_outfile = os.path.join(export_path, "trstop.csv") + trstop_out.to_csv(trstop_outfile, index=False) + + use_node_analysis_to_get_transit_transfers = False + + copy_scenario = _m.Modeller().tool( + "inro.emme.data.scenario.copy_scenario") + create_attribute = _m.Modeller().tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + net_calculator = _m.Modeller().tool( + "inro.emme.network_calculation.network_calculator") + copy_attribute= _m.Modeller().tool( + "inro.emme.data.network.copy_attribute") + delete_scenario = _m.Modeller().tool( + "inro.emme.data.scenario.delete_scenario") + transit_flow_atts = [ + "MODE", + "ACCESSMODE", + "TOD", + "ROUTE", + "FROM_STOP", + "TO_STOP", + "CENTROID", + "FROMMP", + "TOMP", + "TRANSITFLOW", + "BASEIVTT", + "COST", + "VOC", + ] + transit_aggregate_flow_atts = [ + "MODE", + "ACCESSMODE", + "TOD", + "LINK_ID", + "AB_TransitFlow", + "BA_TransitFlow", + "AB_NonTransit", + "BA_NonTransit", + "AB_TotalFlow", + "BA_TotalFlow", + "AB_Access_Walk_Flow", + "BA_Access_Walk_Flow", + "AB_Xfer_Walk_Flow", + "BA_Xfer_Walk_Flow", + "AB_Egress_Walk_Flow", + "BA_Egress_Walk_Flow" + ] + transit_onoff_atts = [ + "MODE", + "ACCESSMODE", + "TOD", + "ROUTE", + "STOP", + "BOARDINGS", + "ALIGHTINGS", + "WALKACCESSON", + "DIRECTTRANSFERON", + "WALKTRANSFERON", + "DIRECTTRANSFEROFF", + "WALKTRANSFEROFF", + "EGRESSOFF" + ] + + transit_flow_file = os.path.join(export_path, "transit_flow.csv") + fout_seg = open(transit_flow_file, 'w') + fout_seg.write(",".join(['"%s"' % x for x in transit_flow_atts])) + fout_seg.write("\n") + + transit_aggregate_flow_file = os.path.join(export_path, "transit_aggflow.csv") + fout_link = open(transit_aggregate_flow_file, 'w') + fout_link.write(",".join(['"%s"' % x for x in transit_aggregate_flow_atts])) + fout_link.write("\n") + + transit_onoff_file = os.path.join(export_path, "transit_onoff.csv") + fout_stop = open(transit_onoff_file, 'w') + fout_stop.write(",".join(['"%s"' % x for x in transit_onoff_atts])) + fout_stop.write("\n") + try: + access_modes = ["WLK", "PNR", "KNR"] + main_modes = ["BUS", "PREM","ALLPEN"] + all_modes = ["b", "c", "e", "l", "r", "p", "y", "o", "a", "w", "x"] + local_bus_modes = ["b", "a", "w", "x"] + premium_modes = ["c", "l", "e", "p", "r", "y", "o", "a", "w", "x"] + for tod, scen_id in period_scenario_ids.iteritems(): + with _m.logbook_trace("Processing period %s" % tod): + scenario = transit_emmebank.scenario(scen_id) + # attributes + total_walk_flow = create_attribute("LINK", "@volax", "total walk flow on links", + 0, overwrite=True, scenario=scenario) + segment_flow = create_attribute("TRANSIT_SEGMENT", "@voltr", "transit segment flow", + 0, overwrite=True, scenario=scenario) + link_transit_flow = create_attribute("LINK", "@link_voltr", "total transit flow on link", + 0, overwrite=True, scenario=scenario) + initial_boardings = create_attribute("TRANSIT_SEGMENT", + "@init_boardings", "transit initial boardings", + 0, overwrite=True, scenario=scenario) + xfer_boardings = create_attribute("TRANSIT_SEGMENT", + "@xfer_boardings", "transit transfer boardings", + 0, overwrite=True, scenario=scenario) + total_boardings = create_attribute("TRANSIT_SEGMENT", + "@total_boardings", "transit total boardings", + 0, overwrite=True, scenario=scenario) + final_alightings = create_attribute("TRANSIT_SEGMENT", + "@final_alightings", "transit final alightings", + 0, overwrite=True, scenario=scenario) + xfer_alightings = create_attribute("TRANSIT_SEGMENT", + "@xfer_alightings", "transit transfer alightings", + 0, overwrite=True, scenario=scenario) + total_alightings = create_attribute("TRANSIT_SEGMENT", + "@total_alightings", "transit total alightings", + 0, overwrite=True, scenario=scenario) + + access_walk_flow = create_attribute("LINK", + "@access_walk_flow", "access walks (orig to init board)", + 0, overwrite=True, scenario=scenario) + xfer_walk_flow = create_attribute("LINK", + "@xfer_walk_flow", "xfer walks (init board to final alight)", + 0, overwrite=True, scenario=scenario) + egress_walk_flow = create_attribute("LINK", + "@egress_walk_flow", "egress walks (final alight to dest)", + 0, overwrite=True, scenario=scenario) + + for main_mode in main_modes: + mode = main_mode + if main_mode == "BUS": + mode_list = local_bus_modes + elif main_mode == "PREM": + mode_list = premium_modes + else: + mode_list = all_modes + + for access_type in access_modes: + with _m.logbook_trace("Main mode %s access mode %s" % (main_mode, access_type)): + class_name = "%s_%s%s" % (tod, access_type, main_mode) + segment_results = { + "transit_volumes": segment_flow.id, + "initial_boardings": initial_boardings.id, + "total_boardings": total_boardings.id, + "final_alightings": final_alightings.id, + "total_alightings": total_alightings.id, + "transfer_boardings": xfer_boardings.id, + "transfer_alightings": xfer_alightings.id + } + link_results = { + "total_walk_flow": total_walk_flow.id, + "link_transit_flow": link_transit_flow.id, + "access_walk_flow": access_walk_flow.id, + "xfer_walk_flow": xfer_walk_flow.id, + "egress_walk_flow": egress_walk_flow.id + } + + self.calc_additional_results( + scenario, class_name, num_processors, + total_walk_flow, segment_results, link_transit_flow, + access_walk_flow, xfer_walk_flow, egress_walk_flow) + attributes = { + "NODE": ["@network_adj", "@network_adj_src"],#, "initial_boardings", "final_alightings"], + "LINK": link_results.values() + ["@tcov_id", "length"], + "TRANSIT_LINE": ["@route_id"], + "TRANSIT_SEGMENT": segment_results.values() + [ + "transit_time", "dwell_time", "@stop_id", "allow_boardings", "allow_alightings"], + } + network = self.get_partial_network(scenario, attributes) + self.collapse_network_adjustments(network, segment_results, link_results) + # =============================================== + # analysis for nodes with/without walk option + if use_node_analysis_to_get_transit_transfers: + stop_on, stop_off = self.transfer_analysis(scenario, class_name, num_processors) + else: + stop_on, stop_off = {}, {} + # =============================================== + transit_modes = [m for m in network.modes() if m.type in ("TRANSIT", "AUX_TRANSIT")] + links = [link for link in network.links() + if link["@tcov_id"] > 0 and (link.modes.union(transit_modes))] + links.sort(key=lambda l: l["@tcov_id"]) + lines = [line for line in network.transit_lines() if line.mode.id in mode_list] + lines.sort(key=lambda l: l["@route_id"]) + + label = ",".join([mode, access_type, tod]) + self.output_transit_flow(label, lines, segment_flow.id, fout_seg) + self.output_transit_aggregate_flow( + label, links, link_transit_flow.id, total_walk_flow.id, access_walk_flow.id, + xfer_walk_flow.id, egress_walk_flow.id, fout_link) + self.output_transit_onoff( + label, lines, total_boardings.id, total_alightings.id, initial_boardings.id, + xfer_boardings.id, xfer_alightings.id, final_alightings.id, + stop_on, stop_off, fout_stop) + finally: + fout_stop.close() + fout_link.close() + fout_seg.close() + return + + @_m.logbook_trace("Export geometries") + def export_geometry(self, export_path, traffic_emmebank): + # --------------------------Export Transit Nework Geometory----------------------------- + # domain: NODE, LINK, TURN, TRANSIT_LINE, TRANSIT_VEHICLE, TRANSIT_SEGMENT + def export_as_csv(domain, attributes, scenario = None): + if scenario is None: + scenario = _m.Modeller().scenario + initial_scenario = _m.Modeller().scenario + #if initial_scenario.number != scenario.number: + #data_explorer.replace_primary_scenario(scenario) + # Create the network table + network_table = project.new_network_table(domain) + for k, a in enumerate(attributes): + column = _ws.Column() + column.name = column.expression = a + network_table.add_column(k, column) + # Extract data + data = network_table.get_data() + f = _np.vectorize(lambda x: x.text) # required to get the WKT representation of the geometry column + data_dict = {} + for a in data.attributes(): + if isinstance(a, _dt.GeometryAttribute): + data_dict[a.name] = f(a.values) + else: + data_dict[a.name] = a.values + df = pd.DataFrame(data_dict) + + network_table.close() + #if initial_scenario.number != scenario.number: + # data_explorer.replace_primary_scenario(initial_scenario) + return df + + desktop = _m.Modeller().desktop + desktop.refresh_data() + data_explorer = desktop.data_explorer() + previous_active_database = data_explorer.active_database() + try: + desktop_traffic_database = data_explorer.add_database(traffic_emmebank.path) + desktop_traffic_database.open() + except Exception as error: + import traceback + print (traceback.format_exc()) + project = desktop.project + scenario = _m.Modeller().emmebank.scenario(101) + data_explorer.replace_primary_scenario(scenario) + node_attributes = ['i','@tap_id'] + link_attributes = ['i', 'j', '@tcov_id', 'modes'] + transit_line_attributes = ['line', 'routeID'] + transit_segment_attributes = ['line', 'i', 'j', 'loop_index','@tcov_id','@stop_id'] + mode_talbe = ['mode', 'type'] + network_table = project.new_network_table('MODE') + for k, a in enumerate(mode_talbe): + column = _ws.Column() + column.name = column.expression = a + network_table.add_column(k, column) + data = network_table.get_data() + data_dict = {} + for a in data.attributes(): + data_dict[a.name] = a.values + df = pd.DataFrame(data_dict) + mode_list = df[df['type'].isin([2.0, 3.0])]['mode'].tolist() + + df = export_as_csv('NODE', node_attributes, scenario) + df = df[['@tap_id', 'geometry']] + is_tap = df['@tap_id'] > 0 + df = df[is_tap] + df.columns = ['tapID', 'geometry'] + df.to_csv(os.path.join(export_path, 'transitTap.csv'), index=False) + + df = export_as_csv('TRANSIT_LINE', transit_line_attributes) + df = df[['line', 'geometry']] + df.columns = ['Route_Name', 'geometry'] + df['Route_Name'] = df['Route_Name'].astype(int) + df_routeFull = pd.read_csv(os.path.join(export_path, 'trrt.csv')) + result = pd.merge(df_routeFull, df, how='left', on=['Route_Name']) + result.to_csv(os.path.join(export_path, 'transitRoute.csv'), index=False) + os.remove(os.path.join(export_path, 'trrt.csv')) + + df = export_as_csv('TRANSIT_SEGMENT', transit_segment_attributes, None) + df_seg = df[['@tcov_id', 'geometry']] + df_seg.columns = ['trcovID', 'geometry'] + df_seg = df_seg.drop_duplicates() + #df_seg.to_csv(os.path.join(export_path, 'transitLink.csv'), index=False) + #df_stop = df[(df['@stop_id'] > 0) & (df['@tcov_id'] > 0)] + df_stop = df[(df['@stop_id'] > 0)] + df_stop = df_stop[['@stop_id', 'geometry']] + df_stop = df_stop.drop_duplicates() + df_stop.columns = ['Stop_ID', 'geometry'] + temp=[] + for value in df_stop['geometry']: + value=value.split(',') + value[0]=value[0]+')' + value[0]=value[0].replace("LINESTRING", "POINT") + temp.append(value[0]) + df_stop['geometry'] = temp + df_stopFull = pd.read_csv(os.path.join(export_path, 'trstop.csv')) + result = pd.merge(df_stopFull, df_stop, how='left', on=['Stop_ID']) + result.to_csv(os.path.join(export_path, 'transitStop.csv'), index=False) + os.remove(os.path.join(export_path, 'trstop.csv')) + + df = export_as_csv('LINK', link_attributes, None) + df_link = df[['@tcov_id', 'geometry']] + df_link.columns = ['hwycov-id:1', 'geometry'] + df_linkFull = pd.read_csv(os.path.join(export_path, 'hwy_tcad.csv')) + result = pd.merge(df_linkFull, df_link, how='left', on=['hwycov-id:1']) + result.to_csv(os.path.join(export_path, 'hwyTcad.csv'), index=False) + os.remove(os.path.join(export_path, 'hwy_tcad.csv')) + ##mode_list = ['Y','b','c','e','l','p','r','y','a','x','w']## + df_transit_link = df[df.modes.str.contains('|'.join(mode_list))] + df_transit_link = df_transit_link[['@tcov_id', 'geometry']] + df_transit_link.columns = ['trcovID', 'geometry'] + df_transit_link = df_transit_link[df_transit_link['trcovID'] != 0] + df_transit_link['AB'] = df_transit_link['trcovID'].apply(lambda x: 1 if x > 0 else 0) + df_transit_link['trcovID'] = abs(df_transit_link['trcovID']) + df_transit_link = df_transit_link[['trcovID', 'AB', 'geometry']] + df_transit_link.to_csv(os.path.join(export_path, 'transitLink.csv'), index=False) + network_table.close() + try: + previous_active_database.open() + data_explorer.remove_database(desktop_traffic_database) + except: + pass + + def get_partial_network(self, scenario, attributes): + domains = attributes.keys() + network = scenario.get_partial_network(domains, include_attributes=False) + for domain, attrs in attributes.iteritems(): + if attrs: + values = scenario.get_attribute_values(domain, attrs) + network.set_attribute_values(domain, attrs, values) + return network + + def output_transit_flow(self, label, lines, segment_flow, fout_seg): + # output segment data (transit_flow) + centroid = "0" # always 0 + voc = "" # volume/capacity, not actually used, + for line in lines: + line_id = id_format(line["@route_id"]) + ivtt = from_mp = to_mp = 0 + segments = iter(line.segments(include_hidden=True)) + seg = segments.next() + from_stop = id_format(seg["@stop_id"]) + for next_seg in segments: + to_mp += seg.link.length + ivtt += seg.transit_time - next_seg.dwell_time + transit_flow = seg[segment_flow] + seg = next_seg + if not next_seg.allow_alightings: + continue + to_stop = id_format(next_seg["@stop_id"]) + formatted_ivtt = format(ivtt) + fout_seg.write(",".join([ + label, line_id, from_stop, to_stop, centroid, format(from_mp), format(to_mp), + format(transit_flow), formatted_ivtt, formatted_ivtt, voc])) + fout_seg.write("\n") + from_stop = to_stop + from_mp = to_mp + ivtt = 0 + + def output_transit_aggregate_flow(self, label, links, + link_transit_flow, total_walk_flow, access_walk_flow, + xfer_walk_flow, egress_walk_flow, fout_link): + # output link data (transit_aggregate_flow) + for link in links: + link_id = id_format(link["@tcov_id"]) + ab_transit_flow = link[link_transit_flow] + ab_non_transit_flow = link[total_walk_flow] + ab_total_flow = ab_transit_flow + ab_non_transit_flow + ab_access_walk_flow = link[access_walk_flow] + ab_xfer_walk_flow = link[xfer_walk_flow] + ab_egress_walk_flow = link[egress_walk_flow] + if link.reverse_link: + ba_transit_flow = link.reverse_link[link_transit_flow] + ba_non_transit_flow = link.reverse_link[total_walk_flow] + ba_total_flow = ba_transit_flow + ba_non_transit_flow + ba_access_walk_flow = link.reverse_link[access_walk_flow] + ba_xfer_walk_flow = link.reverse_link[xfer_walk_flow] + ba_egress_walk_flow = link.reverse_link[egress_walk_flow] + else: + ba_transit_flow = 0.0 + ba_non_transit_flow = 0.0 + ba_total_flow = 0.0 + ba_access_walk_flow = 0.0 + ba_xfer_walk_flow = 0.0 + ba_egress_walk_flow = 0.0 + + fout_link.write(",".join( + [label, link_id, + format(ab_transit_flow), format(ba_transit_flow), + format(ab_non_transit_flow), format(ba_non_transit_flow), + format(ab_total_flow), format(ba_total_flow), + format(ab_access_walk_flow), format(ba_access_walk_flow), + format(ab_xfer_walk_flow), format(ba_xfer_walk_flow), + format(ab_egress_walk_flow), format(ba_egress_walk_flow)])) + fout_link.write("\n") + + def output_transit_onoff(self, label, lines, + total_boardings, total_alightings, initial_boardings, + xfer_boardings, xfer_alightings, final_alightings, + stop_on, stop_off, fout_stop): + # output stop data (transit_onoff) + for line in lines: + line_id = id_format(line["@route_id"]) + for seg in line.segments(True): + if not (seg.allow_alightings or seg.allow_boardings): + continue + i_node = seg.i_node.id + boardings = seg[total_boardings] + alightings = seg[total_alightings] + walk_access_on = seg[initial_boardings] + direct_xfer_on = seg[xfer_boardings] + walk_xfer_on = 0.0 + direct_xfer_off = seg[xfer_alightings] + walk_xfer_off = 0.0 + if stop_on.has_key(i_node): + if stop_on[i_node].has_key(line.id): + if direct_xfer_on > 0: + walk_xfer_on = direct_xfer_on - stop_on[i_node][line.id] + direct_xfer_on = stop_on[i_node][line.id] + if stop_off.has_key(i_node): + if stop_off[i_node].has_key(line.id): + if direct_xfer_off > 0: + walk_xfer_off = direct_xfer_off - stop_off[i_node][line.id] + direct_xfer_off = stop_off[i_node][line.id] + + egress_off = seg[final_alightings] + fout_stop.write(",".join([ + label, line_id, id_format(seg["@stop_id"]), + format(boardings), format(alightings), format(walk_access_on), + format(direct_xfer_on), format(walk_xfer_on), format(direct_xfer_off), + format(walk_xfer_off), format(egress_off)])) + fout_stop.write("\n") + + def collapse_network_adjustments(self, network, segment_results, link_results): + segment_alights = [v for k, v in segment_results.items() if "alightings" in k] + segment_boards = [v for k, v in segment_results.items() if "boardings" in k] + ["transit_boardings"] + segment_result_attrs = segment_alights + segment_boards + link_result_attrs = link_results.values() + ["aux_transit_volume"] + link_attrs = network.attributes("LINK") + link_modified_attrs = [ + "length", "@trtime_link_ea", "@trtime_link_am", "@trtime_link_md", + "@trtime_link_pm", "@trtime_link_ev", link_results["link_transit_flow"]] + seg_attrs = network.attributes("TRANSIT_SEGMENT") + line_attrs = network.attributes("TRANSIT_LINE") + + transit_modes = set([network.mode(m) for m in "blryepc"]) + aux_modes = set([network.mode(m) for m in "wxa"]) + xfer_mode = network.mode('x') + + def copy_seg_attrs(src_seg, dst_seg): + for attr in segment_result_attrs: + dst_seg[attr] += src_seg[attr] + dst_seg["allow_alightings"] |= src_seg["allow_alightings"] + dst_seg["allow_boardings"] |= src_seg["allow_boardings"] + + def get_xfer_link(node, timed_xfer_link, is_outgoing=True): + links = node.outgoing_links() if is_outgoing else node.incoming_links() + for link in links: + if xfer_mode in link.modes and link.length == timed_xfer_link.length: + return link + return None + + lines_to_update = set([]) + nodes_to_merge = [] + nodes_to_delete = [] + + for node in network.regular_nodes(): + if node["@network_adj"] == 1: + nodes_to_merge.append(node) + # copy boarding / alighting attributes for the segments to the original segment / stop + for seg in node.incoming_segments(): + lines_to_update.add(seg.line) + copy_seg_attrs(seg, seg.line.segment(seg.number+2)) + for seg in node.outgoing_segments(): + lines_to_update.add(seg.line) + copy_seg_attrs(seg, seg.line.segment(seg.number+1)) + elif node["@network_adj"] == 2: + nodes_to_delete.append(node) + # copy boarding / alighting attributes for the segments to the original segment / stop + for seg in node.outgoing_segments(True): + lines_to_update.add(seg.line) + if seg.j_node: + copy_seg_attrs(seg, seg.line.segment(seg.number+1)) + else: + copy_seg_attrs(seg, seg.line.segment(seg.number-1)) + elif node["@network_adj"] == 3: + orig_node = network.node(node["@network_adj_src"]) + # Remove transfer walk links and copy data to source walk link + for link in node.outgoing_links(): + if xfer_mode in link.modes and link.j_node["@network_adj"] == 3: + orig_xfer_link = get_xfer_link(orig_node, link) + for attr in link_result_attrs: + orig_xfer_link[attr] += link[attr] + network.delete_link(link.i_node, link.j_node) + # Sum link and segment results and merge links + mapping = network.merge_links_mapping(node) + for (link1, link2), attr_map in mapping['links'].iteritems(): + for attr in link_modified_attrs: + attr_map[attr] = max(link1[attr], link2[attr]) + + for (seg1, seg2), attr_map in mapping['transit_segments'].iteritems(): + if seg2.allow_alightings: + for attr in seg_attrs: + attr_map[attr] = seg1[attr] + else: # if it is a boarding stop or non-stop + for attr in seg_attrs: + attr_map[attr] = max(seg1[attr], seg2[attr]) + attr_map["transit_time_func"] = min(seg1["transit_time_func"], seg2["transit_time_func"]) + for attr in segment_boards: + attr_map[attr] = seg1[attr] + seg2[attr] + next_seg = seg2.line.segment(seg2.number+1) + for attr in segment_alights: + next_seg[attr] += seg2[attr] + network.merge_links(node, mapping) + + # Backup transit lines with altered routes and remove from network + lines = [] + for line in lines_to_update: + seg_data = {} + itinerary = [] + for seg in line.segments(include_hidden=True): + if seg.i_node["@network_adj"] in [1,2] or (seg.j_node and seg.j_node["@network_adj"] == 1): + continue + # for circle line transfers, j_node is now None for new "hidden" segment + j_node = seg.j_node + if (seg.j_node and seg.j_node["@network_adj"] == 2): + j_node = None + seg_data[(seg.i_node, j_node, seg.loop_index)] = dict((k, seg[k]) for k in seg_attrs) + itinerary.append(seg.i_node.number) + + lines.append({ + "id": line.id, + "vehicle": line.vehicle, + "itinerary": itinerary, + "attributes": dict((k, line[k]) for k in line_attrs), + "seg_attributes": seg_data}) + network.delete_transit_line(line) + # Remove duplicate network elements (undo network adjustments) + for node in nodes_to_delete: + for link in _chain(node.incoming_links(), node.outgoing_links()): + network.delete_link(link.i_node, link.j_node) + network.delete_node(node) + for node in nodes_to_merge: + mapping = network.merge_links_mapping(node) + for (link1, link2), attr_map in mapping["links"].iteritems(): + if link2.j_node.is_centroid: + link1, link2 = link2, link1 + for attr in link_attrs: + attr_map[attr] = link1[attr] + network.merge_links(node, mapping) + # Re-create transit lines on new itineraries + for line_data in lines: + new_line = network.create_transit_line( + line_data["id"], line_data["vehicle"], line_data["itinerary"]) + for k, v in line_data["attributes"].iteritems(): + new_line[k] = v + seg_data = line_data["seg_attributes"] + for seg in new_line.segments(include_hidden=True): + data = seg_data.get((seg.i_node, seg.j_node, seg.loop_index), {}) + for k, v in data.iteritems(): + seg[k] = v + + def calc_additional_results(self, scenario, class_name, num_processors, + total_walk_flow, segment_results, link_transit_flow, + access_walk_flow, xfer_walk_flow, egress_walk_flow): + network_results = _m.Modeller().tool( + "inro.emme.transit_assignment.extended.network_results") + path_based_analysis = _m.Modeller().tool( + "inro.emme.transit_assignment.extended.path_based_analysis") + net_calculator = _m.Modeller().tool( + "inro.emme.network_calculation.network_calculator") + + spec = { + "on_links": { + "aux_transit_volumes": total_walk_flow.id + }, + "on_segments": segment_results, + "aggregated_from_segments": None, + "analyzed_demand": None, + "constraint": None, + "type": "EXTENDED_TRANSIT_NETWORK_RESULTS" + } + network_results(specification=spec, scenario=scenario, + class_name=class_name, num_processors=num_processors) + cal_spec = { + "result": "%s" % link_transit_flow.id, + "expression": "%s" % segment_results["transit_volumes"], + "aggregation": "+", + "selections": { + "link": "all", + "transit_line": "all" + }, + "type": "NETWORK_CALCULATION" + } + net_calculator(cal_spec, scenario=scenario) + + walk_flows = [("INITIAL_BOARDING_TO_FINAL_ALIGHTING", access_walk_flow.id), + ("INITIAL_BOARDING_TO_FINAL_ALIGHTING", xfer_walk_flow.id), + ("FINAL_ALIGHTING_TO_DESTINATION", egress_walk_flow.id)] + for portion_of_path, aux_transit_volumes in walk_flows: + spec = { + "portion_of_path": portion_of_path, + "trip_components": { + "in_vehicle": None, + "aux_transit": "length", + "initial_boarding": None, + "transfer_boarding": None, + "transfer_alighting": None, + "final_alighting": None + }, + "path_operator": ".max.", + "path_selection_threshold": { + "lower": -1.0, + "upper": 999999.0 + }, + "path_to_od_aggregation": None, + "constraint": None, + "analyzed_demand": None, + "results_from_retained_paths": { + "paths_to_retain": "SELECTED", + "aux_transit_volumes": aux_transit_volumes + }, + "path_to_od_statistics": None, + "path_details": None, + "type": "EXTENDED_TRANSIT_PATH_ANALYSIS" + } + path_based_analysis( + specification=spec, scenario=scenario, + class_name=class_name, num_processors=num_processors) + + def transfer_analysis(self, scenario, net, class_name, num_processors): + create_attribute = _m.Modeller().tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + transfers_at_stops = _m.Modeller().tool( + "inro.emme.transit_assignment.extended.apps.transfers_at_stops") + + # find stop with/without walk transfer option + stop_walk_list = [] # stop (id) with walk option + stop_flag = "@stop_flag" + create_attribute("NODE", att, "1=stop without walk option, 2=otherwise", + 0, overwrite=True, scenario=scenario) + stop_nline = "@stop_nline" + create_attribute("NODE", stop_nline, "number of lines on the stop", + 0, overwrite=True, scenario=scenario) + + for line in net.transit_lines(): + for seg in line.segments(True): + node = seg.i_node + if seg.allow_alightings or seg.allow_boardings: + node[stop_nline] += 1 + if node[stop_flag] > 0 : #node checked + continue + if seg.allow_alightings or seg.allow_boardings: + node[stop_flag] = 1 + for ilink in node.incoming_links(): + # skip connector + if ilink.i_node.is_centroid: + continue + for m in ilink.modes: + if m.type=="AUX_TRANSIT": + node[stop_flag] = 2 + stop_walk_list.append(node.id) + break + if node[stop_flag]>=2: + break + if node[stop_flag]>=2: + continue + for olink in node.outgoing_links(): + # skip connector + if olink.j_node.is_centroid: + continue + for m in olink.modes: + if m.type=="AUX_TRANSIT": + node[stop_flag] = 2 + stop_walk_list.append(node.id) + break + if node[stop_flag]>=2: + break + #scenario.publish_network(net) + stop_off = {} + stop_on = {} + for stop in stop_walk_list: + stop_off[stop] = {} + stop_on[stop] = {} + selection = "i=%s" % stop + results = transfers_at_stops( + selection, scenario=scenario, + class_name=class_name, num_processors=num_processors) + for off_line in results: + stop_off[stop][off_line] = 0.0 + for on_line in results[off_line]: + trip = float(results[off_line][on_line]) + stop_off[stop][off_line] += trip + if not stop_on[stop].has_key(on_line): + stop_on[stop][on_line] = 0.0 + stop_on[stop][on_line] += trip + return stop_off, stop_on + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg diff --git a/sandag_abm/src/main/emme/toolbox/export/export_for_commercial_vehicle.py b/sandag_abm/src/main/emme/toolbox/export/export_for_commercial_vehicle.py new file mode 100644 index 0000000..fee626d --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/export/export_for_commercial_vehicle.py @@ -0,0 +1,158 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// export/export_for_commercial_vehicle.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Exports the required skims in CSV format for the commercial vehicle model. +# +# +# Inputs: +# source: +# +# Files referenced: +# +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + source_dir = os.path.join(main_directory, "input") + title = "Base 2012 scenario" + tool = modeller.tool("sandag.export.export_for_commercial_vehicle") +""" + + +TOOLBOX_ORDER = 51 + + +import inro.modeller as _m +import numpy as _np +import subprocess as _subprocess +import tempfile as _tempfile +import traceback as _traceback +import os + +_join = os.path.join +_dir = os.path.dirname + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class ExportForCommercialVehicleModel(_m.Tool(), gen_utils.Snapshot): + + output_directory = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = _dir(_m.Modeller().desktop.project.path) + self.output_directory = _join(_dir(project_dir), "output") + self.attributes = ["output_directory"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Export for commercial vehicle model" + pb.description = """ + Exports the required skims in CSV format for the commercial vehicle model. + """ + pb.branding_text = "- SANDAG - Export" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('output_directory', 'directory', + title='Select output directory') + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.output_directory, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Export skims for commercial vehicle model', save_arguments=True) + def __call__(self, output_directory, scenario): + emmebank = scenario.emmebank + modes = ['ldn', 'ldt', 'lhdn', 'lhdt', 'mhdn', 'mhdt', 'hhdn', 'hhdt'] + classes = ['SOV_NT_H', 'SOV_TR_H', 'TRK_L', 'TRK_L', 'TRK_M', 'TRK_M', 'TRK_H', 'TRK_H'] + # Mappings between COMMVEH modes and Emme classes + mode_class = dict(zip(modes, classes)) + class_mode = dict(zip(classes, modes)) + + is_toll_mode = lambda m: m.endswith('t') + #periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + period = "MD" + skims = ['TIME', 'DIST', 'TOLLCOST'] + DUCoef = [ + [-0.313, -0.138, -0.01], + [-0.313, -0.492, -0.01], + [-0.302, -0.580, -0.02] + ] + # Mappings for DUCoef utility index + modes_util = { + 'ldn': 0, + 'ldt': 0, + 'lhdn': 1, + 'lhdt': 1, + 'mhdn': 1, + 'mhdt': 1, + 'hhdn': 2, + 'hhdt': 2 + } + + # Lookup relevant skims as numpy arrays + skim_mat = {} + for cls in classes: + for skim in skims: + name = '%s_%s_%s' % (period, cls, skim) + if name not in skim_mat: + skim_mat[name] = emmebank.matrix(name).get_numpy_data(scenario) + + output_matrices = { + 'impldt_MD_Time.txt': skim_mat['MD_SOV_TR_H_TIME'], + 'impldt_MD_Dist.txt': skim_mat['MD_SOV_TR_H_DIST'], + } + + # Calculate DU matrices in numpy + for mode in modes: + time = skim_mat['%s_%s_TIME' % (period, mode_class[mode])] + distance = skim_mat['%s_%s_DIST' % (period, mode_class[mode])] + # All classes now have a tollcost skim available + toll_cost = skim_mat['%s_%s_TOLLCOST' % (period, mode_class[mode])] + _np.fill_diagonal(toll_cost, 0) + + coeffs = DUCoef[modes_util[mode]] + disutil_mat = coeffs[0] * time + coeffs[1] * distance + coeffs[2] * toll_cost + output_matrices['imp%s_%s_DU.txt' % (mode, period)] = disutil_mat + + # Insert row number into first column of the array + # Note: assumes zone IDs are continuous + for key, array in output_matrices.iteritems(): + output_matrices[key] = _np.insert(array, 0, range(1, array.shape[0]+1), axis=1) + + # Output DU matrices to CSV + # Print first column as integer, subsequent columns as floats rounded to 6 decimals + fmt_spec = ['%i'] + ['%.6f'] * (disutil_mat.shape[0]) + # Save to separate files + for name, array in output_matrices.iteritems(): + _np.savetxt(_join(output_directory, name), array, fmt=fmt_spec, delimiter=',') diff --git a/sandag_abm/src/main/emme/toolbox/export/export_for_transponder.py b/sandag_abm/src/main/emme/toolbox/export/export_for_transponder.py new file mode 100644 index 0000000..f5736a3 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/export/export_for_transponder.py @@ -0,0 +1,374 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2019-2020. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// export_for_transponder.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# + + +TOOLBOX_ORDER = 57 + + +import inro.modeller as _m + +import numpy as _np +import pandas as _pd +import string as _string +import traceback as _traceback +import math +import os +_dir, _join = os.path.dirname, os.path.join + +from shapely.geometry import MultiLineString, Point, LineString +from contextlib import contextmanager as _context +from itertools import izip as _izip + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module('sandag.utilities.demand') + + +class ExportForTransponder(_m.Tool(), gen_utils.Snapshot): + + scenario = _m.Attribute(_m.InstanceType) + output_directory = _m.Attribute(unicode) + num_processors = _m.Attribute(str) + + tool_run_msg = "" + + def __init__(self): + project_dir = _dir(_m.Modeller().desktop.project.path) + modeller = _m.Modeller() + if modeller.emmebank.path == _join(project_dir, "Database", "emmebank"): + self.scenario = modeller.emmebank.scenario(102) + self.num_processors = "max-1" + self.output_directory = _join(_dir(project_dir), "output") + self.attributes = ["scenario", "output_directory", "num_processors"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Export for transponder ownership model" + pb.description = """ +

Calculates and exports the following results for each origin zone:

+ + .""" + pb.branding_text = "- SANDAG - Export" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_scenario("scenario", + title="Representative scenario") + pb.add_select_file('output_directory', 'directory', + title='Select output directory') + + dem_utils.add_select_processors("num_processors", pb, self) + return pb.render() + + + def run(self): + self.tool_run_msg = "" + try: + self(self.output_directory, self.num_processors, self.scenario) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Export results for transponder ownership model", save_arguments=True) + def __call__(self, output_directory, num_processors, scenario): + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties( + _join(_dir(output_directory), "conf", "sandag_abm.properties")) + input_directory = _join(_dir(output_directory), "input") + num_processors = dem_utils.parse_num_processors(num_processors) + network = scenario.get_network() + distances = self.ml_facility_dist(network) + savings = self.avg_travel_time_savings(scenario, input_directory, props, num_processors) + detour = self.percent_detour(scenario, network, props, num_processors) + self.export_results(output_directory, scenario, distances, savings, detour) + + @_m.logbook_trace("Calculate distance to nearest managed lane facility") + def ml_facility_dist(self, network): + # DIST: Straight line distance to the nearest ML facility (nearest link with a ML Cost) + # managed lane is : + # HOV2+ only (carpool lane): "IFC" = 1 and "IHOV" = 2 and "ITOLLO" = 0 and "ITOLLA" = 0 and "ITOLLP" = 0 + # HOV3+ only (carpool lane): "IFC" = 1 and "IHOV" = 3 and "ITOLLO" = 0 and "ITOLLA" = 0 and "ITOLLP" = 0 + # HOV2+ & HOT (managed lane. HOV 2+ free. SOV pay toll): ): "IFC" = 1 and "IHOV" = 2 and "ITOLLO" > 0 and "ITOLLA" > 0 and "ITOLLP" > 0 + # HOV2+ & HOT (managed lane. HOV 3+ free. HOV2 & SOV pay toll): ): "IFC" = 1 and "IHOV" = 3 and "ITOLLO" > 0 and "ITOLLA" > 0 and "ITOLLP" > 0 + # Tollway (all vehicles tolled): "IFC" = 1 and "IHOV" = 4 + #$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + # NOTE: NOT ALL MANAGED LANE LINKS HAVE A TOLL COST, + # SOME COSTS ARE JUST SPECIFIED ON THE ENTRANCE / EXIT LINKS + #$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$$ + + ml_link_coords = [] + ml_links = [] + for link in network.links(): + if link["type"] == 1 and link["@lane_restriction"] in (2,3) and ( + link["@toll_am"] + link["@toll_md"] + link["@toll_pm"]) > 0: + ml_link_coords.append(LineString(link.shape)) + ml_links.append(link) + ml_link_collection = MultiLineString(ml_link_coords) + distances = [] + for zone in network.centroids(): + zone_point = Point((zone.x, zone.y)) + distances.append(zone_point.distance(ml_link_collection) / 5280) + + # distances is a Python list of the distance from each zone to nearest ML link + # in same order as centroids + return distances + + @_m.logbook_trace("Calculate average travel time savings") + def avg_travel_time_savings(self, scenario, input_directory, props, num_processors): + # AVGTTS: The average travel savings of all households in each zone over all possible + # work destinations d. + # This average was calculated using an expected value with probabilities taken + # from a simplified destination + # choice model. The expected travel time savings of households in a zone z is + # SUM[d](NTTime[zd] - TRTime[zd]) * Employment[d] * exp(-0.01*NTTime[zd]) / + # SUM[d]Employmentd * exp(-0.01*NTTime[zd]) + # + # NTTime[zd] = AM_NTTime[zd] + PM_NTTime[dz] + # TRTime[zd] = AM_TRTime[zd] + PM_TRTime[dz] + + emmebank = scenario.emmebank + year = int(props['scenarioYear']) + mgra = _pd.read_csv( + _join(input_directory, 'mgra13_based_input%s.csv' % year)) + taz = mgra[['taz', 'emp_total']].groupby('taz').sum() + taz.reset_index(inplace=True) + taz = dem_utils.add_missing_zones(taz, scenario) + taz.reset_index(inplace=True) + + with setup_for_tt_savings_calc(emmebank): + employment_matrix = emmebank.matrix("mdemployment") + employment_matrix.set_numpy_data(taz["emp_total"].values, scenario.id) + matrix_calc = dem_utils.MatrixCalculator(scenario, num_processors) + matrix_calc.add("NTTime", "AM_SOV_NT_M_TIME + PM_SOV_NT_M_TIME'") + matrix_calc.add("TRTime", "AM_SOV_TR_M_TIME + PM_SOV_TR_M_TIME'") + matrix_calc.add("numerator", "((NTTime - TRTime).max.0) * employment * exp(-0.01 * NTTime)", + aggregation={"destinations": "+"}) + matrix_calc.add("denominator", "employment * exp(-0.01 * NTTime)", + aggregation={"destinations": "+"}) + matrix_calc.add("AVGTTS", "numerator / denominator") + matrix_calc.run() + avg_tts = emmebank.matrix("AVGTTS").get_numpy_data(scenario.id) + return avg_tts + + @_m.logbook_trace("Calculate percent detour without managed lane facilities") + def percent_detour(self, scenario, network, props, num_processors): + # PCTDETOUR: The percent difference between the AM non-toll travel time + # to a sample downtown zone and the AM non-toll travel time to downtown + # when the general purpose lanes parallel to all toll lanes requiring + # transponders are not available. This variable + # is calculated as + # 100*(TimeWithoutFacility - NonTransponderTime) / NonTransponderTime + + destinations = props["transponder.destinations"] + + network.create_attribute("NODE", "@root") + network.create_attribute("NODE", "@leaf") + + mode_id = get_available_mode_id(network) + new_mode = network.create_mode("AUX_AUTO", mode_id) + sov_non_toll_mode = network.mode("s") + + # Find special managed links and potential parallel GP facilities + ml_link_coords = [] + freeway_links = [] + for link in network.links(): + if link["@lane_restriction"] in [2, 3] and link["type"] == 1 and ( + link["@toll_am"] + link["@toll_md"] + link["@toll_pm"]) > 0: + ml_link_coords.append(LineString(link.shape)) + if sov_non_toll_mode in link.modes: + link.modes |= set([new_mode]) + if link["type"] == 1: + freeway_links.append(link) + + # remove mode from nearby GP links to special managed lanes + ml_link_collection = MultiLineString(ml_link_coords) + for link in freeway_links: + link_shape = LineString(link.shape) + distance = link_shape.distance(ml_link_collection) + if distance < 100: + for ml_shape in ml_link_collection: + if ml_shape.distance(link_shape) and close_bearing(link_shape, ml_shape): + link.modes -= set([new_mode]) + break + + for node in network.centroids(): + node["@root"] = 1 + for dst in destinations: + network.node(dst)["@leaf"] = 1 + + reverse_auto_network(network, "@auto_time") + detour_impedances = shortest_paths_impedances( + network, new_mode, "@auto_time", destinations) + direct_impedances = shortest_paths_impedances( + network, sov_non_toll_mode, "@auto_time", destinations) + + percent_detour = (detour_impedances - direct_impedances) / direct_impedances + avg_percent_detour = _np.sum(percent_detour, axis=1) / len(destinations) + avg_percent_detour = _np.nan_to_num(avg_percent_detour) + return avg_percent_detour + + @_m.logbook_trace("Export results to transponderModelAccessibilities.csv file") + def export_results(self, output_directory, scenario, distances, savings, detour): + zones = scenario.zone_numbers + output_file = _join(output_directory, "transponderModelAccessibilities.csv") + with open(output_file, 'w') as f: + f.write("TAZ,DIST,AVGTTS,PCTDETOUR\n") + for row in _izip(zones, distances, savings, detour): + f.write("%d, %.4f, %.5f, %.5f\n" % row) + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg + + +def reverse_auto_network(network, link_cost): + # swap directionality of modes and specified link costs, as well as turn prohibitions + # delete all transit lines + for line in network.transit_lines(): + network.delete_transit_line(line) + + # backup modes so that turns can be swapped (auto mode remains avialable) + network.create_attribute("LINK", "backup_modes") + for link in network.links(): + link.backup_modes = link.modes + # add new reverse links (where needed) and get the one-way links to be deleted + auto_mode = network.mode("d") + links_to_delete = [] + for link in network.links(): + reverse_link = network.link(link.j_node.id, link.i_node.id) + if reverse_link is None: + reverse_link = network.create_link(link.j_node.id, link.i_node.id, link.modes) + reverse_link.backup_modes = reverse_link.modes + links_to_delete.append(link) + reverse_link.modes |= link.modes + + # reverse the turn data + visited = set([]) + for turn in network.turns(): + if turn in visited: + continue + reverse_turn = network.turn(turn.k_node, turn.j_node, turn.i_node) + time, reverse_time = turn["data1"], turn["data1"] + turn["data1"], turn["data1"] = time, reverse_time + tpf, reverse_tpf = turn.penalty_func, reverse_turn.penalty_func + reverse_turn.penalty_func, turn.penalty_func = tpf, reverse_tpf + visited.add(turn) + visited.add(reverse_turn) + + # reverse the link data + visited = set([]) + for link in network.links(): + if link in visited: + continue + reverse_link = network.link(link.j_node.id, link.i_node.id) + time, reverse_time = link[link_cost], reverse_link[link_cost] + reverse_link[link_cost], link[link_cost] = time, reverse_time + reverse_link.modes, link.modes = link.backup_modes, reverse_link.backup_modes + visited.add(link) + visited.add(reverse_link) + + # delete the one-way links + for link in links_to_delete: + network.delete_link(link.i_node, link.j_node) + + +def shortest_paths_impedances(network, mode, link_cost, destinations): + excluded_links = [] + for link in network.links(): + if mode not in link.modes: + excluded_links.append(link) + + impedances = [] + for dest_id in destinations: + tree = network.shortest_path_tree( + dest_id, link_cost, excluded_links=excluded_links, consider_turns=True) + costs = [] + for node in network.centroids(): + if node.number == dest_id: + costs.append(0) + else: + try: + path_cost = tree.cost_to_node(node.id) + except KeyError: + path_cost = 600 + costs.append(path_cost) + impedances.append(costs) + return _np.array(impedances).T + + +@_context +def setup_for_tt_savings_calc(emmebank): + with gen_utils.temp_matrices(emmebank, "FULL", 2) as mf: + mf[0].name = "NTTime" + mf[0].description = "Temp AM + PM' Auto non-transponder time" + mf[1].name = "TRTime" + mf[1].description = "Temp AM + PM' Auto transponder time" + with gen_utils.temp_matrices(emmebank, "ORIGIN", 3) as mo: + mo[0].name = "numerator" + mo[1].name = "denominator" + mo[2].name = "AVGTTS" + mo[2].description = "Temp average travel time savings" + with gen_utils.temp_matrices(emmebank, "DESTINATION", 1) as md: + md[0].name = "employment" + md[0].description = "Temp employment per zone" + yield + +@_context +def get_temp_scenario(src_scenario): + delete_scenario = _m.Modeller().tool( + "inro.emme.data.scenario.delete_scenario") + emmebank = src_scenario.emmebank + scenario_id = get_available_scenario_id(emmebank) + temp_scenario = emmebank.copy_scenario(src_scenario, scenario_id) + try: + yield temp_scenario + finally: + delete_scenario(temp_scenario) + +def get_available_mode_id(network): + for mode_id in _string.letters: + if network.mode(mode_id) is None: + return mode_id + +def get_available_scenario_id(emmebank): + for i in range(1,10000): + if not emmebank.scenario(i): + return i + +def bearing(shape): + pt1 = shape.coords[0] + pt2 = shape.coords[-1] + x_diff = pt2[0] - pt1[0] + y_diff = pt2[1] - pt1[1] + return math.degrees(math.atan2(y_diff, x_diff)) + +def close_bearing(shape1, shape2, tol=25): + b1 = bearing(shape1) + b2 = bearing(shape2) + diff = (b1 - b2) % 360 + if diff >= 180: + diff -= 360 + return abs(diff) < tol diff --git a/sandag_abm/src/main/emme/toolbox/export/export_tap_adjacent_lines.py b/sandag_abm/src/main/emme/toolbox/export/export_tap_adjacent_lines.py new file mode 100644 index 0000000..068481a --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/export/export_tap_adjacent_lines.py @@ -0,0 +1,122 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// export/export_tap_adjacent_lines.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Exports a list of transit lines adjacent to each TAP. +# +# +# Inputs: +# file_path: export path for the tap adjacency file +# scenario: scenario ID for the base scenario (same used in the Import network tool) +# +# Files created: +# output/tapLines.csv (or as specified) +# +# +# Script example: +""" +import inro.modeller as _m +import os +modeller = _m.Modeller() +desktop = modeller.desktop + +export_tap_adjacent_lines = modeller.tool("sandag.export.export_tap_adjacent_lines") + +project_dir = os.path.dirname(desktop.project_path()) +main_directory = os.path.dirname(project_dir) +output_dir = os.path.join(main_directory, "output") + +main_emmebank = os.path.join(project_dir, "Database", "emmebank") +scenario_id = 100 +base_scenario = main_emmebank.scenario(scenario_id) + +export_tap_adjacent_lines(os.path.join(output_dir, "tapLines.csv"), base_scenario) + +""" + + +TOOLBOX_ORDER = 75 + + +import inro.modeller as _m +import traceback as _traceback +import os + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class ExportLines(_m.Tool(), gen_utils.Snapshot): + + file_path = _m.Attribute(unicode) + + tool_run_msg = "" + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + main_dir = os.path.dirname(project_dir) + self.file_path = os.path.join(main_dir, "output", "tapLines.csv") + self.attributes = ["file_path"] + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Export TAP adjacent lines" + pb.description = """Exports a list of the transit lines adjacent to each tap.""" + pb.branding_text = "- SANDAG - Export" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('file_path', 'save_file',title='Select file path') + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.file_path, scenario) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Export list of TAP adjacent lines", save_arguments=True) + def __call__(self, file_path, scenario): + attributes = {"file_path": file_path} + gen_utils.log_snapshot("Export list of TAP adjacent lines", str(self), attributes) + + network = scenario.get_partial_network( + ["NODE", "TRANSIT_LINE"], include_attributes=False) + values = scenario.get_attribute_values("NODE", ["@tap_id"]) + network.set_attribute_values("NODE", ["@tap_id"], values) + with open(file_path, 'w') as f: + f.write("TAP,LINES\n") + for node in network.nodes(): + if node["@tap_id"] == 0: + continue + lines = set([]) + for link in node.outgoing_links(): + for seg in link.j_node.outgoing_segments(include_hidden=True): + if seg.allow_alightings: + lines.add(seg.line) + if not lines: + continue + f.write("%d," % node["@tap_id"]) + f.write(" ".join([l.id for l in lines])) + f.write("\n") diff --git a/sandag_abm/src/main/emme/toolbox/export/export_traffic_skims.py b/sandag_abm/src/main/emme/toolbox/export/export_traffic_skims.py new file mode 100644 index 0000000..247eb60 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/export/export_traffic_skims.py @@ -0,0 +1,95 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// export/export_traffic_skims.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Exports the traffic skims for use in the disaggregate demand models (CT-RAMP) +# and the data loader process. +# +# Note the matrix name mapping from the OMX file names to the Emme database names. +# +# Inputs: +# omx_file: output directory to read the OMX files from +# period: the period for which to export the skim matrices, "EA", "AM", "MD", "PM", "EV" +# scenario: base traffic scenario to use for reference zone system +# +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + output_dir = os.path.join(main_directory, "output") + scenario = modeller.scenario + periods = ["EA", "AM", "MD", "PM", "EV"] + export_traffic_skims = modeller.tool("sandag.import.export_traffic_skims") + for period in periods: + omx_file_path = os.path.join(output_dir, "traffic_skims_%s.omx" % period + export_traffic_skims(output_dir, period, scenario) +""" + +TOOLBOX_ORDER = 71 + + +import inro.modeller as _m +import traceback as _traceback +import os + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class ExportSkims(_m.Tool(), gen_utils.Snapshot): + + omx_file = _m.Attribute(unicode) + period = _m.Attribute(str) + tool_run_msg = "" + + def __init__(self): + self.attributes = ["omx_file", "period"] + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Export traffic skims" + pb.description = """Export the skim matrices to OMX format for the selected period.""" + pb.branding_text = "- SANDAG - Export" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + pb.add_select_file('omx_file', 'save_file', title='Select OMX file') + options = [(x, x) for x in ["EA", "AM", "MD", "PM", "EV"]] + pb.add_select("period", keyvalues=options, title="Select corresponding period") + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.period, self.omx_file, scenario) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Export traffic skims to OMX", save_arguments=True) + def __call__(self, period, omx_file, scenario): + attributes = {"omx_file": omx_file, "period": period} + gen_utils.log_snapshot("Export traffic skims to OMX", str(self), attributes) + init_matrices = _m.Modeller().tool("sandag.initialize.initialize_matrices") + matrices = init_matrices.get_matrix_names("traffic_skims", [period], scenario) + with gen_utils.ExportOMX(omx_file, scenario, omx_key="NAME") as exporter: + exporter.write_matrices(matrices) diff --git a/sandag_abm/src/main/emme/toolbox/export/export_transit_skims.py b/sandag_abm/src/main/emme/toolbox/export/export_transit_skims.py new file mode 100644 index 0000000..7c22691 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/export/export_transit_skims.py @@ -0,0 +1,108 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// export/export_transit_skims.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Exports the transit skims for use in the disaggregate demand models (CT-RAMP) +# and the data loader process. +# +# Note the matrix name mapping from the OMX file names to the Emme database names. +# +# Inputs: +# omx_file: output directory to read the OMX files from +# periods: list of periods, using the standard two-character abbreviation +# big_to_zero: replace big values (>10E6) with zero +# This is used in the final iteration skim (after the demand models are +# complete) to filter large values from the OMX files which are not +# compatible with the data loader process +# scenario: transit scenario to use for reference zone system +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + output_dir = os.path.join(main_directory, "output") + scenario = modeller.scenario + export_transit_skims = modeller.tool("sandag.import.export_transit_skims") + omx_file_path = os.path.join(output_dir, "transit_skims.omx" + export_transit_skims(output_dir, period, scenario) +""" + + +TOOLBOX_ORDER = 72 + + +import inro.modeller as _m +import traceback as _traceback +import os + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class ExportSkims(_m.Tool(), gen_utils.Snapshot): + omx_file = _m.Attribute(unicode) + periods = _m.Attribute(unicode) + big_to_zero = _m.Attribute(bool) + + tool_run_msg = "" + + def __init__(self): + self.attributes = ["omx_file", "periods", "big_to_zero"] + self.periods = "EA, AM, MD, PM, EV" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Export transit skim matrices" + pb.description = """Export the skim matrices to OMX format for all periods.""" + pb.branding_text = "- SANDAG - Export" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + pb.add_select_file('omx_file', 'save_file', title='Select OMX file') + pb.add_text_box('periods', title="Selected periods:") + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + periods = [x.strip() for x in self.periods.split(",")] + self(self.omx_file, periods, scenario, self.big_to_zero) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Export transit skims to OMX", save_arguments=True) + def __call__(self, omx_file, periods, scenario, big_to_zero=False): + attributes = {"omx_file": omx_file, "periods": periods, "big_to_zero": big_to_zero} + gen_utils.log_snapshot("Export transit skims to OMX", str(self), attributes) + init_matrices = _m.Modeller().tool("sandag.initialize.initialize_matrices") + matrices = init_matrices.get_matrix_names( + "transit_skims", periods, scenario) + with gen_utils.ExportOMX(omx_file, scenario, omx_key="NAME") as exporter: + if big_to_zero: + emmebank = scenario.emmebank + for name in matrices: + matrix = emmebank.matrix(name) + array = matrix.get_numpy_data(scenario) + array[array>10E6] = 0 + exporter.write_array(array, exporter.generate_key(matrix)) + else: + exporter.write_matrices(matrices) diff --git a/sandag_abm/src/main/emme/toolbox/import/adjust_network_links.py b/sandag_abm/src/main/emme/toolbox/import/adjust_network_links.py new file mode 100644 index 0000000..7630a5d --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/import/adjust_network_links.py @@ -0,0 +1,156 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/adjust_network_links.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# deletes the existing centroid connectors and create new centroid connectors +# connecting the centroid of aggregated zones to the original end points (on network) +# of old centroid connectors +# +# Inputs: +# source: path to the location of the input network files +# base_scenario: scenario that has highway network only +# emmebank: the Emme database in which to the new network is published +# external_zone: string "1-12" that refernces to range of external zones +# taz_cwk_file: input csv file created after zone aggregation. It has the crosswalk between existing TAZ to new zone structure +# cluster_zone_file: input csv file created after zone aggregation. It has the centroid coordinates of the new zone structure +# +# + +import inro.modeller as _m +import os + +import pandas as pd +from scipy.spatial import distance + + +def adjust_network_links(source, base_scenario, emmebank, external_zone, taz_cwk_file, cluster_zone_file) + + taz_cwk = pd.read_csv(os.path.join(source, taz_cwk_file), index_col = 0) + taz_cwk = taz_cwk['cluster_id'].to_dict() + + emmebank = _m.Modeller().emmebank + scenario = emmebank.scenario(base_scenario) + hwy_network = scenario.get_network() + + centroid_nodes = [] + exclude_nodes = [] + + + ext_zones = [int(s) for s in external_zone.split() if s.isdigit()] + + for node in range(ext_zones[0],ext_zones[1],1): + exclude_nodes.append(hwy_network.node(node)) + + for node in hwy_network.centroids(): + if not node in exclude_nodes: + centroid_nodes.append(node) + + i_nodes = [] + j_nodes = [] + data1 = [] + length = [] + links = [] + + for link in hwy_network.links(): + if link.i_node in centroid_nodes: + links.append(link) + i_nodes.append(int(link.i_node)) + j_nodes.append(int(link.j_node)) + data1.append(link.data1) + length.append(link.length) + + df = pd.DataFrame({'links' : links, 'i_nodes' : i_nodes, 'j_nodes': j_nodes, 'ul1_org': data1, 'length_org':length}) + df['i_nodes_new'] = df['i_nodes'].map(taz_cwk) + + #get XY of existing centroids + j_nodes_list = df['j_nodes'].unique() + j_nodes_list = [hwy_network.node(x) for x in j_nodes_list] + + j_nodes = [] + j_x = [] + j_y = [] + for nodes in hwy_network.nodes(): + if nodes in j_nodes_list: + j_nodes.append(nodes) + j_x.append(nodes.x) + j_y.append(nodes.y) + + j_nodes_XY = pd.DataFrame({'j_nodes' : j_nodes, 'j_x' : j_x, 'j_y': j_y}) + j_nodes_XY['j_nodes'] = [int(x) for x in j_nodes_XY['j_nodes']] + df = pd.merge(df, j_nodes_XY, on = 'j_nodes', how = 'left') + + agg_node_coords = pd.read_csv(os.path.join(source, cluster_zone_file)) + df = pd.merge(df, agg_node_coords, left_on = 'i_nodes_new', right_on = 'cluster_id', how = 'left') + df = df.drop(columns = 'cluster_id') + df = df.rename(columns = {'centroid_x' : 'i_new_x', 'centroid_y' : 'i_new_y'}) + + i_coords = zip(df['j_x'], df['j_y']) + j_coords = zip(df['i_new_x'], df['i_new_y']) + + df['length'] = [distance.euclidean(i, j)/5280.0 for i,j in zip(i_coords, j_coords)] + + #delete all the existing centroid nodes + for index,row in df.iterrows(): + if hwy_network.node(row['i_nodes']): + hwy_network.delete_node(row['i_nodes'], True) + + # create new nodes (centroids of clusters) + for index,row in agg_node_coords.iterrows(): + new_node = hwy_network.create_node(row['cluster_id'], is_centroid = True) + new_node.x = int(row['centroid_x']) + new_node.y = int(row['centroid_y']) + + df['type'] = 10 + df['num_lanes'] = 1 + df['vdf'] = 11 + df['ul3'] = 999999 + + final_df = df[["i_nodes_new", "j_nodes", "length", "type", "num_lanes", "vdf", "ul3"]] + final_df = final_df.drop_duplicates() + final_df = final_df.reset_index(drop=True) + final_df['type'] = final_df['type'].astype("int") + + # create new links + for index,row in final_df.iterrows(): + + link_ij = hwy_network.create_link(row['i_nodes_new'], row['j_nodes'], + modes = ["d", "h", "H", "i","I","s", "S", "v", "V", "m", "M", "t", "T"]) + link_ij.length = row['length'] + link_ij.type = row['type'].astype("int") + link_ij.num_lanes = row['num_lanes'].astype("int") + link_ij.volume_delay_func = row['vdf'].astype("int") + link_ij.data3 = row['ul3'].astype("int") + link_ij['@lane_ea'] = 1 # had to do this as they are being replaced in highway assignment by the values in these columns + link_ij['@lane_am'] = 1 + link_ij['@lane_md'] = 1 + link_ij['@lane_pm'] = 1 + link_ij['@lane_ev'] = 1 + + + link_ji = hwy_network.create_link(row['j_nodes'], row['i_nodes_new'], + modes = ["d", "h", "H", "i","I","s", "S", "v", "V", "m", "M", "t", "T"]) + link_ji.length = row['length'] + link_ji.type = row['type'].astype("int") + link_ji.num_lanes = row['num_lanes'].astype("int") + link_ji.volume_delay_func = row['vdf'].astype("int") + link_ji.data3 = row['ul3'].astype("int") + link_ji['@lane_ea'] = 1 # had to do this as they are being replaced in highway assignment by the values in these columns + link_ji['@lane_am'] = 1 + link_ji['@lane_md'] = 1 + link_ji['@lane_pm'] = 1 + link_ji['@lane_ev'] = 1 + + return(hwy_network) + #publish the highway network to the scenario + #scenario.publish_network(hwy_network) \ No newline at end of file diff --git a/sandag_abm/src/main/emme/toolbox/import/import_auto_demand.py b/sandag_abm/src/main/emme/toolbox/import/import_auto_demand.py new file mode 100644 index 0000000..375a27c --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/import/import_auto_demand.py @@ -0,0 +1,516 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/import_auto_demand.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Imports the auto demand matrices generated from an iteration of the disaggregate +# demand models (CT-RAMP) and adds the saved disaggregated demand matrices to +# generate the total auto demand in preparation for the auto assignment. +# +# Note the matrix name mapping from the OMX file names to the Emme database names. +# +# Inputs: +# external_zones: set of external zone IDs as a range "1-12" +# output_dir: output directory to read the OMX files from +# num_processors: number of processors to use in the matrix calculations +# scenario: traffic scenario to use for reference zone system +# +# Files referenced: +# Note: pp is time period, one of EA, AM, MD, PM, EV, vot is one of low, med, high +# output/autoInternalExternalTrips_pp_vot.omx +# output/autoVisitorTrips_pp_vot.omx +# output/autoCrossBorderTrips_pp_vot.omx +# output/autoAirportTrips.SAN_pp_vot.omx +# output/autoAirportTrips.CDX_pp_vot.omx (if they exist) +# output/autoTrips_pp_vot.omx +# output/othrTrips_pp.omx (added to high vot) +# output/TripMatrices.csv +# output/EmptyAVTrips.omx (added to high vot) +# output/TNCVehicleTrips_pp.omx (added to high vot) +# +# Matrix inputs: +# pp_SOVGP_EIWORK, pp_SOVGP_EINONWORK, pp_SOVTOLL_EIWORK, pp_SOVTOLL_EINONWORK, +# pp_HOV2HOV_EIWORK, pp_HOV2HOV_EINONWORK, pp_HOV2TOLL_EIWORK, pp_HOV2TOLL_EINONWORK, +# pp_HOV3HOV_EIWORK, pp_HOV3HOV_EINONWORK, pp_HOV3TOLL_EIWORK, pp_HOV3TOLL_EINONWORK +# pp_SOV_EETRIPS, pp_HOV2_EETRIPS, pp_HOV3_EETRIPS +# +# Matrix results: +# Note: pp is time period, one of EA, AM, MD, PM, EV, v is one of L, M, H +# pp_SOV_TR_v, pp_SOV_NT_v, pp_HOV2_v, pp_HOV3_v, pp_HOV3_v +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + output_dir = os.path.join(main_directory, "output") + external_zones = "1-12" + num_processors = "MAX-1" + base_scenario = modeller.scenario + import_auto_demand = modeller.tool("sandag.import.import_auto_demand") + import_auto_demand(external_zones, output_dir, num_processors, base_scenario) +""" + +TOOLBOX_ORDER = 13 + + +import inro.modeller as _m +import traceback as _traceback +import pandas as _pandas +import os +import numpy +from contextlib import contextmanager as _context + +_join = os.path.join + +dem_utils = _m.Modeller().module('sandag.utilities.demand') +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class ImportMatrices(_m.Tool(), gen_utils.Snapshot): + + external_zones = _m.Attribute(str) + output_dir = _m.Attribute(unicode) + num_processors = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self.external_zones = "1-12" + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + main_dir = os.path.dirname(project_dir) + self.main_dir = main_dir + self.output_dir = os.path.join(main_dir, "output") + self.num_processors = "MAX-1" + self.attributes = ["external_zones", "output_dir", "num_processors"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Import auto demand and sum matrices" + pb.description = """ +
+ Imports the trip matrices generated by CT-RAMP in OMX format, + the commercial vehicle demand in CSV format, + and adds the demand from the aggregate models for the final + trip assignments.
+ A total of 90 OMX files are expected, for 5 time periods + EA, AM, MD, PM and EV, and value-of-time level low, med or high, + with internal matrices by SOV, HOV2, HOV3+ and toll access type: + + As well as one CSV file "TripMatrices.csv" for the commercial vehicle trips. + Adds the aggregate demand from the + external-external and external-internal demand matrices: + + to the time-of-day total demand matrices. +
+
+ """ + pb.branding_text = "- SANDAG - Model" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + pb.add_select_file('output_dir', 'directory', + title='Select output directory') + pb.add_text_box("external_zones", title="External zones:") + dem_utils.add_select_processors("num_processors", pb, self) + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.output_dir, self.external_zones, self.num_processors, scenario) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Create TOD auto trip tables", save_arguments=True) + def __call__(self, output_dir, external_zones, num_processors, scenario): + attributes = { + "output_dir": output_dir, + "external_zones": external_zones, + "num_processors": num_processors} + gen_utils.log_snapshot("Create TOD auto trip tables", str(self), attributes) + + #get parameters from sandag_abm.properties + modeller = _m.Modeller() + load_properties = modeller.tool('sandag.utilities.properties') + props = load_properties(_join(self.main_dir, "conf", "sandag_abm.properties")) + + self.scenario = scenario + self.output_dir = output_dir + self.external_zones = external_zones + self.num_processors = num_processors + self.import_traffic_trips(props) + self.import_commercial_vehicle_demand(props) + #self.convert_light_trucks_to_pce() + self.add_aggregate_demand() + + @_context + def setup(self): + emmebank = self.scenario.emmebank + self._matrix_cache = {} + with gen_utils.OMXManager(self.output_dir, "%sTrips%s%s.omx") as omx_manager: + try: + yield omx_manager + finally: + for name, value in self._matrix_cache.iteritems(): + matrix = emmebank.matrix(name) + matrix.set_numpy_data(value, self.scenario.id) + + def set_data(self, name, value): + if name in self._matrix_cache: + value = value + self._matrix_cache[name] + self._matrix_cache[name] = value + + @_m.logbook_trace("Import CT-RAMP traffic trips from OMX") + def import_traffic_trips(self, props): + title = "Import CT-RAMP traffic trips from OMX report" + report = _m.PageBuilder(title) + + taxi_da_share = props["Taxi.da.share"] + taxi_s2_share = props["Taxi.s2.share"] + taxi_s3_share = props["Taxi.s3.share"] + taxi_pce = props["Taxi.passengersPerVehicle"] + tnc_single_da_share = props["TNC.single.da.share"] + tnc_single_s2_share = props["TNC.single.s2.share"] + tnc_single_s3_share = props["TNC.single.s3.share"] + tnc_single_pce = props["TNC.single.passengersPerVehicle"] + tnc_shared_da_share = props["TNC.shared.da.share"] + tnc_shared_s2_share = props["TNC.shared.s2.share"] + tnc_shared_s3_share = props["TNC.shared.s3.share"] + tnc_shared_pce = props["TNC.shared.passengersPerVehicle"] + av_share = props["Mobility.AV.Share"] + + periods = ["_EA", "_AM", "_MD", "_PM", "_EV"] + vot_bins = ["_low", "_med", "_high"] + mode_shares = [ + ("mf%s_SOV_TR_H", { + "TAXI": taxi_da_share / taxi_pce + }), + ("mf%s_HOV2_H", { + "TAXI": taxi_s2_share / taxi_pce + }), + ("mf%s_HOV3_H", { + "TAXI": taxi_s3_share / taxi_pce + }), + ] + + with self.setup() as omx_manager: + # SOV transponder "TRPDR" = "TR" and non-transponder "NOTRPDR" = "NT" + for period in periods: + for vot in vot_bins: + # SOV non-transponder demand + matrix_name = "mf%s_SOV_NT_%s" % (period[1:], vot[1].upper()) + logbook_label = "Import auto from OMX SOVNOTRPDR to matrix %s" % (matrix_name) + resident_demand = omx_manager.lookup(("auto", period, vot), "SOVNOTRPDR%s" % period) + visitor_demand = omx_manager.lookup(("autoVisitor", period, vot), "SOV%s" % period) + cross_border_demand = omx_manager.lookup(("autoCrossBorder", period, vot), "SOV%s" % period) + # NOTE: No non-transponder airport or internal-external demand + total_ct_ramp_trips = ( + resident_demand + visitor_demand + cross_border_demand) + dem_utils.demand_report([ + ("resident", resident_demand), + ("cross_border", cross_border_demand), + ("visitor", visitor_demand), + ("total", total_ct_ramp_trips) + ], + logbook_label, self.scenario, report) + self.set_data(matrix_name, total_ct_ramp_trips) + + # SOV transponder demand + matrix_name = "mf%s_SOV_TR_%s" % (period[1:], vot[1].upper()) + logbook_label = "Import auto from OMX SOVTRPDR to matrix %s" % (matrix_name) + resident_demand = omx_manager.lookup(("auto", period, vot), "SOVTRPDR%s" % period) + # NOTE: No transponder visitor or cross-border demand + airport_demand = omx_manager.lookup(("autoAirport", ".SAN" + period, vot), "SOV%s" % period) + if omx_manager.file_exists(("autoAirport", ".CBX" + period, vot)): + airport_demand += omx_manager.lookup(("autoAirport", ".CBX" + period, vot), "SOV%s" % period) + internal_external_demand = omx_manager.lookup(("autoInternalExternal", period, vot), "SOV%s" % period) + + total_ct_ramp_trips = ( + resident_demand + airport_demand + internal_external_demand) + dem_utils.demand_report([ + ("resident", resident_demand), + ("airport", airport_demand), + ("internal_external", internal_external_demand), + ("total", total_ct_ramp_trips) + ], + logbook_label, self.scenario, report) + self.set_data(matrix_name, total_ct_ramp_trips) + + # HOV2 and HOV3 demand + matrix_name_map = [ + ("mf%s_HOV2_%s", "SR2%s"), + ("mf%s_HOV3_%s", "SR3%s") + ] + for matrix_name_tmplt, omx_name in matrix_name_map: + matrix_name = matrix_name_tmplt % (period[1:], vot[1].upper()) + logbook_label = "Import auto from OMX %s to matrix %s" % (omx_name[:3], matrix_name) + resident_demand = ( + omx_manager.lookup(("auto", period, vot), omx_name % ("TRPDR" + period)) + + omx_manager.lookup(("auto", period, vot), omx_name % ("NOTRPDR" + period))) + visitor_demand = omx_manager.lookup(("autoVisitor", period, vot), omx_name % period) + cross_border_demand = omx_manager.lookup(("autoCrossBorder", period, vot), omx_name % period) + airport_demand = omx_manager.lookup(("autoAirport", ".SAN" + period, vot), omx_name % period) + if omx_manager.file_exists(("autoAirport", ".CBX" + period, vot)): + airport_demand += omx_manager.lookup(("autoAirport", ".CBX" + period, vot), omx_name % period) + internal_external_demand = omx_manager.lookup(("autoInternalExternal", period, vot), omx_name % period) + + total_ct_ramp_trips = ( + resident_demand + visitor_demand + cross_border_demand + airport_demand + internal_external_demand) + dem_utils.demand_report([ + ("resident", resident_demand), + ("cross_border", cross_border_demand), + ("visitor", visitor_demand), + ("airport", airport_demand), + ("internal_external", internal_external_demand), + ("total", total_ct_ramp_trips) + ], + logbook_label, self.scenario, report) + self.set_data(matrix_name, total_ct_ramp_trips) + + # add TNC and TAXI demand to vot="high" + for matrix_name_tmplt, share in mode_shares: + matrix_name = matrix_name_tmplt % period[1:] + logbook_label = "Import othr from TAXI, empty AV, and TNC to matrix %s" % (matrix_name) + resident_taxi_demand = ( + omx_manager.lookup(("othr", period, ""), "TAXI" + period) * share["TAXI"]) + visitor_taxi_demand = ( + omx_manager.lookup(("othrVisitor", period, ""), "TAXI" + period) * share["TAXI"]) + cross_border_taxi_demand = ( + omx_manager.lookup(("othrCrossBorder", period, ""), "TAXI" + period) * share["TAXI"]) + # airport SAN + airport_taxi_demand = ( + omx_manager.lookup(("othrAirport", ".SAN", period), "TAXI" + period) * share["TAXI"]) + # airport CBX (optional) + if omx_manager.file_exists(("othrAirport", ".CBX", period)): + airport_taxi_demand += ( + omx_manager.lookup(("othrAirport",".CBX", period), "TAXI" + period) * share["TAXI"]) + internal_external_taxi_demand = ( + omx_manager.lookup(("othrInternalExternal", period, ""), "TAXI" + period) * share["TAXI"]) + + #AV routing models and TNC fleet model demand + empty_av_demand = omx_manager.lookup(("EmptyAV","",""), "EmptyAV%s" % period) + tnc_demand_0 = omx_manager.lookup(("TNCVehicle","",period), "TNC%s_0" % period) + tnc_demand_1 = omx_manager.lookup(("TNCVehicle","",period), "TNC%s_1" % period) + tnc_demand_2 = omx_manager.lookup(("TNCVehicle","",period), "TNC%s_2" % period) + tnc_demand_3 = omx_manager.lookup(("TNCVehicle","",period), "TNC%s_3" % period) + + #AVs: no driver. No AVs: driver + #AVs: 0 and 1 passenger would be SOV. there will be empty vehicles as well. No AVs: 0 passanger would be SOV + #AVs: 2 passenger would be HOV2. No AVs: 1 passenger would be HOV2 + #AVs: 3 passenger would be HOV3. No AVs: 2 and 3 passengers would be HOV3 + if (av_share>0): + if (matrix_name_tmplt[5:-2] == "SOV_TR"): + av_demand = empty_av_demand + tnc_demand_0 + tnc_demand_1 + elif (matrix_name_tmplt[5:-2] == "HOV2"): + av_demand = tnc_demand_2 + else: + av_demand = tnc_demand_3 + else: + if (matrix_name_tmplt[5:-2] == "SOV_TR"): + av_demand = tnc_demand_0 + elif (matrix_name_tmplt[5:-2] == "HOV2"): + av_demand = tnc_demand_1 + else: + av_demand = tnc_demand_2 + tnc_demand_3 + + total_ct_ramp_trips = ( + resident_taxi_demand + visitor_taxi_demand + cross_border_taxi_demand + + airport_taxi_demand + internal_external_taxi_demand + av_demand) + dem_utils.demand_report([ + ("resident_taxi", resident_taxi_demand), + ("visitor_taxi", visitor_taxi_demand), + ("cross_border_taxi", cross_border_taxi_demand), + ("airport_taxi", airport_taxi_demand), + ("internal_external_taxi", internal_external_taxi_demand), + ("av_fleet", av_demand), + ("total", total_ct_ramp_trips) + ], + logbook_label, self.scenario, report) + self.set_data(matrix_name, total_ct_ramp_trips) + _m.logbook_write(title, report.render()) + + @_m.logbook_trace('Import commercial vehicle demand') + def import_commercial_vehicle_demand(self, props): + scale_factor = props["cvm.scale_factor"] + scale_light = props["cvm.scale_light"] + scale_medium = props["cvm.scale_medium"] + scale_heavy = props["cvm.scale_heavy"] + share_light = props["cvm.share.light"] + share_medium = props["cvm.share.medium"] + share_heavy = props["cvm.share.heavy"] + + scenario = self.scenario + emmebank = scenario.emmebank + + mapping = {} + periods = ["EA", "AM", "MD", "PM", "EV"] + # The SOV demand is modified in-place, which was imported + # prior from the CT-RAMP demand + # The truck demand in vehicles is copied from separate matrices + for index, period in enumerate(periods): + mapping["CVM_%s:LNT" % period] = { + "orig": "%s_SOV_TR_H" % period, + "dest": "%s_SOV_TR_H" % period, + "pce": 1.0, + "scale": scale_light[index], + "share": share_light, + "period": period + } + mapping["CVM_%s:INT" % period] = { + "orig": "%s_TRK_L_VEH" % period, + "dest": "%s_TRK_L" % period, + "pce": 1.3, + "scale": scale_medium[index], + "share": share_medium, + "period": period + } + mapping["CVM_%s:MNT" % period] = { + "orig": "%s_TRK_M_VEH" % period, + "dest": "%s_TRK_M" % period, + "pce": 1.5, + "scale": scale_medium[index], + "share": share_medium, + "period": period + } + mapping["CVM_%s:HNT" % period] = { + "orig": "%s_TRK_H_VEH" % period, + "dest": "%s_TRK_H" % period, + "pce": 2.5, + "scale": scale_heavy[index], + "share": share_heavy, + "period": period + } + with _m.logbook_trace('Load starting SOV and truck matrices'): + for key, value in mapping.iteritems(): + value["array"] = emmebank.matrix(value["orig"]).get_numpy_data(scenario) + + with _m.logbook_trace('Processing CVM from TripMatrices.csv'): + path = os.path.join(self.output_dir, "TripMatrices.csv") + table = _pandas.read_csv(path) + for key, value in mapping.iteritems(): + cvm_array = table[key].values.reshape((4996, 4996)) # reshape method deprecated since v 0.19.0, yma, 2/12/2019 + #factor in cvm demand by the scale factor used in trip generation + cvm_array = cvm_array/scale_factor + #scale trips to take care of underestimation + cvm_array = cvm_array * value["scale"] + + #add remaining share to the correspnding truck matrix + value["array"] = value["array"] + (cvm_array * (1-value["share"])) + + #add cvm truck vehicles to light-heavy trucks + for key, value in mapping.iteritems(): + period = value["period"] + cvm_vehs = ['L','M','H'] + if key == "CVM_%s:INT" % period: + for veh in cvm_vehs: + key_new = "CVM_%s:%sNT" % (period, veh) + value_new = mapping[key_new] + if value_new["share"] != 0.0: + cvm_array = table[key_new].values.reshape((4996, 4996)) + cvm_array = cvm_array/scale_factor + cvm_array = cvm_array * value_new["scale"] + value["array"] = value["array"] + (cvm_array * value_new["share"]) + matrix_unique = {} + with _m.logbook_trace('Save SOV matrix and convert CV and truck vehicle demand to PCEs for assignment'): + for key, value in mapping.iteritems(): + matrix = emmebank.matrix(value["dest"]) + array = value["array"] * value["pce"] + if (matrix in matrix_unique.keys()): + array = array + emmebank.matrix(value["dest"]).get_numpy_data(scenario) + matrix.set_numpy_data(array, scenario) + matrix_unique[matrix] = 1 + + @_m.logbook_trace('Convert light truck vehicle demand to PCEs for assignment') + def convert_light_trucks_to_pce(self): + matrix_calc = dem_utils.MatrixCalculator(self.scenario, self.num_processors) + # Calculate PCEs for trucks + periods = ["EA", "AM", "MD", "PM", "EV"] + mat_trucks = ['TRK_L'] + pce_values = [1.3] + for period in periods: + with matrix_calc.trace_run("Period %s" % period): + for name, pce in zip(mat_trucks, pce_values): + demand_name = 'mf%s_%s' % (period, name) + matrix_calc.add(demand_name, '(%s_VEH * %s).max.0' % (demand_name, pce)) + + @_m.logbook_trace('Add aggregate demand') + def add_aggregate_demand(self): + matrix_calc = dem_utils.MatrixCalculator(self.scenario, self.num_processors) + periods = ["EA", "AM", "MD", "PM", "EV"] + vots = ["L", "M", "H"] + # External-internal trips DO have transponder + # all SOV trips go to SOVTP + with matrix_calc.trace_run("Add external-internal trips to auto demand"): + modes = ["SOVGP", "SOVTOLL", "HOV2HOV", "HOV2TOLL", "HOV3HOV", "HOV3TOLL"] + modes_assign = {"SOVGP": "SOV_TR", + "SOVTOLL": "SOV_TR", + "HOV2HOV": "HOV2", + "HOV2TOLL": "HOV2", + "HOV3HOV": "HOV3", + "HOV3TOLL": "HOV3"} + for period in periods: + for mode in modes: + for vot in vots: + # Segment imported demand into 3 equal parts for VOT Low/Med/High + assign_mode = modes_assign[mode] + params = {'p': period, 'm': mode, 'v': vot, 'am': assign_mode} + matrix_calc.add("mf%s_%s_%s" % (period, assign_mode, vot), + "mf%(p)s_%(am)s_%(v)s " + "+ (1.0/3.0)*mf%(p)s_%(m)s_EIWORK " + "+ (1.0/3.0)*mf%(p)s_%(m)s_EINONWORK" % params) + + # External - external faster with single-processor as number of O-D pairs is so small (12 X 12) + # External-external trips do not have transpnder + # all SOV trips go to SOVNTP + matrix_calc.num_processors = 0 + with matrix_calc.trace_run("Add external-external trips to auto demand"): + modes = ["SOV", "HOV2", "HOV3"] + for period in periods: + for mode in modes: + for vot in vots: + # Segment imported demand into 3 equal parts for VOT Low/Med/High + params = {'p': period, 'm': mode, 'v': vot} + if (mode == "SOV"): + matrix_calc.add( + "mf%(p)s_%(m)s_NT_%(v)s" % params, + "mf%(p)s_%(m)s_NT_%(v)s + (1.0/3.0)*mf%(p)s_%(m)s_EETRIPS" % params, + {"origins": self.external_zones, "destinations": self.external_zones}) + else: + matrix_calc.add( + "mf%(p)s_%(m)s_%(v)s" % params, + "mf%(p)s_%(m)s_%(v)s + (1.0/3.0)*mf%(p)s_%(m)s_EETRIPS" % params, + {"origins": self.external_zones, "destinations": self.external_zones}) diff --git a/sandag_abm/src/main/emme/toolbox/import/import_network.py b/sandag_abm/src/main/emme/toolbox/import/import_network.py new file mode 100644 index 0000000..e068a73 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/import/import_network.py @@ -0,0 +1,2151 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/import_network.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Imports the network from the input network files. +# +# +# Inputs: +# source: path to the location of the input network files +# traffic_scenario_id: optional scenario to store the imported network from the traffic files only +# transit_scenario_id: optional scenario to store the imported network from the transit files only +# merged_scenario_id: scenario to store the combined traffic and transit data from all network files +# title: the title to use for the imported scenario +# save_data_tables: if checked, create a data table for each reference file for viewing in the Emme Desktop +# data_table_name: prefix to use to identify all data tables +# overwrite: check to overwrite any existing data tables or scenarios with the same ID or name +# emmebank: the Emme database in which to create the scenario. Default is the current open database +# +# Files referenced: +# hwycov.e00: base nodes and links for traffic network with traffic attributes in ESRI input exchange format +# linktypeturns.dbf: fixed turn travel times by to/from link type (field IFC) pairs +# turns.csv: turn bans and fixed costs by link from/to ID (field HWYCOV-ID) +# trcov.e00: base nodes and links for transit network in ESRI input exchange format +# trrt.csv: transit routes and their attributes +# trlink.csv: itineraries for each route as sequence of link IDs (TRCOV-ID field) +# trstop.csv: transit stop attributes +# timexfer_period.csv: table of timed transfer pairs of lines, by period +# mode5tod.csv: global (per-mode) transit cost and perception attributes +# special_fares.txt: table listing special fares in terms of boarding and incremental in-vehicle costs. +# off_peak_toll_factors.csv (optional): factors to calculate the toll for EA, MD, and EV periods from the OP toll input for specified facilities +# vehicle_class_toll_factors.csv (optional): factors to adjust the toll cost by facility name and class (DA, S2, S3, TRK_L, TRK_M, TRK_H) +# +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + source_dir = os.path.join(main_directory, "input") + title = "Base 2012 scenario" + import_network = modeller.tool("sandag.import.import_network") + import_network(output_dir, merged_scenario_id=100, title=title, + data_table_name="2012_base", overwrite=True) +""" + + +TOOLBOX_ORDER = 11 + + +import inro.modeller as _m +import inro.emme.datatable as _dt +import inro.emme.network as _network +from inro.emme.core.exception import Error as _NetworkError + +from itertools import izip as _izip +from collections import defaultdict as _defaultdict, OrderedDict +from contextlib import contextmanager as _context +import fiona as _fiona + +from math import ceil as _ceiling +from copy import deepcopy as _copy +import numpy as _np +import heapq as _heapq + +import traceback as _traceback +import os + +import pandas as pd +from scipy.spatial import distance + +_join = os.path.join +_dir = os.path.dirname + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + +FILE_NAMES = { + "FARES": "special_fares.txt", + "OFF_PEAK": "off_peak_toll_factors.csv", + "VEHICLE_CLASS": "vehicle_class_toll_factors.csv" +} + + +class ImportNetwork(_m.Tool(), gen_utils.Snapshot): + + source = _m.Attribute(unicode) + traffic_scenario_id = _m.Attribute(int) + transit_scenario_id = _m.Attribute(int) + merged_scenario_id = _m.Attribute(int) + overwrite = _m.Attribute(bool) + title = _m.Attribute(unicode) + save_data_tables = _m.Attribute(bool) + data_table_name = _m.Attribute(unicode) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self._log = [] + self._error = [] + project_dir = _dir(_m.Modeller().desktop.project.path) + self.source = _join(_dir(project_dir), "input") + self.overwrite = False + self.title = "" + self.data_table_name = "" + self.attributes = [ + "source", "traffic_scenario_id", "transit_scenario_id", "merged_scenario_id", + "overwrite", "title", "save_data_tables", "data_table_name"] + + def page(self): + if not self.data_table_name: + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(_dir(self.source), "conf", "sandag_abm.properties")) + self.data_table_name = props["scenarioYear"] + + pb = _m.ToolPageBuilder(self) + pb.title = "Import network" + pb.description = """ + Create an Emme network from the E00 and associated files + generated from TCOVED. + The timed transfer is stored in data tables with the suffix "_timed_xfers_period". +
+
+
+ The following files are used: + +
+ """ + pb.branding_text = "- SANDAG - Import" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file("source", window_type="directory", file_filter="", + title="Source directory:",) + + pb.add_text_box("traffic_scenario_id", size=6, title="Scenario ID for traffic (optional):") + pb.add_text_box("transit_scenario_id", size=6, title="Scenario ID for transit (optional):") + pb.add_text_box("merged_scenario_id", size=6, title="Scenario ID for merged network:") + pb.add_text_box("title", size=80, title="Scenario title:") + pb.add_checkbox("save_data_tables", title=" ", label="Save reference data tables of file data") + pb.add_text_box("data_table_name", size=80, title="Name for data tables:", + note="Prefix name to use for all saved data tables") + pb.add_checkbox("overwrite", title=" ", label="Overwrite existing scenarios and data tables") + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self.emmebank = _m.Modeller().emmebank + with self.setup(): + self.execute() + run_msg = "Network import complete" + if self._error: + run_msg += " with %s non-fatal errors. See logbook for details" % len(self._error) + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc()) + raise + + def __call__(self, source, + traffic_scenario_id=None, transit_scenario_id=None, merged_scenario_id=None, + title="", save_data_tables=False, data_table_name="", overwrite=False, + emmebank=None): + + self.source = source + self.traffic_scenario_id = traffic_scenario_id + self.transit_scenario_id = transit_scenario_id + self.merged_scenario_id = merged_scenario_id + self.title = title + self.save_data_tables = save_data_tables + self.data_table_name = data_table_name + self.overwrite = overwrite + if not emmebank: + self.emmebank = _m.Modeller().emmebank + else: + self.emmebank = emmebank + + with self.setup(): + self.execute() + + return self.emmebank.scenario(merged_scenario_id) + + @_context + def setup(self): + self._log = [] + self._error = [] + fatal_error = False + attributes = OrderedDict([ + ("self", str(self)), + ("source", self.source), + ("traffic_scenario_id", self.traffic_scenario_id), + ("transit_scenario_id", self.transit_scenario_id), + ("merged_scenario_id", self.merged_scenario_id), + ("title", self.title), + ("save_data_tables", self.save_data_tables), + ("data_table_name", self.data_table_name), + ("overwrite", self.overwrite), + ]) + self._log = [{ + "content": attributes.items(), + "type": "table", "header": ["name", "value"], + "title": "Tool input values" + }] + with _m.logbook_trace("Import network", attributes=attributes) as trace: + gen_utils.log_snapshot("Import network", str(self), attributes) + try: + yield + except Exception as error: + self._log.append({"type": "text", "content": error}) + trace_text = _traceback.format_exc().replace("\n", "
") + self._log.append({"type": "text", "content": trace_text}) + self._error.append(error) + fatal_error = True + raise + finally: + self.log_report() + if self._error: + if fatal_error: + trace.write("Import network failed (%s errors)" % len(self._error), attributes=attributes) + else: + trace.write("Import network completed (%s non-fatal errors)" % len(self._error), attributes=attributes) + + def execute(self): + traffic_attr_map = { + "NODE": { + "interchange": ("@interchange", "DERIVED", "EXTRA", "is interchange node") + }, + "LINK": OrderedDict([ + ("HWYCOV-ID", ("@tcov_id", "TWO_WAY", "EXTRA", "SANDAG-assigned link ID")), + ("SPHERE", ("@sphere", "TWO_WAY", "EXTRA", "Jurisdiction sphere of influence")), + ("NM", ("#name", "TWO_WAY", "STRING", "Street name")), + ("FXNM", ("#name_from", "TWO_WAY", "STRING", "Cross street at the FROM end")), + ("TXNM", ("#name_to", "TWO_WAY", "STRING", "Cross street name at the TO end")), + ("DIR", ("@direction_cardinal", "TWO_WAY", "EXTRA", "Link direction")), + ("ASPD", ("@speed_adjusted", "TWO_WAY", "EXTRA", "Adjusted link speed (miles/hr)")), + ("IYR", ("@year_open_traffic", "TWO_WAY", "EXTRA", "The year the link opened to traffic")), + ("IPROJ", ("@project_code", "TWO_WAY", "EXTRA", "Project number for use with hwyproj.xls")), + ("IJUR", ("@jurisdiction_type", "TWO_WAY", "EXTRA", "Link jurisdiction type")), + ("IFC", ("type", "TWO_WAY", "STANDARD", "")), + ("IHOV", ("@lane_restriction", "TWO_WAY", "EXTRA", "Link operation type")), + ("ITRUCK", ("@truck_restriction", "TWO_WAY", "EXTRA", "Truck restriction code (ITRUCK)")), + ("ISPD", ("@speed_posted", "TWO_WAY", "EXTRA", "Posted speed limit (mph)")), + ("IMED", ("@median", "TWO_WAY", "EXTRA", "Median type")), + ("AU", ("@lane_auxiliary", "ONE_WAY", "EXTRA", "Number of auxiliary lanes")), + ("CNT", ("@traffic_control", "ONE_WAY", "EXTRA", "Intersection control type")), + ("TL", ("@turn_thru", "ONE_WAY", "EXTRA", "Intersection approach through lanes")), + ("RL", ("@turn_right", "ONE_WAY", "EXTRA", "Intersection approach right-turn lanes")), + ("LL", ("@turn_left", "ONE_WAY", "EXTRA", "Intersection approach left-turn lanes")), + ("GC", ("@green_to_cycle_init", "ONE_WAY", "EXTRA", "Initial green-to-cycle ratio")), + ("CHO", ("@capacity_hourly_op", "ONE_WAY", "EXTRA", "Off-Peak hourly mid-link capacity")), + ("CHA", ("@capacity_hourly_am", "ONE_WAY", "EXTRA", "AM Peak hourly mid-link capacity")), + ("CHP", ("@capacity_hourly_pm", "ONE_WAY", "EXTRA", "PM Peak hourly mid-link capacity")), + # These attributes are expanded from 3 time periods to 5 + ("ITOLLO", ("toll_op", "TWO_WAY", "INTERNAL", "Expanded to EA, MD and EV")), + ("ITOLLA", ("toll_am", "TWO_WAY", "INTERNAL", "")), + ("ITOLLP", ("toll_pm", "TWO_WAY", "INTERNAL", "")), + ("LNO", ("lane_op", "ONE_WAY", "INTERNAL", "Expanded to EA, MD and EV")), + ("LNA", ("lane_am", "ONE_WAY", "INTERNAL", "")), + ("LNP", ("lane_pm", "ONE_WAY", "INTERNAL", "")), + ("CPO", ("capacity_link_op", "ONE_WAY", "INTERNAL", "Expanded to EA, MD and EV")), + ("CPA", ("capacity_link_am", "ONE_WAY", "INTERNAL", "")), + ("CPP", ("capacity_link_pm", "ONE_WAY", "INTERNAL", "")), + ("CXO", ("capacity_inter_op", "ONE_WAY", "INTERNAL", "Expanded to EA, MD and EV")), + ("CXA", ("capacity_inter_am", "ONE_WAY", "INTERNAL", "")), + ("CXP", ("capacity_inter_pm", "ONE_WAY", "INTERNAL", "")), + ("TMO", ("time_link_op", "ONE_WAY", "INTERNAL", "Expanded to EA, MD and EV")), + ("TMA", ("time_link_am", "ONE_WAY", "INTERNAL", "")), + ("TMP", ("time_link_pm", "ONE_WAY", "INTERNAL", "")), + ("TXO", ("time_inter_op", "ONE_WAY", "INTERNAL", "Expanded to EA, MD and EV")), + ("TXA", ("time_inter_am", "ONE_WAY", "INTERNAL", "")), + ("TXP", ("time_inter_pm", "ONE_WAY", "INTERNAL", "")), + # These three attributes are used to cross-reference the turn directions + ("TLB", ("through_link", "ONE_WAY", "INTERNAL", "")), + ("RLB", ("right_link", "ONE_WAY", "INTERNAL", "")), + ("LLB", ("left_link", "ONE_WAY", "INTERNAL", "")), + ("@cost_operating", ("@cost_operating","DERIVED", "EXTRA", "Fuel and maintenance cost")), + ("INTDIST_UP", ("@intdist_up", "DERIVED", "EXTRA", "Upstream major intersection distance")), + ("INTDIST_DOWN", ("@intdist_down", "DERIVED", "EXTRA", "Downstream major intersection distance")), + ]) + } + time_period_attrs = OrderedDict([ + ("@cost_auto", "toll + cost autos"), + ("@cost_hov2", "toll (non-mngd) + cost HOV2"), + ("@cost_hov3", "toll (non-mngd) + cost HOV3+"), + ("@cost_lgt_truck", "toll + cost light trucks"), + ("@cost_med_truck", "toll + cost medium trucks"), + ("@cost_hvy_truck", "toll + cost heavy trucks"), + ("@cycle", "cycle length (minutes)"), + ("@green_to_cycle", "green to cycle ratio"), + ("@capacity_link", "mid-link capacity"), + ("@capacity_inter", "approach capacity"), + ("@toll", "toll cost (cent)"), + ("@lane", "number of lanes"), + ("@time_link", "link time in minutes"), + ("@time_inter", "intersection delay time"), + ("@sta_reliability", "static reliability") + ]) + time_name = { + "_ea": "Early AM ", "_am": "AM Peak ", "_md": "Mid-day ", "_pm": "PM Peak ", "_ev": "Evening " + } + time_periods = ["_ea", "_am", "_md", "_pm", "_ev"] + for attr, desc_tmplt in time_period_attrs.iteritems(): + for time in time_periods: + traffic_attr_map["LINK"][attr + time] = \ + (attr + time, "DERIVED", "EXTRA", time_name[time] + desc_tmplt) + + transit_attr_map = { + "NODE": OrderedDict([ + ("@tap_id", ("@tap_id", "DERIVED", "EXTRA", "Transit-access point ID")), + ]), + "LINK": OrderedDict([ + ("TRCOV-ID", ("@tcov_id", "TWO_WAY", "EXTRA", "SANDAG-assigned link ID")), + ("NM", ("#name", "TWO_WAY", "STRING", "Street name")), + ("FXNM", ("#name_from", "TWO_WAY", "STRING", "Cross street at the FROM end")), + ("TXNM", ("#name_to", "TWO_WAY", "STRING", "Cross street name at the TO end")), + ("DIR", ("@direction_cardinal", "TWO_WAY", "EXTRA", "Link direction")), + ("OSPD", ("@speed_observed", "TWO_WAY", "EXTRA", "Observed speed")), + ("IYR", ("@year_open_traffic", "TWO_WAY", "EXTRA", "The year the link opened to traffic ")), + ("IFC", ("type", "TWO_WAY", "STANDARD", "")), + ("IHOV", ("@lane_restriction_tr", "TWO_WAY", "EXTRA", "Link operation type")), + ("ISPD", ("@speed_posted_tr_l", "TWO_WAY", "EXTRA", "Posted speed limit (mph)")), + ("IMED", ("@median", "TWO_WAY", "EXTRA", "Median type")), + ("TMO", ("trtime_link_op", "ONE_WAY", "INTERNAL", "Expanded to EA, MD and EV")), + ("TMEA", ("@trtime_link_ea", "DERIVED", "EXTRA", "Early AM transit link time in minutes")), + ("TMA", ("@trtime_link_am", "ONE_WAY", "EXTRA", "AM Peak transit link time in minutes")), + ("TMMD", ("@trtime_link_md", "DERIVED", "EXTRA", "Mid-day transit link time in minutes")), + ("TMP", ("@trtime_link_pm", "ONE_WAY", "EXTRA", "PM Peak transit link time in minutes")), + ("TMEV", ("@trtime_link_ev", "DERIVED", "EXTRA", "Evening transit link time in minutes")), + ("MINMODE", ("@mode_hierarchy", "TWO_WAY", "EXTRA", "Transit mode type")), + ]), + "TRANSIT_LINE": OrderedDict([ + ("AM_Headway", ("@headway_am", "TRRT", "EXTRA", "AM Peak actual headway")), + ("PM_Headway", ("@headway_pm", "TRRT", "EXTRA", "PM Peak actual headway")), + ("OP_Headway", ("@headway_op", "TRRT", "EXTRA", "Off-Peak actual headway")), + ("Night_Headway", ("@headway_night", "TRRT", "EXTRA", "Night actual headway")), + ("AM_Headway_rev", ("@headway_rev_am", "DERIVED", "EXTRA", "AM Peak revised headway")), + ("PM_Headway_rev", ("@headway_rev_pm", "DERIVED", "EXTRA", "PM Peak revised headway")), + ("OP_Headway_rev", ("@headway_rev_op", "DERIVED", "EXTRA", "Off-Peak revised headway")), + ("WT_IVTPK", ("@vehicle_per_pk", "MODE5TOD", "EXTRA", "Peak in-vehicle perception factor")), + ("WT_IVTOP", ("@vehicle_per_op", "MODE5TOD", "EXTRA", "Off-Peak in-vehicle perception factor")), + ("WT_FAREPK", ("@fare_per_pk", "MODE5TOD", "EXTRA", "Peak fare perception factor")), + ("WT_FAREOP", ("@fare_per_op", "MODE5TOD", "EXTRA", "Off-Peak fare perception factor")), + ("DWELLTIME", ("default_dwell_time", "MODE5TOD", "INTERNAL", "")), + ("Fare", ("@fare", "TRRT", "EXTRA", "Boarding fare ($)")), + ("@transfer_penalty",("@transfer_penalty","DERIVED", "EXTRA", "Transfer penalty (min)")), + ("Route_ID", ("@route_id", "TRRT", "EXTRA", "Transit line internal ID")), + ("Night_Hours", ("@night_hours", "TRRT", "EXTRA", "Night hours")), + ("Config", ("@config", "TRRT", "EXTRA", "Config ID (same as route name)")), + ]), + "TRANSIT_SEGMENT": OrderedDict([ + ("Stop_ID", ("@stop_id", "TRSTOP", "EXTRA", "Stop ID from trcov")), + ("Pass_Count", ("@pass_count", "TRSTOP", "EXTRA", "Number of times this stop is passed")), + ("Milepost", ("@milepost", "TRSTOP", "EXTRA", "Distance from start of line")), + ("FareZone", ("@fare_zone", "TRSTOP", "EXTRA", "Fare zone ID")), + ("StopName", ("#stop_name", "TRSTOP", "STRING", "Name of stop")), + ("@coaster_fare_board", ("@coaster_fare_board", "DERIVED", "EXTRA", "Boarding fare for coaster")), + ("@coaster_fare_inveh", ("@coaster_fare_inveh", "DERIVED", "EXTRA", "Incremental fare for Coaster")), + ]) + } + + create_scenario = _m.Modeller().tool( + "inro.emme.data.scenario.create_scenario") + + file_names = [ + "hwycov.e00", "LINKTYPETURNS.DBF", "turns.csv", + "trcov.e00", "trrt.csv", "trlink.csv", "trstop.csv", + "timexfer_EA.csv", "timexfer_AM.csv","timexfer_MD.csv", + "timexfer_PM.csv","timexfer_EV.csv","MODE5TOD.csv", + ] + for name in file_names: + file_path = _join(self.source, name) + if not os.path.exists(file_path): + raise Exception("missing file '%s' in directory %s" % (name, self.source)) + + title = self.title + if not title: + existing_scenario = self.emmebank.scenario(self.merged_scenario_id) + if existing_scenario: + title = existing_scenario.title + + def create_attributes(scenario, attr_map): + for elem_type, mapping in attr_map.iteritems(): + for name, _tcoved_type, emme_type, desc in mapping.values(): + if emme_type == "EXTRA": + if not scenario.extra_attribute(name): + xatt = scenario.create_extra_attribute(elem_type, name) + xatt.description = desc + elif emme_type == "STRING": + if not scenario.network_field(elem_type, name): + scenario.create_network_field(elem_type, name, 'STRING', description=desc) + + if self.traffic_scenario_id: + traffic_scenario = create_scenario( + self.traffic_scenario_id, title + " Traffic", + overwrite=self.overwrite, emmebank=self.emmebank) + create_attributes(traffic_scenario, traffic_attr_map) + else: + traffic_scenario = None + if self.transit_scenario_id: + transit_scenario = create_scenario( + self.transit_scenario_id, title + " Transit", + overwrite=self.overwrite, emmebank=self.emmebank) + create_attributes(transit_scenario, transit_attr_map) + else: + transit_scenario = None + if self.merged_scenario_id: + scenario = create_scenario( + self.merged_scenario_id, title, + overwrite=self.overwrite, emmebank=self.emmebank) + create_attributes(scenario, traffic_attr_map) + create_attributes(scenario, transit_attr_map) + else: + scenario = traffic_scenario or transit_scenario + + traffic_network = _network.Network() + transit_network = _network.Network() + try: + if self.traffic_scenario_id or self.merged_scenario_id: + for elem_type, attrs in traffic_attr_map.iteritems(): + log_content = [] + for k, v in attrs.iteritems(): + if v[3] == "DERIVED": + k = "--" + log_content.append([k] + list(v)) + self._log.append({ + "content": log_content, + "type": "table", + "header": ["TCOVED", "Emme", "Source", "Type", "Description"], + "title": "Traffic %s attributes" % elem_type.lower().replace("_", " "), + "disclosure": True + }) + try: + self.create_traffic_base(traffic_network, traffic_attr_map) + self.create_turns(traffic_network) + self.calc_traffic_attributes(traffic_network) + self.check_zone_access(traffic_network, traffic_network.mode("d")) + finally: + if traffic_scenario: + traffic_scenario.publish_network(traffic_network, resolve_attributes=True) + + if self.transit_scenario_id or self.merged_scenario_id: + for elem_type, attrs in transit_attr_map.iteritems(): + log_content = [] + for k, v in attrs.iteritems(): + if v[3] == "DERIVED": + k = "--" + log_content.append([k] + list(v)) + self._log.append({ + "content": log_content, + "type": "table", + "header": ["TCOVED", "Emme", "Source", "Type", "Description"], + "title": "Transit %s attributes" % elem_type.lower().replace("_", " "), + "disclosure": True + }) + try: + self.create_transit_base(transit_network, transit_attr_map) + self.create_transit_lines(transit_network, transit_attr_map) + self.calc_transit_attributes(transit_network) + finally: + if transit_scenario: + for link in transit_network.links(): + if link.type <= 0: + link.type = 99 + transit_scenario.publish_network(transit_network, resolve_attributes=True) + if self.merged_scenario_id: + self.add_transit_to_traffic(traffic_network, transit_network) + finally: + if self.merged_scenario_id: + scenario.publish_network(traffic_network, resolve_attributes=True) + + self.set_functions(scenario) + self.check_connectivity(scenario) + + def create_traffic_base(self, network, attr_map): + self._log.append({"type": "header", "content": "Import traffic base network from hwycov.e00"}) + hwy_data = gen_utils.DataTableProc("ARC", _join(self.source, "hwycov.e00")) + + if self.save_data_tables: + hwy_data.save("%s_hwycov" % self.data_table_name, self.overwrite) + + for elem_type in "NODE", "TURN": + mapping = attr_map.get(elem_type) + if not mapping: + continue + for field, (attr, tcoved_type, emme_type, desc) in mapping.iteritems(): + default = "" if emme_type == "STRING" else 0 + network.create_attribute(elem_type, attr, default) + + # Create Modes + dummy_auto = network.create_mode("AUTO", "d") + hov2 = network.create_mode("AUX_AUTO", "h") + hov2_toll = network.create_mode("AUX_AUTO", "H") + hov3 = network.create_mode("AUX_AUTO", "i") + hov3_toll = network.create_mode("AUX_AUTO", "I") + sov = network.create_mode("AUX_AUTO", "s") + sov_toll = network.create_mode("AUX_AUTO", "S") + heavy_trk = network.create_mode("AUX_AUTO", "v") + heavy_trk_toll = network.create_mode("AUX_AUTO", "V") + medium_trk = network.create_mode("AUX_AUTO", "m") + medium_trk_toll = network.create_mode("AUX_AUTO", "M") + light_trk = network.create_mode("AUX_AUTO", "t") + light_trk_toll = network.create_mode("AUX_AUTO", "T") + + dummy_auto.description = "dummy auto" + sov.description = "SOV" + hov2.description = "HOV2" + hov3.description = "HOV3+" + light_trk.description = "TRKL" + medium_trk.description = "TRKM" + heavy_trk.description = "TRKH" + + sov_toll.description = "SOV TOLL" + hov2_toll.description = "HOV2 TOLL" + hov3_toll.description = "HOV3+ TOLL" + light_trk_toll.description = "TRKL TOLL" + medium_trk_toll.description = "TRKM TOLL" + heavy_trk_toll.description = "TRKH TOLL" + + is_centroid = lambda arc, node : (arc["IFC"] == 10) and (node == "AN") + + # Note: only truck types 1, 3, 4, and 7 found in 2012 base network + modes_gp_lanes= { + 1: set([dummy_auto, sov, hov2, hov3, light_trk, medium_trk, heavy_trk, + sov_toll, hov2_toll, hov3_toll, light_trk_toll, medium_trk_toll, + heavy_trk_toll]), + 2: set([dummy_auto, sov, hov2, hov3, light_trk, medium_trk, + sov_toll, hov2_toll, hov3_toll, light_trk_toll, medium_trk_toll]), + 3: set([dummy_auto, sov, hov2, hov3, light_trk, sov_toll, hov2_toll, + hov3_toll, light_trk_toll]), + 4: set([dummy_auto, sov, hov2, hov3, sov_toll, hov2_toll, hov3_toll]), + 5: set([dummy_auto, heavy_trk, heavy_trk_toll]), + 6: set([dummy_auto, medium_trk, heavy_trk, medium_trk_toll, heavy_trk_toll]), + 7: set([dummy_auto, light_trk, medium_trk, heavy_trk, light_trk_toll, + medium_trk_toll, heavy_trk_toll]), + } + modes_toll_lanes = { + 1: set([dummy_auto, sov_toll, hov2_toll, hov3_toll, light_trk_toll, + medium_trk_toll, heavy_trk_toll]), + 2: set([dummy_auto, sov_toll, hov2_toll, hov3_toll, light_trk_toll, + medium_trk_toll]), + 3: set([dummy_auto, sov_toll, hov2_toll, hov3_toll, light_trk_toll]), + 4: set([dummy_auto, sov_toll, hov2_toll, hov3_toll]), + 5: set([dummy_auto, heavy_trk_toll]), + 6: set([dummy_auto, medium_trk_toll, heavy_trk_toll]), + 7: set([dummy_auto, light_trk_toll, medium_trk_toll, heavy_trk_toll]), + } + modes_HOV2 = set([dummy_auto, hov2, hov3, hov2_toll, hov3_toll]) + modes_HOV3 = set([dummy_auto, hov3, hov3_toll]) + + + def define_modes(arc): + if arc["IFC"] == 10: # connector + return modes_gp_lanes[1] + elif arc["IHOV"] == 1: + return modes_gp_lanes[arc["ITRUCK"]] + elif arc["IHOV"] == 2: + # managed lanes, free for HOV2 and HOV3+, tolls for SOV + if arc["ITOLLO"] + arc["ITOLLA"] + arc["ITOLLP"] > 0: + return modes_toll_lanes[arc["ITRUCK"]] | modes_HOV2 + # special case of I-15 managed lanes base year and 2020, no build + elif arc["IFC"] == 1 and arc["IPROJ"] in [41, 42, 486, 373, 711]: + return modes_toll_lanes[arc["ITRUCK"]] | modes_HOV2 + elif arc["IFC"] == 8 or arc["IFC"] == 9: + return modes_toll_lanes[arc["ITRUCK"]] | modes_HOV2 + else: + return modes_HOV2 + elif arc["IHOV"] == 3: + # managed lanes, free for HOV3+, tolls for SOV and HOV2 + if arc["ITOLLO"] + arc["ITOLLA"] + arc["ITOLLP"] > 0: + return modes_toll_lanes[arc["ITRUCK"]] | modes_HOV3 + # special case of I-15 managed lanes for base year and 2020, no build + elif arc["IFC"] == 1 and arc["IPROJ"] in [41, 42, 486, 373, 711]: + return modes_toll_lanes[arc["ITRUCK"]] | modes_HOV3 + elif arc["IFC"] == 8 or arc["IFC"] == 9: + return modes_toll_lanes[arc["ITRUCK"]] | modes_HOV3 + else: + return modes_HOV3 + elif arc["IHOV"] == 4: + return modes_toll_lanes[arc["ITRUCK"]] + else: + return modes_gp_lanes[arc["ITRUCK"]] + + self._create_base_net( + hwy_data, network, mode_callback=define_modes, centroid_callback=is_centroid, + arc_id_name="HWYCOV-ID", link_attr_map=attr_map["LINK"]) + self._log.append({"type": "text", "content": "Import traffic base network complete"}) + + def create_transit_base(self, network, attr_map): + self._log.append({"type": "header", "content": "Import transit base network from trcov.e00"}) + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(_dir(self.source), "conf", "sandag_abm.properties")) + transit_data = gen_utils.DataTableProc("ARC", _join(self.source, "trcov.e00")) + + if self.save_data_tables: + transit_data.save("%s_trcov" % self.data_table_name, self.overwrite) + + # aux mode speed is always 3 (miles/hr) + access = network.create_mode("AUX_TRANSIT", "a") + transfer = network.create_mode("AUX_TRANSIT", "x") + walk = network.create_mode("AUX_TRANSIT", "w") + + bus = network.create_mode("TRANSIT", "b") + express_bus = network.create_mode("TRANSIT", "e") + ltdexp_bus = network.create_mode("TRANSIT", "p") + brt_red = network.create_mode("TRANSIT", "r") + brt_yellow = network.create_mode("TRANSIT", "y") + lrt = network.create_mode("TRANSIT", "l") + coaster_rail = network.create_mode("TRANSIT", "c") + tier1 = network.create_mode("TRANSIT", "o") + + access.description = "ACCESS" + transfer.description = "TRANSFER" + walk.description = "WALK" + bus.description = "BUS" # (vehicle type 100, PCE=3.0) + express_bus.description = "EXP BUS" # (vehicle type 90 , PCE=3.0) + ltdexp_bus.description = "LTDEXP BUS" # (vehicle type 80 , PCE=3.0) + lrt.description = "LRT" # (vehicle type 50) + brt_yellow.description = "BRT YEL" # (vehicle type 60 , PCE=3.0) + brt_red.description = "BRT RED" # (vehicle type 70 , PCE=3.0) + coaster_rail.description = "CMR" # (vehicle type 40) + tier1.description = "TIER1" # (vehicle type 45) + + access.speed = 3 + transfer.speed = 3 + walk.speed = 3 + + # define TAP connectors as centroids + is_centroid = lambda arc, node: (int(arc["MINMODE"]) == 3) and (node == "BN") + + mode_setting = { + 1: set([transfer]), # 1 = special transfer walk links between certain nearby stops + 2: set([walk]), # 2 = walk links in the downtown area + 3: set([access]), # 3 = the special TAP connectors + 4: set([coaster_rail]), # 4 = Coaster Rail Line + 5: set([lrt]), # 5 = Light Rail Transit (LRT) Line + 6: set([brt_yellow, ltdexp_bus, express_bus, bus]), # 6 = Yellow Car Bus Rapid Transit (BRT) + 7: set([brt_red, ltdexp_bus, express_bus, bus]), # 7 = Red Car Bus Rapid Transit (BRT) + 8: set([ltdexp_bus, express_bus, bus]), # 8 = Limited Express Bus + 9: set([ltdexp_bus, express_bus, bus]), # 9 = Express Bus + 10: set([ltdexp_bus, express_bus, bus]), # 10 = Local Bus + } + tier1_rail_link_name = props["transit.newMode"] + + def define_modes(arc): + if arc["NM"] == tier1_rail_link_name: + return set([tier1]) + return mode_setting[arc["MINMODE"]] + + arc_filter = lambda arc: (arc["MINMODE"] > 2) + + # first pass to create the main base network for vehicles, xfer links and TAPs + self._create_base_net( + transit_data, network, mode_callback=define_modes, centroid_callback=is_centroid, + arc_id_name="TRCOV-ID", link_attr_map=attr_map["LINK"], arc_filter=arc_filter) + + # second pass to add special walk links / modify modes on existing links + reverse_dir_map = {1:3, 3:1, 2:4, 4:2, 0:0} + + def set_reverse_link(link, modes): + reverse_link = link.reverse_link + if reverse_link: + reverse_link.modes |= modes + else: + reverse_link = network.create_link(link.j_node, link.i_node, modes) + for attr in network.attributes("LINK"): + reverse_link[attr] = link[attr] + reverse_link["@direction_cardinal"] = reverse_dir_map[link["@direction_cardinal"]] + reverse_link["@tcov_id"] = -1*link["@tcov_id"] + reverse_link.vertices = list(reversed(link.vertices)) + + def epsilon_compare(a, b, epsilon): + return abs((a - b) / (a if abs(a) > 1 else 1)) <= epsilon + + for arc in transit_data: + # possible improvement: snap walk nodes to nearby node if not matched and within distance + if arc_filter(arc): + continue + if float(arc["AN"]) == 0 or float(arc["BN"]) == 0: + self._log.append({"type": "text", + "content": "Node ID 0 in AN (%s) or BN (%s) for link ID %s." % + (arc["AN"], arc["BN"], arc["TRCOV-ID"])}) + continue + coordinates = arc["geo_coordinates"] + arc_length = arc["LENGTH"] / 5280.0 # convert feet to miles + i_node = get_node(network, arc['AN'], coordinates[0], False) + j_node = get_node(network, arc['BN'], coordinates[-1], False) + modes = define_modes(arc) + link = network.link(i_node, j_node) + split_link_case = False + if link: + link.modes |= modes + else: + # Note: additional cases of "tunnel" walk links could be + # considered to optimize network matching + # check if this a special "split" link case where + # we do not need to add a "tunnel" walk link + for link1 in i_node.outgoing_links(): + if split_link_case: + break + for link2 in link1.j_node.outgoing_links(): + if link2.j_node == j_node: + if epsilon_compare(link1.length + link2.length, arc_length, 10**-5): + self._log.append({"type": "text", + "content": "Walk link AN %s BN %s matched to two links TCOV-ID %s, %s" % + (arc['AN'], arc['BN'], link1["@tcov_id"], link2["@tcov_id"])}) + link1.modes |= modes + link2.modes |= modes + set_reverse_link(link1, modes) + set_reverse_link(link2, modes) + split_link_case = True + break + if not split_link_case: + link = network.create_link(i_node, j_node, modes) + link.length = arc_length + if len(coordinates) > 2: + link.vertices = coordinates[1:-1] + if not split_link_case: + set_reverse_link(link, modes) + self._log.append({"type": "text", "content": "Import transit base network complete"}) + + def _create_base_net(self, data, network, mode_callback, centroid_callback, arc_id_name, link_attr_map, arc_filter=None): + forward_attr_map = {} + reverse_attr_map = {} + for field, (name, tcoved_type, emme_type, desc) in link_attr_map.iteritems(): + if emme_type != "STANDARD": + default = "" if emme_type == "STRING" else 0 + network.create_attribute("LINK", name, default) + + if field in [arc_id_name, "DIR"]: + # these attributes are special cases for reverse link + forward_attr_map[field] = name + elif tcoved_type == "TWO_WAY": + forward_attr_map[field] = name + reverse_attr_map[field] = name + elif tcoved_type == "ONE_WAY": + forward_attr_map["AB" + field] = name + reverse_attr_map["BA" + field] = name + + emme_id_name = forward_attr_map[arc_id_name] + dir_name = forward_attr_map["DIR"] + reverse_dir_map = {1:3, 3:1, 2:4, 4:2, 0:0} + new_node_id = max(data.values("AN").max(), data.values("BN").max()) + 1 + if arc_filter is None: + arc_filter = lambda arc : True + + # Create nodes and links + for arc in data: + if not arc_filter(arc): + continue + if float(arc["AN"]) == 0 or float(arc["BN"]) == 0: + self._log.append({"type": "text", + "content": "Node ID 0 in AN (%s) or BN (%s) for link ID %s." % + (arc["AN"], arc["BN"], arc[arc_id_name])}) + continue + coordinates = arc["geo_coordinates"] + i_node = get_node(network, arc['AN'], coordinates[0], centroid_callback(arc, "AN")) + j_node = get_node(network, arc['BN'], coordinates[-1], centroid_callback(arc, "BN")) + existing_link = network.link(i_node, j_node) + if existing_link: + msg = "Duplicate link between AN %s and BN %s. Link IDs %s and %s." % \ + (arc["AN"], arc["BN"], existing_link[emme_id_name], arc[arc_id_name]) + self._log.append({"type": "text", "content": msg}) + self._error.append(msg) + self._split_link(network, i_node, j_node, new_node_id) + new_node_id += 1 + + modes = mode_callback(arc) + link = network.create_link(i_node, j_node, modes) + link.length = arc["LENGTH"] / 5280.0 # convert feet to miles + if len(coordinates) > 2: + link.vertices = coordinates[1:-1] + for field, attr in forward_attr_map.iteritems(): + link[attr] = arc[field] + if arc["IWAY"] == 2 or arc["IWAY"] == 0: + reverse_link = network.create_link(j_node, i_node, modes) + reverse_link.length = link.length + reverse_link.vertices = list(reversed(link.vertices)) + for field, attr in reverse_attr_map.iteritems(): + reverse_link[attr] = arc[field] + reverse_link[emme_id_name] = -1*arc[arc_id_name] + reverse_link[dir_name] = reverse_dir_map[arc["DIR"]] + + def create_transit_lines(self, network, attr_map): + self._log.append({"type": "header", "content": "Import transit lines"}) + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(_dir(self.source), "conf", "sandag_abm.properties")) + fatal_errors = 0 + # Route_ID,Route_Name,Mode,AM_Headway,PM_Headway,OP_Headway,Night_Headway,Night_Hours,Config,Fare + transit_line_data = gen_utils.DataTableProc("trrt", _join(self.source, "trrt.csv")) + # Route_ID,Link_ID,Direction + transit_link_data = gen_utils.DataTableProc("trlink", _join(self.source, "trlink.csv")) + # Stop_ID,Route_ID,Link_ID,Pass_Count,Milepost,Longitude, Latitude,HwyNode,TrnNode,FareZone,StopName + transit_stop_data = gen_utils.DataTableProc("trstop", _join(self.source, "trstop.csv")) + # From_line,To_line,Board_stop,Wait_time + # Note: Board_stop is not used + # Timed xfer data + periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + timed_xfer_data = {} + for period in periods: + timed_xfer_data[period] = gen_utils.DataTableProc("timexfer_"+period, _join(self.source, "timexfer_"+period+".csv")) + + mode_properties = gen_utils.DataTableProc("MODE5TOD", _join(self.source, "MODE5TOD.csv"), convert_numeric=True) + mode_details = {} + for record in mode_properties: + mode_details[int(record["MODE_ID"])] = record + + if self.save_data_tables: + transit_link_data.save("%s_trlink" % self.data_table_name, self.overwrite) + transit_line_data.save("%s_trrt" % self.data_table_name, self.overwrite) + transit_stop_data.save("%s_trstop" % self.data_table_name, self.overwrite) + mode_properties.save("%s_MODE5TOD" % self.data_table_name, self.overwrite) + + coaster = network.create_transit_vehicle(40, 'c') # 4 coaster + trolley = network.create_transit_vehicle(50, 'l') # 5 sprinter/trolley + brt_yellow = network.create_transit_vehicle(60, 'y') # 6 BRT yellow line (future line) + brt_red = network.create_transit_vehicle(70, 'r') # 7 BRT red line (future line) + premium_bus = network.create_transit_vehicle(80, 'p') # 8 prem express + express_bus = network.create_transit_vehicle(90, 'e') # 9 regular express + local_bus = network.create_transit_vehicle(100, 'b') # 10 local bus + tier1 = network.create_transit_vehicle(45, 'o') # 11 Tier 1 + + brt_yellow.auto_equivalent = 3.0 + brt_red.auto_equivalent = 3.0 + premium_bus.auto_equivalent = 3.0 + express_bus.auto_equivalent = 3.0 + local_bus.auto_equivalent = 3.0 + + # Capacities - for reference / post-assignment analysis + tier1.seated_capacity, tier1.total_capacity = 7 * 142, 7 * 276 + trolley.seated_capacity, trolley.total_capacity = 4 * 64, 4 * 200 + brt_yellow.seated_capacity, brt_yellow.total_capacity = 32, 70 + brt_red.seated_capacity, brt_red.total_capacity = 32, 70 + premium_bus.seated_capacity, premium_bus.total_capacity = 32, 70 + express_bus.seated_capacity, express_bus.total_capacity = 32, 70 + local_bus.seated_capacity, local_bus.total_capacity = 32, 70 + + trrt_attrs = [] + mode5tod_attrs = [] + for elem_type in "TRANSIT_LINE", "TRANSIT_SEGMENT", "NODE": + mapping = attr_map[elem_type] + for field, (attr, tcoved_type, emme_type, desc) in mapping.iteritems(): + default = "" if emme_type == "STRING" else 0 + network.create_attribute(elem_type, attr, default) + if tcoved_type == "TRRT": + trrt_attrs.append((field, attr)) + elif tcoved_type == "MODE5TOD": + mode5tod_attrs.append((field, attr)) + + # Pre-process transit line (trrt.csv) to know the route names for errors / warnings + transit_line_records = list(transit_line_data) + line_names = {} + for record in transit_line_records: + line_names[int(record["Route_ID"])] = record["Route_Name"].strip() + + links = dict((link["@tcov_id"], link) for link in network.links()) + transit_routes = _defaultdict(lambda: []) + for record in transit_link_data: + line_ref = line_names.get(int(record["Route_ID"]), record["Route_ID"]) + link_id = int(record["Link_ID"]) + if "+" in record["Direction"]: + link = links.get(link_id) + else: + link = links.get(-1*link_id) + if not link: + link = links.get(link_id) + if link and not link.reverse_link: + reverse_link = network.create_link(link.j_node, link.i_node, link.modes) + reverse_link.vertices = list(reversed(link.vertices)) + for attr in network.attributes("LINK"): + if attr not in set(["vertices"]): + reverse_link[attr] = link[attr] + reverse_link["@tcov_id"] = -1 * link["@tcov_id"] + msg = "Transit line %s : Missing reverse link with ID %s (%s) (reverse link created)" % ( + line_ref, record["Link_ID"], link) + self._log.append({"type": "text", "content": msg}) + self._error.append("Transit route import: " + msg) + link = reverse_link + if not link: + msg = "Transit line %s : No link with ID %s, line not created" % ( + line_ref, record["Link_ID"]) + self._log.append({"type": "text", "content": msg}) + self._error.append("Transit route import: " + msg) + fatal_errors += 1 + continue + transit_routes[int(record["Route_ID"])].append(link) + + # lookup list of special tier 1 mode route names + tier1_rail_route_names = [str(n) for n in props["transit.newMode.route"]] + dummy_links = set([]) + transit_lines = {} + for record in transit_line_records: + try: + route = transit_routes[int(record["Route_ID"])] + # Find if name matches one of the names listed in transit.newMode.route and convert to tier 1 rail + is_tier1_rail = False + for name in tier1_rail_route_names: + if str(record["Route_Name"]).startswith(name): + print 'record["Route_Name"]2', record["Route_Name"] + is_tier1_rail = True + break + if is_tier1_rail: + vehicle_type = 45 + mode = network.transit_vehicle(vehicle_type).mode + else: + vehicle_type = int(record["Mode"]) * 10 + mode = network.transit_vehicle(vehicle_type).mode + prev_link = route[0] + itinerary = [prev_link] + for link in route[1:]: + if prev_link.j_node != link.i_node: # filling in the missing gap + msg = "line %s : Links not adjacent, shortest path interpolation used (%s and %s)" % ( + record["Route_Name"], prev_link["@tcov_id"], link["@tcov_id"]) + log_record = {"type": "text", "content": msg} + self._log.append(log_record) + sub_path = find_path(prev_link, link, mode) + itinerary.extend(sub_path) + log_record["content"] = log_record["content"] + " through %s links" % (len(sub_path)) + itinerary.append(link) + prev_link = link + + node_itinerary = [itinerary[0].i_node] + [l.j_node for l in itinerary] + try: + tline = network.create_transit_line( + record["Route_Name"].strip(), vehicle_type, node_itinerary) + except: + msg = "Transit line %s : missing mode added to at least one link" % ( + record["Route_Name"]) + self._log.append({"type": "text", "content": msg}) + for link in itinerary: + link.modes |= set([mode]) + tline = network.create_transit_line( + record["Route_Name"].strip(), vehicle_type, node_itinerary) + + for field, attr in trrt_attrs: + tline[attr] = float(record[field]) + if is_tier1_rail: + line_details = mode_details[11] + else: + line_details = mode_details[int(record["Mode"])] + for field, attr in mode5tod_attrs: + tline[attr] = float(line_details[field]) + #"XFERPENTM": "Transfer penalty time: " + #"WTXFERTM": "Transfer perception:" + # NOTE: an additional transfer penalty perception factor of 5.0 is included + # in assignment + tline["@transfer_penalty"] = float(line_details["XFERPENTM"]) * float(line_details["WTXFERTM"]) + tline.headway = tline["@headway_am"] if tline["@headway_am"] > 0 else 999 + tline.layover_time = 5 + + transit_lines[int(record["Route_ID"])] = tline + for segment in tline.segments(): + segment.allow_boardings = False + segment.allow_alightings = False + segment.transit_time_func = 2 + # ft2 = ul2 -> copied @trtime_link_XX + # segments on links matched to auto network (with auto mode) are changed to ft1 = timau + except Exception as error: + msg = "Transit line %s: %s %s" % (record["Route_Name"], type(error), error) + self._log.append({"type": "text", "content": msg}) + trace_text = _traceback.format_exc().replace("\n", "
") + self._log.append({"type": "text", "content": trace_text}) + self._error.append("Transit route import: line %s not created" % record["Route_Name"]) + fatal_errors += 1 + for link in dummy_links: + network.delete_link(link.i_node, link.j_node) + + line_stops = _defaultdict(lambda: []) + for record in transit_stop_data: + try: + line_name = line_names[int(record["Route_ID"])] + line_stops[line_name].append(record) + except KeyError: + self._log.append( + {"type": "text", + "content": "Stop %s: could not find transit line by ID %s (link ID %s)" % ( + record["Stop_ID"], record["Route_ID"], record["Link_ID"])}) + + seg_float_attr_map = [] + seg_string_attr_map = [] + for field, (attr, t_type, e_type, desc) in attr_map["TRANSIT_SEGMENT"].iteritems(): + if t_type == "TRSTOP": + if e_type == "STRING": + seg_string_attr_map.append([field, attr]) + else: + seg_float_attr_map.append([field, attr]) + + for line_name, stops in line_stops.iteritems(): + tline = network.transit_line(line_name) + if not tline: + continue + itinerary = tline.segments(include_hidden=True) + segment = itinerary.next() + tcov_id = abs(segment.link["@tcov_id"]) + for stop in stops: + if "DUMMY" in stop["StopName"]: + continue + link_id = int(stop['Link_ID']) + node_id = int(stop['TrnNode']) + while tcov_id != link_id: + segment = itinerary.next() + if segment.link is None: + break + tcov_id = abs(segment.link["@tcov_id"]) + + if node_id == segment.i_node.number: + pass + elif node_id == segment.j_node.number: + segment = itinerary.next() # its the next segment + else: + msg = "Transit line %s: could not find stop on link ID %s at node ID %s" % (line_name, link_id, node_id) + self._log.append({"type": "text", "content": msg}) + self._error.append(msg) + fatal_errors += 1 + continue + segment.allow_boardings = True + segment.allow_alightings = True + segment.dwell_time = tline.default_dwell_time + for field, attr in seg_string_attr_map: + segment[attr] = stop[field] + for field, attr in seg_float_attr_map: + segment[attr] = float(stop[field]) + + def lookup_line(ident): + line = network.transit_line(ident) + if line: + return line.id + line = transit_lines.get(int(ident)) + if line: + return line.id + raise Exception("'%s' is not a route name or route ID" % ident) + + # Normalizing the case of the headers as different examples have been seen + for period in periods: + norm_data = [] + for record in timed_xfer_data[period]: + norm_record = {} + for key, val in record.iteritems(): + norm_record[key.lower()] = val + norm_data.append(norm_record) + + from_line, to_line, wait_time = [], [], [] + for i, record in enumerate(norm_data, start=2): + try: + from_line.append(lookup_line(record["from_line"])) + to_line.append(lookup_line(record["to_line"])) + wait_time.append(float(record["wait_time"])) + except Exception as error: + msg = "Error processing timexfer_%s.csv on file line %s: %s" % (period, i, error) + self._log.append({"type": "text", "content": msg}) + self._error.append(msg) + fatal_errors += 1 + + timed_xfer = _dt.Data() + timed_xfer.add_attribute(_dt.Attribute("from_line", _np.array(from_line).astype("O"))) + timed_xfer.add_attribute(_dt.Attribute("to_line", _np.array(to_line).astype("O"))) + timed_xfer.add_attribute(_dt.Attribute("wait_time", _np.array(wait_time))) + # Creates and saves the new table + gen_utils.DataTableProc("%s_timed_xfer_%s" % (self.data_table_name, period), data=timed_xfer) + + if fatal_errors > 0: + raise Exception("Cannot create transit network, %s fatal errors found" % fatal_errors) + self._log.append({"type": "text", "content": "Import transit lines complete"}) + + def calc_transit_attributes(self, network): + self._log.append({"type": "header", "content": "Calculate derived transit attributes"}) + # - TM by 5 TOD periods copied from TM for 3 time periods + # NOTE: the values of @trtime_link_## are only used for + # separate guideway. + # Links shared with the traffic network use the + # assignment results in timau + for link in network.links(): + for time in ["_ea", "_md", "_ev"]: + link["@trtime_link" + time] = link["trtime_link_op"] + if link.type == 0: # walk only links have IFC ==0 + link.type = 99 + + # ON TRANSIT LINES + # Set 3-period headway based on revised headway calculation + for line in network.transit_lines(): + for period in ["am", "pm", "op"]: + line["@headway_rev_" + period] = revised_headway(line["@headway_" + period]) + + for c in network.centroids(): + c["@tap_id"] = c.number + + # Special incremental boarding and in-vehicle fares + # to recreate the coaster zone fares + fares_file_name = FILE_NAMES["FARES"] + special_fare_path = _join(self.source, fares_file_name) + if os.path.isfile(special_fare_path): + with open(special_fare_path) as fare_file: + self._log.append({"type": "text", "content": "Using fare details (for coaster) from %s" % fares_file_name}) + special_fares = None + yaml_installed = True + try: + import yaml + special_fares = yaml.load(fare_file) + self._log.append({"type": "text", "content": yaml.dump(special_fares).replace("\n", "
")}) + except ImportError: + yaml_installed = False + except: + pass + if special_fares is None: + try: + import json + special_fares = json.load(fare_file) + self._log.append({"type": "text", "content": json.dumps(special_fares, indent=4).replace("\n", "
")}) + except: + pass + if special_fares is None: + msg = "YAML or JSON" if yaml_installed else "JSON (YAML parser not installed)" + raise Exception(fares_file_name + ": file could not be parsed as " + msg) + else: + # Default coaster fare for 2012 base year + special_fares = { + "boarding_cost": { + "base": [ + {"line": "398104", "cost" : 4.0}, + {"line": "398204", "cost" : 4.0} + ], + "stop_increment": [ + {"line": "398104", "stop": "SORRENTO VALLEY", "cost": 0.5}, + {"line": "398204", "stop": "SORRENTO VALLEY", "cost": 0.5} + ] + }, + "in_vehicle_cost": [ + {"line": "398104", "from": "SOLANA BEACH", "cost": 1.0}, + {"line": "398104", "from": "SORRENTO VALLEY", "cost": 0.5}, + {"line": "398204", "from": "OLD TOWN", "cost": 1.0}, + {"line": "398204", "from": "SORRENTO VALLEY", "cost": 0.5} + ], + "day_pass": 5.0, + "regional_pass": 12.0 + } + self._log.append({"type": "text", "content": "Using default coaster fare based on 2012 base year setup."}) + + def get_line(line_id): + line = network.transit_line(line_id) + if line is None: + raise Exception("%s: line does not exist: %s" % (fares_file_name, line_id)) + return line + + for record in special_fares["boarding_cost"]["base"]: + line = get_line(record["line"]) + line["@fare"] = 0 + for seg in line.segments(): + seg["@coaster_fare_board"] = record["cost"] + for record in special_fares["boarding_cost"].get("stop_increment", []): + line = get_line(record["line"]) + for seg in line.segments(True): + if record["stop"] in seg["#stop_name"]: + seg["@coaster_fare_board"] += record["cost"] + break + for record in special_fares["in_vehicle_cost"]: + line = get_line(record["line"]) + for seg in line.segments(True): + if record["from"] in seg["#stop_name"]: + seg["@coaster_fare_inveh"] = record["cost"] + break + pass_cost_keys = ['day_pass', 'regional_pass'] + pass_costs = [] + for key in pass_cost_keys: + cost = special_fares.get(key) + if cost is None: + raise Exception("key '%s' missing from %s" % (key, fares_file_name)) + pass_costs.append(cost) + pass_values = _dt.Data() + pass_values.add_attribute(_dt.Attribute("pass_type", _np.array(pass_cost_keys).astype("O"))) + pass_values.add_attribute(_dt.Attribute("cost", _np.array(pass_costs).astype("f8"))) + gen_utils.DataTableProc("%s_transit_passes" % self.data_table_name, data=pass_values) + self._log.append({"type": "text", "content": "Calculate derived transit attributes complete"}) + return + + def create_turns(self, network): + self._log.append({"type": "header", "content": "Import turns and turn restrictions"}) + self._log.append({"type": "text", "content": "Process LINKTYPETURNS.DBF for turn prohibited by type"}) + # Process LINKTYPETURNS.DBF for turn prohibited by type + with _fiona.open(_join(self.source, "LINKTYPETURNS.DBF"), 'r') as f: + link_type_turns = _defaultdict(lambda: {}) + for record in f: + record = record['properties'] + link_type_turns[record["FROM"]][record["TO"]] = { + "LEFT": record["LEFT"], + "RIGHT": record["RIGHT"], + "STRAIGHT": record["STRAIGHT"], + "UTURN": record["UTURN"] + } + for from_link in network.links(): + if from_link.type in link_type_turns: + to_link_turns = link_type_turns[from_link.type] + for to_link in from_link.j_node.outgoing_links(): + if to_link.type in to_link_turns: + record = to_link_turns[to_link.type] + if not from_link.j_node.is_intersection: + network.create_intersection(from_link.j_node) + turn = network.turn(from_link.i_node, from_link.j_node, to_link.j_node) + turn.penalty_func = 1 + if to_link["@tcov_id"] == from_link["left_link"]: + turn.data1 = record["LEFT"] + elif to_link["@tcov_id"] == from_link["through_link"]: + turn.data1 = record["STRAIGHT"] + elif to_link["@tcov_id"] == from_link["right_link"]: + turn.data1 = record["RIGHT"] + else: + turn.data1 = record["UTURN"] + + self._log.append({"type": "text", "content": "Process turns.csv for turn prohibited by ID"}) + turn_data = gen_utils.DataTableProc("turns", _join(self.source, "turns.csv")) + if self.save_data_tables: + turn_data.save("%s_turns" % self.data_table_name, self.overwrite) + links = dict((link["@tcov_id"], link) for link in network.links()) + + # Process turns.csv for prohibited turns from_id, to_id, penalty + for i, record in enumerate(turn_data): + from_link_id, to_link_id = int(record["from_id"]), int(record["to_id"]) + from_link, to_link = links[from_link_id], links[to_link_id] + if from_link.j_node == to_link.i_node: + pass + elif from_link.j_node == to_link.j_node: + to_link = to_link.reverse_link + elif from_link.i_node == to_link.i_node: + from_link = from_link.reverse_link + elif from_link.i_node == to_link.j_node: + from_link = from_link.reverse_link + to_link = to_link.reverse_link + else: + msg = "Record %s: links are not adjacent %s - %s." % (i, from_link_id, to_link_id) + self._log.append({"type": "text", "content": msg}) + self._error.append("Turn import: " + msg) + continue + if not from_link or not to_link: + msg = "Record %s: links adjacent but in reverse direction %s - %s." % (i, from_link_id, to_link_id) + self._log.append({"type": "text", "content": msg}) + self._error.append("Turn import: " + msg) + continue + + node = from_link.j_node + if not node.is_intersection: + network.create_intersection(node) + turn = network.turn(from_link.i_node, node, to_link.j_node) + if not record["penalty"]: + turn.penalty_func = 0 # prohibit turn + else: + turn.penalty_func = 1 + turn.data1 = float(record["penalty"]) + self._log.append({"type": "text", "content": "Import turns and turn restrictions complete"}) + + def calc_traffic_attributes(self, network): + self._log.append({"type": "header", "content": "Calculate derived traffic attributes"}) + # "COST": "@cost_operating" + # "ITOLL": "@toll_flag" # ITOLL - Toll + 100 *[0,1] if managed lane (I-15 tolls) + # Note: toll_flag is no longer used + # "ITOLL2": "@toll" # ITOLL2 - Toll + # "ITOLL3": "@cost_auto" # ITOLL3 - Toll + AOC + # "@cost_hov" + # "ITOLL4": "@cost_med_truck" # ITOLL4 - Toll * 1.03 + AOC + # "ITOLL5": "@cost_hvy_truck" # ITOLL5 - Toll * 2.33 + AOC + fatal_errors = 0 + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(_dir(self.source), "conf", "sandag_abm.properties")) + try: + aoc = float(props["aoc.fuel"]) + float(props["aoc.maintenance"]) + except ValueError: + raise Exception("Error during float conversion for aoc.fuel or aoc.maintenance from sandag_abm.properties file") + scenario_year = int(props["scenarioYear"]) + periods = ["EA", "AM", "MD", "PM", "EV"] + time_periods = ["_ea", "_am", "_md", "_pm", "_ev"] + src_time_periods = ["_op", "_am", "_op", "_pm", "_op"] + mode_d = network.mode('d') + + # Calculate upstream and downstream interchange distance + # First, label the intersection nodes as nodes with type 1 links (freeway) and + # type 8 links (freeway-to-freeway ramp) + network.create_attribute("NODE", "is_interchange") + interchange_points = [] + for node in network.nodes(): + adj_links = list(node.incoming_links()) + list(node.outgoing_links()) + has_freeway_links = bool( + [l for l in adj_links + if l.type == 1 and mode_d in l.modes]) + has_ramp_links = bool( + [l for l in adj_links + if l.type == 8 and mode_d in l.modes and not "HOV" in l["#name"]]) + if has_freeway_links and has_ramp_links: + node.is_interchange = True + interchange_points.append(node) + else: + node.is_interchange = False + for node in network.nodes(): + node["@interchange"] = node.is_interchange + + for link in network.links(): + if link.type == 1 and mode_d in link.modes: + link["@intdist_down"] = interchange_distance(link, "DOWNSTREAM") + link["@intdist_up"] = interchange_distance(link, "UPSTREAM") + self._log.append({"type": "text", "content": "Calculate of nearest interchange distance complete"}) + + # Static reliability parameters + # freeway coefficients + freeway_rel = { + "intercept": 0.1078, + "speed>70": 0.01393, + "upstream": 0.011, + "downstream": 0.0005445, + } + # arterial/ramp/other coefficients + road_rel = { + "intercept": 0.0546552, + "lanes": { + 1: 0.0, + 2: 0.0103589, + 3: 0.0361211, + 4: 0.0446958, + 5: 0.0 + }, + "speed": { + "<35": 0, + 35: 0.0075674, + 40: 0.0091012, + 45: 0.0080996, + 50: -0.0022938, + ">50": -0.0046211 + }, + "control": { + 0: 0, # Uncontrolled + 1: 0.0030973, # Signal + 2: -0.0063281, # Stop + 3: -0.0063281, # Stop + 4: 0.0127692, # Other, Railway, etc. + } + } + for link in network.links(): + # Change SR125 toll speed to 70MPH + if link["@lane_restriction"] == 4 and link.type == 1: + link["@speed_posted"] = 70 + + link["@cost_operating"] = link.length * aoc + + # Expand off-peak TOD attributes, copy peak period attributes + for time, src_time in zip(time_periods, src_time_periods): + link["@lane" + time] = link["lane" + src_time] + link["@time_link" + time] = link["time_link" + src_time] + + # add link delay (30 sec=0.5mins) to HOV connectors to discourage travel + if link.type == 8 and (link["@lane_restriction"] == 2 or link["@lane_restriction"] == 3): + link["@time_link" + time] = link["@time_link" + time] + 0.375 + + # make speed on HOV lanes (70mph) the same as parallel GP lanes (65mph) + # - set speed back to posted speed - increase travel time by (speed_adj/speed_posted) + if link.type == 1 and (link["@lane_restriction"] == 2 or link["@lane_restriction"] == 3): + speed_adj = link["@speed_adjusted"] + speed_posted = link["@speed_posted"] + if speed_adj>0: + link["@time_link" + time] = (speed_adj/(speed_posted*1.0)) * link["@time_link" + time] + + link["@time_inter" + time] = link["time_inter" + src_time] + link["@toll" + time] = link["toll" + src_time] + + off_peak_factor_file = FILE_NAMES["OFF_PEAK"] + if os.path.exists(_join(self.source, off_peak_factor_file)): + msg = "Adjusting off-peak tolls based on factors from %s" % off_peak_factor_file + self._log.append({"type": "text", "content": msg}) + tolled_links = list(link for link in network.links() if link["toll_op"] > 0) + # NOTE: CSV Reader sets the field names to UPPERCASE for consistency + with gen_utils.CSVReader(_join(self.source, off_peak_factor_file)) as r: + for row in r: + name = row["FACILITY_NAME"] + ea_factor = float(row["OP_EA_FACTOR"]) + md_factor = float(row["OP_MD_FACTOR"]) + ev_factor = float(row["OP_EV_FACTOR"]) + count = 0 + for link in tolled_links: + if name in link["#name"]: + count += 1 + link["@toll_ea"] = link["@toll_ea"] * ea_factor + link["@toll_md"] = link["@toll_md"] * md_factor + link["@toll_ev"] = link["@toll_ev"] * ev_factor + + msg = "Facility name '%s' matched to %s links." % (name, count) + msg += " Adjusted off-peak period tolls EA: %s, MD: %s, EV: %s" % (ea_factor, md_factor, ev_factor) + self._log.append({"type": "text2", "content": msg}) + + for link in network.links(): + factors = [(3.0/12.0), 1.0, (6.5/12.0), (3.5/3.0), (8.0/12.0)] + for f, time, src_time in zip(factors, time_periods, src_time_periods): + if link["capacity_link" + src_time] != 999999: + link["@capacity_link" + time] = f * link["capacity_link" + src_time] + else: + link["@capacity_link" + time] = 999999 + if link["capacity_inter" + src_time] != 999999: + link["@capacity_inter" + time] = f * link["capacity_inter" + src_time] + else: + link["@capacity_inter" + time] = 999999 + + # Required file + vehicle_class_factor_file = FILE_NAMES["VEHICLE_CLASS"] + facility_factors = _defaultdict(lambda: {}) + facility_factors["DEFAULT_FACTORS"] = { + "ALL": { + "auto": 1.0, + "hov2": 1.0, + "hov3": 1.0, + "lgt_truck": 1.0, + "med_truck": 1.03, + "hvy_truck": 2.03 + }, + "count": 0 + } + if os.path.exists(_join(self.source, vehicle_class_factor_file)): + msg = "Adjusting tolls based on factors from %s" % vehicle_class_factor_file + self._log.append({"type": "text", "content": msg}) + # NOTE: CSV Reader sets the field names to UPPERCASE for consistency + with gen_utils.CSVReader(_join(self.source, vehicle_class_factor_file)) as r: + for row in r: + if "YEAR" in r.fields and int(row["YEAR"]) != scenario_year: # optional year column + continue + name = row["FACILITY_NAME"] + # optional time-of-day entry, default to ALL if no column or blank + fac_time = row.get("TIME_OF_DAY") + if fac_time is None: + fac_time = "ALL" + facility_factors[name][fac_time] = { + "auto": float(row["DA_FACTOR"]), + "hov2": float(row["S2_FACTOR"]), + "hov3": float(row["S3_FACTOR"]), + "lgt_truck": float(row["TRK_L_FACTOR"]), + "med_truck": float(row["TRK_M_FACTOR"]), + "hvy_truck": float(row["TRK_H_FACTOR"]) + } + facility_factors[name]["count"] = 0 + + # validate ToD entry, either list EA, AM, MD, PM and EV, or ALL, but not both + for name, factors in facility_factors.iteritems(): + # default keys should be "ALL" and "count" + if "ALL" in factors: + if len(factors) > 2: + fatal_errors += 1 + msg = ("Individual time periods and 'ALL' (or blank) listed under " + "TIME_OF_DAY column in {} for facility {}").format(vehicle_class_factor_file, name) + self._log.append({"type": "text", "content": msg}) + self._error.append(msg) + elif set(periods + ["count"]) != set(factors.keys()): + fatal_errors += 1 + msg = ("Missing time periods {} under TIME_OF_DAY column in {} for facility {}").format( + (set(periods) - set(factors.keys())), vehicle_class_factor_file, name) + self._log.append({"type": "text", "content": msg}) + self._error.append(msg) + + def lookup_link_name(link): + for attr_name in ["#name", "#name_from", "#name_to"]: + for name, _factors in facility_factors.iteritems(): + if name in link[attr_name]: + return _factors + return facility_factors["DEFAULT_FACTORS"] + + def match_facility_factors(link): + factors = lookup_link_name(link) + factors["count"] += 1 + factors = _copy(factors) + del factors["count"] + # @lane_restriction = 2 or 3 overrides hov2 and hov3 costs + if link["@lane_restriction"] == 2: + for _, time_factors in factors.iteritems(): + time_factors["hov2"] = 0.0 + time_factors["hov3"] = 0.0 + elif link["@lane_restriction"] == 3: + for _, time_factors in factors.iteritems(): + time_factors["hov3"] = 0.0 + return factors + + vehicle_classes = ["auto", "hov2", "hov3", "lgt_truck", "med_truck", "hvy_truck"] + for link in network.links(): + if sum(link["@toll" + time] for time in time_periods) > 0: + factors = match_facility_factors(link) + for time, period in zip(time_periods, periods): + time_factors = factors.get(period, factors.get("ALL")) + for name in vehicle_classes: + link["@cost_" + name + time] = time_factors[name] * link["@toll" + time] + link["@cost_operating"] + else: + for time in time_periods: + for name in vehicle_classes: + link["@cost_" + name + time] = link["@cost_operating"] + for name, class_factors in facility_factors.iteritems(): + msg = "Facility name '%s' matched to %s links." % (name, class_factors["count"]) + self._log.append({"type": "text2", "content": msg}) + + self._log.append({"type": "text", "content": "Calculation and time period expansion of costs, tolls, capacities and times complete"}) + + # calculate static reliability + for link in network.links(): + for time in time_periods: + sta_reliability = "@sta_reliability" + time + # if freeway apply freeway parameters to this link + if link["type"] == 1 and link["@lane" + time] > 0: + high_speed_factor = freeway_rel["speed>70"] if link["@speed_posted"] >= 70 else 0.0 + upstream_factor = freeway_rel["upstream"] * 1 / link["@intdist_up"] + downstream_factor = freeway_rel["downstream"] * 1 / link["@intdist_down"] + link[sta_reliability] = ( + freeway_rel["intercept"] + high_speed_factor + upstream_factor + downstream_factor) + # arterial/ramp/other apply road parameters + elif link["type"] <= 9 and link["@lane" + time] > 0: + lane_factor = road_rel["lanes"].get(link["@lane" + time], 0.0) + speed_bin = link["@speed_posted"] + if speed_bin < 35: + speed_bin = "<35" + elif speed_bin > 50: + speed_bin = ">50" + speed_factor = road_rel["speed"][speed_bin] + control_bin = min(max(link["@traffic_control"], 0), 4) + control_factor = road_rel["control"][control_bin] + link[sta_reliability] = road_rel["intercept"] + lane_factor + speed_factor + control_factor + else: + link[sta_reliability] = 0.0 + self._log.append({"type": "text", "content": "Calculate of link static reliability factors complete"}) + + # Cycle length matrix + # Intersecting Link + # Approach Link 2 3 4 5 6 7 8 9 + # IFC Description + # 2 Prime Arterial 2.5 2 2 2 2 2 2 2 + # 3 Major Arterial 2 2 2 2 2 2 2 2 + # 4 Collector 2 2 1.5 1.5 1.5 1.5 1.5 1.5 + # 5 Local Collector 2 2 1.5 1.25 1.25 1.25 1.25 1.25 + # 6 Rural Collector 2 2 1.5 1.25 1.25 1.25 1.25 1.25 + # 7 Local Road 2 2 1.5 1.25 1.25 1.25 1.25 1.25 + # 8 Freeway connector 2 2 1.5 1.25 1.25 1.25 1.25 1.25 + # 9 Local Ramp 2 2 1.5 1.25 1.25 1.25 1.25 1.25 + + # Volume-delay functions + # fd10: freeway node approach + # fd11: non-intersection node approach + # fd20: cycle length 1.25 + # fd21: cycle length 1.5 + # fd22: cycle length 2.0 + # fd23: cycle length 2.5 + # fd24: cycle length 2.5 and metered ramp + # fd25: freeway node approach AM and PM only + network.create_attribute("LINK", "green_to_cycle") + network.create_attribute("LINK", "cycle") + vdf_cycle_map = {1.25: 20, 1.5: 21, 2.0: 22, 2.5: 23} + for node in network.nodes(): + incoming = list(node.incoming_links()) + outgoing = list(node.outgoing_links()) + is_signal = False + for link in incoming: + if link["@green_to_cycle_init"] > 0: + is_signal = True + break + if is_signal: + lcs = [link.type for link in incoming + outgoing] + min_lc = max(lcs) # Note: minimum class is actually the HIGHEST value, + max_lc = min(lcs) # and maximum is the LOWEST + + for link in incoming: + # Metered ramps + if link["@traffic_control"] in [4, 5]: + link["cycle"] = 2.5 + link["green_to_cycle"] = 0.42 + link.volume_delay_func = 24 + # Stops + elif link["@traffic_control"] in [2, 3]: + link["cycle"] = 1.25 + link["green_to_cycle"] = 0.42 + link.volume_delay_func = 20 + elif link["@green_to_cycle_init"] > 0 and is_signal: + if link.type == 2: + c_len = 2.5 if min_lc == 2 else 2.0 + elif link.type == 3: + c_len = 2.0 # Major arterial & anything + elif link.type == 4: + c_len = 1.5 if max_lc > 2 else 2.0 + elif link.type > 4: + if max_lc > 4: + c_len = 1.25 + elif max_lc == 4: + c_len = 1.5 + else: + c_len = 2.0 + if link["@green_to_cycle_init"] > 10: + link["green_to_cycle"] = link["@green_to_cycle_init"] / 100.0 + if link["green_to_cycle"] > 1.0: + link["green_to_cycle"] = 1.0 + link["cycle"] = c_len + link.volume_delay_func = vdf_cycle_map[c_len] + elif link.type == 1: + link.volume_delay_func = 10 # freeway + else: + link.volume_delay_func = 11 # non-controlled approach + self._log.append({"type": "text", "content": "Derive cycle, green_to_cycle, and VDF by approach node complete"}) + + for link in network.links(): + if link.volume_delay_func in [10, 11]: + continue + if link["@traffic_control"] in [4, 5]: + # Ramp meter controlled links are only enabled during the peak periods + for time in ["_am", "_pm"]: + link["@cycle" + time] = link["cycle"] + link["@green_to_cycle" + time] = link["green_to_cycle"] + else: + for time in time_periods: + link["@cycle" + time] = link["cycle"] + link["@green_to_cycle" + time] = link["green_to_cycle"] + self._log.append({"type": "text", "content": "Setting of time period @cycle and @green_to_cycle complete"}) + + network.delete_attribute("LINK", "green_to_cycle") + network.delete_attribute("LINK", "cycle") + network.delete_attribute("NODE", "is_interchange") + self._log.append({"type": "text", "content": "Calculate derived traffic attributes complete"}) + if fatal_errors > 0: + raise Exception("%s fatal errors during calculation of traffic attributes" % fatal_errors) + return + + def check_zone_access(self, network, mode): + # Verify that every centroid has at least one available + # access and egress connector + for centroid in network.centroids(): + access = egress = False + for link in centroid.outgoing_links(): + if mode in link.modes: + if link.j_node.is_intersection: + for turn in link.outgoing_turns(): + if turn.i_node != turn.k_node and turn.penalty_func != 0: + egress = True + else: + egress = True + if not egress: + raise Exception("No egress permitted from zone %s" % centroid.id) + for link in centroid.incoming_links(): + if mode in link.modes: + if link.j_node.is_intersection: + for turn in link.incoming_turns(): + if turn.i_node != turn.k_node and turn.penalty_func != 0: + access = True + else: + access = True + if not access: + raise Exception("No access permitted to zone %s" % centroid.id) + + def add_transit_to_traffic(self, hwy_network, tr_network): + if not self.merged_scenario_id or not hwy_network or not tr_network: + return + self._log.append({"type": "header", "content": "Merge transit network to traffic network"}) + fatal_errors = 0 + for tr_mode in tr_network.modes(): + hwy_mode = hwy_network.create_mode(tr_mode.type, tr_mode.id) + hwy_mode.description = tr_mode.description + hwy_mode.speed = tr_mode.speed + for tr_veh in tr_network.transit_vehicles(): + hwy_veh = hwy_network.create_transit_vehicle(tr_veh.id, tr_veh.mode.id) + hwy_veh.description = tr_veh.description + hwy_veh.auto_equivalent = tr_veh.auto_equivalent + hwy_veh.seated_capacity = tr_veh.seated_capacity + hwy_veh.total_capacity = tr_veh.total_capacity + + for elem_type in ["NODE", "LINK", "TRANSIT_LINE", "TRANSIT_SEGMENT"]: + for attr in tr_network.attributes(elem_type): + if not attr in hwy_network.attributes(elem_type): + default = "" if attr.startswith("#") else 0 + new_attr = hwy_network.create_attribute(elem_type, attr, default) + + hwy_link_index = dict((l["@tcov_id"], l) for l in hwy_network.links()) + hwy_node_position_index = dict(((n.x, n.y), n) for n in hwy_network.nodes()) + hwy_node_index = dict() + not_matched_links = [] + for tr_link in tr_network.links(): + tcov_id = tr_link["@tcov_id"] + if tcov_id == 0: + i_node = hwy_node_position_index.get((tr_link.i_node.x, tr_link.i_node.y)) + j_node = hwy_node_position_index.get((tr_link.j_node.x, tr_link.j_node.y)) + if i_node and j_node: + hwy_link = hwy_network.link(i_node, j_node) + else: + hwy_link = None + else: + hwy_link = hwy_link_index.get(tcov_id) + if not hwy_link: + not_matched_links.append(tr_link) + else: + hwy_node_index[tr_link.i_node] = hwy_link.i_node + hwy_node_index[tr_link.j_node] = hwy_link.j_node + hwy_link.modes |= tr_link.modes + + new_node_id = max(n.number for n in hwy_network.nodes()) + new_node_id = int(_ceiling(new_node_id / 10000.0) * 10000) + bus_mode = tr_network.mode("b") + + def lookup_node(src_node, new_node_id): + node = hwy_node_index.get(src_node) + if not node: + node = hwy_node_position_index.get((src_node.x, src_node.y)) + if not node: + node = hwy_network.create_regular_node(new_node_id) + new_node_id += 1 + for attr in tr_network.attributes("NODE"): + node[attr] = src_node[attr] + hwy_node_index[src_node] = node + return node, new_node_id + + for tr_link in not_matched_links: + i_node, new_node_id = lookup_node(tr_link.i_node, new_node_id) + j_node, new_node_id = lookup_node(tr_link.j_node, new_node_id) + # check for duplicate but different links + # All cases to be logged and then an error raised at end + ex_link = hwy_network.link(i_node, j_node) + if ex_link: + self._log.append({ + "type": "text", + "content": "Duplicate links between the same nodes with different IDs in traffic/transit merge. " + "Traffic link ID %s, transit link ID %s." % (ex_link["@tcov_id"], tr_link["@tcov_id"]) + }) + self._error.append("Duplicate links with different IDs between traffic (%s) and transit (%s) networks" % + (ex_link["@tcov_id"], tr_link["@tcov_id"])) + self._split_link(hwy_network, i_node, j_node, new_node_id) + new_node_id += 1 + fatal_errors += 1 + try: + link = hwy_network.create_link(i_node, j_node, tr_link.modes) + except Exception as error: + self._log.append({ + "type": "text", + "content": "Error creating link '%s', I-node '%s', J-node '%s'. Error message %s" % + (tr_link["@tcov_id"], i_node, j_node, error) + }) + self._error.append("Cannot create transit link '%s' in traffic network" % tr_link["@tcov_id"]) + fatal_errors += 1 + continue + hwy_link_index[tr_link["@tcov_id"]] = link + for attr in tr_network.attributes("LINK"): + link[attr] = tr_link[attr] + link.vertices = tr_link.vertices + + # Create transit lines and copy segment data + for tr_line in tr_network.transit_lines(): + itinerary = [] + for seg in tr_line.segments(True): + itinerary.append(hwy_node_index[seg.i_node]) + try: + hwy_line = hwy_network.create_transit_line(tr_line.id, tr_line.vehicle.id, itinerary) + except Exception as error: + msg = "Transit line %s, error message %s" % (tr_line.id, error) + self._log.append({"type": "text", "content": msg}) + self._error.append("Cannot create transit line '%s' in traffic network" % tr_line.id) + fatal_errors += 1 + continue + for attr in hwy_network.attributes("TRANSIT_LINE"): + hwy_line[attr] = tr_line[attr] + for tr_seg, hwy_seg in _izip(tr_line.segments(True), hwy_line.segments(True)): + for attr in hwy_network.attributes("TRANSIT_SEGMENT"): + hwy_seg[attr] = tr_seg[attr] + + # Change ttf from ft2 (fixed speed) to ft1 (congested auto time) + auto_mode = hwy_network.mode("d") + for hwy_link in hwy_network.links(): + if auto_mode in hwy_link.modes: + for seg in hwy_link.segments(): + seg.transit_time_func = 1 + if fatal_errors > 0: + raise Exception("Cannot merge traffic and transit network, %s fatal errors found" % fatal_errors) + + self._log.append({"type": "text", "content": "Merge transit network to traffic network complete"}) + + def _split_link(self, network, i_node, j_node, new_node_id): + # Attribute types to maintain consistency for correspondence with incoming / outgoing link data + periods = ["ea", "am", "md", "pm", "ev"] + approach_attrs = ["@traffic_control", "@turn_thru", "@turn_right", "@turn_left", + "@lane_auxiliary", "@green_to_cycle_init"] + for p_attr in ["@green_to_cycle_", "@time_inter_", "@cycle_"]: + approach_attrs.extend([p_attr + p for p in periods]) + capacity_inter = ["@capacity_inter_" + p for p in periods] + cost_attrs = ["@cost_operating"] + for p_attr in ["@cost_lgt_truck_", "@cost_med_truck_", "@cost_hvy_truck_", "@cost_hov2_", + "@cost_hov3_", "@cost_auto_", "@time_link_", "@trtime_link_", "@toll_"]: + cost_attrs.extend([p_attr + p for p in periods]) + approach_attrs = [a for a in approach_attrs if a in network.attributes("LINK")] + capacity_inter = [a for a in capacity_inter if a in network.attributes("LINK")] + cost_attrs = [a for a in cost_attrs if a in network.attributes("LINK")] + + new_node = network.split_link(i_node, j_node, new_node_id) + + # Correct attributes on the split links + for link in new_node.incoming_links(): + link["#name_to"] = "" + for attr in approach_attrs: + link[attr] = 0 + for attr in capacity_inter: + link[attr] = 999999 + for attr in cost_attrs: + link[attr] = 0.5 * link[attr] + link.volume_delay_func = 10 + for link in new_node.outgoing_links(): + link["#name_from"] = "" + for attr in cost_attrs: + link[attr] = 0.5 * link[attr] + + + @_m.logbook_trace("Set database functions (VDF, TPF and TTF)") + def set_functions(self, scenario): + create_function = _m.Modeller().tool( + "inro.emme.data.function.create_function") + set_extra_function_params = _m.Modeller().tool( + "inro.emme.traffic_assignment.set_extra_function_parameters") + emmebank = self.emmebank + for f_id in ["fd10", "fd11", "fd20", "fd21", "fd22", "fd23", "fd24", "fp1", "ft1", "ft2", "ft3", "ft4"]: + function = emmebank.function(f_id) + if function: + emmebank.delete_function(function) + + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(_dir(self.source), "conf", "sandag_abm.properties")) + smartSignalf_CL = props["smartSignal.factor.LC"] + smartSignalf_MA = props["smartSignal.factor.MA"] + smartSignalf_PA = props["smartSignal.factor.PA"] + atdmf = props["atdm.factor"] + + reliability_tmplt = ( + "* (1 + el2 + {0}*(".format(atdmf)+ + "( {factor[LOS_C]} * ( put(get(1).min.1.5) - {threshold[LOS_C]} + 0.01 ) ) * (get(1) .gt. {threshold[LOS_C]})" + "+ ( {factor[LOS_D]} * ( get(2) - {threshold[LOS_D]} + 0.01 ) ) * (get(1) .gt. {threshold[LOS_D]})" + "+ ( {factor[LOS_E]} * ( get(2) - {threshold[LOS_E]} + 0.01 ) ) * (get(1) .gt. {threshold[LOS_E]})" + "+ ( {factor[LOS_FL]} * ( get(2) - {threshold[LOS_FL]} + 0.01 ) ) * (get(1) .gt. {threshold[LOS_FL]})" + "+ ( {factor[LOS_FH]} * ( get(2) - {threshold[LOS_FH]} + 0.01 ) ) * (get(1) .gt. {threshold[LOS_FH]})" + "))") + parameters = { + "freeway": { + "factor": { + "LOS_C": 0.2429, "LOS_D": 0.1705, "LOS_E": -0.2278, "LOS_FL": -0.1983, "LOS_FH": 1.022 + }, + "threshold": { + "LOS_C": 0.7, "LOS_D": 0.8, "LOS_E": 0.9, "LOS_FL": 1.0, "LOS_FH": 1.2 + }, + }, + "road": { # for arterials, ramps, collectors, local roads, etc. + "factor": { + "LOS_C": 0.1561, "LOS_D": 0.0, "LOS_E": 0.0, "LOS_FL": -0.449, "LOS_FH": 0.0 + }, + "threshold": { + "LOS_C": 0.7, "LOS_D": 0.8, "LOS_E": 0.9, "LOS_FL": 1.0, "LOS_FH": 1.2 + }, + } + } + # freeway fd10 + create_function( + "fd10", + "(ul1 * (1.0 + 0.24 * put((volau + volad) / ul3) ** 5.5))" + + reliability_tmplt.format(**parameters["freeway"]), + emmebank=emmebank) + # non-freeway link which is not an intersection approach fd11 + create_function( + "fd11", + "(ul1 * (1.0 + 0.8 * put((volau + volad) / ul3) ** 4.0))" + + reliability_tmplt.format(**parameters["road"]), + emmebank=emmebank) + create_function( + "fd20", # Local collector and lower intersection and stop controlled approaches + "(ul1 * (1.0 + 0.8 * put((volau + volad) / ul3) ** 4.0) +" + "1.25 / 2 * (1-el1) ** 2 * (1.0 + 4.5 * ( (volau + volad) / el3 ) ** 2.0))" + + reliability_tmplt.format(**parameters["road"]), + emmebank=emmebank) + create_function( + "fd21", # Collector intersection approaches + "(ul1 * (1.0 + 0.8 * put((volau + volad) / ul3) ** 4.0) +" + "{0} * 1.5/ 2 * (1-el1) ** 2 * (1.0 + 4.5 * ( (volau + volad) / el3 ) ** 2.0))".format(smartSignalf_CL) + + reliability_tmplt.format(**parameters["road"]), + emmebank=emmebank) + create_function( + "fd22", # Major arterial and major or prime arterial intersection approaches + "(ul1 * (1.0 + 0.8 * put((volau + volad) / ul3) ** 4.0) +" + "{0} * 2.0 / 2 * (1-el1) ** 2 * (1.0 + 4.5 * ( (volau + volad) / el3 ) ** 2.0))".format(smartSignalf_MA) + + reliability_tmplt.format(**parameters["road"]), + emmebank=emmebank) + create_function( + "fd23", # Primary arterial intersection approaches + "(ul1 * (1.0 + 0.8 * put((volau + volad) / ul3) ** 4.0) +" + "{0} * 2.5/ 2 * (1-el1) ** 2 * (1.0 + 4.5 * ( (volau + volad) / el3 ) ** 2.0))".format(smartSignalf_PA) + + reliability_tmplt.format(**parameters["road"]), + emmebank=emmebank) + create_function( + "fd24", # Metered ramps + "(ul1 * (1.0 + 0.8 * put((volau + volad) / ul3) ** 4.0) +" + "2.5/ 2 * (1-el1) ** 2 * (1.0 + 6.0 * ( (volau + volad) / el3 ) ** 2.0))" + + reliability_tmplt.format(**parameters["road"]), + emmebank=emmebank) + # freeway fd25 (AM and PM only) + create_function( + "fd25", + "(ul1 * (1.0 + 0.6 * put((volau + volad) / ul3) ** 4))" + + reliability_tmplt.format(**parameters["freeway"]), + emmebank=emmebank) + + set_extra_function_params( + el1="@green_to_cycle", el2="@sta_reliability", el3="@capacity_inter_am", + emmebank=emmebank) + + create_function("fp1", "up1", emmebank=emmebank) # fixed cost turns stored in turn data 1 (up1) + + # buses in mixed traffic, use auto time + create_function("ft1", "timau", emmebank=emmebank) + # fixed speed for separate guideway operations + create_function("ft2", "ul2", emmebank=emmebank) + # special 0-cost segments for prohibition of walk to different stop from centroid + create_function("ft3", "0", emmebank=emmebank) + # fixed guideway systems according to vehicle speed (not used at the moment) + create_function("ft4", "60 * length / speed", emmebank=emmebank) + + @_m.logbook_trace("Traffic zone connectivity check") + def check_connectivity(self, scenario): + modeller = _m.Modeller() + sola_assign = modeller.tool( + "inro.emme.traffic_assignment.sola_traffic_assignment") + set_extra_function_para = modeller.tool( + "inro.emme.traffic_assignment.set_extra_function_parameters") + create_matrix = _m.Modeller().tool( + "inro.emme.data.matrix.create_matrix") + net_calc = gen_utils.NetworkCalculator(scenario) + + emmebank = scenario.emmebank + zone_index = dict(enumerate(scenario.zone_numbers)) + num_processors = dem_utils.parse_num_processors("MAX-1") + + # Note matrix is also created in initialize_matrices + create_matrix("ms1", "zero", "zero", scenario=scenario, overwrite=True) + with gen_utils.temp_matrices(emmebank, "FULL", 1) as (result_matrix,): + result_matrix.name = "TEMP_SOV_TRAVEL_TIME" + set_extra_function_para( + el1="@green_to_cycle_am", + el2="@sta_reliability_am", + el3="@capacity_inter_am", emmebank=emmebank) + net_calc("ul1", "@time_link_am", "modes=d") + net_calc("ul3", "@capacity_link_am", "modes=d") + net_calc("lanes", "@lane_am", "modes=d") + spec = { + "type": "SOLA_TRAFFIC_ASSIGNMENT", + "background_traffic": None, + "classes": [ + { + "mode": "S", # SOV toll mode + "demand": 'ms"zero"', + "generalized_cost": None, + "results": { + "od_travel_times": {"shortest_paths": result_matrix.named_id} + } + } + ], + "stopping_criteria": { + "max_iterations": 0, "best_relative_gap": 0.0, + "relative_gap": 0.0, "normalized_gap": 0.0 + }, + "performance_settings": {"number_of_processors": num_processors}, + } + sola_assign(spec, scenario=scenario) + travel_time = result_matrix.get_numpy_data(scenario) + + is_disconnected = (travel_time == 1e20) + disconnected_pairs = is_disconnected.sum() + if disconnected_pairs > 0: + error_msg = "Connectivity error(s) between %s O-D pairs" % disconnected_pairs + self._log.append({"type": "header", "content": error_msg}) + count_disconnects = [] + for axis, term in [(0, "from"), (1, "to")]: + axis_totals = is_disconnected.sum(axis=axis) + for i, v in enumerate(axis_totals): + if v > 0: + count_disconnects.append((zone_index[i], term, v)) + count_disconnects.sort(key=lambda x: x[2], reverse=True) + for z, direction, count in count_disconnects[:50]: + msg ="Zone %s disconnected %s %d other zones" % (z, direction, count) + self._log.append({"type": "text", "content": msg}) + if disconnected_pairs > 50: + self._log.append({"type": "text", "content": "[List truncated]"}) + raise Exception(error_msg) + self._log.append({"type": "header", "content": + "Zone connectivity verified for AM period on SOV toll ('S') mode"}) + scenario.has_traffic_results = False + + def log_report(self): + report = _m.PageBuilder(title="Import network from TCOVED files report") + try: + if self._error: + report.add_html("
Errors detected during import: %s
" % len(self._error)) + error_msg = ["") + report.add_html("".join(error_msg)) + else: + report.add_html("No errors detected during import") + + for item in self._log: + if item["type"] == "text": + report.add_html("
%s
" % item["content"]) + if item["type"] == "text2": + report.add_html("
%s
" % item["content"]) + elif item["type"] == "header": + report.add_html("

%s

" % item["content"]) + elif item["type"] == "table": + table_msg = ["
", "

%s

" % item["title"]] + if "header" in item: + table_msg.append("") + for label in item["header"]: + table_msg.append("" % label) + table_msg.append("") + for row in item["content"]: + table_msg.append("") + for cell in row: + table_msg.append("" % cell) + table_msg.append("") + table_msg.append("
%s
%s
") + report.add_html("".join(table_msg)) + + except Exception as error: + # no raise during report to avoid masking real error + report.add_html("Error generating report") + report.add_html(unicode(error)) + report.add_html(_traceback.format_exc()) + + _m.logbook_write("Import network report", report.render()) + + +def get_node(network, number, coordinates, is_centroid): + node = network.node(number) + if not node: + node = network.create_node(number, is_centroid) + node.x, node.y = coordinates + return node + + +# shortest path interpolation +def find_path(orig_link, dest_link, mode): + visited = set([]) + visited_add = visited.add + back_links = {} + heap = [] + + for link in orig_link.j_node.outgoing_links(): + if mode in link.modes: + back_links[link] = None + _heapq.heappush(heap, (link["length"], link)) + + link_found = False + try: + while not link_found: + link_cost, link = _heapq.heappop(heap) + if link in visited: + continue + visited_add(link) + for outgoing in link.j_node.outgoing_links(): + if mode not in outgoing.modes: + continue + if outgoing in visited: + continue + back_links[outgoing] = link + if outgoing == dest_link: + link_found = True + break + outgoing_cost = link_cost + link["length"] + _heapq.heappush(heap, (outgoing_cost, outgoing)) + except IndexError: + pass # IndexError if heap is empty + if not link_found: + raise NoPathException( + "no path found between links with trcov_id %s and %s (Emme IDs %s and %s)" % ( + orig_link["@tcov_id"], dest_link["@tcov_id"], orig_link, dest_link)) + + prev_link = back_links[dest_link] + route = [] + while prev_link: + route.append(prev_link) + prev_link = back_links[prev_link] + return list(reversed(route)) + + +class NoPathException(Exception): + pass + + +def revised_headway(headway): + # CALCULATE REVISED HEADWAY + # new headway calculation is less aggressive; also only being used for initial wait + # It uses a negative exponential formula to calculate headway + # + if headway <= 10: + rev_headway = headway + else: + rev_headway = headway * (0.275 + 0.788 * _np.exp(-0.011*headway)) + return rev_headway + + +def interchange_distance(orig_link, direction): + visited = set([]) + visited_add = visited.add + back_links = {} + heap = [] + if direction == "DOWNSTREAM": + get_links = lambda l: l.j_node.outgoing_links() + check_far_node = lambda l: l.j_node.is_interchange + elif direction == "UPSTREAM": + get_links = lambda l: l.i_node.incoming_links() + check_far_node = lambda l: l.i_node.is_interchange + # Shortest path search for nearest interchange node along freeway + for link in get_links(orig_link): + _heapq.heappush(heap, (link["length"], link)) + interchange_found = False + try: + while not interchange_found: + link_cost, link = _heapq.heappop(heap) + if link in visited: + continue + visited_add(link) + if check_far_node(link): + interchange_found = True + break + for next_link in get_links(link): + if next_link in visited: + continue + next_cost = link_cost + link["length"] + _heapq.heappush(heap, (next_cost, next_link)) + except IndexError: + # IndexError if heap is empty + # case where start / end of highway, dist = 99 + return 99 + return orig_link["length"] / 2.0 + link_cost diff --git a/sandag_abm/src/main/emme/toolbox/import/import_seed_demand.py b/sandag_abm/src/main/emme/toolbox/import/import_seed_demand.py new file mode 100644 index 0000000..2b87f35 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/import/import_seed_demand.py @@ -0,0 +1,193 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/import_seed_demand.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Imports the warm start demand matrices from specified OMX files for auto, truck and transit. +# +# Note the matrix name mapping from the OMX file names to the Emme database names. +# +# Inputs: +# omx_file: source +# demand_type: The type of demand in the provided OMX file, one of "AUTO", "TRUCK", "TRANSIT". +# Used to determine the matrix mapping for the import. +# period: The period for which to import the matrices, one of "EA", "AM", "MD", "PM", "EV" +# scenario: traffic scenario to use for reference zone system +# convert_truck_to_pce: boolean, if True the result matrices are adjusted to PCEs instead of +# vehicles (default, and required for traffic assignment). Only used if the demand_type is TRUCK. +# +# Matrix results: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# For AUTO: +# pp_SOVNTP, pp_SOVTB, pp_HOV2, pp_HOV3 +# For TRUCK: +# pp_TRKH, pp_TRKL, pp_TRKM +# For TRANSIT: +# pp_WLKBUS, pp_WLKLRT, pp_WLKCMR, pp_WLKEXP, pp_WLKBRT, +# pp_PNRBUS, pp_PNRLRT, pp_PNRCMR, pp_PNREXP, pp_PNRBRT, +# pp_KNRBUS, pp_KNRLRT, pp_KNRCMR, pp_KNREXP, pp_KNRBRT +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + period = "AM" + input_omx_file = os.path.join(main_directory, "input", "trip_%s.omx" % period) + demand_type = "TRUCK" + demand_as_pce = True + base_scenario = modeller.scenario + import_seed_demand = modeller.tool("sandag.import.import_seed_demand") + import_seed_demand(input_omx_file, demand_type, period, demand_as_pce, base_scenario) +""" + + +TOOLBOX_ORDER = 12 + + +import inro.modeller as _m +import inro.emme.matrix as _matrix +import traceback as _traceback + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +_omx = _m.Modeller().module("sandag.utilities.omxwrapper") + + +class ImportMatrices(_m.Tool(), gen_utils.Snapshot): + + omx_file = _m.Attribute(unicode) + demand_type = _m.Attribute(str) + period = _m.Attribute(str) + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self.attributes = ["omx_file", "demand_type", "period"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Import demand matrices" + pb.description = """Imports the seed demand matrices.""" + pb.branding_text = "- SANDAG - Import" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('omx_file', 'file', + title='Select input OMX file') + options = [(x, x) for x in ["AUTO", "TRUCK", "TRANSIT"]] + pb.add_select("demand_type", keyvalues=options, title="Select corresponding demand type") + options = [(x, x) for x in ["EA", "AM", "MD", "PM", "EV"]] + pb.add_select("period", keyvalues=options, title="Select corresponding period") + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.omx_file, self.demand_type, self.period, scenario) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, omx_file, demand_type, period, scenario): + attributes = { + "omx_file": omx_file, + "demand_type": demand_type, + "period": period, + "scenario": scenario.id, + "self": str(self) + } + with _m.logbook_trace("Import %s matrices for period %s" % (demand_type, period), attributes=attributes): + gen_utils.log_snapshot("Import matrices", str(self), attributes) + demand_types = ["AUTO", "TRUCK", "TRANSIT"] + if demand_type not in demand_types: + raise Exception("Invalid demand_type, must be one of %s" % demand_types) + periods = ["EA", "AM", "MD", "PM", "EV"] + if period not in periods: + raise Exception("Invalid period, must be one of %s" % periods) + + if demand_type == "AUTO": + # TODO: update for new seed matrices + matrices = { + '%s_SOV_NT_L': 'mf"%s_SOV_NT_L"', + '%s_SOV_TR_L': 'mf"%s_SOV_TR_L"', + '%s_HOV2_L': 'mf"%s_HOV2_L"', + '%s_HOV3_L': 'mf"%s_HOV3_L"', + '%s_SOV_NT_M': 'mf"%s_SOV_NT_M"', + '%s_SOV_TR_M': 'mf"%s_SOV_TR_M"', + '%s_HOV2_M': 'mf"%s_HOV2_M"', + '%s_HOV3_M': 'mf"%s_HOV3_M"', + '%s_SOV_NT_H': 'mf"%s_SOV_NT_H"', + '%s_SOV_TR_H': 'mf"%s_SOV_TR_H"', + '%s_HOV2_H': 'mf"%s_HOV2_H"', + '%s_HOV3_H': 'mf"%s_HOV3_H"'} + matrices = dict((k % period, v % period) for k, v in matrices.iteritems()) + self._import_from_omx(omx_file, matrices, scenario) + + if demand_type == "TRUCK": + # TODO: update for new seed matrices + matrices = { + '%s_TRK_H': 'mf"%s_TRK_H"', + '%s_TRK_L': 'mf"%s_TRK_L"', + '%s_TRK_M': 'mf"%s_TRK_M"'} + matrices = dict((k % period, v % period) for k, v in matrices.iteritems()) + self._import_from_omx(omx_file, matrices, scenario) + + if demand_type == "TRANSIT": + matrices = { + 'SET1': 'mf"%s_WLKBUS"', + 'SET2': 'mf"%s_WLKPREM"', + 'SET3': 'mf"%s_WLKALLPEN"',} + matrices = dict((k, v % period) for k, v in matrices.iteritems()) + # special custom mapping from subset of TAPs to all TAPs + self._import_from_omx(omx_file, matrices, scenario) + + def _import_from_omx(self, file_path, matrices, scenario): + matrices_to_write = {} + emme_zones = scenario.zone_numbers + emmebank = scenario.emmebank + omx_file_obj = _omx.open_file(file_path, 'r') + try: + zone_mapping = omx_file_obj.mapping(omx_file_obj.list_mappings()[0]).items() + zone_mapping.sort(key=lambda x: x[1]) + omx_zones = [x[0] for x in zone_mapping] + for omx_name, emme_name in matrices.iteritems(): + omx_data = omx_file_obj[omx_name].read() + if emme_name not in matrices_to_write: + matrices_to_write[emme_name] = omx_data + else: + # Allow multiple src matrices from OMX to sum to same matrix in Emme + matrices_to_write[emme_name] = omx_data + matrices_to_write[emme_name] + except Exception as error: + import traceback + print (traceback.format_exc()) + omx_file_obj.close() + + if omx_zones != emme_zones: + # special custom mapping from subset of TAPs to all TAPs + for emme_name, omx_data in matrices_to_write.iteritems(): + matrix_data = _matrix.MatrixData(type='f', indices=[omx_zones, omx_zones]) + matrix_data.from_numpy(omx_data) + expanded_matrix_data = matrix_data.expand([emme_zones, emme_zones]) + matrix = emmebank.matrix(emme_name) + matrix.set_data(expanded_matrix_data, scenario) + else: + for emme_name, omx_data in matrices_to_write.iteritems(): + matrix = emmebank.matrix(emme_name) + matrix.set_numpy_data(omx_data, scenario) diff --git a/sandag_abm/src/main/emme/toolbox/import/import_transit_demand.py b/sandag_abm/src/main/emme/toolbox/import/import_transit_demand.py new file mode 100644 index 0000000..827baff --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/import/import_transit_demand.py @@ -0,0 +1,230 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/import_transit_demand.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Imports the transit demand generated from an iteration of the disaggregate +# demand models (CT-RAMP) in preparation for the transit assignment +# +# Note the matrix name mapping from the OMX file names to the Emme database names. +# +# Inputs: +# output_dir: output directory to read the OMX files from +# scenario: transit scenario to use for reference zone system +# +# Files referenced: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# output/tranTrips_pp.omx +# output/tranCrossBorderTrips_pp.omx +# output/tranAirportTrips.SAN_pp.omx +# output/tranAirportTrips.CBX_pp.omx (optional) +# output/tranVisitorTrips_pp.omx +# output/tranInternalExternalTrips_pp.omx +# +# Matrix results: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# pp_WLKBUS, pp_WLKLRT, pp_WLKCMR, pp_WLKEXP, pp_WLKBRT, +# pp_PNRBUS, pp_PNRLRT, pp_PNRCMR, pp_PNREXP, pp_PNRBRT, +# pp_KNRBUS, pp_KNRLRT, pp_KNRCMR, pp_KNREXP, pp_KNRBRT +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + output_dir = os.path.join(main_directory, "output") + scenario = modeller.scenario + import_transit_demand = modeller.tool("sandag.import.import_transit_demand") + import_transit_demand(output_dir, scenario) +""" + + +TOOLBOX_ORDER = 14 + + +import inro.modeller as _m +import inro.emme.matrix as _matrix +import traceback as _traceback +import os + + +dem_utils = _m.Modeller().module('sandag.utilities.demand') +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class ImportMatrices(_m.Tool(), gen_utils.Snapshot): + + output_dir = _m.Attribute(unicode) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + main_dir = os.path.dirname(project_dir) + self.output_dir = os.path.join(main_dir, "output") + self.attributes = ["output_dir"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Import transit demand" + pb.description = """ +
+ Imports the trip matrices generated by CT-RAMP in OMX format.
+ A total of 30 OMX files are expected, for 5 time periods + EA, AM, MD, PM and EV, with internal matrices by 3 model segments + (assignment access sets) and 3 access modes (walk, PNR, KNR): + +
+ """ + pb.branding_text = "- SANDAG - Model" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + pb.add_select_file('output_dir', 'directory', + title='Select output directory') + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.output_dir, scenario) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Create TOD transit trip tables", save_arguments=True) + def __call__(self, output_dir, scenario): + attributes = {"output_dir": output_dir} + gen_utils.log_snapshot("Sum demand", str(self), attributes) + + self.scenario = scenario + self.output_dir = output_dir + self.import_transit_trips() + + @_m.logbook_trace("Import CT-RAMP transit trips from OMX") + def import_transit_trips(self): + emmebank = self.scenario.emmebank + emme_zones = self.scenario.zone_numbers + matrix_name_tmplts = [ + ("mf%s_%sBUS", "%s_%s_set1_%s"), + ("mf%s_%sPREM", "%s_%s_set2_%s"), + ("mf%s_%sALLPEN", "%s_%s_set3_%s") + ] + periods = ["EA", "AM", "MD", "PM", "EV"] + access_modes = ["WLK", "PNR", "KNR"] + matrix_names = [] + for period in periods: + for acc_mode in access_modes: + #for trip_set in trip_sets: + for emme_name, omx_name in matrix_name_tmplts: + matrix_names.append( + ("_" + period, emme_name % (period, acc_mode), omx_name % (acc_mode, "%s", period))) + + with gen_utils.OMXManager(self.output_dir, "tran%sTrips%s.omx") as omx_manager: + for period, matrix_name, omx_key in matrix_names: + logbook_label = "Report on import from OMX key %s to matrix %s" % (omx_key % "SET", matrix_name) + + #add both KNR_SET and TNC_SET into KNR + if ("KNR" in matrix_name): + #resident + person_knr_demand = omx_manager.lookup(("", period), omx_key % "SET") + person_tnc_Demand = omx_manager.lookup(("", period), omx_key.replace("KNR","TNC") % "SET") + person_demand = person_knr_demand + person_tnc_Demand + #visitor + visitor_knr_demand = omx_manager.lookup(("Visitor", period), omx_key % "SET") + visitor_tnc_Demand = omx_manager.lookup(("Visitor", period), omx_key.replace("KNR","TNC") % "SET") + visitor_demand = visitor_knr_demand + visitor_tnc_Demand + #cross border + cross_border_knr_demand = omx_manager.lookup(("CrossBorder", period), omx_key % "SET") + cross_border_tnc_Demand = omx_manager.lookup(("CrossBorder", period), omx_key.replace("KNR","TNC") % "SET") + cross_border_demand = cross_border_knr_demand + cross_border_tnc_Demand + #airport SAN + airport_knr_demand = omx_manager.lookup(("Airport", ".SAN" + period), omx_key % "SET") + airport_tnc_Demand = omx_manager.lookup(("Airport", ".SAN" + period), omx_key.replace("KNR","TNC") % "SET") + #airport CBX + if omx_manager.file_exists(("Airport", ".CBX" + period)): + airport_knr_demand += omx_manager.lookup(("Airport", ".CBX" + period), omx_key % "SET") + airport_tnc_Demand += omx_manager.lookup(("Airport", ".CBX" + period), omx_key.replace("KNR","TNC") % "SET") + airport_demand = airport_knr_demand + airport_tnc_Demand + #internal external + internal_external_knr_demand = omx_manager.lookup(("InternalExternal", period), omx_key % "SET") + internal_external_tnc_Demand = omx_manager.lookup(("InternalExternal", period), omx_key.replace("KNR","TNC") % "SET") + internal_external_demand = internal_external_knr_demand + internal_external_tnc_Demand + else: + person_demand = omx_manager.lookup(("", period), omx_key % "SET") + visitor_demand = omx_manager.lookup(("Visitor", period), omx_key % "SET") + cross_border_demand = omx_manager.lookup(("CrossBorder", period), omx_key % "SET" ) + airport_demand = omx_manager.lookup(("Airport", ".SAN" + period), omx_key % "SET") + if omx_manager.file_exists(("Airport", ".CBX" + period)): + airport_demand += omx_manager.lookup(("Airport", ".CBX" + period), omx_key % "SET") + + internal_external_demand = omx_manager.lookup(("InternalExternal", period), omx_key % "SET") + + total_ct_ramp_trips = person_demand #for testing only + total_ct_ramp_trips = ( + visitor_demand + cross_border_demand + airport_demand + + person_demand + internal_external_demand) + + # Check the OMX zones are the same Emme database, assume all files have the same zones + omx_zones = omx_manager.zone_list("tranTrips%s.omx" % period) + matrix = emmebank.matrix(matrix_name) + if omx_zones != emme_zones: + matrix_data = _matrix.MatrixData(type='f', indices=[omx_zones, omx_zones]) + matrix_data.from_numpy(total_ct_ramp_trips) + expanded_matrix_data = matrix_data.expand([emme_zones, emme_zones]) + matrix.set_data(expanded_matrix_data, self.scenario) + else: + matrix.set_numpy_data(total_ct_ramp_trips, self.scenario) + + if ("KNR" in matrix_name): + dem_utils.demand_report([ + ("person_demand", person_demand), + (" person_knr_demand", person_knr_demand), + (" person_tnc_Demand", person_tnc_Demand), + ("internal_external_demand", internal_external_demand), + (" internal_external_knr_demand", internal_external_knr_demand), + (" internal_external_tnc_Demand", internal_external_tnc_Demand), + ("cross_border_demand", cross_border_demand), + (" cross_border_knr_demand", cross_border_knr_demand), + (" cross_border_tnc_Demand", cross_border_tnc_Demand), + ("airport_demand", airport_demand), + (" airport_knr_demand", airport_knr_demand), + (" airport_tnc_Demand", airport_tnc_Demand), + ("visitor_demand", visitor_demand), + (" visitor_knr_demand", visitor_knr_demand), + (" visitor_tnc_Demand", visitor_tnc_Demand), + ("total_ct_ramp_trips", total_ct_ramp_trips) + ], logbook_label, self.scenario) + else: + dem_utils.demand_report([ + ("person_demand", person_demand), + ("internal_external_demand", internal_external_demand), + ("cross_border_demand", cross_border_demand), + ("airport_demand", airport_demand), + ("visitor_demand", visitor_demand), + ("total_ct_ramp_trips", total_ct_ramp_trips) + ], logbook_label, self.scenario) diff --git a/sandag_abm/src/main/emme/toolbox/import/input_checker.py b/sandag_abm/src/main/emme/toolbox/import/input_checker.py new file mode 100644 index 0000000..eedffcb --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/import/input_checker.py @@ -0,0 +1,767 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright RSG, 2019-2020. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/input_checker.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Reviews all inputs to SANDAG ABM for possible issues that will result in model errors +# +# Files referenced: +# input_checker\config\inputs_checks.csv +# input_checker\config\inputs_list.csv + +import os, shutil, sys, time, csv, logging +import win32com.client as com +import numpy as np +import pandas as pd +import traceback as _traceback +import datetime +import warnings +from simpledbf import Dbf5 +import inro.modeller as _m +import inro.emme.database.emmebank as _eb +import inro.director.util.qtdialog as dialog +import textwrap + +warnings.filterwarnings("ignore") + +_join = os.path.join +_dir = os.path.dirname + +class input_checker(_m.Tool()): + + path = _m.Attribute(unicode) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = _dir(_m.Modeller().desktop.project.path) + self.path = _dir(project_dir) + self.input_checker_path = '' + self.inputs_list_path = '' + self.inputs_checks_path = '' + self.log_path = '' + self.logical_log_path = '' + self.prop_input_paths = {} + self.inputs_list = pd.DataFrame() + self.inputs_checks = pd.DataFrame() + self.inputs = {} + self.results = {} + self.result_list = {} + self.problem_ids = {} + self.report_stat = {} + self.num_fatal = int() + self.num_warning = int() + self.num_logical = int() + self.logical_fails = pd.DataFrame() + self.scenario_df = pd.DataFrame() + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Input Checker" + pb.description = """ + Reviews all inputs to SANDAG ABM for possible issues that could result + in model errors. List of inputs and checks are read from two CSV files: +
+
+ +
+ The input checker goes through the list of checks and evaluates each + one as True or False. A summary file is produced at the end with results + for each check. The input checker additionally outputs a report for + failed checks of severity type Logical with more than 25 failed records. + The additional summary report lists every failed record. + The following reports are output: +
+
+ +
+ """ + pb.branding_text = "SANDAG - Input Checker" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self(path = self.path) + run_msg = "Input Checker Complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, path = ""): + _m.logbook_write("Started running input checker...") + + self.path = path + + self.input_checker_path = _join(self.path, 'input_checker') + self.inputs_list_path = _join(self.input_checker_path, 'config', 'inputs_list.csv') + self.inputs_checks_path = _join(self.input_checker_path, 'config', 'inputs_checks.csv') + + file_paths = [self.inputs_list_path, self.inputs_checks_path] + for path in file_paths: + if not os.path.exists(path): + raise Exception("missing file '%s'" % (path)) + + _m.logbook_write("Reading inputs...") + self.read_inputs() + + _m.logbook_write("Conducting checks...") + self.checks() + + _m.logbook_write("Writing logical fail logs...") + self.write_logical_log() + + _m.logbook_write("Writing logs...") + self.write_log() + + _m.logbook_write("Checking for logical errors...") + self.check_logical() + + _m.logbook_write("Checking for fatal errors...") + self.check_num_fatal() + + _m.logbook_write("Finisehd running input checker") + + def read_inputs(self): + # read list of inputs from CSV file + self.inputs_list = pd.read_csv(self.inputs_list_path) + + # remove all commented inputs from the inputs list + self.inputs_list = self.inputs_list.loc[[not i for i in (self.inputs_list['Input_Table'].str.startswith('#'))]] + + # obtain file paths from the sandag_abm.properties + self.prop_file_paths() + + # load emmebank + eb_path = _join(self.path, "emme_project", "Database", "emmebank") + eb = _eb.Emmebank(eb_path) + + # load emme network + network = eb.scenario(100).get_network() + + # create extra network attributes (maybe temporary) + + # link modes_str attribute + network.create_attribute("LINK", "mode_str") + for link in network.links(): + link.mode_str = "".join([m.id for m in link.modes]) + + # link isTransit flag attribute + network.create_attribute("LINK", "isTransit") + transit_modes = set([m for m in network.modes() if m.type == "TRANSIT"]) + for link in network.links(): + link.isTransit = bool(link.modes.intersection(transit_modes)) + + # transit segment isFirst and isLast flags attributes + network.create_attribute("TRANSIT_SEGMENT", "isFirst", False) + network.create_attribute("TRANSIT_SEGMENT", "isLast", False) + for line in network.transit_lines(): + first_seg = line.segment(0) + last_seg = line.segment(-2) + first_seg.isFirst = True + last_seg.isLast = True + + # node isCentroid flag attribute + network.create_attribute("NODE", "isCentroid", False) + centroids = [c for c in network.nodes() if c.is_centroid] + for node in network.nodes(): + node.isCentroid = bool(node in centroids) + + # node numInLinks and numOutLinks attributes + network.create_attribute("NODE", "numInLinks") + network.create_attribute("NODE", "numOutLinks") + for node in network.nodes(): + node.numInLinks = len(list(node.incoming_links())) + node.numOutLinks = len(list(node.outgoing_links())) + + # node hasLocalConnection flag attribute + class BreakLoop (Exception): + pass + + network.create_attribute("NODE", "hasLocalConnection", False) + for node in network.centroids(): + try: + for zone_connector in node.incoming_links(): + for local_link in zone_connector.i_node.incoming_links(): + if local_link["@lane_restriction"] == 1.0: + node.hasLocalConnection = True + raise BreakLoop("") + except: + pass + + # transit line hasTAP flag attribute + network.create_attribute("TRANSIT_LINE", "hasTAP", False) + for line in network.transit_lines(): + has_first_tap = False + has_last_tap = False + for link in line.segment(0).i_node.outgoing_links(): + if link.j_node["@tap_id"] > 0: + has_first_tap = True + break + for link in line.segment(-2).j_node.outgoing_links(): + if link.j_node["@tap_id"] > 0: + has_last_tap = True + break + line.hasTAP = has_first_tap and has_last_tap + + # link names attribute + network.create_attribute("LINK", "linkNames") + for link in network.links(): + link.linkNames = str(link['#name'] + "," + link['#name_from'] + "," + link['#name_to']) + + def get_emme_object(emme_network, emme_network_object, fields_to_export): + # Emme network attribute and object names + net_attr = { + 'NODE':'nodes', + 'LINK':'links', + 'TRANSIT_SEGMENT':'transit_segments', + 'TRANSIT_LINE':'transit_lines', + 'CENTROID':'centroids' + } + + # read-in entire emme network object as a list + get_objs = 'list(emme_network.' + net_attr[emme_network_object] + '())' + uda = eval(get_objs) + + # get list of network object attributes + obj_attr = [] + if fields_to_export[0] in ['all','All','ALL']: + if emme_network_object == 'CENTROID': + obj_attr = emme_network.attributes('NODE') + else: + obj_attr = emme_network.attributes(emme_network_object) + else: + obj_attr = fields_to_export + + # instantiate list of network objects + net_objs = [] + for i in range(len(uda)): + obj_fields = [] + get_id = 'uda[i].id' + obj_fields.append(eval(get_id)) + for attr in obj_attr: + get_field = 'uda[i]["' + attr + '"]' + obj_fields.append(eval(get_field)) + net_objs.append(obj_fields) + net_obj_df = pd.DataFrame(net_objs, columns = ['id'] + obj_attr) + + return(net_obj_df) + + for item, row in self.inputs_list.iterrows(): + + table_name = row['Input_Table'] + emme_network_object = row['Emme_Object'] + column_map = row['Column_Map'] + fields_to_export = row['Fields'].split(',') + + # obtain emme network object, csv or dbf input + if not (pd.isnull(emme_network_object)): + df = get_emme_object(network, emme_network_object, fields_to_export) + self.inputs[table_name] = df + else: + input_path = self.prop_input_paths[table_name] + input_ext = os.path.splitext(input_path)[1] + if input_ext == '.csv': + df = pd.read_csv(_join(self.path, input_path)) + self.inputs[table_name] = df + else: + dbf_path = input_path + if '%project.folder%' in dbf_path: + dbf_path = dbf_path.replace('%project.folder%/', '') + dbf = Dbf5(_join(self.path, dbf_path)) + df = dbf.to_dataframe() + self.inputs[table_name] = df + + # add scenario year + self.inputs['scenario'] = self.scenario_df + + def checks(self): + # read all input DFs into memory + for key, df in self.inputs.items(): + expr = key + ' = df' + exec(expr) + + # copy of locals(), a dictionary of all local variables + calc_dict = locals() + + # read list of checks from CSV file + self.inputs_checks = pd.read_csv(self.inputs_checks_path) + + # remove all commented checks from the checks list + self.inputs_checks = self.inputs_checks.loc[[not i for i in (self.inputs_checks['Test'].str.startswith('#'))]] + + # perform calculations and add user-defined data frame subsets + for item, row in self.inputs_checks.iterrows(): + + test = row['Test'] + table = row['Input_Table'] + id_col = row['Input_ID_Column'] + expr = row['Expression'] + test_vals = row['Test_Vals'] + if not (pd.isnull(row['Test_Vals'])): + test_vals = test_vals.split(',') + test_vals = [txt.strip() for txt in test_vals] + test_type = row['Type'] + Severity = row['Severity'] + stat_expr = row['Report_Statistic'] + + if test_type == 'Calculation': + + try: + calc_expr = test + ' = ' + expr + exec(calc_expr, {}, calc_dict) + calc_out = eval(expr, calc_dict) + except Exception as error: + print('An error occurred with the calculation: {}'.format(test)) + raise + + if str(type(calc_out)) == "": + print('added '+ row['Test'] + ' as new DataFrame input') + self.inputs[row['Test']] = calc_out + self.inputs_list = self.inputs_list.append({'Input_Table': row['Test'],'Property_Token':'NA','Emme_Object':'NA', \ + 'Fields':'NA','Column_Map':'NA','Input_Description':'NA'}, ignore_index = True) + self.inputs_checks = self.inputs_checks.append({'Test':test, 'Input_Table': table, 'Input_ID_Column':id_col, 'Severity':Severity, \ + 'Type':test_type, 'Expression': expr, 'Test_Vals':test_vals, 'Report_Statistic':stat_expr, 'Test_Description': row['Test_Description']}, \ + ignore_index = True) + + # loop through list of checks and conduct all checks + # checks must evaluate to True if inputs are correct + for item, row in self.inputs_checks.iterrows(): + + test = row['Test'] + table = row['Input_Table'] + id_col = row['Input_ID_Column'] + expr = row['Expression'] + test_vals = row['Test_Vals'] + if not (pd.isnull(row['Test_Vals'])): + test_vals = test_vals.split(',') + test_vals = [txt.strip() for txt in test_vals] + test_type = row['Type'] + Severity = row['Severity'] + stat_expr = row['Report_Statistic'] + + if test_type == 'Test': + + if (pd.isnull(row['Test_Vals'])): + + # perform test + try: + out = eval(expr, calc_dict) + except Exception as error: + print('An error occurred with the check: {}'.format(test)) + raise + + # check if test result is a series + if str(type(out)) == "": + # for series, the test must be evaluated across all items + # result is False if a single False is found + self.results[test] = not (False in out.values) + + # reverse results list since we need all False IDs + reverse_results = [not i for i in out.values] + error_expr = table + "['" + id_col + "']" + "[reverse_results]" + error_id_list = eval(error_expr) + + # report first 25 problem IDs in the log + self.problem_ids[test] = error_id_list if error_id_list.size > 0 else [] + + # compute report statistics + if (pd.isnull(stat_expr)): + self.report_stat[test] = '' + else: + stat_list = eval(stat_expr) + self.report_stat[test] = stat_list[reverse_results] + else: + self.results[test] = out + self.problem_ids[test] = [] + if (pd.isnull(stat_expr)): + self.report_stat[test] = '' + else: + self.report_stat[test] = eval(stat_expr) + else: + # loop through test_vals and perform test for each item + self.result_list[test] = [] + for test_val in test_vals: + # perform test (test result must not be of type Series) + try: + out = eval(expr) + except Exception as error: + print('An error occurred with the check: {}'.format(test)) + raise + + # compute report statistic + if (pd.isnull(stat_expr)): + self.report_stat[test] = '' + else: + self.report_stat[test] = eval(stat_expr) + + # append to list + self.result_list[test].append(out) + self.results[test] = not (False in self.result_list[test]) + self.problem_ids[test] = [] + else: + # perform calculation + try: + calc_expr = test + ' = ' + expr + exec(calc_expr, {}, calc_dict) + except Exception as error: + print('An error occurred with the calculation: {}'.format(test)) + raise + + def prop_file_paths(self): + prop_files = self.inputs_list[['Input_Table','Property_Token']].dropna() + + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(self.path, 'conf', 'sandag_abm.properties')) + + for item, row in prop_files.iterrows(): + input_table = row['Input_Table'] + input_path = props[row['Property_Token']] + self.prop_input_paths[input_table] = input_path + + # obtain scenario year + self.scenario_df['Year'] = [props['scenarioYear']] + + def write_log(self): + # function to write out the input checker log file + # there are four blocks + # - Introduction + # - Summary of checks + # - Action Required: FATAL, LOGICAL, WARNINGS + # - List of passed checks + + # create log file + now = datetime.datetime.now() + + self.log_path = _join(self.input_checker_path, ('inputCheckerSummary_' + now.strftime("[%Y-%m-%d]") + '.txt')) + f = open(self.log_path, 'wb') + + # define re-usable elements + seperator1 = '###########################################################' + seperator2 = '***********************************************************' + + # write out Header + f.write(seperator1 + seperator1 + "\r\n") + f.write(seperator1 + seperator1 + "\r\n\r\n") + f.write("\t SANDAG ABM Input Checker Summary File \r\n") + f.write("\t _____________________________________ \r\n\r\n\r\n") + f.write("\t Created on: " + now.strftime("%Y-%m-%d %H:%M") + "\r\n\r\n") + f.write("\t Notes:-\r\n") + f.write("\t The SANDAG ABM Input Checker performs various QA/QC checks on SANDAG ABM inputs as specified by the user.\r\n") + f.write("\t The Input Checker allows the user to specify three severity levels for each QA/QC check:\r\n\r\n") + f.write("\t 1) FATAL 2) LOGICAL 3) WARNING\r\n\r\n") + f.write("\t FATAL Checks: The failure of these checks would result in a FATAL errors in the SANDAG ABM run.\r\n") + f.write("\t In case of FATAL failure, the Input Checker returns a return code of 1 to the\r\n") + f.write("\t main SANDAG ABM model, cauing the model run to halt.\r\n") + f.write("\t LOGICAL Checks: The failure of these checks indicate logical inconsistencies in the inputs.\r\n") + f.write("\t With logical errors in inputs, the SANDAG ABM outputs may not be meaningful.\r\n") + f.write("\t WARNING Checks: The failure of Warning checks would indicate problems in data that would not.\r\n") + f.write("\t halt the run or affect model outputs but might indicate an issue with inputs.\r\n\r\n\r\n") + f.write("\t The contents of this summary file are organized as follows: \r\n\r\n") + f.write("\t TALLY OF FAILED CHECKS:\r\n") + f.write("\t -----------------------\r\n") + f.write("\t A tally of all failed checks per severity level\r\n\r\n") + f.write("\t IMMEDIATE ACTION REQUIRED:\r\n") + f.write("\t -------------------------\r\n") + f.write("\t A log under this heading will be generated in case of failure of a FATAL check\r\n\r\n") + f.write("\t ACTION REQUIRED:\r\n") + f.write("\t ---------------\r\n") + f.write("\t A log under this heading will be generated in case of failure of a LOGICAL check\r\n\r\n") + f.write("\t WARNINGS:\r\n") + f.write("\t ---------\r\n") + f.write("\t A log under this heading will be generated in case of failure of a WARNING check\r\n\r\n") + f.write("\t SUMMARY OF ALL PASSED CHECKS:\r\n") + f.write("\t ----------------------------\r\n") + f.write("\t A complete listing of results of all passed checks\r\n\r\n") + f.write(seperator1 + seperator1 + "\r\n") + f.write(seperator1 + seperator1 + "\r\n\r\n\r\n\r\n") + + # combine results, inputs_checks and inputs_list + self.inputs_checks['result'] = self.inputs_checks['Test'].map(self.results) + checks_df = pd.merge(self.inputs_checks, self.inputs_list, on='Input_Table') + checks_df = checks_df[checks_df.Type=='Test'] + checks_df['reverse_result'] = [not i for i in checks_df.result] + + # get count of all FATAL failures + self.num_fatal = checks_df.result[(checks_df.Severity=='Fatal') & (checks_df.reverse_result)].count() + + # get count of all LOGICAL failures + self.num_logical = checks_df.result[(checks_df.Severity=='Logical') & (checks_df.reverse_result)].count() + self.logical_fails = checks_df[(checks_df.Severity=='Logical') & (checks_df.reverse_result)] + + # get count of all WARNING failures + self.num_warning = checks_df.result[(checks_df.Severity=='Warning') & (checks_df.reverse_result)].count() + + # write summary of failed checks + f.write('\r\n\r\n' + seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n") + f.write('\t' + "TALLY OF FAILED CHECKS \r\n") + f.write('\t' + "---------------------- \r\n\r\n") + f.write(seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n\t") + f.write(' Number of Fatal Errors: ' + str(self.num_fatal)) + f.write('\r\n\t Number of Logical Errors: ' + str(self.num_logical)) + f.write('\r\n\t Number of Warnings: ' + str(self.num_warning)) + + def write_check_log(self, fh, row): + # define constants + seperator2 = '-----------------------------------------------------------' + + # integerize problem ID list + problem_ids = self.problem_ids[row['Test']] + #problem_ids = [int(x) for x in problem_ids] + + # write check summary + fh.write('\r\n\r\n' + seperator2 + seperator2) + fh.write("\r\n\t Input File Name: " + ('NA' if not pd.isnull(row['Emme_Object']) else + (self.prop_input_paths[row['Input_Table']].rsplit('/', 1)[-1]))) + fh.write("\r\n\t Input File Location: " + ('NA' if not pd.isnull(row['Emme_Object']) else + (_join(self.input_checker_path, self.prop_input_paths[row['Input_Table']].replace('/','\\'))))) + fh.write("\r\n\t Emme Object: " + (row['Emme_Object'] if not pd.isnull(row['Emme_Object']) else 'NA')) + fh.write("\r\n\t Input Description: " + (row['Input_Description'] if not pd.isnull(row['Input_Description']) else "")) + fh.write("\r\n\t Test Name: " + row['Test']) + fh.write("\r\n\t Test_Description: " + (row['Test_Description'] if not pd.isnull(row['Test_Description']) else "")) + fh.write("\r\n\t Test Severity: " + row['Severity']) + fh.write("\r\n\r\n\t TEST RESULT: " + ('PASSED' if row['result'] else 'FAILED')) + + # display problem IDs for failed column checks + wrapper = textwrap.TextWrapper(width = 70) + if (not row['result']) & (len(problem_ids)>0) : + fh.write("\r\n\t TEST failed for following values of ID Column: " + row['Input_ID_Column'] + " (only up to 25 IDs displayed)") + fh.write("\r\n\t " + row['Input_ID_Column'] + ": " + "\r\n\t " + "\r\n\t ".join(wrapper.wrap(text = ", ".join(map(str, problem_ids[0:25]))))) + if not (pd.isnull(row['Report_Statistic'])): + this_report_stat = self.report_stat[row['Test']] + fh.write("\r\n\t Test Statistics: " + "\r\n\t " + "\r\n\t ".join(wrapper.wrap(text = ", ".join(map(str, this_report_stat[0:25]))))) + fh.write("\r\n\t Total number of failures: " + str(len(self.problem_ids[row['Test']]))) + if ((len(self.problem_ids[row['Test']])) > 25) and (row['Severity'] == 'Logical'): + fh.write("\r\n\t Open {} for complete list of failed Logical failures.".format(self.logical_log_path)) + else: + if not (pd.isnull(row['Report_Statistic'])): + fh.write("\r\n\t Test Statistic: " + str(self.report_stat[row['Test']])) + + # display result for each test val if it was specified + if not (pd.isnull(row['Test_Vals'])): + fh.write("\r\n\t TEST results for each test val") + result_tuples = zip(row['Test_Vals'].split(","), self.result_list[row['Test']]) + fh.write("\r\n\t ") + fh.write(','.join('[{} - {}]'.format(x[0],x[1]) for x in result_tuples)) + + fh.write("\r\n" + seperator2 + seperator2 + "\r\n\r\n") + + # write out IMMEDIATE ACTION REQUIRED section if needed + if self.num_fatal > 0: + fatal_checks = checks_df[(checks_df.Severity=='Fatal') & (checks_df.reverse_result)] + f.write('\r\n\r\n' + seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n") + f.write('\t' + "IMMEDIATE ACTION REQUIRED \r\n") + f.write('\t' + "------------------------- \r\n\r\n") + f.write(seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n") + + # write out log for each check + for item, row in fatal_checks.iterrows(): + #self.write_check_log(f, row, self.problem_ids[row['Test']]) + #write_check_log(self, f, row, self.problem_ids[row['Test']]) + write_check_log(self, f, row) + + # write out ACTION REQUIRED section if needed + if self.num_logical > 0: + logical_checks = checks_df[(checks_df.Severity=='Logical') & (checks_df.reverse_result)] + f.write('\r\n\r\n' + seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n") + f.write('\t' + "ACTION REQUIRED \r\n") + f.write('\t' + "--------------- \r\n\r\n") + f.write(seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n") + + #write out log for each check + for item, row in logical_checks.iterrows(): + write_check_log(self, f, row) + + # write out WARNINGS section if needed + if self.num_warning > 0: + warning_checks = checks_df[(checks_df.Severity=='Warning') & (checks_df.reverse_result)] + f.write('\r\n\r\n' + seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n") + f.write('\t' + "WARNINGS \r\n") + f.write('\t' + "-------- \r\n\r\n") + f.write(seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n") + + # write out log for each check + for item, row in warning_checks.iterrows(): + write_check_log(self, f, row) + + # write out the complete listing of all checks that passed + passed_checks = checks_df[(checks_df.result)] + f.write('\r\n\r\n' + seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n") + f.write('\t' + "LOG OF ALL PASSED CHECKS \r\n") + f.write('\t' + "------------------------ \r\n\r\n") + f.write(seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n") + + # write out log for each check + for item, row in passed_checks.iterrows(): + write_check_log(self, f, row) + + f.close() + + def write_logical_log(self): + # function to write out the complete list of Logical failures + + # combine results, inputs_checks and inputs_list + self.inputs_checks['result'] = self.inputs_checks['Test'].map(self.results) + checks_df = pd.merge(self.inputs_checks, self.inputs_list, on='Input_Table') + checks_df = checks_df[checks_df.Type=='Test'] + checks_df['reverse_result'] = [not i for i in checks_df.result] + + # get count of all LOGICAL failures + self.num_logical = checks_df.result[(checks_df.Severity=='Logical') & (checks_df.reverse_result)].count() + self.logical_fails = checks_df[(checks_df.Severity=='Logical') & (checks_df.reverse_result)] + + log_fail_id_tally = 0 + if self.num_logical > 0: + for item, row in self.logical_fails.iterrows(): + problem_ids = self.problem_ids[row['Test']] + if len(problem_ids) > 0: + log_fail_id_tally += 1 + + if log_fail_id_tally > 0: + + # create log file + now = datetime.datetime.now() + + self.logical_log_path = _join(self.input_checker_path, ('completeLogicalFails_' + now.strftime("[%Y-%m-%d]") + '.txt')) + f = open(self.logical_log_path, 'wb') + + # define re-usable elements + seperator1 = '###########################################################' + seperator2 = '***********************************************************' + + # write out Header + f.write(seperator1 + seperator1 + "\r\n") + f.write(seperator1 + seperator1 + "\r\n\r\n") + f.write("\t SANDAG ABM Input Checker Logical Failures Complete List \r\n") + f.write("\t _______________________________________________________ \r\n\r\n\r\n") + f.write("\t Created on: " + now.strftime("%Y-%m-%d %H:%M") + "\r\n\r\n") + f.write("\t Notes:-\r\n") + f.write("\t The SANDAG ABM Input Checker performs various QA/QC checks on SANDAG ABM inputs as specified by the user.\r\n") + f.write("\t The Input Checker allows the user to specify three severity levels for each QA/QC check:\r\n\r\n") + f.write("\t 1) FATAL 2) LOGICAL 3) WARNING\r\n\r\n") + f.write("\t This file provides the complete list of failed checks for checks of severity type Logical. \r\n") + f.write(seperator1 + seperator1 + "\r\n") + f.write(seperator1 + seperator1 + "\r\n\r\n\r\n\r\n") + + # write total number of failed logical checks + f.write('\r\n\r\n' + seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n") + f.write('\t' + "TALLY OF FAILED CHECKS \r\n") + f.write('\t' + "---------------------- \r\n\r\n") + f.write(seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n\t") + f.write('\r\n\t Number of Logical Errors: ' + str(self.num_logical)) + + def write_logical_check_log(self, fh, row): + # define constants + seperator2 = '-----------------------------------------------------------' + + # integerize problem ID list + problem_ids = self.problem_ids[row['Test']] + #problem_ids = [int(x) for x in problem_ids] + + # write check summary + fh.write('\r\n\r\n' + seperator2 + seperator2) + fh.write("\r\n\t Input File Name: " + ('NA' if not pd.isnull(row['Emme_Object']) else + (self.prop_input_paths[row['Input_Table']].rsplit('/', 1)[-1]))) + fh.write("\r\n\t Input File Location: " + ('NA' if not pd.isnull(row['Emme_Object']) else + (_join(self.input_checker_path, self.prop_input_paths[row['Input_Table']].replace('/','\\'))))) + fh.write("\r\n\t Emme Object: " + (row['Emme_Object'] if not pd.isnull(row['Emme_Object']) else 'NA')) + fh.write("\r\n\t Input Description: " + (row['Input_Description'] if not pd.isnull(row['Input_Description']) else "")) + fh.write("\r\n\t Test Name: " + row['Test']) + fh.write("\r\n\t Test_Description: " + (row['Test_Description'] if not pd.isnull(row['Test_Description']) else "")) + fh.write("\r\n\t Test Severity: " + row['Severity']) + fh.write("\r\n\r\n\t TEST RESULT: " + ('PASSED' if row['result'] else 'FAILED')) + + # display problem IDs for failed column checks + wrapper = textwrap.TextWrapper(width = 70) + if (not row['result']) & (len(problem_ids)>0) : + fh.write("\r\n\t TEST failed for following values of ID Column: " + row['Input_ID_Column']) + fh.write("\r\n\t " + row['Input_ID_Column'] + ": " + "\r\n\t " + "\r\n\t ".join(wrapper.wrap(text = ", ".join(map(str, problem_ids))))) + if not (pd.isnull(row['Report_Statistic'])): + this_report_stat = self.report_stat[row['Test']] + fh.write("\r\n\t Test Statistics: " + "\r\n\t " + "\r\n\t ".join(wrapper.wrap(text = ", ".join(map(str, this_report_stat))))) + fh.write("\r\n\t Total number of failures: " + str(len(self.problem_ids[row['Test']]))) + else: + if not (pd.isnull(row['Report_Statistic'])): + fh.write("\r\n\t Test Statistic: " + str(self.report_stat[row['Test']])) + + # display result for each test val if it was specified + if not (pd.isnull(row['Test_Vals'])): + fh.write("\r\n\t TEST results for each test val") + result_tuples = zip(row['Test_Vals'].split(","), self.result_list[row['Test']]) + fh.write("\r\n\t ") + fh.write(','.join('[{} - {}]'.format(x[0],x[1]) for x in result_tuples)) + + fh.write("\r\n" + seperator2 + seperator2 + "\r\n\r\n") + + # write out ACTION REQUIRED section if needed + if self.num_logical > 0: + logical_checks = checks_df[(checks_df.Severity=='Logical') & (checks_df.reverse_result)] + f.write('\r\n\r\n' + seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n\r\n") + f.write('\t' + "LOG OF ALL FAILED LOGICAL CHECKS \r\n") + f.write('\t' + "-------------------------------- \r\n\r\n") + f.write(seperator2 + seperator2 + "\r\n") + f.write(seperator2 + seperator2 + "\r\n") + + #write out log for each check + for item, row in logical_checks.iterrows(): + if len(self.problem_ids[row['Test']]) > 25: + write_logical_check_log(self, f, row) + + f.close() + + def check_logical(self): + if self.num_logical > 0: + # raise exception for each logical check fail + for item, row in self.logical_fails.iterrows(): + answer = dialog.alert_question( + message = "The following Logical check resulted in at least 1 error: {} \n Open {} for details. \ + \n\n Click OK to continue or Cancel to stop run.".format(row['Test'], self.log_path), + title = "Logical Check Error", + answers = [("OK", dialog.YES_ROLE), ("Cancel", dialog.REJECT_ROLE)] + ) + + if answer == 1: + raise Exception("Input checker was cancelled") + + def check_num_fatal(self): + # return code to the main model based on input checks and results + if self.num_fatal > 0: + raise Exception("Input checker failed, {} fatal errors found. Open {} for details.".format(self.num_fatal, self.log_path)) \ No newline at end of file diff --git a/sandag_abm/src/main/emme/toolbox/import/run4Ds.py b/sandag_abm/src/main/emme/toolbox/import/run4Ds.py new file mode 100644 index 0000000..89ff0d0 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/import/run4Ds.py @@ -0,0 +1,412 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright RSG, 2019-2020. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// import/run4Ds.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Generates density variables and adds in mgra socio economic variables +# +# +# Inputs: +# path: path to the current scenario +# ref_path: path to the comparison model scenario +# int_radius: buffer radius for intersection counts +# maps: default unchecked - means not generating spatial heat maps for +# intersection counts. This functionality requires +# following packages; geopandas, folium, and branca +# +# File referenced: +# input\mgra13_based_input2016.csv +# input\SANDAG_Bike_Net.dbf +# input\SANDAG_Bike_Node.dbf +# output\walkMgraEquivMinutes.csv +# +# Script example +# python C:\ABM_runs\maint_2019_RSG\Tasks\4ds\emme_toolbox\emme\toolbox\import\run4Ds.py +# 0.65 r'C:\ABM_runs\maint_2019_RSG\Model\ABM2_14_2_0' r'C:\ABM_runs\maint_2019_RSG\Model\abm_test_fortran_4d' + + +TOOLBOX_ORDER = 10 + +#import modules +import inro.modeller as _m +from simpledbf import Dbf5 +import os +import pandas as pd, numpy as np +#import datetime +import matplotlib.pyplot as plt +import seaborn as sns +import warnings +import traceback as _traceback + +warnings.filterwarnings("ignore") + +_join = os.path.join +_dir = os.path.dirname + +gen_utils = _m.Modeller().module("sandag.utilities.general") + +class FourDs(_m.Tool()): + + path = _m.Attribute(unicode) + ref_path = _m.Attribute(unicode) + int_radius = _m.Attribute(float) + maps = _m.Attribute(bool) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self._log = [] + self._error = [] + project_dir = _dir(_m.Modeller().desktop.project.path) + self.path = _dir(project_dir) + self.mgradata_file = '' + self.equivmins_file = '' + self.inNet = '' + self.inNode = '' + self.ref_path = '' + self.maps = False + self.int_radius = 0.65 #mile + self.oth_radius = self.int_radius #same as intersection radius + self.new_cols = ['totint','duden','empden','popden','retempden','totintbin','empdenbin','dudenbin','PopEmpDenPerMi'] + self.continuous_fields = ['totint', 'popden', 'empden', 'retempden'] + self.discrete_fields = ['totintbin', 'empdenbin', 'dudenbin'] + self.mgra_shape_file = '' + self.base = pd.DataFrame() + self.build = pd.DataFrame() + self.mgra_data = pd.DataFrame() + self.base_cols = [] + self.attributes = ["path", "int_radius", "ref_path"] + + def page(self): + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(self.path, "conf", "sandag_abm.properties")) + self.ref_path = props["visualizer.reference.path"] + + pb = _m.ToolPageBuilder(self) + pb.title = "Run 4Ds" + pb.description = """ + Generate Density Variables. + Generated from MGRA socio economic file and active transportation (AT) network. +
+
+ The following files are used: +
+
    +
  • input\mgra13_based_input2016.csv
  • +
  • input\SANDAG_Bike_Net.dbf
  • +
  • input\SANDAG_Bike_Node.dbf
  • +
  • output\walkMgraEquivMinutes.csv
  • +
+
+ """ + pb.branding_text = "SANDAG - Run 4Ds" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file("path", window_type="directory", file_filter="", + title="Source directory:",) + + pb.add_text_box("int_radius", size=6, title="Buffer size (miles):") + #pb.add_checkbox("maps", title=" ", label="Generate 4D maps") + pb.add_select_file("ref_path", window_type="directory", file_filter="", title="Reference directory for comparison") + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self(path=self.path, int_radius=self.int_radius, ref_path=self.ref_path) + run_msg = "Run 4Ds complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, path= "", + int_radius = 0.65, + ref_path = ""): + _m.logbook_write("Started running 4Ds ...") + + self.path = path + self.ref_path = ref_path + self.int_radius = int_radius + #self.maps = maps + + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(self.path, "conf", "sandag_abm.properties")) + + + self.mgradata_file = props["mgra.socec.file"] #input/filename + self.syn_households_file = props["PopulationSynthesizer.InputToCTRAMP.HouseholdFile"] #input/filename + self.equivmins_file = props["active.logsum.matrix.file.walk.mgra"] #filename + self.inNet = os.path.basename(props["active.edge.file"]) #filename + self.inNode = os.path.basename(props["active.node.file"]) #filename + + attributes = { + "path": self.path, + "ref_path": self.ref_path, + "int_radius": self.int_radius, + "maps": self.maps, + } + gen_utils.log_snapshot("Run 4Ds", str(self), attributes) + + file_paths = [_join(self.path, self.mgradata_file),_join(self.path, self.syn_households_file),_join(self.path, "output", self.equivmins_file), _join(self.path, "input", self.inNet), _join(self.path, "input", self.inNode)] + for path in file_paths: + if not os.path.exists(path): + raise Exception("missing file '%s'" % (path)) + + self.mgra_data = pd.read_csv(os.path.join(self.path,self.mgradata_file)) + self.base_cols = self.mgra_data.columns.tolist() + + _m.logbook_write("Tagging intersections to mgra") + self.get_intersection_count() + + _m.logbook_write("Generating density variables") + self.get_density() + + _m.logbook_write("Creating comparison plots") + self.make_plots() + + _m.logbook_write("Finished running 4Ds") + + def get_intersection_count(self): + links = Dbf5(_join(self.path, "input", self.inNet)) + links = links.to_dataframe() + + nodes = Dbf5(_join(self.path, "input", self.inNode)) + nodes = nodes.to_dataframe() + + nodes_int = nodes.loc[(nodes.NodeLev_ID < 100000000)] + + #links + #remove taz, mgra, and tap connectors + links = links.loc[(links.A <100000000) & (links.B <100000000)] + + #remove freeways (Func_Class=1), ramps (Func_Class=2), and others (Func_Class =0 or -1) + links = links.loc[(links.Func_Class > 2)] + links['link_count'] = 1 + + #aggregate by Node A and Node B + links_nodeA = links[['A', 'link_count']].groupby('A').sum().reset_index() + links_nodeB = links[['B', 'link_count']].groupby('B').sum().reset_index() + + #merge the two and keep all records from both dataframes (how='outer') + nodes_linkcount = pd.merge(links_nodeA, links_nodeB, left_on='A', right_on='B', how = 'outer') + nodes_linkcount = nodes_linkcount.fillna(0) + nodes_linkcount['link_count'] = nodes_linkcount['link_count_x'] + nodes_linkcount['link_count_y'] + + #get node id from both dataframes + nodes_linkcount['N']=0 + nodes_linkcount['N'][nodes_linkcount.A>0] = nodes_linkcount['A'] + nodes_linkcount['N'][nodes_linkcount.B>0] = nodes_linkcount['B'] + nodes_linkcount['N']=nodes_linkcount['N'].astype(float) + nodes_linkcount = nodes_linkcount[['N','link_count']] + + #keep nodes with 3+ link count + intersections_temp = nodes_linkcount.loc[nodes_linkcount.link_count>=3] + + #get node X and Y + intersections = pd.merge(intersections_temp,nodes_int[['NodeLev_ID','XCOORD','YCOORD']], left_on = 'N', right_on = 'NodeLev_ID', how = 'left') + intersections = intersections[['N','XCOORD','YCOORD']] + intersections = intersections.rename(columns = {'XCOORD': 'X', 'YCOORD': 'Y'}) + + mgra_nodes = nodes[nodes.MGRA > 0][['MGRA','XCOORD','YCOORD']] + mgra_nodes.columns = ['mgra','x','y'] + int_dict = {} + for int in intersections.iterrows(): + mgra_nodes['dist'] = np.sqrt((int[1][1] - mgra_nodes['x'])**2+(int[1][2] - mgra_nodes['y'])**2) + int_dict[int[1][0]] = mgra_nodes.loc[mgra_nodes['dist'] == mgra_nodes['dist'].min()]['mgra'].values[0] + + intersections['near_mgra'] = intersections['N'].map(int_dict) + intersections = intersections.groupby('near_mgra', as_index = False).count()[['near_mgra','N']].rename(columns = {'near_mgra':'mgra','N':'icnt'}) + try: + self.mgra_data = self.mgra_data.drop('icnt',axis = 1).merge(intersections, how = 'outer', on = "mgra") + except: + self.mgra_data = self.mgra_data.merge(intersections, how = 'outer', on = "mgra") + + def get_density(self): + if len(self.mgra_data) == 0: + mgra_landuse = pd.read_csv(os.path.join(self.path, self.mgradata_file)) + else: + mgra_landuse = self.mgra_data + + # get population from synthetic population instead of mgra data file + syn_pop = pd.read_csv(os.path.join(self.path, self.syn_households_file)) + syn_pop = syn_pop.rename(columns = {'MGRA':'mgra'})[['persons','mgra']].groupby('mgra',as_index = False).sum() + #remove if 4D columns exist + for col in self.new_cols: + if col in self.base_cols: + self.base_cols.remove(col) + mgra_landuse = mgra_landuse.drop(col,axis=1) + + #merge syntetic population to landuse + mgra_landuse = mgra_landuse.merge(syn_pop, how = 'left', on = 'mgra') + #all street distance + equiv_min = pd.read_csv(_join(self.path, "output", self.equivmins_file)) + equiv_min['dist'] = equiv_min['actual']/60*3 + print("MGRA input landuse: " + self.mgradata_file) + + def density_function(mgra_in): + eqmn = equiv_min[equiv_min['i'] == mgra_in] + mgra_circa_int = eqmn[eqmn['dist'] < self.int_radius]['j'].unique() + mgra_circa_oth = eqmn[eqmn['dist'] < self.oth_radius]['j'].unique() + totEmp = mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_oth)]['emp_total'].sum() + totRet = mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_oth)]['emp_retail'].sum() + mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_oth)]['emp_personal_svcs_retail'].sum() + mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_oth)]['emp_restaurant_bar'].sum() + totHH = mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_oth)]['hh'].sum() + totPop = mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_oth)]['persons'].sum() + totAcres = mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_oth)]['land_acres'].sum() + totInt = mgra_landuse[mgra_landuse.mgra.isin(mgra_circa_int)]['icnt'].sum() + if(totAcres>0): + empDen = totEmp/totAcres + retDen = totRet/totAcres + duDen = totHH/totAcres + popDen = totPop/totAcres + popEmpDenPerMi = (totEmp+totPop)/(totAcres/640) #Acres to miles + tot_icnt = totInt + else: + empDen = 0 + retDen = 0 + duDen = 0 + popDen = 0 + popEmpDenPerMi = 0 + tot_icnt = 0 + return tot_icnt,duDen,empDen,popDen,retDen,popEmpDenPerMi + + #new_cols = [0-'totint',1-'duden',2-'empden',3-'popden',4-'retempden',5-'totintbin',6-'empdenbin',7-'dudenbin',8-'PopEmpDenPerMi'] + mgra_landuse[self.new_cols[0]],mgra_landuse[self.new_cols[1]],mgra_landuse[self.new_cols[2]],mgra_landuse[self.new_cols[3]],mgra_landuse[self.new_cols[4]],mgra_landuse[self.new_cols[8]] = zip(*mgra_landuse['mgra'].map(density_function)) + + mgra_landuse = mgra_landuse.fillna(0) + mgra_landuse[self.new_cols[5]] = np.where(mgra_landuse[self.new_cols[0]] < 80, 1, np.where(mgra_landuse[self.new_cols[0]] < 130, 2, 3)) + mgra_landuse[self.new_cols[6]] = np.where(mgra_landuse[self.new_cols[2]] < 10, 1, np.where(mgra_landuse[self.new_cols[2]] < 30, 2,3)) + mgra_landuse[self.new_cols[7]] = np.where(mgra_landuse[self.new_cols[1]] < 5, 1, np.where(mgra_landuse[self.new_cols[1]] < 10, 2,3)) + + mgra_landuse[self.base_cols+self.new_cols].to_csv(os.path.join(self.path, self.mgradata_file), index = False, float_format='%.4f' ) + + self.mgra_data = mgra_landuse + print( "*** Finished ***") + + #plot comparisons of build and old density values and create heat maps + def make_plots(self): + if len(self.mgra_data) == 0: + self.build = pd.read_csv(os.path.join(self.path, self.mgradata_file)) + else: + self.build = self.mgra_data + + def plot_continuous(field): + #colors + rsg_orange = '#f68b1f' + rsg_marine = '#006fa1' + #rsg_leaf = '#63af5e' + #rsg_grey = '#48484a' + #rsg_mist = '#dcddde' + + max = self.base[field].max() + self.base[field].max()%5 + div = max/5 if max/5 >= 10 else max/2 + bins = np.linspace(0,max,div) + plt.hist(self.base[field], bins, normed = True, alpha = 0.5, label = 'Base', color = rsg_marine) + plt.hist(self.build[field], bins, normed = True, alpha = 0.5, label = 'Build', color = rsg_orange) + mean_base = self.base[field].mean() + mean = self.build[field].mean() + median_base = self.base[field].median() + median = self.build[field].median() + plt.axvline(mean_base, color = 'b', linestyle = '-', label = 'Base Mean') + plt.axvline(median_base, color = 'b', linestyle = '--', label = 'Base Median') + plt.axvline(mean, color = 'r', linestyle = '-', label = 'Build Mean') + plt.axvline(median, color = 'r', linestyle = '--',label = 'Build Median') + plt.legend(loc = 'upper right') + ylims = plt.ylim()[1] + plt.text(mean_base + div/4, ylims-ylims/32, "mean: {:0.2f}".format(mean_base), color = 'b') + plt.text(mean_base + div/4, ylims - 5*ylims/32, "median: {:0.0f}".format(median_base), color = 'b') + plt.text(mean_base + div/4, ylims-2*ylims/32, "mean: {:0.2f}".format(mean), size = 'medium',color = 'r') + plt.text(mean_base + div/4, ylims-6*ylims/32, "median: {:0.0f}".format(median), color = 'r') + plt.text(self.base[field].min() , ylims/32, "min: {:0.0f}".format(self.base[field].min()), color = 'b') + plt.text(self.base[field].max()-div , ylims/32, "max: {:0.0f}".format(self.base[field].max()), color = 'b') + plt.text(self.build[field].min() , 2*ylims/32, "min: {:0.0f}".format(self.build[field].min()), color = 'r') + plt.text(self.base[field].max()-div , 2*ylims/32, "max: {:0.0f}".format(self.build[field].max()), color = 'r') + + plt.xlabel(field) + plt.ylabel("MGRA's") + plt.title(field.replace('den','') + ' Density') + outfile = _join(self.path, "output", '4Ds_{}_plot.png'.format(field)) + if os.path.isfile(outfile): + os.remove(outfile) + plt.savefig(outfile) + plt.clf() + + def plot_discrete(field): + fig, ax = plt.subplots() + df1 = discretedf_base.groupby(field, as_index = False).agg({'mgra':'count','type':'first'}) + df2 = discretedf_build.groupby(field, as_index = False).agg({'mgra':'count','type':'first'}) + df = df1.append(df2) + ax = sns.barplot(x=field, y = 'mgra', hue = 'type', data = df) + ax.set_title(field) + outfile = _join(self.path, "output", '4Ds_{}_plot.png'.format(field)) + if os.path.isfile(outfile): + os.remove(outfile) + ax.get_figure().savefig(outfile) + + self.base = pd.read_csv(self.ref_path) + self.base['type'] = 'base' + self.build['type'] = 'build' + + discretedf_base = self.base[['mgra','type']+self.discrete_fields] + discretedf_build = self.build[['mgra','type']+self.discrete_fields] + + for f in self.continuous_fields: + plot_continuous(f) + for f in self.discrete_fields: + plot_discrete(f) + + if self.maps: + import geopandas as gpd + import folium + from branca.colormap import linear + compare_int = self.base.merge(self.build, how = 'outer', on = 'mgra', suffixes = ['_base','_build']) + compare_int['diff'] = compare_int['TotInt'] - compare_int['totint'] + + compare_int = gpd.read_file(self.mgra_shape_file).rename(columns = {'MGRA':'mgra'}).merge(compare_int, how = 'left', on = 'mgra') + compare_int = compare_int.to_crs({'init': 'epsg:4326'}) + + colormap = linear.OrRd_09.scale( + compare_int.TotInt.min(), + compare_int.TotInt.max()) + colormapA = linear.RdBu_04.scale( + compare_int['diff'].min(), + compare_int['diff'].min()*-1) + + compare_int['colordiff'] = compare_int['diff'].map(lambda n: colormapA(n)) + compare_int['colororig'] = compare_int['TotInt'].map(lambda n: colormap(n)) + compare_int['colornew'] = compare_int['totint'].map(lambda n: colormap(n)) + + def makeheatmap(self,df, colormp,color_field,caption): + mapname = folium.Map(location=[32.76, -117.15], zoom_start = 13.459) + folium.GeoJson(compare_int, + style_function=lambda feature: { + 'fillColor': feature['properties'][color_field], + 'color' : rsg_marine, + 'weight' : 0, + 'fillOpacity' : 0.75, + }).add_to(mapname) + + colormp.caption = caption + colormp.add_to(mapname) + return mapname + + makeheatmap(compare_int,colormapA,'colordiff','Intersection Diff (base - build)').save('diff_intersections.html') + makeheatmap(compare_int,colormap,'colororig','Intersections').save('base_intersections.html') + makeheatmap(compare_int,colormap,'colororig','Intersections').save('build_intersections.html') diff --git a/sandag_abm/src/main/emme/toolbox/initialize/initialize_matrices.py b/sandag_abm/src/main/emme/toolbox/initialize/initialize_matrices.py new file mode 100644 index 0000000..f4e880a --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/initialize/initialize_matrices.py @@ -0,0 +1,426 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// initialize_matrices.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Coordinates the initialization of all matrices. +# The matrix names are listed for each of the model components / steps, +# and the matrix IDs are assigned consistently from the set of matrices. +# In each of the model steps the matrices are only referenced by name, +# never by ID. +# +# +# Inputs: +# components: A list of the model components / steps for which to initialize matrices +# One or more of "traffic_demand", "transit_demand", +# "traffic_skims", "transit_skims", "external_internal_model", +# "external_external_model", "truck_model", "commercial_vehicle_model" +# periods: A list of periods for which to initialize matrices, "EA", "AM", "MD", "PM", "EV" +# scenario: scenario to use for reference zone system and the emmebank in which +# the matrices will be created +# +# Script example: +""" + import os + import inro.emme.database.emmebank as _eb + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + main_emmebank = _eb.Emmebank(os.path.join(main_directory, "emme_project", "Database", "emmebank")) + transit_emmebank = _eb.Emmebank(os.path.join(main_directory, "emme_project", "Database", "emmebank")) + periods = ["EA", "AM", "MD", "PM", "EV"] + traffic_components = [ + "traffic_demand", "traffic_skims", "external_internal_model", + "external_external_model", "truck_model", "commercial_vehicle_model"] + transit_components = ["transit_demand", "transit_skims"] + base_scenario = main_emmebank.scenario(100) + transit_scenario = transit_emmebank.scenario(100) + initialize_matrices = modeller.tool("sandag.initialize.initialize_matrices") + # Create / initialize matrices in the base, traffic emmebank + initialize_matrices(traffic_components, periods, base_scenario) + # Create / initialize matrices in the transit emmebank + initialize_matrices(transit_components, periods, transit_scenario) +""" + + +TOOLBOX_ORDER = 9 + + +import inro.modeller as _m +import traceback as _traceback + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class Initialize(_m.Tool(), gen_utils.Snapshot): + + components = _m.Attribute(_m.ListType) + periods = _m.Attribute(_m.ListType) + delete_all_existing = _m.Attribute(bool) + + tool_run_msg = "" + + def __init__(self): + self._all_components = [ + "traffic_demand", + "transit_demand", + "traffic_skims", + "transit_skims", + "external_internal_model", + "external_external_model", + "truck_model", + "commercial_vehicle_model", + ] + self._all_periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + self.components = self._all_components[:] + self.periods = self._all_periods[:] + self.attributes = ["components", "periods", "delete_all_existing"] + self._matrices = {} + self._count = {} + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Initialize matrices" + pb.description = """Creates and initializes the required matrices + for the selected components / sub-models. + Includes all components by default.""" + pb.branding_text = "- SANDAG" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select("components", keyvalues=[(k,k) for k in self._all_components], + title="Select components:") + pb.add_select("periods", keyvalues=[(k,k) for k in self._all_periods], + title="Select periods:") + pb.add_checkbox("delete_all_existing", label="Delete all existing matrices") + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.components, self.periods, scenario, self.delete_all_existing) + run_msg = "Tool completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace("Create and initialize matrices", save_arguments=True) + def __call__(self, components, periods, scenario, delete_all_existing=False): + attributes = { + "components": components, + "periods": periods, + "delete_all_existing": delete_all_existing + } + gen_utils.log_snapshot("Initialize matrices", str(self), attributes) + + self.scenario = scenario + emmebank = scenario.emmebank + self._create_matrix_tool = _m.Modeller().tool( + "inro.emme.data.matrix.create_matrix") + if components == "all": + components = self._all_components[:] + if periods == "all": + periods = self._all_periods[:] + if delete_all_existing: + with _m.logbook_trace("Delete all existing matrices"): + for matrix in emmebank.matrices(): + emmebank.delete_matrix(matrix) + self.generate_matrix_list(self.scenario) + matrices = [] + for component in components: + matrices.extend(self.create_matrices(component, periods)) + # Note: matrix is also created in import_network + self._create_matrix_tool("ms1", "zero", "zero", scenario=self.scenario, overwrite=True) + return matrices + + def generate_matrix_list(self, scenario): + self._matrices = dict( + (name, dict((k, []) for k in self._all_periods + ["ALL"])) + for name in self._all_components) + self._count = {"ms": 2, "md": 100, "mo": 100, "mf": 100} + + for component in self._all_components: + fcn = getattr(self, component) + fcn() + # check dimensions can fit full set of matrices + type_names = [ + ('mf', 'full_matrices'), + ('mo', 'origin_matrices'), + ('md', 'destination_matrices'), + ('ms', 'scalar_matrices')] + dims = scenario.emmebank.dimensions + for prefix, name in type_names: + if self._count[prefix] > dims[name]: + raise Exception("emmebank capacity error, increase %s to at least %s" % (name, self._count[prefix])) + + def traffic_demand(self): + tmplt_matrices = [ + ("SOV_NT_L", "SOV non-transponder demand low VOT"), + ("SOV_TR_L", "SOV transponder demand low VOT"), + ("HOV2_L", "HOV2 demand low VOT"), + ("HOV3_L", "HOV3+ demand low VOT"), + ("SOV_NT_M", "SOV non-transponder demand medium VOT"), + ("SOV_TR_M", "SOV transponder demand medium VOT"), + ("HOV2_M", "HOV2 demand medium VOT"), + ("HOV3_M", "HOV3+ demand medium VOT"), + ("SOV_NT_H", "SOV non-transponder demand high VOT"), + ("SOV_TR_H", "SOV transponder demand high VOT"), + ("HOV2_H", "HOV2 demand high VOT"), + ("HOV3_H", "HOV3+ demand high VOT"), + ("TRK_H", "Truck Heavy PCE demand"), + ("TRK_L", "Truck Light PCE demand"), + ("TRK_M", "Truck Medium PCE demand"), + ] + for period in self._all_periods: + self.add_matrices("traffic_demand", period, + [("mf", period + "_" + name, period + " " + desc) + for name, desc in tmplt_matrices]) + + def transit_demand(self): + tmplt_matrices = [ + ("BUS", "local bus demand"), + ("PREM", "Premium modes demand"), + ("ALLPEN", "all modes xfer pen demand"), + ] + for period in self._all_periods: + for a_name in ["WLK", "PNR", "KNR"]: + self.add_matrices("transit_demand", period, + [("mf", "%s_%s%s" % (period, a_name, name), "%s %s access %s" % (period, a_name, desc)) + for name, desc in tmplt_matrices]) + + def traffic_skims(self): + tp_desc = {"TR": "transponder", "NT": "non-transponder"} + vot_desc = {"L": "low", "M": "medium", "H": "high"} + truck_desc = {"L": "light", "M": "medium", "H": "heavy"} + + sov_tmplt_matrices = [ + ("TIME", "SOV %s travel time"), + ("DIST", "SOV %s distance"), + ("REL", "SOV %s reliability skim"), + ("TOLLCOST", "SOV %s toll cost $0.01"), + ("TOLLDIST", "SOV %s distance on toll facility"), + ] + hov_tmplt_matrices = [ + ("TIME", "HOV%s travel time"), + ("DIST", "HOV%s distance"), + ("REL", "HOV%s reliability skim"), + ("TOLLCOST", "HOV%s toll cost $0.01"), + ("TOLLDIST", "HOV%s distance on toll facility"), + ("HOVDIST", "HOV%s HOV distance on HOV facility") + ] + truck_tmplt_matrices = [ + ("TIME", "Truck %s travel time"), + ("DIST", "Truck %s distance"), + ("TOLLCOST", "Truck %s toll cost $0.01") + ] + for period in self._all_periods: + for vot_type in "L", "M", "H": + for tp_type in "NT", "TR": + cls_name = "SOV_" + tp_type + "_" + vot_type + cls_desc = tp_desc[tp_type] + " " + vot_desc[vot_type] + " VOT" + self.add_matrices("traffic_skims", period, + [("mf", period + "_" + cls_name + "_" + name, period + " " + desc % cls_desc) for name, desc in sov_tmplt_matrices]) + for hov_type in "2", "3": + cls_name = "HOV" + hov_type + "_" + vot_type + cls_desc = hov_type + " " + vot_desc[vot_type] + " VOT" + self.add_matrices("traffic_skims", period, + [("mf", period + "_" + cls_name + "_" + name, + period + " " + desc % cls_desc) + for name, desc in hov_tmplt_matrices]) + for truck_type in "L", "M", "H": + cls_name = "TRK" + "_" + truck_type + cls_desc = truck_desc[truck_type] + self.add_matrices("traffic_skims", period, + [("mf", period + "_" + cls_name + "_" + name, + period + " " + desc % cls_desc) + for name, desc in truck_tmplt_matrices]) + + self.add_matrices("traffic_skims", "MD", + [("mf", "MD_TRK_TIME", "MD Truck generic travel time")]) + + def transit_skims(self): + tmplt_matrices = [ + ("GENCOST", "total impedance"), + ("FIRSTWAIT", "first wait time"), + ("XFERWAIT", "transfer wait time"), + ("TOTALWAIT", "total wait time"), + ("FARE", "fare"), + ("XFERS", "num transfers"), + ("ACCWALK", "access walk time"), + ("XFERWALK", "transfer walk time"), + ("EGRWALK", "egress walk time"), + ("TOTALWALK", "total walk time"), + ("TOTALIVTT", "in-vehicle time"), + ("DWELLTIME", "dwell time"), + ("BUSIVTT", "local bus in-vehicle time"), + ("LRTIVTT", "LRT in-vehicle time"), + ("CMRIVTT", "Rail in-vehicle time"), + ("EXPIVTT", "Express in-vehicle time"), + ("LTDEXPIVTT", "Ltd exp bus in-vehicle time"), + ("BRTREDIVTT", "BRT red in-vehicle time"), + ("BRTYELIVTT", "BRT yellow in-vehicle time"), + ("TIER1IVTT", "Tier1 in-vehicle time"), + ("BUSDIST", "Bus IV distance"), + ("LRTDIST", "LRT IV distance"), + ("CMRDIST", "Rail IV distance"), + ("EXPDIST", "Express and Ltd IV distance"), + ("BRTDIST", "BRT red and yel IV distance"), + ("TIER1DIST", "Tier1 distance"), + ("TOTDIST", "Total transit distance") + ] + skim_sets = [ + ("BUS", "Local bus only"), + ("PREM", "Premium modes only"), + ("ALLPEN", "All w/ xfer pen") + ] + for period in self._all_periods: + for set_name, set_desc in skim_sets: + self.add_matrices("transit_skims", period, + [("mf", period + "_" + set_name + "_" + name, + period + " " + set_desc + ": " + desc) + for name, desc in tmplt_matrices]) + + def truck_model(self): + tmplt_matrices = [ + ("TRKL", "Truck Light"), + ("TRKM", "Truck Medium"), + ("TRKH", "Truck Heavy"), + ("TRKEI", "Truck external-internal"), + ("TRKIE", "Truck internal-external"), + ] + self.add_matrices("truck_model", "ALL", + [("mo", name + '_PROD', desc + ' production') + for name, desc in tmplt_matrices]) + self.add_matrices("truck_model", "ALL", + [("md", name + '_ATTR', desc + ' attraction') + for name, desc in tmplt_matrices]) + + tmplt_matrices = [ + ("TRKEE_DEMAND", "Truck total external-external demand"), + ("TRKL_FRICTION", "Truck Light friction factors"), + ("TRKM_FRICTION", "Truck Medium friction factors"), + ("TRKH_FRICTION", "Truck Heavy friction factors"), + ("TRKIE_FRICTION", "Truck internal-external friction factors"), + ("TRKEI_FRICTION", "Truck external-internal friction factors"), + ("TRKL_DEMAND", "Truck Light total demand"), + ("TRKM_DEMAND", "Truck Medium total demand"), + ("TRKH_DEMAND", "Truck Heavy total demand"), + ("TRKIE_DEMAND", "Truck internal-external total demand"), + ("TRKEI_DEMAND", "Truck external-internal total demand"), + ] + self.add_matrices("truck_model", "ALL", + [("mf", name, desc) for name, desc in tmplt_matrices]) + + # TODO: remove GP and TOLL matrices, no longer used + tmplt_matrices = [ + ("TRK_L_VEH", "Truck Light demand"), + ("TRKLGP_VEH", "Truck Light GP-only vehicle demand"), + ("TRKLTOLL_VEH", "Truck Light toll vehicle demand"), + ("TRK_M_VEH", "Truck Medium demand"), + ("TRKMGP_VEH", "Truck Medium GP-only vehicle demand"), + ("TRKMTOLL_VEH", "Truck Medium toll vehicle demand"), + ("TRK_H_VEH", "Truck Heavy demand"), + ("TRKHGP_VEH", "Truck Heavy GP-only vehicle demand"), + ("TRKHTOLL_VEH", "Truck Heavy toll vehicle demand"), + ] + for period in self._all_periods: + self.add_matrices("truck_model", period, + [("mf", period + "_" + name, period + " " + desc) + for name, desc in tmplt_matrices]) + + def commercial_vehicle_model(self): + # TODO : remove commercial vehicle matrices, no longer used + tmplt_matrices = [ + ('mo', 'COMVEH_PROD', 'Commercial vehicle production'), + ('md', 'COMVEH_ATTR', 'Commercial vehicle attraction'), + ('mf', 'COMVEH_BLENDED_SKIM', 'Commercial vehicle blended skim'), + ('mf', 'COMVEH_FRICTION', 'Commercial vehicle friction factors'), + ('mf', 'COMVEH_TOTAL_DEMAND', 'Commercial vehicle total demand all periods'), + ] + self.add_matrices("commercial_vehicle_model", "ALL", + [(ident, name, desc) for ident, name, desc in tmplt_matrices]) + + tmplt_matrices = [ + ('COMVEH', 'Commerical vehicle total demand'), + ('COMVEHGP', 'Commerical vehicle GP demand'), + ('COMVEHTOLL', 'Commerical vehicle Toll demand'), + ] + for period in self._all_periods: + self.add_matrices("commercial_vehicle_model", period, + [("mf", period + "_" + name, period + " " + desc) + for name, desc in tmplt_matrices]) + + def external_internal_model(self): + tmplt_matrices = [ + ('SOVTOLL_EIWORK', 'US to SD SOV Work TOLL demand'), + ('HOV2TOLL_EIWORK', 'US to SD HOV2 Work TOLL demand'), + ('HOV3TOLL_EIWORK', 'US to SD HOV3 Work TOLL demand'), + ('SOVGP_EIWORK', 'US to SD SOV Work GP demand'), + ('HOV2HOV_EIWORK', 'US to SD HOV2 Work HOV demand'), + ('HOV3HOV_EIWORK', 'US to SD HOV3 Work HOV demand'), + ('SOVTOLL_EINONWORK', 'US to SD SOV Non-Work TOLL demand'), + ('HOV2TOLL_EINONWORK', 'US to SD HOV2 Non-Work TOLL demand'), + ('HOV3TOLL_EINONWORK', 'US to SD HOV3 Non-Work TOLL demand'), + ('SOVGP_EINONWORK', 'US to SD SOV Non-Work GP demand'), + ('HOV2HOV_EINONWORK', 'US to SD HOV2 Non-Work HOV demand'), + ('HOV3HOV_EINONWORK', 'US to SD HOV3 Non-Work HOV demand'), + ] + for period in self._all_periods: + self.add_matrices("external_internal_model", period, + [("mf", period + "_" + name, period + " " + desc) + for name, desc in tmplt_matrices]) + + def external_external_model(self): + self.add_matrices("external_external_model", "ALL", + [("mf", "ALL_TOTAL_EETRIPS", "All periods Total for all modes external-external trips")]) + tmplt_matrices = [ + ('SOV_EETRIPS', 'SOV external-external demand'), + ('HOV2_EETRIPS', 'HOV2 external-external demand'), + ('HOV3_EETRIPS', 'HOV3 external-external demand'), + ] + for period in self._all_periods: + self.add_matrices("external_external_model", period, + [("mf", period + "_" + name, period + " " + desc) + for name, desc in tmplt_matrices]) + + def add_matrices(self, component, period, matrices): + for ident, name, desc in matrices: + self._matrices[component][period].append([ident+str(self._count[ident]), name, desc]) + self._count[ident] += 1 + + def create_matrices(self, component, periods): + with _m.logbook_trace("Create matrices for component %s" % (component.replace("_", " "))): + emmebank = self.scenario.emmebank + matrices = [] + for period in periods + ["ALL"]: + with _m.logbook_trace("For period %s" % (period)): + for ident, name, desc in self._matrices[component][period]: + existing_matrix = emmebank.matrix(name) + if existing_matrix and (existing_matrix.id != ident): + raise Exception("Matrix name conflict '%s', with id %s instead of %s. Delete all matrices first." + % (name, existing_matrix.id, ident)) + matrices.append(self._create_matrix_tool(ident, name, desc, scenario=self.scenario, overwrite=True)) + return matrices + + def get_matrix_names(self, component, periods, scenario): + self.generate_matrix_list(scenario) + matrices = [] + for period in periods: + matrices.extend([m[1] for m in self._matrices[component][period]]) + return matrices + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg diff --git a/sandag_abm/src/main/emme/toolbox/initialize/initialize_transit_database.py b/sandag_abm/src/main/emme/toolbox/initialize/initialize_transit_database.py new file mode 100644 index 0000000..513dba3 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/initialize/initialize_transit_database.py @@ -0,0 +1,168 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// initialize_transit_databse.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Coordinates the initialization of all matrices. +# The matrix names are listed for each of the model components / steps, +# and the matrix IDs are assigned consistently from the set of matrices. +# In each of the model steps the matrices are only referenced by name, +# never by ID. +# +# +# Inputs: +# components: A list of the model components / steps for which to initialize matrices +# One or more of "traffic_demand", "transit_demand", +# "traffic_skims", "transit_skims", "external_internal_model", +# "external_external_model", "truck_model", "commercial_vehicle_model" +# periods: A list of periods for which to initialize matrices, "EA", "AM", "MD", "PM", "EV" +# scenario: scenario to use for reference zone system and the emmebank in which +# the matrices will be created. Defaults to the current primary scenario. +# +# Script example: +""" + import os + import inro.emme.database.emmebank as _eb + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + main_emmebank = _eb.Emmebank(os.path.join(main_directory, "emme_project", "Database", "emmebank")) + base_scenario = main_emmebank.scenario(100) + initialize_transit_db = modeller.tool("sandag.initialize.initialize_transit_database") + initialize_transit_db(base_scenario) +""" +TOOLBOX_ORDER = 8 + + +import inro.modeller as _m +import inro.emme.network as _network +import inro.emme.database.emmebank as _eb +from inro.emme.desktop.exception import AddDatabaseError +import traceback as _traceback +import shutil as _shutil +import time +import os + +join = os.path.join + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class InitializeTransitDatabase(_m.Tool(), gen_utils.Snapshot): + + base_scenario = _m.Attribute(_m.InstanceType) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self.base_scenario = _m.Modeller().scenario + self.attributes = ["base_scenario"] + + def from_snapshot(self, snapshot): + super(InitializeTransitDatabase, self).from_snapshot(snapshot) + # custom from_snapshot to load scenario object + self.base_scenario = _m.Modeller().emmebank.scenario(self.base_scenario) + return self + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Initialize transit database" + pb.description = """Create and setup database for transit assignments under 'Database_transit' directory. + Will overwrite an existing database. The TAZs will be removed and TAP nodes converted to zones.""" + pb.branding_text = "- SANDAG" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_scenario("base_scenario", + title="Base scenario:", note="Base traffic and transit scenario with TAZs.") + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self(self.base_scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Initialize transit database', save_arguments=True) + def __call__(self, base_scenario, add_database=True): + attributes = {"base_scenario": base_scenario.id} + gen_utils.log_snapshot("Initialize transit database", str(self), attributes) + create_function = _m.Modeller().tool("inro.emme.data.function.create_function") + build_transit_scen = _m.Modeller().tool("sandag.assignment.build_transit_scenario") + load_properties = _m.Modeller().tool('sandag.utilities.properties') + + base_eb = base_scenario.emmebank + project_dir = os.path.dirname(os.path.dirname(base_eb.path)) + main_directory = os.path.dirname(project_dir) + props = load_properties(os.path.join(main_directory, "conf", "sandag_abm.properties")) + scenarioYear = props["scenarioYear"] + + transit_db_dir = join(project_dir, "Database_transit") + transit_db_path = join(transit_db_dir, "emmebank") + network = base_scenario.get_partial_network(["NODE"], include_attributes=True) + num_zones = sum([1 for n in network.nodes() if n["@tap_id"] > 0]) + dimensions = base_eb.dimensions + dimensions["centroids"] = num_zones + dimensions["scenarios"] = 10 + if not os.path.exists(transit_db_dir): + os.mkdir(transit_db_dir) + if os.path.exists(transit_db_path): + transit_eb = _eb.Emmebank(transit_db_path) + for scenario in transit_eb.scenarios(): + transit_eb.delete_scenario(scenario.id) + for function in transit_eb.functions(): + transit_eb.delete_function(function.id) + if transit_eb.dimensions != dimensions: + _eb.change_dimensions(transit_db_path, dimensions, keep_backup=False) + else: + transit_eb = _eb.create(transit_db_path, dimensions) + + transit_eb.title = base_eb.title[:65] + "-transit" + transit_eb.coord_unit_length = base_eb.coord_unit_length + transit_eb.unit_of_length = base_eb.unit_of_length + transit_eb.unit_of_cost = base_eb.unit_of_cost + transit_eb.unit_of_energy = base_eb.unit_of_energy + transit_eb.use_engineering_notation = base_eb.use_engineering_notation + transit_eb.node_number_digits = base_eb.node_number_digits + + zone_scenario = build_transit_scen( + period="AM", base_scenario=base_scenario, transit_emmebank=transit_eb, + scenario_id=base_scenario.id, scenario_title="%s transit zones" % (base_scenario.title), + data_table_name=scenarioYear, overwrite=True) + for function in base_scenario.emmebank.functions(): + create_function(function.id, function.expression, transit_eb) + if add_database: + self.add_database(transit_eb) + return zone_scenario + + def add_database(self, emmebank): + modeller = _m.Modeller() + desktop = modeller.desktop + data_explorer = desktop.data_explorer() + for db in data_explorer.databases(): + if os.path.normpath(db.path) == os.path.normpath(emmebank.path): + return + try: + data_explorer.add_database(emmebank.path) + except AddDatabaseError: + pass # database has already been added to the project diff --git a/sandag_abm/src/main/emme/toolbox/master_run.py b/sandag_abm/src/main/emme/toolbox/master_run.py new file mode 100644 index 0000000..de0a8ad --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/master_run.py @@ -0,0 +1,1220 @@ +# ////////////////////////////////////////////////////////////////////////////// +# //// /// +# //// Copyright INRO, 2016-2017. /// +# //// Rights to use and modify are granted to the /// +# //// San Diego Association of Governments and partner agencies. /// +# //// This copyright notice must be preserved. /// +# //// /// +# //// model/master_run.py /// +# //// /// +# //// /// +# //// /// +# //// /// +# ////////////////////////////////////////////////////////////////////////////// +# +# The Master run tool is the primary method to operate the SANDAG +# travel demand model. It operates all the model components. +# +# main_directory: Main ABM directory: directory which contains all of the +# ABM scenario data, including this project. The default is the parent +# directory of the current Emme project. +# scenario_id: Scenario ID for the base imported network data. The result +# scenarios are indexed in the next five scenarios by time period. +# scenario_title: title to use for the scenario. +# emmebank_title: title to use for the Emmebank (Emme database) +# num_processors: the number of processors to use for traffic and transit +# assignments and skims, aggregate demand models (where required) and +# other parallelized procedures in Emme. Default is Max available - 1. +# Properties loaded from conf/sandag_abm.properties: +# When using the tool UI, the sandag_abm.properties file is read +# and the values cached and the inputs below are pre-set. When the tool +# is started button is clicked this file is written out with the +# values specified. +# Sample rate by iteration: three values for the sample rates for each iteration +# Start from iteration: iteration from which to start the model run +# Skip steps: optional checkboxes to skip model steps. +# Note that most steps are dependent upon the results of the previous steps. +# Select link: add select link analyses for traffic. +# See the Select link analysis section under the Traffic assignment tool. +# +# Also reads and processes the per-scenario +# vehicle_class_availability.csv (optional): 0 or 1 indicators by vehicle class and specified facilities to indicate availability +# +# Script example: +""" +import inro.modeller as _m +import os +modeller = _m.Modeller() +desktop = modeller.desktop + +master_run = modeller.tool("sandag.master_run") +main_directory = os.path.dirname(os.path.dirname(desktop.project_path())) +scenario_id = 100 +scenario_title = "Base 2015 scenario" +emmebank_title = "Base 2015 with updated landuse" +num_processors = "MAX-1" +master_run(main_directory, scenario_id, scenario_title, emmebank_title, num_processors) +""" + +TOOLBOX_ORDER = 1 +VIRUTALENV_PATH = "C:\\python_virtualenv\\abm14_2_0" + +import inro.modeller as _m +import inro.emme.database.emmebank as _eb + +import traceback as _traceback +import glob as _glob +import subprocess as _subprocess +import ctypes as _ctypes +import json as _json +import shutil as _shutil +import tempfile as _tempfile +from copy import deepcopy as _copy +from collections import defaultdict as _defaultdict +import time as _time +import socket as _socket +import sys +import os + +import pandas as pd +import numpy as np +import csv +import datetime +import pyodbc +import win32com.client as win32 + +_join = os.path.join +_dir = os.path.dirname +_norm = os.path.normpath + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") +props_utils = _m.Modeller().module("sandag.utilities.properties") + + +class MasterRun(props_utils.PropertiesSetter, _m.Tool(), gen_utils.Snapshot): + main_directory = _m.Attribute(unicode) + scenario_id = _m.Attribute(int) + scenario_title = _m.Attribute(unicode) + emmebank_title = _m.Attribute(unicode) + num_processors = _m.Attribute(str) + select_link = _m.Attribute(unicode) + username = _m.Attribute(unicode) + password = _m.Attribute(unicode) + + properties_path = _m.Attribute(unicode) + + tool_run_msg = "" + + def __init__(self): + super(MasterRun, self).__init__() + project_dir = _dir(_m.Modeller().desktop.project.path) + self.main_directory = _dir(project_dir) + self.properties_path = _join(_dir(project_dir), "conf", "sandag_abm.properties") + self.scenario_id = 100 + self.scenario_title = "" + self.emmebank_title = "" + self.num_processors = "MAX-1" + self.select_link = '[]' + self.username = os.environ.get("USERNAME") + self.attributes = [ + "main_directory", "scenario_id", "scenario_title", "emmebank_title", + "num_processors", "select_link" + ] + self._log_level = "ENABLED" + self.LOCAL_ROOT = "C:\\abm_runs" + + def page(self): + self.load_properties() + pb = _m.ToolPageBuilder(self) + pb.title = "Master run ABM" + pb.description = """Runs the SANDAG ABM, assignments, and other demand model tools.""" + pb.branding_text = "- SANDAG - Model" + tool_proxy_tag = pb.tool_proxy_tag + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('main_directory', 'directory', + title='Select main ABM directory', note='') + pb.add_text_box('scenario_id', title="Scenario ID:") + pb.add_text_box('scenario_title', title="Scenario title:", size=80) + pb.add_text_box('emmebank_title', title="Emmebank title:", size=60) + dem_utils.add_select_processors("num_processors", pb, self) + + # username and password input for distributed assignment + # username also used in the folder name for the local drive operation + pb.add_html(''' +
+
Credentials for remote run
+
+ Username: + + Password: + +
+
+ Note: required for running distributed traffic assignments using PsExec. +
+ Distributed / single node modes are configured in "config/server-config.csv". +
The username is also used for the folder name when running on the local drive. +
+
''' % {"tool_proxy_tag": tool_proxy_tag}) + + # defined in properties utilities + self.add_properties_interface(pb, disclosure=True) + # redirect properties file after browse of main_directory + pb.add_html(""" +""" % {"tool_proxy_tag": tool_proxy_tag}) + + traffic_assign = _m.Modeller().tool("sandag.assignment.traffic_assignment") + traffic_assign._add_select_link_interface(pb) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self.save_properties() + self(self.main_directory, self.scenario_id, self.scenario_title, self.emmebank_title, + self.num_processors, self.select_link, username=self.username, password=self.password) + run_msg = "Model run complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception(error, _traceback.format_exc()) + + raise + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + @_m.logbook_trace("Master run model", save_arguments=True) + def __call__(self, main_directory, scenario_id, scenario_title, emmebank_title, num_processors, + select_link=None, periods=["EA", "AM", "MD", "PM", "EV"], username=None, password=None): + attributes = { + "main_directory": main_directory, + "scenario_id": scenario_id, + "scenario_title": scenario_title, + "emmebank_title": emmebank_title, + "num_processors": num_processors, + "select_link": select_link, + "periods": periods, + "username": username, + } + gen_utils.log_snapshot("Master run model", str(self), attributes) + + modeller = _m.Modeller() + # Checking that the virtualenv path is set and the folder is installed + if not os.path.exists(VIRUTALENV_PATH): + raise Exception("Python virtual environment not installed at expected location %s" % VIRUTALENV_PATH) + venv_path = os.environ.get("PYTHON_VIRTUALENV") + if not venv_path: + raise Exception("Environment variable PYTHON_VIRTUALENV not set, start Emme from 'start_emme_with_virtualenv.bat'") + if not venv_path == VIRUTALENV_PATH: + raise Exception("PYTHON_VIRTUALENV is not the expected value (%s instead of %s)" % (venv_path, VIRUTALENV_PATH)) + venv_path_found = False + for path in sys.path: + if VIRUTALENV_PATH in path: + venv_path_found = True + break + if not venv_path_found: + raise Exception("Python virtual environment not found in system path %s" % VIRUTALENV_PATH) + copy_scenario = modeller.tool("inro.emme.data.scenario.copy_scenario") + run4Ds = modeller.tool("sandag.import.run4Ds") + import_network = modeller.tool("sandag.import.import_network") + input_checker = modeller.tool("sandag.import.input_checker") + init_transit_db = modeller.tool("sandag.initialize.initialize_transit_database") + init_matrices = modeller.tool("sandag.initialize.initialize_matrices") + import_demand = modeller.tool("sandag.import.import_seed_demand") + build_transit_scen = modeller.tool("sandag.assignment.build_transit_scenario") + transit_assign = modeller.tool("sandag.assignment.transit_assignment") + run_truck = modeller.tool("sandag.model.truck.run_truck_model") + external_internal = modeller.tool("sandag.model.external_internal") + external_external = modeller.tool("sandag.model.external_external") + import_auto_demand = modeller.tool("sandag.import.import_auto_demand") + import_transit_demand = modeller.tool("sandag.import.import_transit_demand") + export_transit_skims = modeller.tool("sandag.export.export_transit_skims") + export_for_transponder = modeller.tool("sandag.export.export_for_transponder") + export_network_data = modeller.tool("sandag.export.export_data_loader_network") + export_matrix_data = modeller.tool("sandag.export.export_data_loader_matrices") + export_tap_adjacent_lines = modeller.tool("sandag.export.export_tap_adjacent_lines") + export_for_commercial_vehicle = modeller.tool("sandag.export.export_for_commercial_vehicle") + validation = modeller.tool("sandag.validation.validation") + file_manager = modeller.tool("sandag.utilities.file_manager") + utils = modeller.module('sandag.utilities.demand') + load_properties = modeller.tool('sandag.utilities.properties') + run_summary = modeller.tool("sandag.utilities.run_summary") + + self.username = username + self.password = password + + props = load_properties(_join(main_directory, "conf", "sandag_abm.properties")) + props.set_year_specific_properties(_join(main_directory, "input", "parametersByYears.csv")) + props.set_year_specific_properties(_join(main_directory, "input", "filesByYears.csv")) + props.save() + # Log current state of props file for debugging of UI / file sync issues + attributes = dict((name, props["RunModel." + name]) for name in self._run_model_names) + _m.logbook_write("SANDAG properties file", attributes=attributes) + if self._properties: # Tool has been called via the UI + # Compare UI values and file values to make sure they are the same + error_text = ("Different value found in sandag_abm.properties than specified in UI for '%s'. " + "Close sandag_abm.properties if open in any text editor, check UI and re-run.") + for name in self._run_model_names: + if getattr(self, name) != props["RunModel." + name]: + raise Exception(error_text % name) + + scenarioYear = str(props["scenarioYear"]) + startFromIteration = props["RunModel.startFromIteration"] + precision = props["RunModel.MatrixPrecision"] + minSpaceOnC = props["RunModel.minSpaceOnC"] + sample_rate = props["sample_rates"] + end_iteration = len(sample_rate) + scale_factor = props["cvm.scale_factor"] + visualizer_reference_path = props["visualizer.reference.path"] + visualizer_output_file = props["visualizer.output"] + visualizer_reference_label = props["visualizer.reference.label"] + visualizer_build_label = props["visualizer.build.label"] + mgraInputFile = props["mgra.socec.file"] + + #for zone restructing in network files + taz_cwk_file = props["taz.to.cluster.crosswalk.file"] + cluster_zone_file = props["cluster.zone.centroid.file"] + + period_ids = list(enumerate(periods, start=int(scenario_id) + 1)) + + useLocalDrive = props["RunModel.useLocalDrive"] + + skip4Ds = props["RunModel.skip4Ds"] + skipInputChecker = props["RunModel.skipInputChecker"] + skipInitialization = props["RunModel.skipInitialization"] + deleteAllMatrices = props["RunModel.deleteAllMatrices"] + skipCopyWarmupTripTables = props["RunModel.skipCopyWarmupTripTables"] + skipCopyBikeLogsum = props["RunModel.skipCopyBikeLogsum"] + skipCopyWalkImpedance = props["RunModel.skipCopyWalkImpedance"] + skipWalkLogsums = props["RunModel.skipWalkLogsums"] + skipBikeLogsums = props["RunModel.skipBikeLogsums"] + skipBuildNetwork = props["RunModel.skipBuildNetwork"] + skipHighwayAssignment = props["RunModel.skipHighwayAssignment"] + skipTransitSkimming = props["RunModel.skipTransitSkimming"] + skipTransponderExport = props["RunModel.skipTransponderExport"] + skipCoreABM = props["RunModel.skipCoreABM"] + skipOtherSimulateModel = props["RunModel.skipOtherSimulateModel"] + skipMAASModel = props["RunModel.skipMAASModel"] + skipCTM = props["RunModel.skipCTM"] + skipEI = props["RunModel.skipEI"] + skipExternal = props["RunModel.skipExternalExternal"] + skipTruck = props["RunModel.skipTruck"] + skipTripTableCreation = props["RunModel.skipTripTableCreation"] + skipFinalHighwayAssignment = props["RunModel.skipFinalHighwayAssignment"] + skipFinalHighwayAssignmentStochastic = props["RunModel.skipFinalHighwayAssignmentStochastic"] + if skipFinalHighwayAssignmentStochastic == True: + makeFinalHighwayAssignmentStochastic = False + else: + makeFinalHighwayAssignmentStochastic = True + skipFinalTransitAssignment = props["RunModel.skipFinalTransitAssignment"] + skipVisualizer = props["RunModel.skipVisualizer"] + skipDataExport = props["RunModel.skipDataExport"] + skipDataLoadRequest = props["RunModel.skipDataLoadRequest"] + skipDeleteIntermediateFiles = props["RunModel.skipDeleteIntermediateFiles"] + skipTransitShed = props["RunModel.skipTransitShed"] + transitShedThreshold = props["transitShed.threshold"] + transitShedTOD = props["transitShed.TOD"] + + #check if visualizer.reference.path is valid in filesbyyears.csv + if not os.path.exists(visualizer_reference_path): + raise Exception("Visualizer reference %s does not exist. Check filesbyyears.csv." %(visualizer_reference_path)) + + if useLocalDrive: + folder_name = os.path.basename(main_directory) + if not os.path.exists(_join(self.LOCAL_ROOT, username, folder_name, "report")): # check free space only if it is a new run + self.check_free_space(minSpaceOnC) + # if initialization copy ALL files from remote + # else check file meta data and copy those that have changed + initialize = (skipInitialization == False and startFromIteration == 1) + local_directory = file_manager( + "DOWNLOAD", main_directory, username, scenario_id, initialize=initialize) + self._path = local_directory + else: + self._path = main_directory + + drive, path_no_drive = os.path.splitdrive(self._path) + path_forward_slash = path_no_drive.replace("\\", "/") + input_dir = _join(self._path, "input") + input_truck_dir = _join(self._path, "input_truck") + output_dir = _join(self._path, "output") + validation_dir = _join(self._path, "analysis/validation") + main_emmebank = _eb.Emmebank(_join(self._path, "emme_project", "Database", "emmebank")) + if emmebank_title: + main_emmebank.title = emmebank_title + external_zones = "1-12" + + travel_modes = ["auto", "tran", "nmot", "othr"] + core_abm_files = ["Trips*.omx", "InternalExternalTrips*.omx"] + core_abm_files = [mode + name for name in core_abm_files for mode in travel_modes] + smm_abm_files = ["AirportTrips*.omx", "CrossBorderTrips*.omx", "VisitorTrips*.omx"] + smm_abm_files = [mode + name for name in smm_abm_files for mode in travel_modes] + maas_abm_files = ["EmptyAVTrips.omx", "TNCVehicleTrips*.omx"] + + relative_gap = props["convergence"] + max_assign_iterations = 1000 + mgra_lu_input_file = props["mgra.socec.file"] + + with _m.logbook_trace("Setup and initialization"): + self.set_global_logbook_level(props) + + # Swap Server Configurations + self.run_proc("serverswap.bat", [drive, path_no_drive, path_forward_slash], "Run ServerSwap") + self.check_for_fatal(_join(self._path, "logFiles", "serverswap.log"), + "ServerSwap failed! Open logFiles/serverswap.log for details.") + self.run_proc("checkAtTransitNetworkConsistency.cmd", [drive, path_forward_slash], + "Checking if AT and Transit Networks are consistent") + self.check_for_fatal(_join(self._path, "logFiles", "AtTransitCheck_event.log"), + "AT and Transit network consistency checking failed! Open AtTransitCheck_event.log for details.") + + if startFromIteration == 1: # only run the setup / init steps if starting from iteration 1 + if not skipWalkLogsums: + self.run_proc("runSandagWalkLogsums.cmd", [drive, path_forward_slash], + "Walk - create AT logsums and impedances") + if not skipCopyWalkImpedance: + self.copy_files(["walkMgraEquivMinutes.csv", "walkMgraTapEquivMinutes.csv", "microMgraEquivMinutes.csv", "microMgraTapEquivMinutes.csv"], + input_dir, output_dir) + + if not skip4Ds: + run4Ds(path=self._path, int_radius=0.65, ref_path=visualizer_reference_path) + + + mgraFile = 'mgra13_based_input' + str(scenarioYear) + '.csv' + self.complete_work(scenarioYear, input_dir, output_dir, mgraFile, "walkMgraEquivMinutes.csv") + + if not skipBuildNetwork: + base_scenario = import_network( + source=input_dir, + merged_scenario_id=scenario_id, + title=scenario_title, + data_table_name=scenarioYear, + overwrite=True, + emmebank=main_emmebank) + + if "modify_network.py" in os.listdir(os.getcwd()): + try: + with _m.logbook_trace("Modify network script"): + import modify_network + reload(modify_network) + modify_network.run(base_scenario) + except ImportError as e: + pass + + hwy_network = self.update_centroid_connectors( + input_dir, + base_scenario, + main_emmebank, + external_zones, + taz_cwk_file, + cluster_zone_file) + + base_scenario.publish_network(hwy_network) + + if not skipInputChecker: + input_checker(path=self._path) + + export_tap_adjacent_lines(_join(output_dir, "tapLines.csv"), base_scenario) + # parse vehicle availablility file by time-of-day + availability_file = "vehicle_class_availability.csv" + availabilities = self.parse_availability_file(_join(input_dir, availability_file), periods) + # initialize per time-period scenarios + for number, period in period_ids: + title = "%s - %s assign" % (base_scenario.title, period) + # copy_scenario(base_scenario, number, title, overwrite=True) + _m.logbook_write( + name="Copy scenario %s to %s" % (base_scenario.number, number), + attributes={ + 'from_scenario': base_scenario.number, + 'scenario_id': number, + 'overwrite': True, + 'scenario_title': title + } + ) + if main_emmebank.scenario(number): + main_emmebank.delete_scenario(number) + scenario = main_emmebank.copy_scenario(base_scenario.number, number) + scenario.title = title + # Apply availabilities by facility and vehicle class to this time period + self.apply_availabilities(period, scenario, availabilities) + else: + base_scenario = main_emmebank.scenario(scenario_id) + + if not skipInitialization: + # initialize traffic demand, skims, truck, CV, EI, EE matrices + traffic_components = [ + "traffic_skims", + "truck_model", + "external_internal_model", "external_external_model"] + if not skipCopyWarmupTripTables: + traffic_components.append("traffic_demand") + init_matrices(traffic_components, periods, base_scenario, deleteAllMatrices) + + transit_scenario = init_transit_db(base_scenario, add_database=not useLocalDrive) + transit_emmebank = transit_scenario.emmebank + transit_components = ["transit_skims"] + if not skipCopyWarmupTripTables: + transit_components.append("transit_demand") + init_matrices(transit_components, periods, transit_scenario, deleteAllMatrices) + else: + transit_emmebank = _eb.Emmebank(_join(self._path, "emme_project", "Database_transit", "emmebank")) + transit_scenario = transit_emmebank.scenario(base_scenario.number) + + if not skipCopyWarmupTripTables: + # import seed auto demand and seed truck demand + for period in periods: + omx_file = _join(input_dir, "trip_%s.omx" % period) + import_demand(omx_file, "AUTO", period, base_scenario) + import_demand(omx_file, "TRUCK", period, base_scenario) + + if not skipBikeLogsums: + self.run_proc("runSandagBikeLogsums.cmd", [drive, path_forward_slash], + "Bike - create AT logsums and impedances") + if not skipCopyBikeLogsum: + self.copy_files(["bikeMgraLogsum.csv", "bikeTazLogsum.csv"], input_dir, output_dir) + + else: + base_scenario = main_emmebank.scenario(scenario_id) + transit_emmebank = _eb.Emmebank(_join(self._path, "emme_project", "Database_transit", "emmebank")) + transit_scenario = transit_emmebank.scenario(base_scenario.number) + + # Check that setup files were generated + self.run_proc("CheckOutput.bat", [drive + path_no_drive, 'Setup'], "Check for outputs") + + # Note: iteration indexes from 0, msa_iteration indexes from 1 + for iteration in range(startFromIteration - 1, end_iteration): + msa_iteration = iteration + 1 + with _m.logbook_trace("Iteration %s" % msa_iteration): + if not skipCoreABM[iteration] or not skipOtherSimulateModel[iteration] or not skipMAASModel[iteration]: + self.run_proc("runMtxMgr.cmd", [drive, drive + path_no_drive], "Start matrix manager") + self.run_proc("runHhMgr.cmd", [drive, drive + path_no_drive], "Start Hh manager") + + if not skipHighwayAssignment[iteration]: + # run traffic assignment + # export traffic skims + with _m.logbook_trace("Traffic assignment and skims"): + self.run_traffic_assignments( + base_scenario, period_ids, msa_iteration, relative_gap, + max_assign_iterations, num_processors) + self.run_proc("CreateD2TAccessFile.bat", [drive, path_forward_slash], + "Create drive to transit access file", capture_output=True) + + if not skipTransitSkimming[iteration]: + # run transit assignment + # export transit skims + with _m.logbook_trace("Transit assignments and skims"): + for number, period in period_ids: + src_period_scenario = main_emmebank.scenario(number) + transit_assign_scen = build_transit_scen( + period=period, base_scenario=src_period_scenario, + transit_emmebank=transit_emmebank, + scenario_id=src_period_scenario.id, + scenario_title="%s %s transit assign" % (base_scenario.title, period), + data_table_name=scenarioYear, overwrite=True) + transit_assign(period, transit_assign_scen, data_table_name=scenarioYear, + skims_only=True, num_processors=num_processors) + + omx_file = _join(output_dir, "transit_skims.omx") + export_transit_skims(omx_file, periods, transit_scenario) + + if not skipTransponderExport[iteration]: + am_scenario = main_emmebank.scenario(base_scenario.number + 2) + export_for_transponder(output_dir, num_processors, am_scenario) + + # For each step move trip matrices so run will stop if ctramp model + # doesn't produced csv/omx files for assignment + # also needed as CT-RAMP does not overwrite existing files + if not skipCoreABM[iteration]: + self.remove_prev_iter_files(core_abm_files, output_dir, iteration) + self.run_proc( + "runSandagAbm_SDRM.cmd", + [drive, drive + path_forward_slash, sample_rate[iteration], msa_iteration], + "Java-Run CT-RAMP", capture_output=True) + if not skipOtherSimulateModel[iteration]: + self.remove_prev_iter_files(smm_abm_files, output_dir, iteration) + self.run_proc( + "runSandagAbm_SMM.cmd", + [drive, drive + path_forward_slash, sample_rate[iteration], msa_iteration], + "Java-Run airport model, visitor model, cross-border model", capture_output=True) + + if not skipMAASModel[iteration]: + self.remove_prev_iter_files(maas_abm_files, output_dir, iteration) + self.run_proc( + "runSandagAbm_MAAS.cmd", + [drive, drive + path_forward_slash, sample_rate[iteration], msa_iteration], + "Java-Run AV allocation model and TNC routing model", capture_output=True) + + if not skipCTM[iteration]: + export_for_commercial_vehicle(output_dir, base_scenario) + self.run_proc( + "cvm.bat", + [drive, path_no_drive, path_forward_slash, scale_factor, mgra_lu_input_file, + "tazcentroids_cvm.csv"], + "Commercial vehicle model", capture_output=True) + if msa_iteration == startFromIteration: + external_zones = "1-12" + if not skipTruck[iteration]: + # run truck model (generate truck trips) + run_truck(True, input_dir, input_truck_dir, num_processors, base_scenario) + # run EI model "US to SD External Trip Model" + if not skipEI[iteration]: + external_internal(input_dir, base_scenario) + # run EE model + if not skipExternal[iteration]: + external_external(input_dir, external_zones, base_scenario) + + # import demand from all sub-market models from CT-RAMP and + # add CV trips to auto demand + # add EE and EI trips to auto demand + if not skipTripTableCreation[iteration]: + import_auto_demand(output_dir, external_zones, num_processors, base_scenario) + + if not skipFinalHighwayAssignment: + with _m.logbook_trace("Final traffic assignments"): + # Final iteration is assignment only, no skims + final_iteration = 4 + self.run_traffic_assignments( + base_scenario, period_ids, final_iteration, relative_gap, max_assign_iterations, + num_processors, select_link, makeFinalHighwayAssignmentStochastic, input_dir) + + if not skipFinalTransitAssignment: + import_transit_demand(output_dir, transit_scenario) + with _m.logbook_trace("Final transit assignments"): + # Final iteration includes the transit skims per ABM-1072 + for number, period in period_ids: + src_period_scenario = main_emmebank.scenario(number) + transit_assign_scen = build_transit_scen( + period=period, base_scenario=src_period_scenario, + transit_emmebank=transit_emmebank, scenario_id=src_period_scenario.id, + scenario_title="%s - %s transit assign" % (base_scenario.title, period), + data_table_name=scenarioYear, overwrite=True) + transit_assign(period, transit_assign_scen, data_table_name=scenarioYear, + num_processors=num_processors) + omx_file = _join(output_dir, "transit_skims.omx") + export_transit_skims(omx_file, periods, transit_scenario, big_to_zero=True) + + if not skipTransitShed: + # write walk and drive transit sheds + self.run_proc("runtransitreporter.cmd", [drive, path_forward_slash, transitShedThreshold, transitShedTOD], + "Create walk and drive transit sheds", + capture_output=True) + + if not skipVisualizer: + self.run_proc("RunViz.bat", + [drive, path_no_drive, visualizer_reference_path, visualizer_output_file, "NO", visualizer_reference_label, visualizer_build_label, mgraInputFile], + "HTML Visualizer", capture_output=True) + + if not skipDataExport: + # export network and matrix results from Emme directly to T if using local drive + output_directory = _join(self._path, "output") + export_network_data(self._path, scenario_id, main_emmebank, transit_emmebank, num_processors) + export_matrix_data(output_directory, base_scenario, transit_scenario) + # export core ABM data + # Note: uses relative project structure, so cannot redirect to T drive + self.run_proc("DataExporter.bat", [drive, path_no_drive], "Export core ABM data",capture_output=True) + + #Validation for 2016 scenario + if scenarioYear == "2016": + validation(self._path, main_emmebank, base_scenario) # to create source_EMME.xlsx + + # #Create Worksheet for ABM Validation using PowerBI Visualization #JY: can be uncommented if deciding to incorporate PowerBI vis in ABM workflow + # self.run_proc("VisPowerBI.bat", # forced to update excel links + # [drive, path_no_drive, scenarioYear, 0], + # "VisPowerBI", + # capture_output=True) + + ### CL: Below step is temporarily used to update validation output files. When Gregor complete Upload procedure, below step should be removed. 05/31/20 + # self.run_proc("ExcelUpdate.bat", # forced to update excel links + # [drive, path_no_drive, scenarioYear, 0], + # "ExcelUpdate", + # capture_output=True) + + ### ES: Commented out until this segment is updated to reference new database. 9/10/20 ### + # add segments below for auto-reporting, YMA, 1/23/2019 + # add this loop to find the sceanro_id in the [dimension].[scenario] table + + #database_scenario_id = 0 + #int_hour = 0 + #while int_hour <= 96: + + # database_scenario_id = self.sql_select_scenario(scenarioYear, end_iteration, + # sample_rate[end_iteration - 1], path_no_drive, + # start_db_time) + # if database_scenario_id > 0: + # break + + # int_hour = int_hour + 1 + # _time.sleep(900) # wait for 15 mins + + # if load failed, then send notification email + #if database_scenario_id == 0 and int_hour > 96: + # str_request_check_result = self.sql_check_load_request(scenarioYear, path_no_drive, username, + # start_db_time) + # print(str_request_check_result) + # sys.exit(0) + # self.send_notification(str_request_check_result,username) #not working in server + #else: + # print(database_scenario_id) + # self.run_proc("DataSummary.bat", # get summary from database, added for auto-reporting + # [drive, path_no_drive, scenarioYear, database_scenario_id], + # "Data Summary") + + # self.run_proc("ExcelUpdate.bat", # forced to update excel links + # [drive, path_no_drive, scenarioYear, database_scenario_id], + # "Excel Update", + # capture_output=True) + + # terminate all java processes + _subprocess.call("taskkill /F /IM java.exe") + + # close all DOS windows + _subprocess.call("taskkill /F /IM cmd.exe") + + # UPLOAD DATA AND SWITCH PATHS + if useLocalDrive: + file_manager("UPLOAD", main_directory, username, scenario_id, + delete_local_files=not skipDeleteIntermediateFiles) + self._path = main_directory + drive, path_no_drive = os.path.splitdrive(self._path) + # self._path = main_directory + # drive, path_no_drive = os.path.splitdrive(self._path) + init_transit_db.add_database( + _eb.Emmebank(_join(main_directory, "emme_project", "Database_transit", "emmebank"))) + + if not skipDataLoadRequest: + start_db_time = datetime.datetime.now() # record the time to search for request id in the load request table, YMA, 1/23/2019 + # start_db_time = start_db_time + datetime.timedelta(minutes=0) + self.run_proc("DataLoadRequest.bat", + [drive + path_no_drive, end_iteration, scenarioYear, sample_rate[end_iteration - 1]], + "Data load request") + + # delete trip table files in iteration sub folder if model finishes without errors + if not useLocalDrive and not skipDeleteIntermediateFiles: + for msa_iteration in range(startFromIteration, end_iteration + 1): + self.delete_files( + ["auto*Trips*.omx", "tran*Trips*.omx", "nmot*.omx", "othr*.omx", "trip*.omx"], + _join(output_dir, "iter%s" % (msa_iteration))) + + # record run time + run_summary(path=self._path) + + def set_global_logbook_level(self, props): + self._log_level = props.get("RunModel.LogbookLevel", "ENABLED") + log_all = _m.LogbookLevel.ATTRIBUTE | _m.LogbookLevel.VALUE | _m.LogbookLevel.COOKIE | _m.LogbookLevel.TRACE | _m.LogbookLevel.LOG + log_states = { + "ENABLED": log_all, + "DISABLE_ON_ERROR": log_all, + "NO_EXTERNAL_REPORTS": log_all, + "NO_REPORTS": _m.LogbookLevel.ATTRIBUTE | _m.LogbookLevel.COOKIE | _m.LogbookLevel.TRACE | _m.LogbookLevel.LOG, + "TITLES_ONLY": _m.LogbookLevel.TRACE | _m.LogbookLevel.LOG, + "DISABLED": _m.LogbookLevel.NONE, + } + _m.logbook_write("Setting logbook level to %s" % self._log_level) + try: + _m.logbook_level(log_states[self._log_level]) + except KeyError: + raise Exception("properties.RunModel.LogLevel: value must be one of %s" % ",".join(log_states.keys())) + + def run_traffic_assignments(self, base_scenario, period_ids, msa_iteration, relative_gap, + max_assign_iterations, num_processors, select_link=None, + makeFinalHighwayAssignmentStochastic=False, input_dir=None): + modeller = _m.Modeller() + traffic_assign = modeller.tool("sandag.assignment.traffic_assignment") + export_traffic_skims = modeller.tool("sandag.export.export_traffic_skims") + output_dir = _join(self._path, "output") + main_emmebank = base_scenario.emmebank + + machine_name = _socket.gethostname().lower() + with open(_join(self._path, "conf", "server-config.csv")) as f: + columns = f.next().split(",") + for line in f: + values = dict(zip(columns, line.split(","))) + name = values["ServerName"].lower() + if name == machine_name: + server_config = values + break + else: + _m.logbook_write("Warning: current machine name not found in " + "conf\\server-config.csv ServerName column") + server_config = {"SNODE": "yes"} + distributed = server_config["SNODE"] == "no" + if distributed and not makeFinalHighwayAssignmentStochastic: + scen_map = dict((p, main_emmebank.scenario(n)) for n, p in period_ids) + input_args = { + "msa_iteration": msa_iteration, + "relative_gap": relative_gap, + "max_assign_iterations": max_assign_iterations, + "select_link": select_link + } + + periods_node1 = ["PM", "MD"] + input_args["num_processors"] = server_config["THREADN1"], + database_path1, skim_names1 = self.setup_remote_database( + [scen_map[p] for p in periods_node1], periods_node1, 1, msa_iteration) + self.start_assignments( + server_config["NODE1"], database_path1, periods_node1, scen_map, input_args) + + periods_node2 = ["AM"] + input_args["num_processors"] = server_config["THREADN2"] + database_path2, skim_names2 = self.setup_remote_database( + [scen_map[p] for p in periods_node2], periods_node2, 2, msa_iteration) + self.start_assignments( + server_config["NODE2"], database_path2, periods_node2, scen_map, input_args) + + try: + # run assignments locally + periods_local = ["EA", "EV"] + for period in periods_local: + local_scenario = scen_map[period] + traffic_assign(period, msa_iteration, relative_gap, max_assign_iterations, + num_processors, local_scenario, select_link) + omx_file = _join(output_dir, "traffic_skims_%s.omx" % period) + if msa_iteration <= 4: + export_traffic_skims(period, omx_file, base_scenario) + scenarios = { + database_path1: [scen_map[p] for p in periods_node1], + database_path2: [scen_map[p] for p in periods_node2] + } + skim_names = { + database_path1: skim_names1, database_path2: skim_names2 + } + self.wait_and_copy([database_path1, database_path2], scenarios, skim_names) + except: + # Note: this will kill ALL python processes - not suitable if servers are being + # used for other tasks + _subprocess.call("taskkill /F /T /S \\\\%s /IM python.exe" % server_config["NODE1"]) + _subprocess.call("taskkill /F /T /S \\\\%s /IM python.exe" % server_config["NODE2"]) + raise + else: + for number, period in period_ids: + period_scenario = main_emmebank.scenario(number) + traffic_assign(period, msa_iteration, relative_gap, max_assign_iterations, + num_processors, period_scenario, select_link, stochastic=makeFinalHighwayAssignmentStochastic, input_directory=input_dir) + omx_file = _join(output_dir, "traffic_skims_%s.omx" % period) + if msa_iteration <= 4: + export_traffic_skims(period, omx_file, base_scenario) + + def run_proc(self, name, arguments, log_message, capture_output=False): + path = _join(self._path, "bin", name) + if not os.path.exists(path): + raise Exception("No command / batch file '%s'" % path) + command = path + " " + " ".join([str(x) for x in arguments]) + attrs = {"command": command, "name": name, "arguments": arguments} + with _m.logbook_trace(log_message, attributes=attrs): + if capture_output and self._log_level != "NO_EXTERNAL_REPORTS": + report = _m.PageBuilder(title="Process run %s" % name) + report.add_html('Command:

%s

' % command) + # temporary file to capture output error messages generated by Java + err_file_ref, err_file_path = _tempfile.mkstemp(suffix='.log') + err_file = os.fdopen(err_file_ref, "w") + try: + output = _subprocess.check_output(command, stderr=err_file, cwd=self._path, shell=True) + report.add_html('Output:

%s
' % output) + except _subprocess.CalledProcessError as error: + report.add_html('Output:

%s
' % error.output) + raise + finally: + err_file.close() + with open(err_file_path, 'r') as f: + error_msg = f.read() + os.remove(err_file_path) + if error_msg: + report.add_html('Error message(s):

%s
' % error_msg) + try: + # No raise on writing report error + # due to observed issue with runs generating reports which cause + # errors when logged + _m.logbook_write("Process run %s report" % name, report.render()) + except Exception as error: + print _time.strftime("%Y-%M-%d %H:%m:%S") + print "Error writing report '%s' to logbook" % name + print error + print _traceback.format_exc(error) + if self._log_level == "DISABLE_ON_ERROR": + _m.logbook_level(_m.LogbookLevel.NONE) + else: + _subprocess.check_call(command, cwd=self._path, shell=True) + + @_m.logbook_trace("Check free space on C") + def check_free_space(self, min_space): + path = "c:\\" + temp, total, free = _ctypes.c_ulonglong(), _ctypes.c_ulonglong(), _ctypes.c_ulonglong() + if sys.version_info >= (3,) or isinstance(path, unicode): + fun = _ctypes.windll.kernel32.GetDiskFreeSpaceExW + else: + fun = _ctypes.windll.kernel32.GetDiskFreeSpaceExA + ret = fun(path, _ctypes.byref(temp), _ctypes.byref(total), _ctypes.byref(free)) + if ret == 0: + raise _ctypes.WinError() + total = total.value / (1024.0 ** 3) + free = free.value / (1024.0 ** 3) + if free < min_space: + raise Exception("Free space on C drive %s is less than %s" % (free, min_space)) + + def remove_prev_iter_files(self, file_names, output_dir, iteration): + if iteration == 0: + self.delete_files(file_names, output_dir) + else: + self.move_files(file_names, output_dir, _join(output_dir, "iter%s" % (iteration))) + + def copy_files(self, file_names, from_dir, to_dir): + with _m.logbook_trace("Copy files %s" % ", ".join(file_names)): + for file_name in file_names: + from_file = _join(from_dir, file_name) + _shutil.copy(from_file, to_dir) + + def complete_work(self, scenarioYear, input_dir, output_dir, input_file, output_file): + + fullList = np.array(pd.read_csv(_join(input_dir, input_file))['mgra']) + workList = np.array(pd.read_csv(_join(output_dir, output_file))['i']) + + list_set = set(workList) + unique_list = (list(list_set)) + notMatch = [x for x in fullList if x not in unique_list] + + if notMatch: + out_file = _join(output_dir, output_file) + with open(out_file, 'ab') as csvfile: + spamwriter = csv.writer(csvfile) + # spamwriter.writerow([]) + for item in notMatch: + # pdb.set_trace() + spamwriter.writerow([item, item, '30', '30', '30']) + + def move_files(self, file_names, from_dir, to_dir): + with _m.logbook_trace("Move files %s" % ", ".join(file_names)): + if not os.path.exists(to_dir): + os.mkdir(to_dir) + for file_name in file_names: + all_files = _glob.glob(_join(from_dir, file_name)) + for path in all_files: + try: + dst_file = _join(to_dir, os.path.basename(path)) + if os.path.exists(dst_file): + os.remove(dst_file) + _shutil.move(path, to_dir) + except Exception as error: + _m.logbook_write( + "Error moving file %s" % path, {"error": _traceback.format_exc(error)}) + + def delete_files(self, file_names, directory): + with _m.logbook_trace("Delete files %s" % ", ".join(file_names)): + for file_name in file_names: + all_files = _glob.glob(_join(directory, file_name)) + for path in all_files: + os.remove(path) + + def check_for_fatal(self, file_name, error_msg): + with open(file_name, 'a+') as f: + for line in f: + if "FATAL" in line: + raise Exception(error_msg) + + def set_active(self, emmebank): + modeller = _m.Modeller() + desktop = modeller.desktop + data_explorer = desktop.data_explorer() + for db in data_explorer.databases(): + if _norm(db.path) == _norm(unicode(emmebank)): + db.open() + return db + return None + + def parse_availability_file(self, file_path, periods): + if os.path.exists(file_path): + availabilities = _defaultdict(lambda: _defaultdict(lambda: dict())) + # NOTE: CSV Reader sets the field names to UPPERCASE for consistency + with gen_utils.CSVReader(file_path) as r: + for row in r: + name = row.pop("FACILITY_NAME") + class_name = row.pop("VEHICLE_CLASS") + for period in periods: + is_avail = int(row[period + "_AVAIL"]) + if is_avail not in [1, 0]: + msg = "Error processing file '%s': value for period %s class %s facility %s is not 1 or 0" + raise Exception(msg % (file_path, period, class_name, name)) + availabilities[period][name][class_name] = is_avail + else: + availabilities = None + return availabilities + + def apply_availabilities(self, period, scenario, availabilities): + if availabilities is None: + return + + network = scenario.get_network() + hov2 = network.mode("h") + hov2_trnpdr = network.mode("H") + hov3 = network.mode("i") + hov3_trnpdr = network.mode("I") + sov = network.mode("s") + sov_trnpdr = network.mode("S") + heavy_trk = network.mode("v") + heavy_trk_trnpdr = network.mode("V") + medium_trk = network.mode("m") + medium_trk_trnpdr = network.mode("M") + light_trk = network.mode("t") + light_trk_trnpdr = network.mode("T") + + class_mode_map = { + "DA": set([sov_trnpdr, sov]), + "S2": set([hov2_trnpdr, hov2]), + "S3": set([hov3_trnpdr, hov3]), + "TRK_L": set([light_trk_trnpdr, light_trk]), + "TRK_M": set([medium_trk_trnpdr, medium_trk]), + "TRK_H": set([heavy_trk_trnpdr, heavy_trk]), + } + report = ["
Link mode changes
"] + for name, class_availabilities in availabilities[period].iteritems(): + report.append("
%s
" % name) + changes = _defaultdict(lambda: 0) + for link in network.links(): + if name in link["#name"]: + for class_name, is_avail in class_availabilities.iteritems(): + modes = class_mode_map[class_name] + if is_avail == 1 and not modes.issubset(link.modes): + link.modes |= modes + changes["added %s to" % class_name] += 1 + elif is_avail == 0 and modes.issubset(link.modes): + link.modes -= modes + changes["removed %s from" % class_name] += 1 + report.append("
    ") + for x in changes.iteritems(): + report.append("
  • %s %s links
  • " % x) + report.append("
") + scenario.publish_network(network) + + title = "Apply global class availabilities by faclity name for period %s" % period + log_report = _m.PageBuilder(title=title) + for item in report: + log_report.add_html(item) + _m.logbook_write(title, log_report.render()) + + def setup_remote_database(self, src_scenarios, periods, remote_num, msa_iteration): + with _m.logbook_trace("Set up remote database #%s for %s" % (remote_num, ", ".join(periods))): + init_matrices = _m.Modeller().tool("sandag.initialize.initialize_matrices") + create_function = _m.Modeller().tool("inro.emme.data.function.create_function") + src_emmebank = src_scenarios[0].emmebank + remote_db_dir = _join(self._path, "emme_project", "Database_remote" + str(remote_num)) + if msa_iteration == 1: + # Create and initialize database at first iteration, overwrite existing + if os.path.exists(remote_db_dir): + _shutil.rmtree(remote_db_dir) + _time.sleep(1) + os.mkdir(remote_db_dir) + dimensions = src_emmebank.dimensions + dimensions["scenarios"] = len(src_scenarios) + remote_emmebank = _eb.create(_join(remote_db_dir, "emmebank"), dimensions) + try: + remote_emmebank.title = src_emmebank.title + remote_emmebank.coord_unit_length = src_emmebank.coord_unit_length + remote_emmebank.unit_of_length = src_emmebank.unit_of_length + remote_emmebank.unit_of_cost = src_emmebank.unit_of_cost + remote_emmebank.unit_of_energy = src_emmebank.unit_of_energy + remote_emmebank.use_engineering_notation = src_emmebank.use_engineering_notation + remote_emmebank.node_number_digits = src_emmebank.node_number_digits + + for src_scen in src_scenarios: + remote_scen = remote_emmebank.create_scenario(src_scen.id) + remote_scen.title = src_scen.title + for attr in sorted(src_scen.extra_attributes(), key=lambda x: x._id): + dst_attr = remote_scen.create_extra_attribute( + attr.type, attr.name, attr.default_value) + dst_attr.description = attr.description + for field in src_scen.network_fields(): + remote_scen.create_network_field( + field.type, field.name, field.atype, field.description) + remote_scen.has_traffic_results = src_scen.has_traffic_results + remote_scen.has_transit_results = src_scen.has_transit_results + remote_scen.publish_network(src_scen.get_network()) + for function in src_emmebank.functions(): + create_function(function.id, function.expression, remote_emmebank) + init_matrices(["traffic_skims", "traffic_demand"], periods, remote_scen) + finally: + remote_emmebank.dispose() + + src_scen = src_scenarios[0] + with _m.logbook_trace("Copy demand matrices to remote database"): + with _eb.Emmebank(_join(remote_db_dir, "emmebank")) as remote_emmebank: + demand_matrices = init_matrices.get_matrix_names("traffic_demand", periods, src_scen) + for matrix_name in demand_matrices: + matrix = remote_emmebank.matrix(matrix_name) + src_matrix = src_emmebank.matrix(matrix_name) + if matrix.type == "SCALAR": + matrix.data = src_matrix.data + else: + matrix.set_data(src_matrix.get_data(src_scen.id), src_scen.id) + skim_matrices = init_matrices.get_matrix_names("traffic_skims", periods, src_scen) + return remote_db_dir, skim_matrices + + def start_assignments(self, machine, database_path, periods, scenarios, assign_args): + with _m.logbook_trace("Start remote process for traffic assignments %s" % (", ".join(periods))): + assign_args["database_path"] = database_path + end_path = _join(database_path, "finish") + if os.path.exists(end_path): + os.remove(end_path) + for period in periods: + assign_args["period_scenario"] = scenarios[period].id + assign_args["period"] = period + with open(_join(database_path, "start_%s.args" % period), 'w') as f: + _json.dump(assign_args, f, indent=4) + script_dir = _join(self._path, "python") + bin_dir = _join(self._path, "bin") + args = [ + 'start %s\\PsExec.exe' % bin_dir, + '-c', + '-f', + '\\\\%s' % machine, + '-u \%s' % self.username, + '-p %s' % self.password, + "-d", + '%s\\emme_python.bat' % bin_dir, + "T:", + self._path, + '%s\\remote_run_traffic.py' % script_dir, + database_path, + ] + command = " ".join(args) + p = _subprocess.Popen(command, shell=True) + + @_m.logbook_trace("Wait for remote assignments to complete and copy results") + def wait_and_copy(self, database_dirs, scenarios, matrices): + database_dirs = database_dirs[:] + wait = True + while wait: + _time.sleep(5) + for path in database_dirs: + end_path = _join(path, "finish") + if os.path.exists(end_path): + database_dirs.remove(path) + _time.sleep(2) + self.check_for_fatal( + end_path, "error during remote run of traffic assignment. " + "Check logFiles/traffic_assign_database_remote*.log") + self.copy_results(path, scenarios[path], matrices[path]) + if not database_dirs: + wait = False + + @_m.logbook_trace("Copy skim results from remote database", save_arguments=True) + def copy_results(self, database_path, scenarios, matrices): + with _eb.Emmebank(_join(database_path, "emmebank")) as remote_emmebank: + for dst_scen in scenarios: + remote_scen = remote_emmebank.scenario(dst_scen.id) + # Create extra attributes and network fields which do not exist + for attr in sorted(remote_scen.extra_attributes(), key=lambda x: x._id): + if not dst_scen.extra_attribute(attr.name): + dst_attr = dst_scen.create_extra_attribute( + attr.type, attr.name, attr.default_value) + dst_attr.description = attr.description + for field in remote_scen.network_fields(): + if not dst_scen.network_field(field.type, field.name): + dst_scen.create_network_field( + field.type, field.name, field.atype, field.description) + dst_scen.has_traffic_results = remote_scen.has_traffic_results + dst_scen.has_transit_results = remote_scen.has_transit_results + + dst_scen.publish_network(remote_scen.get_network()) + + dst_emmebank = dst_scen.emmebank + scen_id = dst_scen.id + for matrix_id in matrices: + src_matrix = remote_emmebank.matrix(matrix_id) + dst_matrix = dst_emmebank.matrix(matrix_id) + dst_matrix.set_data(src_matrix.get_data(scen_id), scen_id) + + @_m.method(return_type=unicode) + def get_link_attributes(self): + export_utils = _m.Modeller().module("inro.emme.utility.export_utilities") + return export_utils.get_link_attributes(_m.Modeller().scenario) + + def update_centroid_connectors(self, source, base_scenario, emmebank, external_zone, taz_cwk_file, cluster_zone_file): + adjust_network = _m.Modeller().module("inro.import.adjust_network_links") + return adjust_network.adjust_network_links(source, base_scenario, emmebank, external_zone, taz_cwk_file, cluster_zone_file) + + def sql_select_scenario(self, year, iteration, sample, path, dbtime): # YMA, 1/24/2019 + """Return scenario_id from [dimension].[scenario] given path""" + + import datetime + + sql_con = pyodbc.connect(driver='{SQL Server}', + server='sql2014a8', + database='abm_2', + trusted_connection='yes') + + # dbtime = dbtime + datetime.timedelta(days=0) + + df = pd.read_sql_query( + sql=("SELECT [scenario_id] " + "FROM [dimension].[scenario]" + "WHERE [year] = ? AND [iteration] = ? AND [sample_rate]= ? AND [path] Like ('%' + ? + '%') AND [date_loaded] > ? "), + con=sql_con, + params=[year, iteration, sample, path, dbtime] + ) + + if len(df) > 0: + return (df.iloc[len(df) - 1]['scenario_id']) + else: + return 0 + + def sql_check_load_request(self, year, path, user, ldtime): # YMA, 1/24/2019 + """Return information from [data_load].[load_request] given path,username,and requested time""" + + import datetime + + t0 = ldtime + datetime.timedelta(minutes=-1) + t1 = t0 + datetime.timedelta(minutes=30) + + sql_con = pyodbc.connect(driver='{SQL Server}', + server='sql2014a8', + database='abm_2', + trusted_connection='yes') + + df = pd.read_sql_query( + sql=( + "SELECT [load_request_id],[year],[name],[path],[iteration],[sample_rate],[abm_version],[user_name],[date_requested],[loading],[loading_failed],[scenario_id] " + "FROM [data_load].[load_request] " + "WHERE [year] = ? AND [path] LIKE ('%' + ? + '%') AND [user_name] LIKE ('%' + ? + '%') AND [date_requested] >= ? AND [date_requested] <= ? "), + con=sql_con, + params=[year, path, user, t0, t1] + ) + + if len(df) > 0: + return "You have successfully made the loading request, but the loading to the database failed. \r\nThe information is below. \r\n\r\n" + df.to_string() + else: + return "The data load request was not successfully made, please double check the [data_load].[load_request] table to confirm." + + +''' + def send_notification(self,str_message,user): # YMA, 1/24/2019, not working on server + """automate to send email notification if load request or loading failed""" + + import win32com.client as win32 + + outlook = win32.Dispatch('outlook.application') + Msg = outlook.CreateItem(0) + Msg.To = user + '@sandag.org' + Msg.CC = 'yma@sandag.org' + Msg.Subject = 'Loading Scenario to Database Failed' + Msg.body = str_message + '\r\n' + '\r\n' + 'This email alert is auto generated.\r\n' + 'Please do not respond.\r\n' + Msg.send''' diff --git a/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/distribution.py b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/distribution.py new file mode 100644 index 0000000..c271e56 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/distribution.py @@ -0,0 +1,197 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/commercial_vehicle/distribution.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Distributes the total daily trips from production and attraction vectors. +# Friction factors are calculated based on a blended travel time skim of +# 1/3 AM_SOV_NT_M_TIME and 2/3 MD_SOV_NT_M_TIME, and a table of friction factor +# lookup values from commVehFF.csv. +# +# Inputs: +# input_directory: source directory for input files +# scenario: traffic scenario to use for reference zone system +# +# Files referenced: +# input/commVehFF.csv +# +# Matrix inputs: +# moCOMVEH_PROD, mdCOMVEH_ATTR +# mfAM_SOV_NT_M_TIME, mfMD_SOV_NT_M_TIME +# +# Matrix intermediates (only used internally): +# mfCOMVEH_BLENDED_SKIM, mfCOMVEH_FRICTION +# +# Matrix results: +# mfCOMVEH_TOTAL_DEMAND +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + project_dir = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(project_dir, "input") + base_scenario = modeller.scenario + distribution = modeller.tool("sandag.model.commercial_vehicle.distribution") + distribution(input_dir, base_scenario) +""" + + +TOOLBOX_ORDER = 53 + + +import inro.modeller as _m +import traceback as _traceback + +import pandas as pd +import os +import numpy as np + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class CommercialVehicleDistribution(_m.Tool(), gen_utils.Snapshot): + + input_directory = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.attributes = ["input_directory"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Commercial Vehicle Distribution" + pb.description = """ +
+ Calculates total daily trips. + The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. +
+ A simple gravity model is used to distribute the truck trips. + A blended travel time of + 1/3 AM_SOV_NT_M_TIME and 2/3 MD_SOV_NT_M_TIME is used, along with + friction factor lookup table stored in commVehFF.csv. +
+ Input: +
  • + (1) Level-of-service matrices for the AM peak period (6 am to 10 am) 'mfAM_SOVGPM_TIME' + and midday period (10 am to 3 pm) 'mfMD_SOVGPM_TIME' + which contain congested travel time (in minutes). +
  • + (2) Trip generation results 'moCOMVEH_PROD' and 'mdCOMVEH_ATTR' +
  • + (4) A table of friction factors in commVehFF.csv with: +
    • + (a) impedance measure (blended travel time) index; +
    • + (b) friction factors +
    +
+ Output: +
  • + (1) A trip table matrix 'mfCOMVEH_TOTAL_DEMAND' + of daily class-specific truck trips for very small trucks. +
  • + (2) A blended travel time matrix 'mfCOMVEH_BLENDED_SKIM' +
+
""" + pb.branding_text = "- SANDAG - Model - Commercial vehicle" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.input_directory, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Commercial vehicle distribution') + def __call__(self, input_directory, scenario): + attributes = {"input_directory": input_directory} + gen_utils.log_snapshot("Commercial vehicle distribution", str(self), attributes) + self.calc_blended_skims(scenario) + self.calc_friction_matrix(input_directory, scenario) + self.balance_matrix(scenario) + + @_m.logbook_trace('Calculate blended skims') + def calc_blended_skims(self, scenario): + matrix_calc = _m.Modeller().tool( + 'inro.emme.matrix_calculation.matrix_calculator') + spec = { + "expression": "0.3333 * mfAM_SOV_NT_M_TIME + 0.6666 * mfMD_SOV_NT_M_TIME", + "result": "mfCOMVEH_BLENDED_SKIM", + "type": "MATRIX_CALCULATION" + } + matrix_calc(spec, scenario=scenario) + + # Prevent intrazonal trips + spec = { + "expression": "99999 * (p.eq.q) + mfCOMVEH_BLENDED_SKIM * (p.ne.q)", + "result": "mfCOMVEH_BLENDED_SKIM", + "type": "MATRIX_CALCULATION" + } + matrix_calc(spec, scenario=scenario) + + @_m.logbook_trace('Calculate friction factor matrix') + def calc_friction_matrix(self, input_directory, scenario): + emmebank = scenario.emmebank + + imp_matrix = emmebank.matrix('mfCOMVEH_BLENDED_SKIM') + friction_matrix = emmebank.matrix('mfCOMVEH_FRICTION') + imp_array = imp_matrix.get_numpy_data(scenario_id=scenario.id) + + # create the vector function to bin the impedances and get friction values + friction_table = pd.read_csv( + os.path.join(input_directory, 'commVehFF.csv'), + header=None, names=['index', 'factors']) + + factors_array = friction_table.factors.values + max_index = len(factors_array) - 1 + + # interpolation: floor + values_array = np.clip(np.floor(imp_array).astype(int) - 1, 0, max_index) + friction_array = np.take(factors_array, values_array) + friction_matrix.set_numpy_data(friction_array, scenario_id=scenario.id) + + def balance_matrix(self, scenario): + balance = _m.Modeller().tool( + 'inro.emme.matrix_calculation.matrix_balancing') + spec = { + "type": "MATRIX_BALANCING", + "od_values_to_balance": "mfCOMVEH_FRICTION", + "origin_totals": "moCOMVEH_PROD", + "destination_totals": "mdCOMVEH_ATTR", + "results": { + "od_balanced_values": "mfCOMVEH_TOTAL_DEMAND", + }, + "max_iterations": 100, + "max_relative_error": 0.001 + } + balance(spec, scenario=scenario) diff --git a/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/generation.py b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/generation.py new file mode 100644 index 0000000..9842de1 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/generation.py @@ -0,0 +1,187 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/commercial_vehicle/generation.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Runs the commercial vehicle generation step, calculate commercial vehicle +# productions and attractions. Linear regression models generate trip ends, +# balancing attractions to productions. +# +# Inputs: +# input_directory: source directory for most input files, including demographics and trip rates +# scenario: traffic scenario to use for reference zone system +# +# Files referenced: +# Note: YEAR is replaced by truck.FFyear in the conf/sandag_abm.properties file +# input/mgra13_based_inputYEAR.csv +# +# Matrix results: +# moCOMVEH_PROD, mdCOMVEH_ATTR +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + project_dir = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(project_dir, "input") + base_scenario = modeller.scenario + generation = modeller.tool("sandag.model.commercial_vehicle.generation") + generation(input_dir, base_scenario) +""" + + +TOOLBOX_ORDER = 52 + + +import inro.modeller as _m +import traceback as _traceback + +import pandas as pd +import os + + +dem_utils = _m.Modeller().module('sandag.utilities.demand') +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class CommercialVehicleDistribution(_m.Tool(), gen_utils.Snapshot): + + input_directory = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.attributes = ["input_directory"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Commercial Vehicle Generation" + pb.description = """ +
+ Calculate commerical vehicle productions and attractions + based on mgra13_based_inputYYYY.csv. + The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. + + Linear regression models generate trip ends, balancing attractions to productions. +
+ Input: MGRA file in CSV format with the following fields: +
    +
  • + (a) TOTEMP, total employment (same regardless of classification system); +
  • + (b) RETEMPN, retail trade employment per the NAICS classification system; +
  • + (c) FPSEMPN, financial and professional services employment per the NAICS classification system; +
  • + (d) HEREMPN, health, educational, and recreational employment per the NAICS classification system; +
  • + (e) OTHEMPN, other employment per the NAICS classification system; +
  • + (f) AGREMPN, agricultural employmentper the NAICS classificatin system; +
  • + (g) MWTEMPN, manufacturing, warehousing, and transportation emp;loyment per the NAICS classification system; and, +
  • + (h) TOTHH, total households. +
+
+ Output: Trip productions and attractions in matrices 'moCOMMVEH_PROD' and 'mdCOMMVEH_ATTR' respectively. +
+ """ + + pb.branding_text = "- SANDAG - Model - Commercial vehicle" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.input_directory, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Commercial vehicle generation') + def __call__(self, input_directory, scenario): + attributes = {"input_directory": input_directory} + gen_utils.log_snapshot("Commercial vehicle generation", str(self), attributes) + emmebank = scenario.emmebank + + load_properties = _m.Modeller().tool('sandag.utilities.properties') + main_directory = os.path.dirname(input_directory) + props = load_properties( + os.path.join(main_directory, "conf", "sandag_abm.properties")) + year = props['scenarioYear'] + mgra = pd.read_csv( + os.path.join(input_directory, 'mgra13_based_input%s.csv' % year)) + + calibration = 1.4 + + mgra['RETEMPN'] = mgra.emp_retail + mgra.emp_personal_svcs_retail + mgra['FPSEMPN'] = mgra.emp_prof_bus_svcs + mgra['HEREMPN'] = mgra.emp_health + mgra.emp_pvt_ed_k12 \ + + mgra.emp_pvt_ed_post_k12_oth + mgra.emp_amusement + mgra['AGREMPN'] = mgra.emp_ag + mgra['MWTEMPN'] = mgra.emp_const_non_bldg_prod \ + + mgra.emp_const_bldg_prod + mgra.emp_mfg_prod \ + + mgra.emp_trans + mgra['MILITARY'] = mgra.emp_fed_mil + mgra['TOTEMP'] = mgra.emp_total + mgra['OTHEMPN'] = mgra.TOTEMP - (mgra.RETEMPN + mgra.FPSEMPN + + mgra.HEREMPN + mgra.AGREMPN + + mgra.MWTEMPN + mgra.MILITARY) + mgra['TOTHH'] = mgra.hh + + mgra['PROD'] = calibration * ( + 0.95409 * mgra.RETEMPN + 0.54333 * mgra.FPSEMPN + + 0.50769 * mgra.HEREMPN + 0.63558 * mgra.OTHEMPN + + 1.10181 * mgra.AGREMPN + 0.81576 * mgra.MWTEMPN + + 0.15000 * mgra.MILITARY + 0.1 * mgra.TOTHH) + mgra['ATTR'] = mgra.PROD + + # Adjustment to match military CTM trips to match gate counts + military_ctm_adjustment = props["RunModel.militaryCtmAdjustment"] + if military_ctm_adjustment: + mgra_m = pd.read_csv(os.path.join( + input_directory, 'cvm_military_adjustment.csv')) + mgra = pd.merge(mgra, mgra_m, on='mgra', how='outer') + mgra.fillna(1, inplace=True) + mgra['PROD'] = mgra['PROD'] * mgra['scale'] + mgra['ATTR'] = mgra['ATTR'] * mgra['scale'] + + taz = mgra.groupby('taz').sum() + taz.reset_index(inplace=True) + taz = dem_utils.add_missing_zones(taz, scenario) + taz.sort('taz', inplace=True) + + prod = emmebank.matrix('moCOMVEH_PROD') + attr = emmebank.matrix('mdCOMVEH_ATTR') + prod.set_numpy_data(taz.PROD.values, scenario) + attr.set_numpy_data(taz.ATTR.values, scenario) + + return taz[['taz', 'PROD', 'ATTR']] diff --git a/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/run_commercial_vehicle_model.py b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/run_commercial_vehicle_model.py new file mode 100644 index 0000000..3899456 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/run_commercial_vehicle_model.py @@ -0,0 +1,122 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/commercial_vehicle/run_commercial_vehicle_model.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Runs the commercial vehicle model, the generation, distribution, time-of-day, +# and toll diversion tools, in sequence. +# 1) Generates +# 2) Generates +# 3) Distributes trips based on congested skims +# 4) Time-of-day split +# 5) Applies toll diversion model with toll and non-toll SOV skims +# +# The very small truck generation model is based on the Phoenix +# four-tire truck model documented in the TMIP Quick Response Freight Manual. +# +# Inputs: +# run_generation: boolean, if True run generation tool. +# input_directory: source directory for most input files, including demographics and trip rates +# (see generation and distribtuion tools) +# scenario: traffic scenario to use for reference zone system +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + project_dir = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(project_dir, "input") + base_scenario = modeller.scenario + run_truck = modeller.tool("sandag.model.commercial_vehicle.run_commercial_vehicle") + run_truck(True, input_dir, base_scenario) +""" + +TOOLBOX_ORDER = 51 + + +import inro.modeller as _m +import traceback as _traceback +import os + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class CommercialVehicleModel(_m.Tool(), gen_utils.Snapshot): + + input_directory = _m.Attribute(str) + run_generation = _m.Attribute(bool) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self.run_generation = True + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.attributes = ["input_directory", "run_generation"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Commercial vehicle model" + pb.description = """ +
+ Run the 4 steps of the commercial vehicle model: generation, distribution, + time of day, toll diversion. + + The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. +
+""" + pb.branding_text = "- SANDAG - Model - Commercial vehicle" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + pb.add_checkbox("run_generation", title=" ", label="Run generation (first iteration)") + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.run_generation, self.input_directory, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Commercial vehicle model', save_arguments=True) + def __call__(self, run_generation, input_directory, scenario): + attributes = {"run_generation": run_generation, "input_directory": input_directory} + gen_utils.log_snapshot("Commercial vehicle model", str(self), attributes) + generation = _m.Modeller().tool( + 'sandag.model.commercial_vehicle.generation') + distribution = _m.Modeller().tool( + 'sandag.model.commercial_vehicle.distribution') + time_of_day = _m.Modeller().tool( + 'sandag.model.commercial_vehicle.time_of_day') + diversion = _m.Modeller().tool( + 'sandag.model.commercial_vehicle.toll_diversion') + if run_generation: + generation(input_directory, scenario) + distribution(input_directory, scenario) + time_of_day(scenario) + diversion(scenario) diff --git a/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/time_of_day.py b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/time_of_day.py new file mode 100644 index 0000000..163bba7 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/time_of_day.py @@ -0,0 +1,99 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/commercial_vehicle/time_of_day.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Applies time-of-day factoring to the Commercial vehicle total daily demand. +# The diurnal factors are taken from the BAYCAST-90 model with adjustments +# made during calibration to the very small truck values to better match counts. +# +# Inputs: +# scenario: traffic scenario to use for reference zone system +# +# Matrix inputs: +# mfCOMVEH_TOTAL_DEMAND +# +# Matrix results: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# mfpp_COMVEH +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + base_scenario = modeller.scenario + time_of_day = modeller.tool("sandag.model.commercial_vehicle.time_of_day") + time_of_day(base_scenario) +""" + +TOOLBOX_ORDER = 54 + + +import inro.modeller as _m +import traceback as _traceback + + +dem_utils = _m.Modeller().module("sandag.utilities.demand") + + +class TimeOfDay(_m.Tool()): + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Commercial Vehicle Time of Day split" + pb.description = """ +
+ Commercial vehicle time-of-day factoring. + The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. +
+ The diurnal factors are taken from the BAYCAST-90 model with adjustments + made during calibration to the very small truck values to better match counts. +

Input: A production/attraction format trip table matrix of daily very small truck trips.

+

Output: Five, time-of-day-specific trip table matrices for very small trucks, + of the form 'mfpp_COMVEH'. +

+
""" + pb.branding_text = "- SANDAG - Model - Commercial vehicle" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Commercial vehicle Time of Day split') + def __call__(self, scenario): + matrix_calc = dem_utils.MatrixCalculator(scenario, 0) + periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + period_factors = [0.0235, 0.1, 0.5080, 0.1980, 0.1705] + for p, f in zip(periods, period_factors): + matrix_calc.add( + "mf%s_COMVEH" % p, + "%s * 0.5 * (mfCOMVEH_TOTAL_DEMAND + mfCOMVEH_TOTAL_DEMAND')" % f) + matrix_calc.run() diff --git a/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/toll_diversion.py b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/toll_diversion.py new file mode 100644 index 0000000..07bc4fe --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/commercial_vehicle/toll_diversion.py @@ -0,0 +1,119 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/commercial_vehicle/toll_diversion.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# Applies toll and non-toll split to Commercial vehicle time period demand. +# Uses the travel TIME for GP and TOLL modes as well as the TOLLCOST +# by time period. +# +# Inputs: +# scenario: traffic scenario to use for reference zone system +# +# Matrix inputs: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# mfpp_COMVEH +# mfpp_SOVGPM_TIME, mfpp_SOVTOLLM_TIME, mfpp_SOVTOLLM_TOLLCOST +# +# Matrix results: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# mfpp_COMVEHGP, mfpp_COMVEHTOLL +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + base_scenario = modeller.scenario + toll_diversion = modeller.tool("sandag.model.commercial_vehicle.toll_diversion") + toll_diversion(base_scenario) +""" + +TOOLBOX_ORDER = 55 + + +import inro.modeller as _m +import traceback as _traceback + + +gen_utils = _m.Modeller().module('sandag.utilities.general') +dem_utils = _m.Modeller().module('sandag.utilities.demand') + + +class TollDiversion(_m.Tool()): + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Commercial vehicle toll diversion" + pb.description = """ +
+ Commercial vehicle toll and non-toll (GP) split. + The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. +
+

Input: Time-of-day-specific trip table matrices 'mfpp_COMVEH', + and travel time for GP and TOLL modes 'mfpp_SOVGPM_TIME', 'mfpp_SOVTOLLM_TIME', + and toll cost 'mfpp_SOVTOLLM_TOLLCOST' (medium VOT bin). +

+

Output: Corresponding time-of-day 'mfpp_COMVEHGP' and 'mfpp_COMVEHTOLL' + trip demand matrices.

+
+""" + pb.branding_text = "- SANDAG - Model - Commercial vehicle" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Commercial vehicle toll diversion') + def __call__(self, scenario): + emmebank = scenario.emmebank + matrix_calc = dem_utils.MatrixCalculator(scenario, "MAX-1") + init_matrix = _m.Modeller().tool( + "inro.emme.data.matrix.init_matrix") + + periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + for p in periods: + init_matrix("mf%s_COMVEHTOLL" % p, scenario=scenario) + + nest = 10 + vot = 0.02 + toll_factor = 1 + for p in periods: + with matrix_calc.trace_run("Diversion for %s" % p): + init_matrix("mf%s_COMVEHTOLL" % p, scenario=scenario) + params = {'p': p, 'v': vot, 'tf': toll_factor, 'n': nest} + utility = ('(mf%(p)s_SOVGPM_TIME - mf%(p)s_SOVTOLLM_TIME' + '- %(v)s * mf%(p)s_SOVTOLLM_TOLLCOST * %(tf)s) / %(n)s') % params + matrix_calc.add( + "mf%s_COMVEHTOLL" % p, + "mf%s_COMVEH / (1 + exp(- %s))" % (p, utility), + ["mf%s_SOVTOLLM_TOLLCOST" % p, 0, 0, "EXCLUDE"]) + matrix_calc.add( + "mf%s_COMVEHGP" % p, "mf%(p)s_COMVEH - mf%(p)s_COMVEHTOLL" % {'p': p}) diff --git a/sandag_abm/src/main/emme/toolbox/model/external_external.py b/sandag_abm/src/main/emme/toolbox/model/external_external.py new file mode 100644 index 0000000..c928d36 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/external_external.py @@ -0,0 +1,190 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/external_external.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Runs the external-external, cross-regional demand model. Imports the total +# daily demand from file and splits by time-of-day and SOVGP, HOV2HOV, and +# HOV3HOV classes using fixed factors. +# +# +# Inputs: +# input_directory: source directory for input file +# external_zones: the set of external zones specified as a range, default is "1-12" +# scenario: traffic scenario to use for reference zone system +# +# Files referenced: +# Note: YEAR is replaced by scenarioYear in the conf/sandag_abm.properties file +# input/mgra13_based_inputYEAR.csv +# input/externalInternalControlTotalsByYear.csv +# input/externalInternalControlTotals.csv +# (if externalInternalControlTotalsByYear.csv is unavailable) +# +# Matrix results: +# pp_SOV_EETRIPS, pp_HOV2_EETRIPS, pp_HOV3_EETRIPS +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(main_directory, "input") + external_zones = "1-12" + base_scenario = modeller.scenario + external_external = modeller.tool("sandag.model.external_external") + external_external(input_dir, external_zones, base_scenario) +""" + + +TOOLBOX_ORDER = 62 + + +import inro.modeller as _m + +import multiprocessing as _multiprocessing +import traceback as _traceback +import os + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class ExternalExternal(_m.Tool(), gen_utils.Snapshot): + input_directory = _m.Attribute(unicode) + external_zones = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.external_zones = "1-12" + self.attributes = ["external_zones", "num_processors"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "External external model" + pb.description = """ + Total trips are read from externalExternalTripsByYear.csv for + the year in sandag_abm.properties. If this file does not exist + externalExternalTrips.csv will be used instead. + The total trips are split by time-of-day and traffic class + SOVGP, HOV2HOV, and HOV3HOV using fixed factors. + """ + pb.branding_text = "- SANDAG - Model" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + pb.add_text_box("external_zones", title="External zones:") + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.input_directory, self.external_zones, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('External-external model', save_arguments=True) + def __call__(self, input_directory, external_zones, scenario): + attributes = { + "external_zones": external_zones, + "input_directory": input_directory, + } + gen_utils.log_snapshot("External-external model", str(self), attributes) + emmebank = scenario.emmebank + matrix_calc = _m.Modeller().tool( + "inro.emme.matrix_calculation.matrix_calculator") + + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties( + os.path.join(os.path.dirname(input_directory), "conf", "sandag_abm.properties")) + year = int(props['scenarioYear']) + + periods = ["EA", "AM", "MD", "PM", "EV"] + time_of_day_factors = [0.074, 0.137, 0.472, 0.183, 0.133] + modes = ["SOV", "HOV2", "HOV3"] + mode_factors = [0.43, 0.42, 0.15] + + ee_matrix = emmebank.matrix("ALL_TOTAL_EETRIPS") + matrix_data = ee_matrix.get_data(scenario) + file_path = os.path.join( + input_directory, "externalExternalTripsByYear.csv") + if os.path.isfile(file_path): + with open(file_path, 'r') as f: + header = f.readline() + for line in f: + tyear, orig, dest, trips = line.split(",") + if int(tyear) == year: + matrix_data.set(int(orig), int(dest), float(trips)) + else: + file_path = os.path.join( + input_directory, "externalExternalTrips.csv") + if not os.path.isfile(file_path): + raise Exception("External-external model: no file 'externalExternalTrips.csv' or 'externalExternalTripsByYear.csv'") + with open(file_path, 'r') as f: + header = f.readline() + for line in f: + orig, dest, trips = line.split(",") + matrix_data.set(int(orig), int(dest), float(trips)) + _m.logbook_write("Control totals read from %s" % file_path) + ee_matrix.set_data(matrix_data, scenario) + + # factor for final demand matrix by time and mode type + # all external-external trips are non-toll + # SOV_GP, SR2_HOV SR3_HOV = "SOV", "HOV2", "HOV3" + for period, tod_fac in zip(periods, time_of_day_factors): + for mode, mode_fac in zip(modes, mode_factors): + spec = { + "expression": "ALL_TOTAL_EETRIPS * %s * %s" % (tod_fac, mode_fac), + "result": "mf%s_%s_EETRIPS" % (period, mode), + "constraint": { + "by_zone": { + "origins": external_zones, + "destinations": external_zones + } + }, + "type": "MATRIX_CALCULATION" + } + matrix_calc(spec, scenario=scenario) + + precision = float(props['RunModel.MatrixPrecision']) + self.matrix_rounding(scenario, precision) + + @_m.logbook_trace('Controlled rounding of demand') + def matrix_rounding(self, scenario, precision): + round_matrix = _m.Modeller().tool( + "inro.emme.matrix_calculation.matrix_controlled_rounding") + emmebank = scenario.emmebank + periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + modes = ["SOV", "HOV2", "HOV3"] + for period in periods: + for mode in modes: + matrix = emmebank.matrix("mf%s_%s_EETRIPS" % (period, mode)) + report = round_matrix(demand_to_round=matrix, + rounded_demand=matrix, + min_demand=precision, + values_to_round="SMALLER_THAN_MIN", + scenario=scenario) + diff --git a/sandag_abm/src/main/emme/toolbox/model/external_internal.py b/sandag_abm/src/main/emme/toolbox/model/external_internal.py new file mode 100644 index 0000000..19203e6 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/external_internal.py @@ -0,0 +1,331 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/external_internal.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Runs the external USA to internal demand model. +# 1) Work and non-work trip gateway total trips are read from control totals +# 2) Generates internal trip ends based on relative attractiveness from employment (by category) and households +# 3) Applies time-of-day and occupancy factors +# 4) Applies toll diversion model with toll and non-toll skims +# Control totals are read from externalInternalControlTotalsByYear.csv for +# the specified year in sandag_abm.properties. If this file does not exist +# externalInternalControlTotals.csv will be used instead. +# +# Inputs: +# input_directory: source directory for most input files, including demographics and trip rates +# scenario: traffic scenario to use for reference zone system +# +# Files referenced: +# Note: YEAR is replaced by scenarioYear in the conf/sandag_abm.properties file +# input/mgra13_based_inputYEAR.csv +# input/externalInternalControlTotalsByYear.csv +# input/externalInternalControlTotals.csv +# (if externalInternalControlTotalsByYear.csv is unavailable) +# +# Matrix results: +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(main_directory, "input") + base_scenario = modeller.scenario + external_internal = modeller.tool("sandag.model.external_internal") + external_internal(input_dir, input_truck_dir, base_scenario) +""" + +TOOLBOX_ORDER = 61 + + +import inro.modeller as _m +import numpy as np +import pandas as pd +import traceback as _traceback +import os + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + + +class ExternalInternal(_m.Tool(), gen_utils.Snapshot): + input_directory = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.attributes = ["input_directory"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "External internal model" + pb.description = """ + Runs the external USA to internal demand model. + Control totals are read from externalInternalControlTotalsByYear.csv for + the specified year in sandag_abm.properties. If this file does not exist + externalInternalControlTotals.csv will be used instead.""" + pb.branding_text = "- SANDAG - Model" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.input_directory, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('External-internal model', save_arguments=True) + def __call__(self, input_directory, scenario): + attributes = {"input_directory": input_directory} + gen_utils.log_snapshot("External-internal model", str(self), attributes) + np.seterr(divide='ignore', invalid='ignore') + + emmebank = scenario.emmebank + zones = scenario.zone_numbers + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties( + os.path.join(os.path.dirname(input_directory), "conf", "sandag_abm.properties")) + + year = int(props['scenarioYear']) + mgra = pd.read_csv( + os.path.join(input_directory, 'mgra13_based_input%s.csv' % year)) + + # Load data + file_path = os.path.join( + input_directory, "externalInternalControlTotalsByYear.csv") + if os.path.isfile(file_path): + control_totals = pd.read_csv(file_path) + control_totals = control_totals[control_totals.year==year] + control_totals = control_totals.drop("year", axis=1) + else: + file_path = os.path.join( + input_directory, 'externalInternalControlTotals.csv') + if not os.path.isfile(file_path): + raise Exception( + "External-internal model: no file 'externalInternalControlTotals.csv' " + "or 'externalInternalControlTotalsByYear.csv'") + control_totals = pd.read_csv(file_path) + _m.logbook_write("Control totals read from %s" % file_path) + + # Aggregate purposes + mgra['emp_blu'] = (mgra.emp_const_non_bldg_prod + + mgra.emp_const_non_bldg_office + + mgra.emp_utilities_prod + + mgra.emp_utilities_office + + mgra.emp_const_bldg_prod + + mgra.emp_const_bldg_office + + mgra.emp_mfg_prod + + mgra.emp_mfg_office + + mgra.emp_whsle_whs + + mgra.emp_trans) + + mgra['emp_svc'] = (mgra.emp_prof_bus_svcs + + mgra.emp_prof_bus_svcs_bldg_maint + + mgra.emp_personal_svcs_office + + mgra.emp_personal_svcs_retail) + + mgra['emp_edu'] = (mgra.emp_pvt_ed_k12 + + mgra.emp_pvt_ed_post_k12_oth + + mgra.emp_public_ed) + + mgra['emp_gov'] = (mgra.emp_state_local_gov_ent + + mgra.emp_fed_non_mil + + mgra.emp_fed_non_mil + + mgra.emp_state_local_gov_blue + + mgra.emp_state_local_gov_white) + + mgra['emp_ent'] = (mgra.emp_amusement + + mgra.emp_hotel + + mgra.emp_restaurant_bar) + + mgra['emp_oth'] = (mgra.emp_religious + + mgra.emp_pvt_hh + + mgra.emp_fed_mil) + + mgra['work_size'] = (mgra.emp_blu + + 1.364 * mgra.emp_retail + + 4.264 * mgra.emp_ent + + 0.781 * mgra.emp_svc + + 1.403 * mgra.emp_edu + + 1.779 * mgra.emp_health + + 0.819 * mgra.emp_gov + + 0.708 * mgra.emp_oth) + + mgra['non_work_size'] = (mgra.hh + + 1.069 * mgra.emp_blu + + 4.001 * mgra.emp_retail + + 6.274 * mgra.emp_ent + + 0.901 * mgra.emp_svc + + 1.129 * mgra.emp_edu + + 2.754 * mgra.emp_health + + 1.407 * mgra.emp_gov + + 0.304 * mgra.emp_oth) + + # aggregate to TAZ + taz = mgra[['taz', 'work_size', 'non_work_size']].groupby('taz').sum() + taz.reset_index(inplace=True) + taz = dem_utils.add_missing_zones(taz, scenario) + taz.sort_values('taz', ascending=True, inplace=True) # method sort was deprecated since pandas version 0.20.0, yma, 2/12/2019 + taz.reset_index(inplace=True, drop=True) + control_totals = pd.merge(control_totals, taz[['taz']], how='outer') + control_totals.sort_values('taz', inplace=True) # method sort was deprecated since pandas version 0.20.0, yma, 2/12/2019 + + length_skim = emmebank.matrix('mf"MD_SOV_TR_M_DIST"').get_numpy_data(scenario) + + # Compute probabilities for work purpose + wrk_dist_coef = -0.029 + wrk_prob = taz.work_size.values * np.exp(wrk_dist_coef * length_skim) + wrk_sum = np.sum(wrk_prob, 1) + wrk_prob = wrk_prob / wrk_sum[:, np.newaxis] + wrk_prob = np.nan_to_num(wrk_prob) + # Apply probabilities to control totals + wrk_pa_mtx = wrk_prob * control_totals.work.values[:, np.newaxis] + wrk_pa_mtx = np.nan_to_num(wrk_pa_mtx) + wrk_pa_mtx = wrk_pa_mtx.astype("float32") + + # compute probabilities for non work purpose + non_wrk_dist_coef = -0.006 + nwrk_prob = taz.non_work_size.values * np.exp(non_wrk_dist_coef * length_skim) + non_wrk_sum = np.sum(nwrk_prob, 1) + nwrk_prob = nwrk_prob / non_wrk_sum[:, np.newaxis] + nwrk_prob = np.nan_to_num(nwrk_prob) + # Apply probabilities to control totals + nwrk_pa_mtx = nwrk_prob * control_totals.nonwork.values[:, np.newaxis] + nwrk_pa_mtx = np.nan_to_num(nwrk_pa_mtx) + nwrk_pa_mtx = nwrk_pa_mtx.astype("float32") + + # Convert PA to OD and apply Diurnal Facotrs + wrk_ap_mtx = 0.5 * np.transpose(wrk_pa_mtx) + wrk_pa_mtx = 0.5 * wrk_pa_mtx + nwrk_ap_mtx = 0.5 * np.transpose(nwrk_pa_mtx) + nwrk_pa_mtx = 0.5 * nwrk_pa_mtx + + # Apply occupancy and diurnal factors + work_time_PA_factors = [0.26, 0.26, 0.41, 0.06, 0.02] + work_time_AP_factors = [0.08, 0.07, 0.41, 0.42, 0.02] + + nonwork_time_PA_factors = [0.25, 0.39, 0.30, 0.04, 0.02] + nonwork_time_AP_factors = [0.12, 0.11, 0.37, 0.38, 0.02] + + work_occupancy_factors = [0.58, 0.31, 0.11] + nonwork_occupancy_factors = [0.55, 0.29, 0.15] + + # value of time is in cents per minute (toll cost is in cents) + vot_work = 15.00 # $9.00/hr + vot_non_work = 22.86 # $13.70/hr + ivt_coef = -0.03 + + gp_modes = ["SOVGP", "HOV2HOV", "HOV3HOV"] + toll_modes = ["SOVTOLL", "HOV2TOLL", "HOV3TOLL"] + # TODO: the GP vs. TOLL distinction should be collapsed + # (all demand added to transponder demand in import_auto_demand) + skim_lookup = { + "SOVGP": "SOV_NT_M", + "HOV2HOV": "HOV2_M", + "HOV3HOV": "HOV3_M", + "SOVTOLL": "SOV_TR_M", + "HOV2TOLL": "HOV2_M", + "HOV3TOLL": "HOV3_M" + } + periods = ["EA", "AM", "MD", "PM", "EV"] + for p, w_d_pa, w_d_ap, nw_d_pa, nw_d_ap in zip( + periods, work_time_PA_factors, work_time_AP_factors, + nonwork_time_PA_factors, nonwork_time_AP_factors): + for gp_mode, toll_mode, w_o, nw_o in zip( + gp_modes, toll_modes, work_occupancy_factors, nonwork_occupancy_factors): + wrk_mtx = w_o * (w_d_pa * wrk_pa_mtx + w_d_ap * wrk_ap_mtx) + nwrk_mtx = nw_o * (nw_d_pa * nwrk_pa_mtx + nw_d_ap * nwrk_ap_mtx) + + # Toll choice split + f_tm_imp = emmebank.matrix('mf%s_%s_TIME' % (p, skim_lookup[gp_mode])).get_numpy_data(scenario) + t_tm_imp = emmebank.matrix('mf%s_%s_TIME' % (p, skim_lookup[toll_mode])).get_numpy_data(scenario) + t_cst_imp = emmebank.matrix('mf%s_%s_TOLLCOST' % (p, skim_lookup[toll_mode])).get_numpy_data(scenario) + + # Toll diversion for work purpose + # TODO: .mod no longer needed, to confirm + wrk_toll_prb = np.exp( + ivt_coef * (t_tm_imp - f_tm_imp + np.mod(t_cst_imp, 10000) / vot_work) - 3.39 + ) + wrk_toll_prb[t_cst_imp <= 0] = 0 + wrk_toll_prb = wrk_toll_prb / (1 + wrk_toll_prb) + work_matrix_toll = wrk_mtx * wrk_toll_prb + work_matrix_non_toll = wrk_mtx * (1 - wrk_toll_prb) + + toll_eiwork = emmebank.matrix('%s_%s_EIWORK' % (p, toll_mode)) + gp_ei_work = emmebank.matrix('%s_%s_EIWORK' % (p, gp_mode)) + toll_eiwork.set_numpy_data(work_matrix_toll, scenario) + gp_ei_work.set_numpy_data(work_matrix_non_toll, scenario) + + # Toll diversion for non work purpose + nwrk_toll_prb = np.exp( + ivt_coef * (t_tm_imp - f_tm_imp + np.mod(t_cst_imp, 10000) / vot_non_work) - 3.39 + ) + + nwrk_toll_prb[t_cst_imp <= 0] = 0 + nwrk_toll_prb = nwrk_toll_prb / (1 + nwrk_toll_prb) + + non_work_toll_matrix = nwrk_mtx * nwrk_toll_prb + non_work_gp_matrix = nwrk_mtx * (1 - nwrk_toll_prb) + + toll_einonwork = emmebank.matrix('%s_%s_EINONWORK' % (p, toll_mode)) + gp_einonwork = emmebank.matrix('%s_%s_EINONWORK' % (p, gp_mode)) + toll_einonwork.set_numpy_data(non_work_toll_matrix, scenario) + gp_einonwork.set_numpy_data(non_work_gp_matrix, scenario) + + precision = float(props['RunModel.MatrixPrecision']) + self.matrix_rounding(scenario, precision) + + @_m.logbook_trace('Controlled rounding of demand') + def matrix_rounding(self, scenario, precision): + round_matrix = _m.Modeller().tool( + "inro.emme.matrix_calculation.matrix_controlled_rounding") + emmebank = scenario.emmebank + periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + modes = ["SOVGP", "HOV2HOV", "HOV3HOV", "SOVTOLL", "HOV2TOLL", "HOV3TOLL"] + purpose_types = ["EIWORK", "EINONWORK"] + for period in periods: + for mode in modes: + for purpose in purpose_types: + matrix = emmebank.matrix("mf%s_%s_%s" % (period, mode, purpose)) + try: + report = round_matrix(demand_to_round=matrix, + rounded_demand=matrix, + min_demand=precision, + values_to_round="SMALLER_THAN_MIN", + scenario=scenario) + except: + max_val = matrix.get_numpy_data(scenario.id).max() + if max_val == 0: + # if max_val is 0 the error is that the matrix is 0, log a warning + _m.logbook_write('Warning: matrix %s is all 0s' % matrix.named_id) + else: + raise diff --git a/sandag_abm/src/main/emme/toolbox/model/truck/distribution.py b/sandag_abm/src/main/emme/toolbox/model/truck/distribution.py new file mode 100644 index 0000000..7a9207a --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/truck/distribution.py @@ -0,0 +1,288 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/truck/distribution.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Runs the truck distribution step. Distributes truck trips with congested +# skims and splits by time of day. +# The distribution is based on the mid-day travel time for the "generic" +# truck skim "mfMD_TRK_TIME". Applies truck toll diversion model with +# toll and non-toll skims. +# +# Inputs: +# input_directory: source directory for input files +# num_processors: Number of processors to use, either as a number or "MAX-#" +# scenario: traffic scenario to use for reference zone system +# +# Files referenced: +# Note: YEAR is replaced by truck.FFyear in the conf/sandag_abm.properties file +# input/TruckTripRates.csv +# input/mgra13_based_inputYEAR.csv +# input/specialGenerators.csv +# +# Matrix inputs: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# moTRKL_PROD, moTRKM_PROD, moTRKH_PROD, moTRKEI_PROD, moTRKIE_PROD +# mdTRKL_ATTR, mdTRKM_ATTR, mdTRKH_ATTR, mdTRKEI_ATTR, mdTRKIE_ATTR +# mfTRKEE_DEMAND +# mfMD_TRK_TIME +# mfpp_TRKLGP_TIME, mfpp_TRKLTOLL_TIME, mfpp_TRKLTOLL_TOLLCOST +# mfpp_TRKMGP_TIME, mfpp_TRKMTOLL_TIME, mfpp_TRKMTOLL_TOLLCOST +# mfpp_TRKHGP_TIME, mfpp_TRKHTOLL_TIME, mfpp_TRKHTOLL_TOLLCOST +# +# Matrix intermediates (only used internally): +# mfTRKEI_FRICTION, mfTRKIE_FRICTION, mfTRKL_FRICTION, mfTRKM_FRICTION, mfTRKH_FRICTION +# +# Matrix results: +# Note: pp is time period, one of EA, AM, MD, PM, EV +# mfpp_TRKLGP_VEH, mfpp_TRKMGP_VEH, mfpp_TRKHGP_VEH +# mfpp_TRKLTOLL_VEH, mfpp_TRKMTOLL_VEH, mfpp_TRKHTOLL_VEH +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + main_directory = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(main_directory, "input") + num_processors = "MAX-1" + base_scenario = modeller.scenario + distribution = modeller.tool("sandag.model.truck.distribution") + distribution(input_dir, num_processors, base_scenario) +""" + + +TOOLBOX_ORDER = 43 + +import traceback as _traceback +import pandas as pd +import numpy as np +import os + +import inro.modeller as _m + + +gen_utils = _m.Modeller().module('sandag.utilities.general') +dem_utils = _m.Modeller().module('sandag.utilities.demand') + + +class TruckModel(_m.Tool(), gen_utils.Snapshot): + + input_directory = _m.Attribute(str) + num_processors = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.num_processors = "MAX-1" + self.attributes = ["input_directory", "num_processors"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Truck distribution" + pb.description = """ +
+ Distributes truck trips with congested skims and splits by time of day. + The distribution is based on the mid-day travel time for the "generic" truck + skim "mfMD_TRK_TIME". +
+ Applies truck toll diversion model with toll and non-toll skims, + and generates truck vehicle trips. +
+ Note that the truck vehicle trips must be converted to PCE values by the Import auto + demand tool and stored in matrices without the _VEH ending for the auto assignment. +
+ """ + pb.branding_text = "- SANDAG - Model - Truck" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + dem_utils.add_select_processors("num_processors", pb, self) + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.input_directory, self.num_processors, scenario) + run_msg = "Truck trip distribution complete." + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Truck distribution') + def __call__(self, input_directory, num_processors, scenario): + attributes = { + "input_directory": input_directory, + "num_processors": num_processors + } + gen_utils.log_snapshot("Truck distribution", str(self), attributes) + self.scenario = scenario + self.num_processors = num_processors + + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties( + os.path.join(os.path.dirname(input_directory), "conf", "sandag_abm.properties")) + + with _m.logbook_trace('Daily demand matrices'): + coefficents = [0.045, 0.03, 0.03, 0.03, 0.03] + truck_list = ['L', 'M', 'H', 'IE', 'EI'] + # distribution based on the "generic" truck MD time only + time_skim = scenario.emmebank.matrix('mf"MD_TRK_TIME"') + for truck_type, coeff in zip(truck_list, coefficents): + with _m.logbook_trace('Create %s daily demand matrix' % truck_type): + self.calc_friction_factors(truck_type, time_skim, coeff) + self.matrix_balancing(truck_type) + + self.split_external_demand() + self.split_into_time_of_day() + # NOTE: TOLL diversion skipped with new class definitions + #self.toll_diversion() + + with _m.logbook_trace('Reduce matrix precision'): + precision = props['RunModel.MatrixPrecision'] + matrices = [] + for t, pce in [('L', 1.3), ('M', 1.5), ('H', 2.5)]: + for p in ['EA', 'AM', 'MD', 'PM', 'EV']: + matrices.append('mf%s_TRK_%s_VEH' % (p, t)) + dem_utils.reduce_matrix_precision(matrices, precision, num_processors, scenario) + + @_m.logbook_trace('Create friction factors matrix') + def calc_friction_factors(self, truck_type, impedance, coeff): + matrix_calc = dem_utils.MatrixCalculator(self.scenario, self.num_processors) + matrix_calc.run_single('mfTRK%s_FRICTION' % truck_type, + 'exp(-%s*%s)' % (coeff, impedance.named_id)) + return + + def matrix_balancing(self, truck_type): + matrix_calc = dem_utils.MatrixCalculator(self.scenario, self.num_processors) + emmebank = self.scenario.emmebank + with _m.logbook_trace('Matrix balancing for %s' % truck_type): + if truck_type == 'IE': + with gen_utils.temp_matrices(emmebank, "DESTINATION") as (temp_md,): + temp_md.name = 'TRKIE_ROWTOTAL' + matrix_calc.add('md"TRKIE_ROWTOTAL"', 'mf"TRKIE_FRICTION"', aggregation={"origins": "+", "destinations": None}) + matrix_calc.add('mf"TRKIE_DEMAND"', 'mf"TRKIE_FRICTION" * md"TRKIE_ATTR" / md"TRKIE_ROWTOTAL"', + constraint=['md"TRKIE_ROWTOTAL"', 0, 0, "EXCLUDE"]) + matrix_calc.run() + + elif truck_type == 'EI': + with gen_utils.temp_matrices(emmebank, "ORIGIN") as (temp_mo,): + temp_mo.name = 'TRKEI_COLTOTAL' + matrix_calc.add('mo"TRKEI_COLTOTAL"', 'mf"TRKEI_FRICTION"', aggregation={"origins": None, "destinations": "+"}) + matrix_calc.add('mf"TRKEI_DEMAND"', 'mf"TRKEI_FRICTION" * mo"TRKEI_PROD" / mo"TRKEI_COLTOTAL"', + constraint=['mo"TRKEI_COLTOTAL"', 0, 0, "EXCLUDE"]) + matrix_calc.run() + else: + matrix_balancing = _m.Modeller().tool( + 'inro.emme.matrix_calculation.matrix_balancing') + spec = { + "type": "MATRIX_BALANCING", + "od_values_to_balance": 'mf"TRK%s_FRICTION"' % truck_type, + "origin_totals": 'mo"TRK%s_PROD"' % truck_type, + "destination_totals": 'md"TRK%s_ATTR"' % truck_type, + "results": { + "od_balanced_values": 'mf"TRK%s_DEMAND"' % truck_type, + }, + "max_iterations": 100, + "max_relative_error": 0.01 + } + matrix_balancing(spec, self.scenario) + + @_m.logbook_trace('Split cross-regional demand by truck type') + def split_external_demand(self): + matrix_calc = dem_utils.MatrixCalculator(self.scenario, self.num_processors) + + truck_types = ['L', 'M', 'H'] + truck_share = [0.307, 0.155, 0.538] + for t_type, share in zip(truck_types, truck_share): + matrix_calc.add('mf"TRK%s_DEMAND"' % (t_type), + '%s * (mf"TRKEI_DEMAND" + mf"TRKIE_DEMAND" + mf"TRKEE_DEMAND")' % (share)) + # Set intrazonal truck trips to 0 + matrix_calc.add('mf"TRK%s_DEMAND"' % (t_type), 'mf"TRK%s_DEMAND" * (p.ne.q)' % (t_type)) + matrix_calc.run() + + @_m.logbook_trace('Distribute daily demand into time of day') + def split_into_time_of_day(self): + matrix_calc = dem_utils.MatrixCalculator(self.scenario, self.num_processors) + periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + time_share = [0.1018, 0.1698, 0.4284, 0.1543, 0.1457] + border_time_share = [0.0188, 0.1812, 0.4629, 0.2310, 0.1061] + border_correction = [bs/s for bs, s in zip(border_time_share, time_share)] + + truck_types = ['L', 'M', 'H'] + truck_names = {"L": "light trucks", "M": "medium trucks", "H": "heavy trucks"} + + for period, share, border_corr in zip(periods, time_share, border_correction): + for t in truck_types: + with matrix_calc.trace_run('Calculate %s demand matrix for %s' % (period, truck_names[t])): + tod_demand = 'mf"%s_TRK_%s_VEH"' % (period, t) + matrix_calc.add(tod_demand, 'mf"TRK%s_DEMAND"' % (t)) + matrix_calc.add(tod_demand, 'mf%s_TRK_%s_VEH * %s' % (period, t, share)) + matrix_calc.add(tod_demand, 'mf%s_TRK_%s_VEH * %s' % (period, t, border_corr), + {"origins": "1-5", "destinations": "1-9999"}) + matrix_calc.add(tod_demand, 'mf%s_TRK_%s_VEH * %s' % (period, t, border_corr), + {"origins": "1-9999", "destinations": "1-5"}) + + @_m.logbook_trace('Toll diversion') + def toll_diversion(self): + # NOTE: toll diversion skipped + pass + # matrix_calc = dem_utils.MatrixCalculator(self.scenario, self.num_processors) + # nest_factor = 10 + # vot = 0.02 # cent/min + # periods = ['EA', 'AM', 'MD', 'PM', 'EV'] + # truck_types = ['L', 'M', 'H'] + # truck_toll_factors = [1, 1.03, 2.33] + + # for period in periods: + # for truck, toll_factor in zip(truck_types, truck_toll_factors): + # with matrix_calc.trace_run('Toll diversion for period %s, truck type %s' % (period, truck) ): + # # Define the utility expression + # utility = """ + # ( + # (mf"%(p)s_TRK%(t)sGP_TIME" - mf"%(p)s_TRK%(t)sTOLL_TIME") + # - %(vot)s * mf"%(p)s_TRK%(t)sTOLL_TOLLCOST" * %(t_fact)s + # ) + # / %(n_fact)s + # """ % { + # 'p': period, + # 't': truck, + # 'vot': vot, + # 't_fact': toll_factor, + # 'n_fact': nest_factor + # } + # # If there is no toll probability of using toll is 0 + # matrix_calc.add('mf"%s_TRK%sTOLL_VEH"' % (period, truck), '0') + # # If there is a non-zero toll value compute the share of + # # toll-available passengers using the utility expression defined earlier + # matrix_calc.add('mf"%s_TRK%sTOLL_VEH"' % (period, truck), + # 'mf"%(p)s_TRK%(t)s" * (1/(1 + exp(- %(u)s)))' % {'p': period, 't': truck, 'u': utility}, + # ['mf"%s_TRK%sTOLL_TOLLCOST"' % (period, truck), 0, 0 , "EXCLUDE"]) + # # if non-toll path is not available (GP time=0), set all demand to toll + # matrix_calc.add('mf"%s_TRK%sTOLL_VEH"' % (period, truck), + # 'mf"%(p)s_TRK%(t)s"' % {'p': period, 't': truck}, + # ['mf"%(p)s_TRK%(t)sGP_TIME"' % {'p': period, 't': truck}, 0, 0 , "INCLUDE"]) + # # Compute the truck demand for non toll + # matrix_calc.add('mf"%s_TRK%sGP_VEH"' % (period, truck), + # '(mf"%(p)s_TRK%(t)s" - mf"%(p)s_TRK%(t)sTOLL_VEH").max.0' % {'p': period, 't': truck}) diff --git a/sandag_abm/src/main/emme/toolbox/model/truck/generation.py b/sandag_abm/src/main/emme/toolbox/model/truck/generation.py new file mode 100644 index 0000000..c0c10a8 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/truck/generation.py @@ -0,0 +1,443 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// model/truck/generation.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Runs the truck generation step. Generates standard truck trip and special (military) truck trips, +# and generates regional truck trips, IE trips, EI trips and EE trips and balances truck trips. +# +# Inputs: +# input_directory: source directory for most input files, including demographics and trip rates +# input_truck_directory: source for special truck files +# scenario: traffic scenario to use for reference zone system +# +# Files referenced: +# Note: YEAR is replaced by truck.FFyear in the conf/sandag_abm.properties file +# input/TruckTripRates.csv +# file referenced by key mgra.socec.file, e.g. input/mgra13_based_inputYEAR.csv +# input/specialGenerators.csv +# input_truck/regionalIEtripsYEAR.csv +# input_truck/regionalEItripsYEAR.csv +# input_truck/regionalEEtripsYEAR.csv +# +# Matrix results: +# moTRKL_PROD, moTRKM_PROD, moTRKH_PROD, moTRKEI_PROD, moTRKIE_PROD +# mdTRKL_ATTR, mdTRKM_ATTR, mdTRKH_ATTR, mdTRKEI_ATTR, mdTRKIE_ATTR +# mfTRKEE_DEMAND +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + project_dir = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(project_dir, "input") + input_truck_dir = os.path.join(project_dir, "input_truck") + base_scenario = modeller.scenario + generation = modeller.tool("sandag.model.truck.generation") + generation(input_dir, input_truck_dir, base_scenario) +""" + + + + +TOOLBOX_ORDER = 42 + + +import inro.modeller as _m +import traceback as _traceback +import numpy as np +import pandas as pd +import os + + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class TruckGeneration(_m.Tool(), gen_utils.Snapshot): + + input_directory = _m.Attribute(str) + input_truck_directory = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.input_truck_directory = os.path.join(os.path.dirname(project_dir), "input_truck") + self.attributes = ["input_directory", "input_truck_directory"] + self._properties = None + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Truck generation" + pb.description = """ +
+ Generates standard truck trip and special (military) truck trips as well as + regional truck trips, IE trips, EI trips and EE trips and balances truck trips + productions / attractions. +
""" + pb.branding_text = "- SANDAG - Model - Truck" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + pb.add_select_file('input_truck_directory', 'directory', + title='Select truck input directory') + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.input_directory, self.input_truck_directory, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Truck generation') + def __call__(self, input_directory, input_truck_directory, scenario): + attributes = {"input_directory": input_directory, "input_truck_directory": input_truck_directory} + gen_utils.log_snapshot("Truck generation", str(self), attributes) + self.input_directory = input_directory + self.input_truck_directory = input_truck_directory + self.scenario = scenario + load_properties = _m.Modeller().tool('sandag.utilities.properties') + + self._properties = load_properties( + os.path.join(os.path.dirname(input_directory), "conf", "sandag_abm.properties")) + base_trucks_PA = self.truck_standard_generation() + special_trucks_PA = self.special_truck_generation(base_trucks_PA) + trucks_PA = self.balance_truck_PA(special_trucks_PA) + self.store_PA_to_matrices(trucks_PA) + self.read_external_external_demand() + return trucks_PA + + def truck_standard_generation(self): + year = self._properties['truck.FFyear'] + is_interim_year, prev_year, next_year = self.interim_year_check(year) + head, mgra_input_file = os.path.split(self._properties['mgra.socec.file']) + if is_interim_year: + taz_prev_year = self.create_demographics_by_taz( + mgra_input_file.replace(str(year), str(prev_year))) + taz_next_year = self.create_demographics_by_taz( + mgra_input_file.replace(str(year), str(next_year))) + taz = self.interpolate_df(prev_year, year, next_year, taz_prev_year, taz_next_year) + else: + taz = self.create_demographics_by_taz(mgra_input_file) + + trip_rates = pd.read_csv( + os.path.join(self.input_directory, 'TruckTripRates.csv')) + taz = pd.merge(taz, trip_rates, + left_on='truckregiontype', right_on='RegionType', how='left') + taz.fillna(0, inplace=True) + + # Compute lhd truck productions "AGREMPN", "CONEMPN", "RETEMPN", "GOVEMPN", + # "MANEMPN", "UTLEMPN", "WHSEMPN", "OTHEMPN" + taz['LHD_Productions'] = \ + (taz['emp_agmin'] + taz['emp_cons']) * taz['TG_L_Ag/Min/Constr'] \ + + taz['emp_retrade'] * taz['TG_L_Retail'] \ + + taz['emp_gov'] * taz['TG_L_Government'] \ + + taz['emp_mfg'] * taz['TG_L_Manufacturing'] \ + + taz['emp_twu'] * taz['TG_L_Transp/Utilities'] \ + + taz['emp_whtrade'] * taz['TG_L_Wholesale'] \ + + taz['emp_other'] * taz['TG_L_Other'] \ + + taz['hh'] * taz['TG_L_Households'] + + taz['LHD_Attractions'] = \ + (taz['emp_agmin'] + taz['emp_cons']) * taz['TA_L_Ag/Min/Constr'] \ + + taz['emp_retrade'] * taz['TA_L_Retail'] \ + + taz['emp_gov'] * taz['TA_L_Government'] \ + + taz['emp_mfg'] * taz['TA_L_Manufacturing'] \ + + taz['emp_twu'] * taz['TA_L_Transp/Utilities'] \ + + taz['emp_whtrade'] * taz['TA_L_Wholesale'] \ + + taz['emp_other'] * taz['TA_L_Other'] \ + + taz['hh'] * taz['TA_L_Households'] + + taz['MHD_Productions'] = \ + (taz['emp_agmin'] + taz['emp_cons']) * taz['TG_M_Ag/Min/Constr'] \ + + taz['emp_retrade'] * taz['TG_M_Retail'] \ + + taz['emp_gov'] * taz['TG_M_Government'] \ + + taz['emp_mfg'] * taz['TG_M_Manufacturing'] \ + + taz['emp_twu'] * taz['TG_M_Transp/Utilities'] \ + + taz['emp_whtrade'] * taz['TG_M_Wholesale'] \ + + taz['emp_other'] * taz['TG_M_Other'] \ + + taz['hh'] * taz['TG_M_Households'] + + taz['MHD_Attractions'] = \ + (taz['emp_agmin'] + taz['emp_cons']) * taz['TA_M_Ag/Min/Constr'] \ + + taz['emp_retrade'] * taz['TA_M_Retail'] \ + + taz['emp_gov'] * taz['TA_M_Government'] \ + + taz['emp_mfg'] * taz['TA_M_Manufacturing'] \ + + taz['emp_twu'] * taz['TA_M_Transp/Utilities'] \ + + taz['emp_whtrade'] * taz['TA_M_Wholesale'] \ + + taz['emp_other'] * taz['TA_M_Other'] \ + + taz['hh'] * taz['TA_M_Households'] + + taz['HHD_Productions'] = \ + (taz['emp_agmin'] + taz['emp_cons']) * taz['TG_H_Ag/Min/Constr'] \ + + taz['emp_retrade'] * taz['TG_H_Retail'] \ + + taz['emp_gov'] * taz['TG_H_Government'] \ + + taz['emp_mfg'] * taz['TG_H_Manufacturing'] \ + + taz['emp_twu'] * taz['TG_H_Transp/Utilities'] \ + + taz['emp_whtrade'] * taz['TG_H_Wholesale'] \ + + taz['emp_other'] * taz['TG_H_Other'] \ + + taz['hh'] * taz['TG_H_Households'] + + taz['HHD_Attractions'] = \ + (taz['emp_agmin'] + taz['emp_cons']) * taz['TA_H_Ag/Min/Constr'] \ + + taz['emp_retrade'] * taz['TA_H_Retail'] \ + + taz['emp_gov'] * taz['TA_H_Government'] \ + + taz['emp_mfg'] * taz['TA_H_Manufacturing'] \ + + taz['emp_twu'] * taz['TA_H_Transp/Utilities'] \ + + taz['emp_whtrade'] * taz['TA_H_Wholesale'] \ + + taz['emp_other'] * taz['TA_H_Other'] \ + + taz['hh'] * taz['TA_H_Households'] + + taz.reset_index(inplace=True) + taz = taz[['taz', + 'LHD_Productions', 'LHD_Attractions', + 'MHD_Productions', 'MHD_Attractions', + 'HHD_Productions', 'HHD_Attractions']] + return taz + + # Creates households and employments by TAZ. + # Specific to the truck trip generation model. + # Inputs: + # - sandag.properties + # - input/mgra13_based_input20XX.csv (referenced by mgra.socec.file in properties file) + def create_demographics_by_taz(self, mgra_input_file): + utils = _m.Modeller().module('sandag.utilities.demand') + dt = _m.Modeller().desktop.project.data_tables() + file_path = os.path.join(self.input_directory, mgra_input_file) + if not os.path.exists(file_path): + raise Exception("MGRA input file '%s' does not exist" % file_path) + mgra = pd.read_csv(file_path) + # Combine employment fields that match to the truck trip rate classification + mgra['TOTEMP'] = mgra.emp_total + mgra['emp_agmin'] = mgra.emp_ag + mgra['emp_cons'] = mgra.emp_const_bldg_prod + mgra.emp_const_bldg_office + mgra['emp_retrade'] = mgra.emp_retail + mgra.emp_personal_svcs_retail + mgra['emp_gov']= mgra.emp_state_local_gov_ent \ + + mgra.emp_state_local_gov_blue \ + + mgra.emp_state_local_gov_white \ + + mgra.emp_fed_non_mil \ + + mgra.emp_fed_mil + mgra['emp_mfg'] = mgra.emp_mfg_prod \ + + mgra.emp_mfg_office + mgra['emp_twu'] = mgra.emp_trans \ + + mgra.emp_utilities_office \ + + mgra.emp_utilities_prod + mgra['emp_whtrade'] = mgra.emp_whsle_whs + mgra['emp_other'] = mgra.TOTEMP \ + - mgra.emp_agmin \ + - mgra.emp_cons \ + - mgra.emp_retrade \ + - mgra.emp_gov \ + - mgra.emp_mfg \ + - mgra.emp_twu \ + - mgra.emp_whtrade + + f = { + 'truckregiontype':['mean'], + 'emp_agmin':['sum'], + 'emp_cons': ['sum'], + 'emp_retrade': ['sum'], + 'emp_gov': ['sum'], + 'emp_mfg': ['sum'], + 'emp_twu': ['sum'], + 'emp_whtrade': ['sum'], + 'emp_other': ['sum'], + 'hh': ['sum'] + } + + mgra = mgra[['truckregiontype', 'emp_agmin', 'emp_cons', + 'emp_retrade', 'emp_gov', 'emp_mfg', 'emp_twu', + 'emp_whtrade', 'emp_other', 'taz', 'hh']] + taz = mgra.groupby('taz').agg(f) + taz.reset_index(inplace=True) + taz.columns = taz.columns.droplevel(-1) + # Add external zones + taz = utils.add_missing_zones(taz, self.scenario) + return taz + + # Add trucks generated by special generators, such as military sites, + # mail to//from airport, cruise ships etc + # Inputs: + # - input/specialGenerators.csv + # - dataframe: base_trucks + def special_truck_generation(self, base_trucks): + year = self._properties['truck.FFyear'] + is_interim_year, prev_year, next_year = self.interim_year_check(year) + spec_gen = pd.read_csv(os.path.join(self.input_directory, 'specialGenerators.csv')) + spec_gen = pd.merge(spec_gen, base_trucks, + left_on=['TAZ'], right_on=['taz'], how='outer') + spec_gen.fillna(0, inplace=True) + if is_interim_year: + year_ratio = float(year - prev_year) / (next_year - prev_year) + prev_year, next_year = 'Y%s' % prev_year, 'Y%s' % next_year + spec_gen['Y%s' % year] = spec_gen[prev_year] + year_ratio * (spec_gen[next_year] - spec_gen[prev_year]) + + for t in ['L', 'M', 'H']: + spec_gen['%sHD_Attr' % t] = spec_gen['%sHD_Attractions' % t] + \ + (spec_gen['Y%s' % year] * + spec_gen['trkAttraction'] * + spec_gen['%shdShare' % t.lower()]) + spec_gen['%sHD_Prod' % t] = spec_gen['%sHD_Productions' % t] + \ + (spec_gen['Y%s' % year] * + spec_gen['trkProduction'] * + spec_gen['%shdShare' % t.lower()]) + + special_trucks = spec_gen[ + ['taz', 'LHD_Prod', 'LHD_Attr', 'MHD_Prod', 'MHD_Attr', 'HHD_Prod', 'HHD_Attr']] + return special_trucks + + # Balance truck Productions and Attractions + def balance_truck_PA(self, truck_pa): + truck_pa = self.balance_internal_truck_PA(truck_pa) + regional_truck_pa = self.get_regional_truck_PA() + truck_pa = self.add_balanced_regional_PA(regional_truck_pa, truck_pa) + truck_pa.fillna(0, inplace=True) + + truck_pa['TRKL_Prod'] = truck_pa['LHD_Prod'] + truck_pa['TRKM_Prod'] = truck_pa['MHD_Prod'] + truck_pa['TRKH_Prod'] = truck_pa['HHD_Prod'] + truck_pa['TRKIE_Prod'] = truck_pa['IE_Prod'] + truck_pa['TRKEI_Prod'] = truck_pa['EI_Prod'] + + truck_pa['TRKL_Attr'] = truck_pa['LHD_Attr'] + truck_pa['TRKM_Attr'] = truck_pa['MHD_Attr'] + truck_pa['TRKH_Attr'] = truck_pa['HHD_Attr'] + truck_pa['TRKIE_Attr'] = truck_pa['IE_Attr'] + truck_pa['TRKEI_Attr'] = truck_pa['EI_Attr'] + return truck_pa + + def get_regional_truck_PA(self): + year = self._properties['truck.FFyear'] + trips = {} + regional_trip_types = ['IE', 'EI', 'EE'] + is_interim_year, prev_year, next_year = self.interim_year_check(year) + if is_interim_year: + for t in regional_trip_types: + prev_trips = pd.read_csv(os.path.join( + self.input_truck_directory, + 'regional%strips%s.csv' % (t, prev_year))) + next_trips = pd.read_csv(os.path.join( + self.input_truck_directory, + 'regional%strips%s.csv' % (t, next_year))) + trips_df = self.interpolate_df(prev_year, year, next_year, prev_trips, next_trips) + trips[t] = trips_df + + for t in regional_trip_types: + trips[t] = pd.read_csv(os.path.join( + self.input_truck_directory, + 'regional%strips%s.csv' % (t, year))) + return trips + + def balance_internal_truck_PA(self, truck_pa): + truck_types = ['LHD', 'MHD', 'HHD'] + for t in truck_types: + s1 = truck_pa['%s_Prod' % t].sum() + s2 = truck_pa['%s_Attr' % t].sum() + avg = (s1 + s2)/2.0 + w1 = avg / s1 + w2 = avg / s2 + truck_pa['%s_Prod_unbalanced' % t] = truck_pa['%s_Prod' % t] + truck_pa['%s_Attr_unbalanced' % t] = truck_pa['%s_Attr' % t] + truck_pa['%s_Prod' % t] = truck_pa['%s_Prod' % t] * w1 + truck_pa['%s_Attr' % t] = truck_pa['%s_Attr' % t] * w2 + return truck_pa + + # Balance only EI and IE. EE truck trips are already balanced and can be + # directly imported as a matrix + def add_balanced_regional_PA(self, regional_trips, truck_pa): + ei_trips = regional_trips['EI'] + ei_trips = ei_trips.groupby('fromZone').sum() + ei_trips.reset_index(inplace=True) + + truck_pa = pd.merge(truck_pa, + ei_trips[['fromZone', 'EITrucks']], + left_on='taz', right_on='fromZone', + how='outer') + + sum_ei = ei_trips['EITrucks'].sum() + sum_hhd_attr = truck_pa['HHD_Attr'].sum() + truck_pa['EI_Attr'] = truck_pa['HHD_Attr'] * sum_ei / sum_hhd_attr + truck_pa['EI_Prod'] = truck_pa['EITrucks'] + + ie_trips = regional_trips['IE'] + ie_trips = ie_trips.groupby('toZone').sum() + ie_trips.reset_index(inplace=True) + truck_pa = pd.merge(truck_pa, + ie_trips[['toZone', 'IETrucks']], + left_on='taz', right_on='toZone', + how='outer') + + sum_ie = ie_trips['IETrucks'].sum() + sum_hhd_prod = truck_pa['HHD_Prod'].sum() + truck_pa['IE_Prod'] = truck_pa['HHD_Prod'] * sum_ie / sum_hhd_prod + truck_pa['IE_Attr'] = truck_pa['IETrucks'] + truck_pa.fillna(0, inplace=True) + + return truck_pa + + def store_PA_to_matrices(self, truck_pa): + emmebank = self.scenario.emmebank + truck_pa.sort_values('taz', inplace=True) #sort method was deprecated since version 0.20.0, yma, 2/12/2019 + control_to_store = ['L', 'M', 'H', 'EI', 'IE'] + for t in control_to_store: + prod = emmebank.matrix('moTRK%s_PROD' % t) + prod.set_numpy_data(truck_pa['TRK%s_Prod' % t].values, self.scenario) + attr = emmebank.matrix('mdTRK%s_ATTR' % t) + attr.set_numpy_data(truck_pa['TRK%s_Attr' % t].values, self.scenario) + + @_m.logbook_trace('External - external truck matrix') + def read_external_external_demand(self): + utils = _m.Modeller().module('sandag.utilities.demand') + emmebank = self.scenario.emmebank + regional_trips = self.get_regional_truck_PA() + ee = regional_trips['EE'] + m_ee = emmebank.matrix('mfTRKEE_DEMAND') + m_ee_data = m_ee.get_data(self.scenario) + for i, row in ee.iterrows(): + m_ee_data.set(row['fromZone'], row['toZone'], row['EETrucks']) + m_ee.set_data(m_ee_data, self.scenario) + + def interpolate_df(self, prev_year, new_year, next_year, prev_year_df, next_year_df): + current_year_df = pd.DataFrame() + year_ratio = float(new_year - prev_year) / (next_year - prev_year) + for key in prev_year_df.columns: + current_year_df[key] = ( + prev_year_df[key] + year_ratio * (next_year_df[key] - prev_year_df[key])) + return current_year_df + + def interim_year_check(self, year): + years_with_data = self._properties['truck.DFyear'] + if year in years_with_data: + return (False, year, year) + else: + next_year_idx = np.searchsorted(years_with_data, year) + if next_year_idx == 0 or next_year_idx > len(years_with_data): + raise Exception('Cannot interpolate data for year %s' % year) + prev_year = years_with_data[next_year_idx - 1] + next_year = years_with_data[next_year_idx] + return (True, prev_year, next_year) diff --git a/sandag_abm/src/main/emme/toolbox/model/truck/run_truck_model.py b/sandag_abm/src/main/emme/toolbox/model/truck/run_truck_model.py new file mode 100644 index 0000000..8185ca0 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/model/truck/run_truck_model.py @@ -0,0 +1,130 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// truck/run_truck_model.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +# +# Runs the truck model, the generation and distribution tools, in sequence. +# 1) Generates standard truck trip and special (military) truck trips +# 2) Generates regional truck trips, IE trips, EI trips and EE trips and +# balances truck trips +# 3) Distributes trips based on congested skims and splits by time of day +# 4) Applies truck toll diversion model with toll and non-toll skims +# +# Inputs: +# run_generation: boolean, if True run generation tool. +# input_directory: source directory for most input files, including demographics and trip rates +# (see generation and distribtuion tools) +# input_truck_directory: source for special truck files (see generation tool) +# num_processors: Number of processors to use, either as a number or "MAX-#" +# scenario: traffic scenario to use for reference zone system +# +# Script example: +""" + import os + modeller = inro.modeller.Modeller() + project_dir = os.path.dirname(os.path.dirname(modeller.desktop.project.path)) + input_dir = os.path.join(project_dir, "input") + input_truck_dir = os.path.join(project_dir, "input_truck") + base_scenario = modeller.scenario + num_processors = "MAX-1" + run_truck = modeller.tool("sandag.model.truck.run_truck_model") + run_truck(True, input_dir, input_truck_dir, num_processors, base_scenario) +""" + + + +TOOLBOX_ORDER = 41 + + +import inro.modeller as _m +import traceback as _traceback +import os + + +dem_utils = _m.Modeller().module("sandag.utilities.demand") +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class TruckModel(_m.Tool(), gen_utils.Snapshot): + + input_directory = _m.Attribute(str) + input_truck_directory = _m.Attribute(str) + run_generation = _m.Attribute(bool) + num_processors = _m.Attribute(str) + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def __init__(self): + self.run_generation = True + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.input_directory = os.path.join(os.path.dirname(project_dir), "input") + self.input_truck_directory = os.path.join(os.path.dirname(project_dir), "input_truck") + self.num_processors = "MAX-1" + self.attributes = ["input_directory", "input_truck_directory", "run_generation", "num_processors"] + + def page(self): + # Equivalent to TruckModel.rsc + pb = _m.ToolPageBuilder(self) + pb.title = "Truck model" + pb.description = """ +
+ 1) Generates standard truck trip and special (military) truck trips
+ 2) Gets regional truck trips, IE trips, EI trips and EE trips and balances truck trips
+ 3) Distributes truck trips with congested skims and splits by time of day
+ 4) Applies truck toll diversion model with free-flow toll and non-toll skims
+
+""" + pb.branding_text = "- SANDAG - Model - Truck" + + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + pb.add_checkbox("run_generation", title=" ", label="Run generation (first iteration)") + + pb.add_select_file('input_directory', 'directory', + title='Select input directory') + pb.add_select_file('input_truck_directory', 'directory', + title='Select truck input directory') + dem_utils.add_select_processors("num_processors", pb, self) + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + scenario = _m.Modeller().scenario + self(self.run_generation, self.input_directory, self.input_truck_directory, self.num_processors, scenario) + run_msg = "Tool complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + @_m.logbook_trace('Truck model', save_arguments=True) + def __call__(self, run_generation, input_directory, input_truck_directory, num_processors, scenario): + attributes = { + "input_directory": input_directory, "input_truck_directory": input_truck_directory, + "run_generation": run_generation, "num_processors": num_processors + } + gen_utils.log_snapshot("Truck model", str(self), attributes) + + generation = _m.Modeller().tool('sandag.model.truck.generation') + distribution = _m.Modeller().tool('sandag.model.truck.distribution') + + if run_generation: + generation(input_directory, input_truck_directory, scenario) + distribution(input_directory, num_processors, scenario) diff --git a/sandag_abm/src/main/emme/toolbox/utilities/demand.py b/sandag_abm/src/main/emme/toolbox/utilities/demand.py new file mode 100644 index 0000000..bcd0f5f --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/utilities/demand.py @@ -0,0 +1,297 @@ +##////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// utilities/demand.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// + +TOOLBOX_ORDER = 101 + + +import inro.emme.datatable as _dt +import inro.modeller as _m +from collections import OrderedDict +from contextlib import contextmanager as _context +from copy import deepcopy as _copy +import multiprocessing as _multiprocessing +import re as _re +import pandas as _pandas +import numpy as _numpy +import os + + +class Utils(_m.Tool()): + + def page(self): + pb = _m.ToolPageBuilder(self, runnable=False) + pb.title = 'Demand utility' + pb.description = """Utility tool / module for common code. Not runnable.""" + pb.branding_text = ' - SANDAG - Utilities' + return pb.render() + + +# Read a CSV file, store it as a DataTable and return a representative DataFrame +def csv_to_data_table(path, overwrite=False): + layer_name = os.path.splitext(os.path.basename(path))[0] + data_source = _dt.DataSource(path) + data = data_source.layer(layer_name).get_data() + desktop = _m.Modeller().desktop + dt_db = desktop.project.data_tables() + table = dt_db.create_table(layer_name, data, overwrite=overwrite) + return table_to_dataframe(table) + + +# Convert a DataTable into a DataFrame +def table_to_dataframe(table): + if type(table) == str: + desktop = _m.Modeller().desktop + dt_db = desktop.project.data_tables() + table_name = table + table = dt_db.table(table) + if not table: + raise Exception('%s is not a valid table name.' %table_name) + + df = _pandas.DataFrame() + for attribute in table.get_data().attributes(): + try: + df[attribute.name] = attribute.values.astype(float) + except Exception, e: + df[attribute.name] = attribute.values + + return df + + +# Convert a dataframe to a datatable +def dataframe_to_table(df, name): + desktop = _m.Modeller().desktop + dt_db = desktop.project.data_tables() + data = _dt.Data() + for key in df.columns: + found_dtype = False + dtypes = [ + (bool, True, 'BOOLEAN'), + (int, 0, 'INTEGER32'), + (int, 0, 'INTEGER'), + (float, 0, 'REAL') + ] + for caster, default, name in dtypes: + try: + df[[key]] = df[[key]].fillna(default) + values = df[key].astype(caster) + attribute = _dt.Attribute(key, values, name) + found_dtype = True + break + except ValueError: + pass + + if not found_dtype: + df[[key]] = df[[key]].fillna(0) + values = df[key].astype(str) + attribute = _dt.Attribute(key, values, 'STRING') + + data.add_attribute(attribute) + + table = dt_db.create_table(name, data, overwrite=True) + return table + +# Add missing (usually external zones 1 to 12) zones to the DataFrame +# and populate with zeros +def add_missing_zones(df, scenario): + all_zones = scenario.zone_numbers + existing_zones = df['taz'].values + missing_zones = set(all_zones) - set(existing_zones) + num_missing = len(missing_zones) + if num_missing == 0: + return df + + ext_df = _pandas.DataFrame() + for c in df.columns: + ext_df[c] = _numpy.zeros(num_missing) + ext_df['taz'] = _numpy.array(list(missing_zones)) + df = _pandas.concat([df, ext_df]) + df = df.sort_values('taz', ascending=True) # sort method was deprecated in version 0.20.0,yma,2/12/2019 + return df + + +def add_select_processors(tool_attr_name, pb, tool): + max_processors = _multiprocessing.cpu_count() + tool._max_processors = max_processors + options = [("MAX-1", "Maximum available - 1"), ("MAX", "Maximum available")] + options.extend([(n, "%s processors" % n) for n in range(1, max_processors + 1) ]) + pb.add_select(tool_attr_name, options, title="Number of processors:") + + +def parse_num_processors(value): + max_processors = _multiprocessing.cpu_count() + if isinstance(value, int): + return value + if isinstance(value, basestring): + if value == "MAX": + return max_processors + if _re.match("^[0-9]+$", value): + return int(value) + result = _re.split("^MAX[\s]*-[\s]*", value) + if len(result) == 2: + return max(max_processors - int(result[1]), 1) + if value: + return int(value) + return value + +class MatrixCalculator(object): + def __init__(self, scenario, num_processors=0): + self._scenario = scenario + self._matrix_calc = _m.Modeller().tool( + "inro.emme.matrix_calculation.matrix_calculator") + self._specs = [] + self._last_report = None + self.num_processors = num_processors + + @property + def num_processors(self): + return self._num_processors + + @num_processors.setter + def num_processors(self, value): + self._num_processors = parse_num_processors(value) + + @property + def last_report(self): + return _copy(self._last_report) + + @_context + def trace_run(self, name): + with _m.logbook_trace(name): + yield + self.run() + + def add(self, result, expression, constraint=None, aggregation=None): + spec = self._format_spec(result, expression, constraint, aggregation) + self._specs.append(spec) + + def _format_spec(self, result, expression, constraint, aggregation): + spec = { + "result": result, + "expression": expression, + "type": "MATRIX_CALCULATION" + } + if constraint is not None: + if isinstance(constraint, (list, tuple)): + # specified as list of by_value inputs + constraint = { + "by_value": { + "od_values": constraint[0], + "interval_min": constraint[1], + "interval_max": constraint[2], + "condition": constraint[3] + } + } + elif "od_values" in constraint: + # specified as the by_value sub-dictionary only + constraint = {"by_value": constraint} + # By zone constraints + elif ("destinations" in constraint or "origins" in constraint): + # specified as the by_zone sub-dictionary only + constraint = {"by_zone": constraint} + # otherwise, specified as a regular full constraint dictionary + if "by_value" in constraint: + # cast the inputs to the correct values + constraint["by_value"]["od_values"] = \ + str(constraint["by_value"]["od_values"]) + constraint["by_value"]["condition"] = \ + constraint["by_value"]["condition"].upper() + spec["constraint"] = constraint + + #Add None for missing key values if needed + if "by_value" not in constraint: + constraint["by_value"] = None + if "by_zone" not in constraint: + constraint["by_zone"] = None + + else: + spec["constraint"] = None + + if aggregation is not None: + if isinstance(aggregation, basestring): + aggregation = {"origins": aggregation} + spec["aggregation"] = aggregation + else: + spec["aggregation"] = None + return spec + + def add_spec(self, spec): + self._specs.append(spec) + + def run(self): + specs, self._specs = self._specs, [] + report = self._matrix_calc(specs, scenario=self._scenario, + num_processors=self._num_processors) + self._last_report = report + return report + + def run_single(self, result, expression, constraint=None, aggregation=None): + spec = self._format_spec(result, expression, constraint, aggregation) + return self._matrix_calc(spec, scenario=self._scenario, + num_processors=self._num_processors) + + +def reduce_matrix_precision(matrices, precision, num_processors, scenario): + emmebank = scenario.emmebank + calc = MatrixCalculator(scenario, num_processors) + gen_utils = _m.Modeller().module('sandag.utilities.general') + with gen_utils.temp_matrices(emmebank, "SCALAR", 2) as (sum1, sum2): + sum1.name = "ORIGINAL_SUM" + sum2.name = "ROUNDED_SUM" + for mat in matrices: + mat = emmebank.matrix(mat).named_id + with calc.trace_run('Reduce precision for matrix %s' % mat): + calc.add(sum1.named_id, mat, aggregation={"destinations": "+", "origins": "+"}) + calc.add(mat, "{mat} * ({mat} >= {precision})".format( + mat=mat, precision=precision)) + calc.add(sum2.named_id, mat, aggregation={"destinations": "+", "origins": "+"}) + calc.add(sum2.named_id, "({sum2} + ({sum2} == 0))".format(sum2=sum2.named_id)) + calc.add(mat, "{mat} * ({sum1} / {sum2})".format( + mat=mat, sum2=sum2.named_id, sum1=sum1.named_id)) + + +def create_full_matrix(name, desc, scenario): + create_matrix = _m.Modeller().tool( + "inro.emme.data.matrix.create_matrix") + emmebank = scenario.emmebank + matrix = emmebank.matrix(name) + if matrix: + ident = matrix.id + else: + used_ids = set([]) + for m in emmebank.matrices(): + if m.prefix == "mf": + used_ids.add(int(m.id[2:])) + for i in range(900, emmebank.dimensions["full_matrices"]): + if i not in used_ids: + ident = "mf" + str(i) + break + else: + raise Exception("Not enough available matrix IDs for selected demand. Change database dimensions to increase full matrices.") + return create_matrix(ident, name, desc, scenario=scenario, overwrite=True) + + +def demand_report(matrices, label, scenario, report=None): + text = ['
'] + text.append("%-28s %13s" % ("name", "sum")) + for name, data in matrices: + stats = (name, data.sum()) + text.append("%-28s %13.7g" % stats) + text.append("
") + title = "Demand summary" + if report is None: + report = _m.PageBuilder(title) + report.wrap_html('Matrix details', "
".join(text)) + _m.logbook_write(label, report.render()) + else: + report.wrap_html(label, "
".join(text)) diff --git a/sandag_abm/src/main/emme/toolbox/utilities/file_manager.py b/sandag_abm/src/main/emme/toolbox/utilities/file_manager.py new file mode 100644 index 0000000..6e56df5 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/utilities/file_manager.py @@ -0,0 +1,370 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2018. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// utilities/file_manager.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// +# +TOOLBOX_ORDER = 104 + + +import inro.modeller as _m +import inro.emme.database.emmebank as _eb +import inro.director.logging as _log + +import traceback as _traceback +import shutil as _shutil +import time as _time +import os +from fnmatch import fnmatch as _fnmatch +from math import log10 + +_join = os.path.join +_dir = os.path.dirname +_norm = os.path.normpath + +gen_utils = _m.Modeller().module("sandag.utilities.general") + + +class FileManagerTool(_m.Tool(), gen_utils.Snapshot): + + operation = _m.Attribute(unicode) + remote_dir = _m.Attribute(unicode) + local_dir = _m.Attribute(unicode) + user_folder = _m.Attribute(unicode) + scenario_id = _m.Attribute(unicode) + initialize = _m.Attribute(_m.BooleanType) + delete_local_files = _m.Attribute(_m.BooleanType) + + tool_run_msg = "" + LOCAL_ROOT = "C:\\abm_runs" + + def __init__(self): + self.operation = "UPLOAD" + project_dir = _dir(_m.Modeller().desktop.project.path) + self.remote_dir = _dir(project_dir) + folder_name = os.path.basename(self.remote_dir) + self.user_folder = os.environ.get("USERNAME") + self.scenario_id = 100 + self.initialize = True + self.delete_local_files = True + self.attributes = [ + "operation", "remote_dir", "local_dir", "user_folder", + "scenario_id", "initialize", "delete_local_files" + ] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "File run manager utility" + pb.description = """ +

+ Utility tool to manually manage the use of the local drive for subsequent model run. + The remote data can be downloaded (copied) to the local drive; + or the local data can be uploaded to the remote drive. + In normal operation this tool does not need to run manually, but in case of an + error it may be necessary to upload the project data in order to run on + a different machine, or operate directly on the server. +

+

+ Note that file masks are used from config/sandag_abm.properties to identify which + files to copy. See RunModel.FileMask.Upload and RunModel.FileMask.Download for + upload and download respectively. +

""" + pb.branding_text = "- SANDAG" + if self.tool_run_msg: + pb.add_html(self.tool_run_msg) + + pb.add_radio_group('operation', title="File copy operation", + keyvalues=[("UPLOAD", "Upload from local directory to remote directory"), + ("DOWNLOAD", "Download from remote directory to local directory")], ) + pb.add_select_file('remote_dir','directory', + title='Select remote ABM directory (e.g. on T drive)', note='') + pb.add_text_box('user_folder', title="User folder (for local drive):") + pb.add_text_box('scenario_id', title="Base scenario ID:") + pb.add_checkbox_group( + [{"attribute": "delete_local_files", "label": "Delete all local files on completion (upload only)"}, + {"attribute": "initialize", "label": "Initialize all local files; if false only download files which are different (download only)"}]) + pb.add_html(""" +""") + + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self(self.operation, self.remote_dir, self.user_folder, self.scenario_id, + self.initialize, self.delete_local_files) + run_msg = "File copying complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + def __call__(self, operation, remote_dir, user_folder, scenario_id, initialize=True, delete_local_files=True): + load_properties = _m.Modeller().tool('sandag.utilities.properties') + props = load_properties(_join(remote_dir, "conf", "sandag_abm.properties")) + if operation == "DOWNLOAD": + file_masks = props.get("RunModel.FileMask.Download") + return self.download(remote_dir, user_folder, scenario_id, initialize, file_masks) + elif operation == "UPLOAD": + file_masks = props.get("RunModel.FileMask.Upload") + self.upload(remote_dir, user_folder, scenario_id, delete_local_files, file_masks) + else: + raise Exception("operation must be one of UPLOAD or DOWNLOAD") + + @_m.logbook_trace("Copy project data to local drive", save_arguments=True) + def download(self, remote_dir, user_folder, scenario_id, initialize, file_masks): + folder_name = os.path.basename(remote_dir) + user_folder = user_folder or os.environ.get("USERNAME") + if not user_folder: + raise Exception("Username must be specified for local drive operation " + "(or define USERNAME environment variable)") + if not os.path.exists(self.LOCAL_ROOT): + os.mkdir(self.LOCAL_ROOT) + user_directory = _join(self.LOCAL_ROOT, user_folder) + if not os.path.exists(user_directory): + os.mkdir(user_directory) + local_dir = _join(user_directory, folder_name) + if not os.path.exists(local_dir): + os.mkdir(local_dir) + + self._report = ["Copy"] + self._stats = {"size": 0, "count": 0} + if not file_masks: + # suggested default: "output", "report", "sql", "logFiles" + file_masks = [] + file_masks = [_join(remote_dir, p) for p in file_masks] + file_masks.append(_join(remote_dir, "emme_project")) + if initialize: + # make sure that all of the root directories are created + root_dirs = [ + "application", "bin", "conf", "emme_project", "input", "input_truck", + "logFiles", "output", "python", "report", "sql", "uec" + ] + for name in root_dirs: + if not os.path.exists(_join(local_dir, name)): + os.mkdir(_join(local_dir, name)) + # create new Emmebanks with scenario and matrix data + title_fcn = lambda t: "(local) " + t[:50] + emmebank_paths = self._copy_emme_data( + src=remote_dir, dst=local_dir, initialize=True, + title_fcn=title_fcn, scenario_id=scenario_id) + # add new emmebanks to the open project + # db_paths = set([db.core_emmebank.path for db in data_explorer.databases()]) + # for path in emmebank_paths: + # if path not in db_paths: + # _m.Modeller().desktop.data_explorer().add_database(path) + + # copy all files (except Emme project, and other file_masks) + self._copy_dir(src=remote_dir, dst=local_dir, + file_masks=file_masks, check_metadata=not initialize) + self.log_report() + return local_dir + + @_m.logbook_trace("Copy project data to remote drive", save_arguments=True) + def upload(self, remote_dir, user_folder, scenario_id, delete_local_files, file_masks): + folder_name = os.path.basename(remote_dir) + user_folder = user_folder or os.environ.get("USERNAME") + user_directory = _join(self.LOCAL_ROOT, user_folder) + local_dir = _join(user_directory, folder_name) + + self._report = [] + self._stats = {"size": 0, "count": 0} + if not file_masks: + # suggested defaults: "application", "bin", "input", "input_truck", "uec", + # "output\\iter*", "output\\*_1.csv", "output\\*_2.csv" + file_masks = [] + # prepend the src dir to the project masks + file_masks = [_join(local_dir, p) for p in file_masks] + # add to mask the emme_project folder + file_masks.append(_join(local_dir, "emme_project")) + + title_fcn = lambda t: t[8:] if t.startswith("(local)") else t + emmebank_paths = self._copy_emme_data( + src=local_dir, dst=remote_dir, title_fcn=title_fcn, scenario_id=scenario_id) + # copy all files (except Emme project, and other file_masks) + self._copy_dir(src=local_dir, dst=remote_dir, file_masks=file_masks) + self.log_report() + + # data_explorer = _m.Modeller().desktop.data_explorer() + # for path in emmebank_paths: + # for db in data_explorer.databases(): + # if db.core_emmebank.path == path: + # db.close() + # data_explorer.remove_database(db) + # data_explorer.databases()[0].open() + + if delete_local_files: + # small pause for file handles to close + _time.sleep(2) + for name in os.listdir(local_dir): + path = os.path.join(local_dir, name) + if os.path.isfile(path): + try: # no raise, local files can be left behind + os.remove(path) + except: + pass + elif os.path.isdir(path): + try: + _shutil.rmtree(path, ignore_errors=False) + except: + pass + + _shutil.rmtree(local_dir, ignore_errors=False) + + def _copy_emme_data(self, src, dst, title_fcn, scenario_id, initialize=False): + # copy data from Database and Database_transit using API and import tool + # create new emmebanks and copy emmebank data to local drive + import_from_db = _m.Modeller().tool("inro.emme.data.database.import_from_database") + emmebank_paths = [] + for db_dir in ["Database", "Database_transit"]: + src_db_path = _join(src, "emme_project", db_dir, "emmebank") + if not os.path.exists(src_db_path): + # skip if the database does not exist (will be created later) + continue + src_db = _eb.Emmebank(src_db_path) + dst_db_dir = _join(dst, "emme_project", db_dir) + dst_db_path = _join(dst_db_dir, "emmebank") + emmebank_paths.append(dst_db_path) + self._report.append("Copying Emme data
from %s
to %s" % (src_db_path, dst_db_path)) + self._report.append("Start: %s" % _time.strftime("%c")) + if initialize: + # remove any existing database (overwrite) + if os.path.exists(dst_db_path): + self._report.append("Warning: overwritting existing Emme database %s" % dst_db_path) + dst_db = _eb.Emmebank(dst_db_path) + dst_db.dispose() + if os.path.exists(dst_db_dir): + gen_utils.retry(lambda: _shutil.rmtree(dst_db_dir)) + gen_utils.retry(lambda: os.mkdir(dst_db_dir)) + dst_db = _eb.create(dst_db_path, src_db.dimensions) + else: + if not os.path.exists(dst_db_dir): + os.mkdir(dst_db_dir) + if os.path.exists(dst_db_path): + dst_db = _eb.Emmebank(dst_db_path) + else: + dst_db = _eb.create(dst_db_path, src_db.dimensions) + + dst_db.title = title_fcn(src_db.title) + for prop in ["coord_unit_length", "unit_of_length", "unit_of_cost", + "unit_of_energy", "use_engineering_notation", "node_number_digits"]: + setattr(dst_db, prop, getattr(src_db, prop)) + + if initialize: + src_db.dispose() + continue + + exfpars = [p for p in dir(src_db.extra_function_parameters) if p.startswith("e")] + for exfpar in exfpars: + value = getattr(src_db.extra_function_parameters, exfpar) + setattr(dst_db.extra_function_parameters, exfpar, value) + + for s in src_db.scenarios(): + if dst_db.scenario(s.id): + dst_db.delete_scenario(s) + for f in src_db.functions(): + if dst_db.function(f.id): + dst_db.delete_function(f) + for m in src_db.matrices(): + if dst_db.matrix(m.id): + dst_db.delete_matrix(m) + for p in dst_db.partitions(): + p.description = "" + p.initialize(0) + ref_scen = dst_db.scenario(999) + if not ref_scen: + ref_scen = dst_db.create_scenario(999) + import_from_db( + src_database=src_db, + src_scenario_ids=[s.id for s in src_db.scenarios()], + src_function_ids=[f.id for f in src_db.functions()], + copy_path_strat_files=True, + dst_database=dst_db, + dst_zone_system_scenario=ref_scen) + dst_db.delete_scenario(999) + src_matrices = [m.id for m in src_db.matrices()] + src_partitions = [p.id for p in src_db.partitions() + if not(p.description == '' and not (sum(p.raw_data)))] + if src_matrices or src_partitions: + import_from_db( + src_database=src_db, + src_zone_system_scenario=src_db.scenario(scenario_id), + src_matrix_ids=src_matrices, + src_partition_ids=src_partitions, + dst_database=dst_db, + dst_zone_system_scenario=dst_db.scenario(scenario_id)) + src_db.dispose() + self._report.append("End: %s" % _time.strftime("%c")) + return emmebank_paths + + def _copy_dir(self, src, dst, file_masks, check_metadata=False): + for name in os.listdir(src): + src_path = _join(src, name) + skip_file = bool([1 for mask in file_masks if _fnmatch(src_path, mask)]) + if skip_file: + continue + dst_path = _join(dst, name) + if os.path.isfile(src_path): + size = os.path.getsize(src_path) + if check_metadata and os.path.exists(dst_path): + same_size = os.path.getsize(dst_path) == size + same_time = os.path.getmtime(dst_path) == os.path.getmtime(src_path) + if same_size and same_time: + continue + self._report.append(_time.strftime("%c")) + self._report.append(dst_path + file_size(size)) + self._stats["size"] += size + self._stats["count"] += 1 + # shutil.copy2 performs 5-10 times faster on download, and ~20% faster on upload + # than os.system copy calls + src_time = os.path.getmtime(src_path) + if name == 'persons.csv' or "mgra13_based" in name: + src_time = os.path.getmtime(src_path) + if os.path.exists(dst_path): + dest_time = os.path.getmtime(dst_path) + if dest_time <= src_time: + _shutil.copy2(src_path, dst_path) + else: + pass + else: + _shutil.copy2(src_path, dst_path) + else: + _shutil.copy2(src_path, dst_path) + self._report.append(_time.strftime("%c")) + elif os.path.isdir(src_path): + if not os.path.exists(dst_path): + os.mkdir(dst_path) + self._report.append(dst_path) + self._copy_dir(src_path, dst_path, file_masks, check_metadata) + + def log_report(self): + size, count = file_size(self._stats["size"]), self._stats["count"] + name = "File copy report: copied {count} files {size}".format(count=count, size=size) + report = _m.PageBuilder(title=name) + report.add_html("
".join(self._report)) + _m.logbook_write(name, report.render()) + + +_suffixes = ['bytes', 'KiB', 'MiB', 'GiB', 'TiB'] + +def file_size(size): + order = int(log10(size) / 3) if size else 0 + return ' {} {}'.format(round(float(size) / (10**(order*3)), 1), _suffixes[order]) diff --git a/sandag_abm/src/main/emme/toolbox/utilities/general.py b/sandag_abm/src/main/emme/toolbox/utilities/general.py new file mode 100644 index 0000000..6879412 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/utilities/general.py @@ -0,0 +1,386 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// transit_assignment.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// + +TOOLBOX_ORDER = 102 + + +import inro.modeller as _m +import inro.emme.datatable as _dt +import inro.emme.core.exception as _except +from osgeo import ogr as _ogr +from contextlib import contextmanager as _context +from itertools import izip as _izip +import traceback as _traceback +import re as _re +import json as _json +import time as _time +import os +import numpy as _numpy + +_omx = _m.Modeller().module("sandag.utilities.omxwrapper") + + +class UtilityTool(_m.Tool()): + + tool_run_msg = "" + + def page(self): + pb = _m.ToolPageBuilder(self, runnable=False) + pb.title = "General utility" + pb.description = """Utility tool / module for common code. Not runnable.""" + pb.branding_text = "- SANDAG" + if self.tool_run_msg: + pb.add_html(self.tool_run_msg) + + return pb.render() + + def run(self): + pass + + +class NetworkCalculator(object): + def __init__(self, scenario): + self._scenario = scenario + self._network_calc = _m.Modeller().tool( + "inro.emme.network_calculation.network_calculator") + + def __call__(self, result, expression, selections=None, aggregation=None): + spec = { + "result": result, + "expression": expression, + "aggregation": aggregation, + "type": "NETWORK_CALCULATION" + } + if selections is not None: + if isinstance(selections, basestring): + selections = {"link": selections} + spec["selections"] = selections + else: + spec["selections"] = {"link": "all"} + return self._network_calc(spec, self._scenario) + + +@_context +def temp_matrices(emmebank, mat_type, total=1, default_value=0.0): + matrices = [] + try: + while len(matrices) != int(total): + try: + ident = emmebank.available_matrix_identifier(mat_type) + except _except.CapacityError: + raise _except.CapacityError( + "Insufficient room for %s required temp matrices." % total) + matrices.append(emmebank.create_matrix(ident, default_value)) + yield matrices[:] + finally: + for matrix in matrices: + # In case of transient file conflicts and lag in windows file handles over the network + # attempt to delete file 10 times with increasing delays 0.05, 0.2, 0.45, 0.8 ... 5 + remove_matrix = lambda: emmebank.delete_matrix(matrix) + retry(remove_matrix) + + +def retry(fcn, attempts=10, init_wait=0.05, error_types=(RuntimeError, WindowsError)): + for attempt in range(1, attempts + 1): + try: + fcn() + return + except error_types: + if attempt > attempts: + raise + _time.sleep(init_wait * (attempt**2)) + + +@_context +def temp_attrs(scenario, attr_type, idents, default_value=0.0): + attrs = [] + try: + for ident in idents: + attrs.append(scenario.create_extra_attribute(attr_type, ident, default_value)) + yield attrs[:] + finally: + for attr in attrs: + scenario.delete_extra_attribute(attr) + + +@_context +def backup_and_restore(scenario, backup_attributes): + backup = {} + for elem_type, attributes in backup_attributes.iteritems(): + backup[elem_type] = scenario.get_attribute_values(elem_type, attributes) + try: + yield + finally: + for elem_type, attributes in backup_attributes.iteritems(): + scenario.set_attribute_values(elem_type, attributes, backup[elem_type]) + + +class DataTableProc(object): + + def __init__(self, table_name, path=None, data=None, convert_numeric=False): + modeller = _m.Modeller() + desktop = modeller.desktop + project = desktop.project + self._dt_db = dt_db = project.data_tables() + self._convert_numeric = convert_numeric + if path: + #try: + source = _dt.DataSource(path) + #except: + # raise Exception("Cannot open file at %s" % path) + layer = source.layer(table_name) + self._data = layer.get_data() + elif data: + table = dt_db.create_table(table_name, data, overwrite=True) + self._data = data + else: + table = dt_db.table(table_name) + self._data = table.get_data() + self._load_data() + + def _load_data(self): + data = self._data + if self._convert_numeric: + values = [] + for a in data.attributes(): + attr_values = _numpy.copy(a.values) + attr_values[attr_values == ''] = 0 + try: + values.append(attr_values.astype("int")) + except ValueError: + try: + values.append(attr_values.astype("float")) + except ValueError: + values.append(a.values) + self._values = values + else: + self._values = [a.values for a in data.attributes()] + self._attr_names = [a.name for a in data.attributes()] + self._index = dict((k, i) for i,k in enumerate(self._attr_names)) + if "geometry" in self._attr_names: + geo_coords = [] + attr = data.attribute("geometry") + for record in attr.values: + geo_obj = _ogr.CreateGeometryFromWkt(record.text) + geo_coords.append(geo_obj.GetPoints()) + self._values.append(geo_coords) + self._attr_names.append("geo_coordinates") + + def __iter__(self): + values, attr_names = self._values, self._attr_names + return (dict(_izip(attr_names, record)) + for record in _izip(*values)) + + def save(self, name, overwrite=False): + self._dt_db.create_table(name, self._data, overwrite=overwrite) + + def values(self, name): + index = self._index[name] + return self._values[index] + + +class Snapshot(object): + def __getitem__(self, key): + return getattr(self, key) + + def __setitem__(self, key, value): + setattr(self, key, value) + + def to_snapshot(self): + try: + attributes = getattr(self, "attributes", []) + snapshot = {} + for name in attributes: + snapshot[name] = unicode(self[name]) + return _json.dumps(snapshot) + except Exception: + return "{}" + + def from_snapshot(self, snapshot): + try: + snapshot = _json.loads(snapshot) + attributes = getattr(self, "attributes", []) + for name in attributes: + self[name] = snapshot[name] + except Exception, error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error), False) + return self + + def get_state(self): + attributes = getattr(self, "attributes", []) + state = {} + for name in attributes: + try: + state[name] = self[name] + except _m.AttributeError, error: + state[name] = unicode(error) + return state + + +def log_snapshot(name, namespace, snapshot): + try: + _m.logbook_snapshot(name=name, comment="", namespace=namespace, + value=_json.dumps(snapshot)) + except Exception as error: + print error + + +class ExportOMX(object): + def __init__(self, file_path, scenario, omx_key="NAME"): + self.file_path = file_path + self.scenario = scenario + self.emmebank = scenario.emmebank + self.omx_key = omx_key + + @property + def omx_key(self): + return self._omx_key + + @omx_key.setter + def omx_key(self, omx_key): + self._omx_key = omx_key + text_encoding = self.emmebank.text_encoding + if omx_key == "ID_NAME": + self.generate_key = lambda m: "%s_%s" % ( + m.id.encode(text_encoding), m.name.encode(text_encoding)) + elif omx_key == "NAME": + self.generate_key = lambda m: m.name.encode(text_encoding) + elif omx_key == "ID": + self.generate_key = lambda m: m.id.encode(text_encoding) + + def __enter__(self): + self.trace = _m.logbook_trace(name="Export matrices to OMX", + attributes={ + "file_path": self.file_path, "omx_key": self.omx_key, + "scenario": self.scenario, "emmebank": self.emmebank.path}) + self.trace.__enter__() + self.omx_file = _omx.open_file(self.file_path, 'w') + try: + self.omx_file.create_mapping('zone_number', self.scenario.zone_numbers) + except LookupError: + pass + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + self.omx_file.close() + self.trace.__exit__(exc_type, exc_val, exc_tb) + + def write_matrices(self, matrices): + if isinstance(matrices, dict): + for key, matrix in matrices.iteritems(): + self.write_matrix(matrix, key) + else: + for matrix in matrices: + self.write_matrix(matrix) + + def write_matrix(self, matrix, key=None): + text_encoding = self.emmebank.text_encoding + matrix = self.emmebank.matrix(matrix) + if key is None: + key = self.generate_key(matrix) + numpy_array = matrix.get_numpy_data(self.scenario.id) + if matrix.type == "DESTINATION": + n_zones = len(numpy_array) + numpy_array = _numpy.resize(numpy_array, (1, n_zones)) + elif matrix.type == "ORIGIN": + n_zones = len(numpy_array) + numpy_array = _numpy.resize(numpy_array, (n_zones, 1)) + attrs = {"description": matrix.description.encode(text_encoding)} + self.write_array(numpy_array, key, attrs) + + def write_clipped_array(self, numpy_array, key, a_min, a_max=None, attrs={}): + if a_max is not None: + numpy_array = numpy_array.clip(a_min, a_max) + else: + numpy_array = numpy_array.clip(a_min) + self.write_array(numpy_array, key, attrs) + + def write_array(self, numpy_array, key, attrs={}): + shape = numpy_array.shape + if len(shape) == 2: + chunkshape = (1, shape[0]) + else: + chunkshape = None + attrs["source"] = "Emme" + numpy_array = numpy_array.astype(dtype="float64", copy=False) + omx_matrix = self.omx_file.create_matrix( + key, obj=numpy_array, chunkshape=chunkshape, attrs=attrs) + + +class OMXManager(object): + def __init__(self, directory, name_tmplt): + self._directory = directory + self._name_tmplt = name_tmplt + self._omx_files = {} + + def lookup(self, name_args, key): + file_name = self._name_tmplt % name_args + omx_file = self._omx_files.get(file_name) + if omx_file is None: + file_path = os.path.join(self._directory, file_name) + omx_file = _omx.open_file(file_path, 'r') + self._omx_files[file_name] = omx_file + return omx_file[key].read() + + def file_exists(self, name_args): + file_name = self._name_tmplt % name_args + file_path = os.path.join(self._directory, file_name) + return os.path.isfile(file_path) + + def zone_list(self, file_name): + omx_file = self._omx_files[file_name] + mapping_name = omx_file.list_mappings()[0] + zone_mapping = omx_file.mapping(mapping_name).items() + zone_mapping.sort(key=lambda x: x[1]) + omx_zones = [x[0] for x in zone_mapping] + return omx_zones + + def __enter__(self): + return self + + def __exit__(self, exc_type, exc_val, exc_tb): + for omx_file in self._omx_files.values(): + omx_file.close() + self._omx_files = {} + + +class CSVReader(object): + def __init__(self, path): + self._path = path + self._f = None + self._fields = None + + def __enter__(self): + self._f = open(self._path) + header = self._f.next() + self._fields = [h.strip().upper() for h in header.split(",")] + return self + + def __exit__(self, exception_type, exception_value, traceback): + self._f.close() + self._f = None + self._fields = None + + def __iter__(self): + return self + + @property + def fields(self): + return list(self._fields) + + def next(self): + line = self._f.next() + tokens = [t.strip() for t in line.split(",")] + return dict(zip(self._fields, tokens)) diff --git a/sandag_abm/src/main/emme/toolbox/utilities/omxwrapper.py b/sandag_abm/src/main/emme/toolbox/utilities/omxwrapper.py new file mode 100644 index 0000000..67564f8 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/utilities/omxwrapper.py @@ -0,0 +1,91 @@ +##////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2019. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// utilities/omxwrapper.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#/////////////////////////////////////////////////////////////////////////////// +import inro.modeller as _m + + +try: + import openmatrix as _omx + + + def open_file(file_path, mode): + return OmxMatrix(_omx.open_file(file_path, mode)) +except Exception, e: + import omx as _omx + + + def open_file(file_path, mode): + return OmxMatrix(_omx.openFile(file_path, mode)) + +class OmxMatrix(object): + + def __init__(self, matrix): + self.matrix = matrix + + def mapping(self, name): + return self.matrix.mapping(name) + + def list_mappings(self): + return self.matrix.listMappings() + + def __getitem__(self, key): + return self.matrix[key] + + def __setitem__(self, key, value): + self.matrix[key] = value + + def create_mapping(self, name, ids): + exception_raised = False + try: + self.matrix.create_mapping(name, ids) # Emme 44 and above + except Exception, e: + exception_raised = True + + if exception_raised: + self.matrix.createMapping(name, ids) # Emme 437 + + + def create_matrix(self, key, obj, chunkshape, attrs): + exception_raised = False + try: # Emme 44 and above + self.matrix.create_matrix( + key, + obj=obj, + chunkshape=chunkshape, + attrs=attrs + ) + except Exception, e: + exception_raised = True + + if exception_raised: # Emme 437 + self.matrix.createMatrix( + key, + obj=obj, + chunkshape=chunkshape, + attrs=attrs + ) + + def close(self): + self.matrix.close() + + + +class OmxWrapper(_m.Tool()): + def page(self): + pb = _m.ToolPageBuilder( + self, + runnable=False, + title="OMX wrapper", + description="OMX utility for handling of OMX related libraries" + ) + return pb.render() \ No newline at end of file diff --git a/sandag_abm/src/main/emme/toolbox/utilities/properties.py b/sandag_abm/src/main/emme/toolbox/utilities/properties.py new file mode 100644 index 0000000..228bc07 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/utilities/properties.py @@ -0,0 +1,599 @@ +##////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// utilities/properties.py /// +#//// /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// + +TOOLBOX_ORDER = 103 + + +import inro.modeller as _m +import traceback as _traceback +from collections import OrderedDict +import csv +import os +import time + + +class PropertiesSetter(object): + + startFromIteration = _m.Attribute(int) + sample_rates = _m.Attribute(str) + + useLocalDrive = _m.Attribute(bool) + skip4Ds = _m.Attribute(bool) + skipBuildNetwork = _m.Attribute(bool) + skipInputChecker = _m.Attribute(bool) + skipInitialization = _m.Attribute(bool) + deleteAllMatrices = _m.Attribute(bool) + skipCopyWarmupTripTables = _m.Attribute(bool) + skipWalkLogsums = _m.Attribute(bool) + skipCopyWalkImpedance = _m.Attribute(bool) + skipBikeLogsums = _m.Attribute(bool) + skipCopyBikeLogsum = _m.Attribute(bool) + + skipHighwayAssignment_1 = _m.Attribute(bool) + skipHighwayAssignment_2 = _m.Attribute(bool) + skipHighwayAssignment_3 = _m.Attribute(bool) + skipTransitSkimming_1 = _m.Attribute(bool) + skipTransitSkimming_2 = _m.Attribute(bool) + skipTransitSkimming_3 = _m.Attribute(bool) + skipTransponderExport_1 = _m.Attribute(bool) + skipTransponderExport_2 = _m.Attribute(bool) + skipTransponderExport_3 = _m.Attribute(bool) + skipCoreABM_1 = _m.Attribute(bool) + skipCoreABM_2 = _m.Attribute(bool) + skipCoreABM_3 = _m.Attribute(bool) + skipOtherSimulateModel_1 = _m.Attribute(bool) + skipOtherSimulateModel_2 = _m.Attribute(bool) + skipOtherSimulateModel_3 = _m.Attribute(bool) + skipMAASModel_1 = _m.Attribute(bool) + skipMAASModel_2 = _m.Attribute(bool) + skipMAASModel_3 = _m.Attribute(bool) + skipCTM_1 = _m.Attribute(bool) + skipCTM_2 = _m.Attribute(bool) + skipCTM_3 = _m.Attribute(bool) + skipEI_1 = _m.Attribute(bool) + skipEI_2 = _m.Attribute(bool) + skipEI_3 = _m.Attribute(bool) + skipExternalExternal_1 = _m.Attribute(bool) + skipExternalExternal_2 = _m.Attribute(bool) + skipExternalExternal_3 = _m.Attribute(bool) + skipTruck_1 = _m.Attribute(bool) + skipTruck_2 = _m.Attribute(bool) + skipTruck_3 = _m.Attribute(bool) + skipTripTableCreation_1 = _m.Attribute(bool) + skipTripTableCreation_2 = _m.Attribute(bool) + skipTripTableCreation_3 = _m.Attribute(bool) + + skipFinalHighwayAssignment = _m.Attribute(bool) + skipFinalHighwayAssignmentStochastic = _m.Attribute(bool) + skipFinalTransitAssignment = _m.Attribute(bool) + skipVisualizer = _m.Attribute(bool) + skipDataExport = _m.Attribute(bool) + skipDataLoadRequest = _m.Attribute(bool) + skipDeleteIntermediateFiles = _m.Attribute(bool) + + def _get_list_prop(self, name): + return [getattr(self, name + suffix) for suffix in ["_1", "_2", "_3"]] + + def _set_list_prop(self, name, value): + try: + for v_sub, suffix in zip(value, ["_1", "_2", "_3"]): + setattr(self, name + suffix, v_sub) + except: + for suffix in ["_1", "_2", "_3"]: + setattr(self, name + suffix, False) + + skipHighwayAssignment = property( + fget=lambda self: self._get_list_prop("skipHighwayAssignment"), + fset=lambda self, value: self._set_list_prop("skipHighwayAssignment", value)) + skipTransitSkimming = property( + fget=lambda self: self._get_list_prop("skipTransitSkimming"), + fset=lambda self, value: self._set_list_prop("skipTransitSkimming", value)) + skipTransponderExport = property( + fget=lambda self: self._get_list_prop("skipTransponderExport"), + fset=lambda self, value: self._set_list_prop("skipTransponderExport", value)) + skipCoreABM = property( + fget=lambda self: self._get_list_prop("skipCoreABM"), + fset=lambda self, value: self._set_list_prop("skipCoreABM", value)) + skipOtherSimulateModel = property( + fget=lambda self: self._get_list_prop("skipOtherSimulateModel"), + fset=lambda self, value: self._set_list_prop("skipOtherSimulateModel", value)) + skipMAASModel = property( + fget=lambda self: self._get_list_prop("skipMAASModel"), + fset=lambda self, value: self._set_list_prop("skipMAASModel", value)) + skipCTM = property( + fget=lambda self: self._get_list_prop("skipCTM"), + fset=lambda self, value: self._set_list_prop("skipCTM", value)) + skipEI = property( + fget=lambda self: self._get_list_prop("skipEI"), + fset=lambda self, value: self._set_list_prop("skipEI", value)) + skipExternalExternal = property( + fget=lambda self: self._get_list_prop("skipExternalExternal"), + fset=lambda self, value: self._set_list_prop("skipExternalExternal", value)) + skipTruck = property( + fget=lambda self: self._get_list_prop("skipTruck"), + fset=lambda self, value: self._set_list_prop("skipTruck", value)) + skipTripTableCreation = property( + fget=lambda self: self._get_list_prop("skipTripTableCreation"), + fset=lambda self, value: self._set_list_prop("skipTripTableCreation", value)) + + def __init__(self): + self._run_model_names = ( + "useLocalDrive", "skip4Ds", "skipInputChecker", + "startFromIteration", "skipInitialization", "deleteAllMatrices", "skipCopyWarmupTripTables", + "skipCopyBikeLogsum", "skipCopyWalkImpedance", "skipWalkLogsums", "skipBikeLogsums", "skipBuildNetwork", + "skipHighwayAssignment", "skipTransitSkimming", "skipTransponderExport", "skipCoreABM", "skipOtherSimulateModel", "skipMAASModel","skipCTM", + "skipEI", "skipExternalExternal", "skipTruck", "skipTripTableCreation", "skipFinalHighwayAssignment", 'skipFinalHighwayAssignmentStochastic', + "skipFinalTransitAssignment", "skipVisualizer", "skipDataExport", "skipDataLoadRequest", + "skipDeleteIntermediateFiles") + self._properties = None + + def add_properties_interface(self, pb, disclosure=False): + tool_proxy_tag = pb.tool_proxy_tag + title = "Run model - skip steps" + + pb.add_text_box('sample_rates', title="Sample rate by iteration:", size=20) + + contents = [""" +
+
+ +            + +
+ + + + + + + + """ % {"tool_proxy_tag": tool_proxy_tag}] + + skip_startup_items = [ + ("useLocalDrive", "Use the local drive during the model run"), + ("skip4Ds", "Skip running 4Ds"), + ("skipBuildNetwork", "Skip build of highway and transit network"), + ("skipInputChecker", "Skip running input checker"), + ("skipInitialization", "Skip matrix and transit database initialization"), + ("deleteAllMatrices", "    Delete all matrices"), + ("skipCopyWarmupTripTables","Skip import of warmup trip tables"), + ("skipWalkLogsums", "Skip walk logsums"), + ("skipCopyWalkImpedance", "Skip copy of walk impedance"), + ("skipBikeLogsums", "Skip bike logsums"), + ("skipCopyBikeLogsum", "Skip copy of bike logsum"), + ] + skip_per_iteration_items = [ + ("skipHighwayAssignment", "Skip highway assignments and skims"), + ("skipTransitSkimming", "Skip transit skims"), + ("skipTransponderExport", "Skip transponder accessibilities"), + ("skipCoreABM", "Skip core ABM"), + ("skipOtherSimulateModel", "Skip other simulation model"), + ("skipMAASModel", "Skip MAAS model"), + ("skipCTM", "Skip commercial vehicle sub-model"), + ("skipTruck", "Skip truck sub-model"), + ("skipEI", "Skip external-internal sub-model"), + ("skipExternalExternal", "Skip external-external sub-model"), + ("skipTripTableCreation", "Skip trip table creation"), + ] + skip_final_items = [ + ("skipFinalHighwayAssignment", "Skip final highway assignments"), + ("skipFinalHighwayAssignmentStochastic", "    Skip stochastic assignment"), + ("skipFinalTransitAssignment", "Skip final transit assignments"), + ("skipVisualizer", "Skip running visualizer"), + ("skipDataExport", "Skip data export"), + ("skipDataLoadRequest", "Skip data load request"), + ("skipDeleteIntermediateFiles", "Skip delete intermediate files"), + ] + + if disclosure: + contents.insert(0, """ +
+
%s
""" % title) + title = "" + + checkbox = '
' + checkbox_no_data = '' + + for name, label in skip_startup_items: + contents.append("" % label) + contents.append(checkbox % {"name": name, "tag": tool_proxy_tag}) + contents.append("") + contents.append("") + for i in range(1,4): + contents.append(checkbox_no_data % {"name": "all" + "_" + str(i)}) + for name, label in skip_per_iteration_items: + contents.append("" % label) + for i in range(1,4): + contents.append(checkbox % {"name": name + "_" + str(i), "tag": tool_proxy_tag}) + for name, label in skip_final_items: + contents.append("" % label) + contents.append("") + contents.append(checkbox % {"name": name, "tag": tool_proxy_tag}) + + contents.append("
Iteration 1Iteration 2Iteration 3
%s
Set / reset all
    %s
%s
") + if disclosure: + contents.append("") + + pb.wrap_html(title, "".join(contents)) + + pb.add_html(""" +""" % {"tool_proxy_tag": tool_proxy_tag, + "iter_items": str([x[0] for x in skip_per_iteration_items]), + "startup_items": str([x[0] for x in skip_startup_items]), + }) + return + + @_m.method(return_type=bool, argument_types=(str,)) + def get_value(self, name): + return bool(getattr(self, name)) + + @_m.method() + def load_properties(self): + if not os.path.exists(self.properties_path): + return + self._properties = props = Properties(self.properties_path) + _m.logbook_write("SANDAG properties interface load") + + self.startFromIteration = props.get("RunModel.startFromIteration", 1) + self.sample_rates = ",".join(str(x) for x in props.get("sample_rates")) + + self.useLocalDrive = props.get("RunModel.useLocalDrive", True) + self.skip4Ds = props.get("RunModel.skip4Ds", False) + self.skipBuildNetwork = props.get("RunModel.skipBuildNetwork", False) + self.skipInputChecker = props.get("RunModel.skipInputChecker", False) + self.skipInitialization = props.get("RunModel.skipInitialization", False) + self.deleteAllMatrices = props.get("RunModel.deleteAllMatrices", False) + self.skipCopyWarmupTripTables = props.get("RunModel.skipCopyWarmupTripTables", False) + self.skipWalkLogsums = props.get("RunModel.skipWalkLogsums", False) + self.skipCopyWalkImpedance = props.get("RunModel.skipCopyWalkImpedance", False) + self.skipBikeLogsums = props.get("RunModel.skipBikeLogsums", False) + self.skipCopyBikeLogsum = props.get("RunModel.skipCopyBikeLogsum", False) + + self.skipHighwayAssignment = props.get("RunModel.skipHighwayAssignment", [False, False, False]) + self.skipTransitSkimming = props.get("RunModel.skipTransitSkimming", [False, False, False]) + self.skipTransponderExport = props.get("RunModel.skipTransponderExport", [False, False, False]) + self.skipCoreABM = props.get("RunModel.skipCoreABM", [False, False, False]) + self.skipOtherSimulateModel = props.get("RunModel.skipOtherSimulateModel", [False, False, False]) + self.skipMAASModel = props.get("RunModel.skipMAASModel", [False, False, False]) + self.skipCTM = props.get("RunModel.skipCTM", [False, False, False]) + self.skipEI = props.get("RunModel.skipEI", [False, False, False]) + self.skipExternalExternal = props.get("RunModel.skipExternalExternal", [False, False, False]) + self.skipTruck = props.get("RunModel.skipTruck", [False, False, False]) + self.skipTripTableCreation = props.get("RunModel.skipTripTableCreation", [False, False, False]) + + self.skipFinalHighwayAssignment = props.get("RunModel.skipFinalHighwayAssignment", False) + self.skipFinalHighwayAssignmentStochastic = props.get("RunModel.skipFinalHighwayAssignmentStochastic", True) + self.skipFinalTransitAssignment = props.get("RunModel.skipFinalTransitAssignment", False) + self.skipVisualizer = props.get("RunModel.skipVisualizer", False) + self.skipDataExport = props.get("RunModel.skipDataExport", False) + self.skipDataLoadRequest = props.get("RunModel.skipDataLoadRequest", False) + self.skipDeleteIntermediateFiles = props.get("RunModel.skipDeleteIntermediateFiles", False) + + def save_properties(self): + props = self._properties + props["RunModel.startFromIteration"] = self.startFromIteration + props["sample_rates"] = [float(x) for x in self.sample_rates.split(",")] + + props["RunModel.useLocalDrive"] = self.useLocalDrive + props["RunModel.skip4Ds"] = self.skip4Ds + props["RunModel.skipBuildNetwork"] = self.skipBuildNetwork + props["RunModel.skipInputChecker"] = self.skipInputChecker + props["RunModel.skipInitialization"] = self.skipInitialization + props["RunModel.deleteAllMatrices"] = self.deleteAllMatrices + props["RunModel.skipCopyWarmupTripTables"] = self.skipCopyWarmupTripTables + props["RunModel.skipWalkLogsums"] = self.skipWalkLogsums + props["RunModel.skipCopyWalkImpedance"] = self.skipCopyWalkImpedance + props["RunModel.skipBikeLogsums"] = self.skipBikeLogsums + props["RunModel.skipCopyBikeLogsum"] = self.skipCopyBikeLogsum + + props["RunModel.skipHighwayAssignment"] = self.skipHighwayAssignment + props["RunModel.skipTransitSkimming"] = self.skipTransitSkimming + props["RunModel.skipTransponderExport"] = self.skipTransponderExport + props["RunModel.skipCoreABM"] = self.skipCoreABM + props["RunModel.skipOtherSimulateModel"] = self.skipOtherSimulateModel + props["RunModel.skipMAASModel"] = self.skipMAASModel + props["RunModel.skipCTM"] = self.skipCTM + props["RunModel.skipEI"] = self.skipEI + props["RunModel.skipExternalExternal"] = self.skipExternalExternal + props["RunModel.skipTruck"] = self.skipTruck + props["RunModel.skipTripTableCreation"] = self.skipTripTableCreation + + props["RunModel.skipFinalHighwayAssignment"] = self.skipFinalHighwayAssignment + props["RunModel.skipFinalHighwayAssignmentStochastic"] = self.skipFinalHighwayAssignmentStochastic + props["RunModel.skipFinalTransitAssignment"] = self.skipFinalTransitAssignment + props["RunModel.skipVisualizer"] = self.skipVisualizer + props["RunModel.skipDataExport"] = self.skipDataExport + props["RunModel.skipDataLoadRequest"] = self.skipDataLoadRequest + props["RunModel.skipDeleteIntermediateFiles"] = self.skipDeleteIntermediateFiles + + props.save() + + # Log current state of props interface for debugging of UI / file sync issues + tool_attributes = dict((name, getattr(self, name)) for name in self._run_model_names) + _m.logbook_write("SANDAG properties interface save", attributes=tool_attributes) + + +class PropertiesTool(PropertiesSetter, _m.Tool()): + + properties_path = _m.Attribute(unicode) + + def __init__(self): + super(PropertiesTool, self).__init__() + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.properties_path = os.path.join( + os.path.dirname(project_dir), "conf", "sandag_abm.properties") + + tool_run_msg = "" + + @_m.method(return_type=_m.UnicodeType) + def tool_run_msg_status(self): + return self.tool_run_msg + + def page(self): + if os.path.exists(self.properties_path): + self.load_properties() + pb = _m.ToolPageBuilder(self) + pb.title = 'Set properties' + pb.description = """Properties setting tool.""" + pb.branding_text = ' - SANDAG - Utilities' + tool_proxy_tag = pb.tool_proxy_tag + + pb.add_select_file('properties_path', 'file', title='Path to properties file:') + + pb.wrap_html("", """ +
""") + + pb.add_html(""" +""" % {"tool_proxy_tag": tool_proxy_tag}) + self.add_properties_interface(pb) + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + self.save_properties() + message = "Properties file saved" + self.tool_run_msg = _m.PageBuilder.format_info(message, escape=False) + except Exception, e: + self.tool_run_msg = _m.PageBuilder.format_exception( + e, _traceback.format_exc(e)) + raise + + def __call__(self, file_path): + return Properties(file_path) + + +class Properties(object): + + def __init__(self, path): + if os.path.isdir(path): + path = os.path.join(path, "sandag_abm.properties") + if not os.path.isfile(path): + raise Exception("properties files does not exist '%s'" % path) + self._path = os.path.normpath(os.path.abspath(path)) + self.load_properties() + + def load_properties(self): + self._prop = prop = OrderedDict() + self._comments = comments = {} + with open(self._path, 'r') as properties: + comment = [] + for line in properties: + line = line.strip() + if not line or line.startswith('#'): + comment.append(line) + continue + key, value = line.split('=') + key = key.strip() + tokens = value.split(',') + if len(tokens) > 1: + value = self._parse_list(tokens) + else: + value = self._parse(value) + prop[key] = value + comments[key], comment = comment, [] + self._timestamp = os.path.getmtime(self._path) + + def _parse_list(self, values): + converted_values = [] + for v in values: + converted_values.append(self._parse(v)) + return converted_values + + def _parse(self, value): + value = str(value).strip() + if value == 'true': + return True + elif value == 'false': + return False + for caster in int, float: + try: + return caster(value) + except ValueError: + pass + return value + + def _format(self, value): + if isinstance(value, bool): + return "true" if value else "false" + return str(value) + + def save(self, path=None): + if not path: + path = self._path + # check for possible interference if user edits the + # properties files directly while it is already open in Modeller + timestamp = os.path.getmtime(path) + if timestamp != self._timestamp: + raise Exception("%s file conflict - edited externally after loading" % path) + self["SavedFrom"] = "Emme Modeller properties writer Process ID %s" % os.getpid() + self["SavedLast"] = time.strftime("%b-%d-%Y %H:%M:%S") + with open(path, 'w') as f: + for key, value in self.iteritems(): + if isinstance(value, list): + value = ",".join([self._format(v) for v in value]) + else: + value = self._format(value) + comment = self._comments.get(key) + if comment: + for line in comment: + f.write(line) + f.write("\n") + f.write("%s = %s\n" % (key, value)) + self._timestamp = os.path.getmtime(path) + + def set_year_specific_properties(self, file_path): + with open(file_path, 'r') as f: + reader = csv.DictReader(f) + properties_by_year = {} + for row in reader: + year = str(row.pop("year")) + properties_by_year[year] = row + year_properties = properties_by_year.get(str(self["scenarioBuild"])) + if year_properties is None: + raise Exception("Row with year %s not found in %s" % (self["scenarioBuild"], file_path)) + self.update(year_properties) + + def __setitem__(self, key, item): + self._prop[key] = item + + def __getitem__(self, key): + return self._prop[key] + + def __repr__(self): + return "Properties(%s)" % self._path + + def __len__(self): + return len(self._prop) + + def __delitem__(self, key): + del self._prop[key] + + def clear(self): + return self._prop.clear() + + def has_key(self, k): + return self._prop.has_key(k) + + def pop(self, k, d=None): + return self._prop.pop(k, d) + + def update(self, *args, **kwargs): + return self._prop.update(*args, **kwargs) + + def keys(self): + return self._prop.keys() + + def values(self): + return self._prop.values() + + def items(self): + return self._prop.items() + + def iteritems(self): + return self._prop.iteritems() + + def pop(self, *args): + return self._prop.pop(*args) + + def get(self, k, default=None): + try: + return self[k] + except KeyError: + return default + + def __cmp__(self, dict): + return cmp(self._prop, dict) + + def __contains__(self, item): + return item in self._prop + + def __iter__(self): + return iter(self._prop) + + def __unicode__(self): + return unicode(repr(self._prop)) diff --git a/sandag_abm/src/main/emme/toolbox/utilities/run_summary.py b/sandag_abm/src/main/emme/toolbox/utilities/run_summary.py new file mode 100644 index 0000000..ebaf2e1 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/utilities/run_summary.py @@ -0,0 +1,326 @@ +""" ABM Run Time Summary Tool + +Generates a CSV file containing a run time summary for +a completed ABM run. Utilizes the Emme Modeler API to +query the Emme logbook for the run time information. + +""" + +# Importing libraries +import os +import pandas as pd +import traceback as _traceback +import inro.emme.desktop.app as _app +import inro.modeller as _m +from functools import reduce + +_dir = os.path.dirname +_join = os.path.join + +ATTR_SUFFIX = "_304A7365_C276_493A_AB3B_9B2D195E203F" + +# Define unneeded entries +exclude = ('Copy project data to local drive', + 'Export results for transponder ownership model', + 'Check free space on C', + 'Data load request', + 'Delete', + 'Move', + 'Create drive', + 'Start matrix', + 'Start JPPF', + 'Start Hh', + 'Start HH') + + +class RunTime(_m.Tool()): + + def __init__(self): + project_dir = _dir(_m.Modeller().desktop.project.path) + self.path = _dir(project_dir) + self.output_path = '' + self.output_summary_path = '' + self.begin = '' + self.end = '' + + def run(self): + """ + Executes Run Time Summary tool + """ + self.tool_run_msg = "" + try: + self(path=self.path) + run_msg = "Run Time Tool Complete" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg, + escape=False) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + + return + + def __call__(self, path=""): + """ + Calculates ABM run times and saves to CSV file + + :param path: Scenario file path + """ + + # Get element IDs for model runs + run_ids = self.get_runs() + + # Define needed attributes (begin and end times) + self.begin = "begin" + ATTR_SUFFIX + self.end = "end" + ATTR_SUFFIX + attrs = [self.begin, self.end] + + runtime_dfs = [] + for run_id in run_ids: + name = 'Run ID: {}'.format(run_id) + + # Creating dummy total time + total_entry = (run_id, 'Total Run Time', '0:0') + + # Get second level child entry run times if they exist + child_runtimes = self.get_child_runtimes(run_id, attrs) + + # Get third (final) level child entry run times + final_runtimes = [total_entry] + for index, info in enumerate(child_runtimes): + if info[1] == 'Final traffic assignments': + final_runtimes.append([0, 'Iteration 4', 0]) + final_runtimes.append(info) + if 'Iteration' in info[1]: + iter_str = '_{}'.format(info[1]) + + # Manually inserting matrix, hh, node, and jppf runtimes + start_proc = "Start Matrix manager, JPPF Driver, " + \ + "HH manager, and Nodes manager" + iter_str + final_runtimes += [[0, start_proc, '0:01']] + + # Add iteration to children + iteration_children = self.get_child_runtimes( + info[0], attrs) + for index, child in enumerate(iteration_children): + step = child[1] + iteration_children[index][1] = step + iter_str + + final_runtimes += iteration_children + + # Create run time summary table + index = [x[1] for x in final_runtimes] + values = [x[2] for x in final_runtimes] + runtime_series = pd.Series(index=index, data=values) + runtime_series.name = name + runtime_df = runtime_series.to_frame() + + # Create intial time + zero_time = pd.to_datetime('0:0', format='%H:%M') + + # Calculate iteration 4 run time if it exists + iter_str = 'Iteration 4' + if iter_str in runtime_df.index: + iter_4_index = runtime_df.index.get_loc('Iteration 4') + iter_4_df = runtime_df.iloc[iter_4_index+1:, :].copy() + iter_4_df[name] = (pd.to_datetime( + iter_4_df[name], format='%H:%M') - + zero_time) + iter_4_time = iter_4_df[name].sum() + runtime_df.loc[iter_str, :] = self.format_runtime(iter_4_time) + + # Calculate total runtime + is_iter_row = pd.Series(runtime_df.index).str.startswith('Iter') + total_df = runtime_df[~is_iter_row.values].copy() + total_df[name] = (pd.to_datetime(total_df[name], format='%H:%M') - + zero_time) + total_time = total_df[name].sum() + run_str = 'Total Run Time' + runtime_df.loc[run_str, :] = self.format_runtime(total_time) + + # Remove unneeded entries + is_excluded = pd.Series(runtime_df.index).str.startswith(exclude) + runtime_df = runtime_df[~(is_excluded.values)] + runtime_dfs.append(runtime_df) + + # Merge all run time data frames if more than one exists and save + file_name = 'runtime_summary.csv' + self.output_path = _join(path, 'output', file_name) + result = self.combine_dfs(runtime_dfs) + if result[1]: + result[0].to_csv(self.output_path, header=True, index=False) + else: + result[0].to_csv(self.output_path, header=False) + + return + + def get_runs(self): + """ + Queries the Emme logbook to retrieve the IDs of all + model runs. + + :returns: List of IDs of model runs + """ + + # Emme logbook query + query = """ + SELECT elements.element_id, elements.tag + FROM elements + JOIN attributes KEYVAL1 ON (elements.element_id=KEYVAL1.element_id) + WHERE (KEYVAL1.name=="self" + AND KEYVAL1.value LIKE "sandag.master_run") + ORDER BY elements.element_id ASC + """ + all_entries = _m.logbook_query(query) + + # Retrieves model run IDs + run_ids = [] + for entry in all_entries: + parent_id = entry[0] + run_ids.append(parent_id) + + if len(run_ids) == 0: + raise ValueError('A model run does not exist.') + + return run_ids + + def get_attributes(self, element_id): + """ + Queries all the attributes of an Emme logbook element + + :param element_id: Integer ID of element + :returns: List of tuples containing information for + different attributes of an element. + """ + + # Emme logbook query + query = """ + SELECT name, value FROM attributes + WHERE attributes.element_id == %i + """ % element_id + + return _m.logbook_query(query) + + def format_runtime(self, time): + """ + Transforms a datetime object to a reformatted + date string. Formatted as '{hours}:{'minutes'}' + + :param time Datetime object + """ + + hours = str(int(time.total_seconds() // 3600)) + minutes = str(int((time.total_seconds() % 3600) // 60)).zfill(2) + formatted_runtime = hours + ":" + minutes + + return formatted_runtime + + def calc_runtime(self, begin, end): + """ + Helper function for get_child_runtimes + + Converts beginning and end datetime strings into + a formatted time delta. Formatted as '{hours}:{minutes}' + + :param begin: String representing beginning date + :param end: String representating ending date + :returns: String representing element runtime + """ + + # Calculate total run time + total_runtime = pd.to_datetime(end) - pd.to_datetime(begin) + + # Format run time: '{hours}:{minutes}' + formatted_runtime = self.format_runtime(total_runtime) + + # Defaulting zero second times to 1 second + if formatted_runtime == '0:00': + formatted_runtime = '0:01' + + return formatted_runtime + + def get_children(self, parent_id): + """ + Retrieves all child elements for a parent element + + :param parent_id: Integer ID of parent element + :returns: List of tuples containing child IDs and names + """ + + # Emme logbook query + query = """ + SELECT elements.element_id, elements.tag + FROM elements WHERE parent_id==%i + ORDER BY elements.element_id ASC + """ % parent_id + child_entries = _m.logbook_query(query) + + return child_entries + + def get_child_runtimes(self, parent_id, attrs): + """ + Calculates the run times for the child elements of + a parent element + + :param parent_id: Integer ID of parent element + :param attrs: List of strings representing attributes to query + :returns: List of tuples containing information for child elements + """ + + # Get child elements + all_child_entries = self.get_children(parent_id) + + # Calculates run times for each child element + runtime_child_entries = [] + for element_id, name in all_child_entries: + attributes = dict(self.get_attributes(element_id)) + + # Gets element information if desired attribute is + # available and it is not included in the excluded list + if attrs[0] in attributes: + begin = attributes[attrs[0]] + + # Handles cases where model fails mid iteration + try: + end = attributes[attrs[1]] + runtime = self.calc_runtime(begin, end) + except KeyError: + end = None + runtime = None + runtime_child_entries.append([element_id, name, runtime]) + + return runtime_child_entries + + def combine_dfs(self, df_list): + """ + Combines a list of Pandas DataFrames into a single + summary DataFrame + + :param df_list: List of Pandas DataFrames + :returns: Tuple contianing single run time summary DataFrame + and boolean whether it contains multiple runs + """ + if len(df_list) > 1: + # Drop tables with less than 2 entries + final_dfs = [] + for df in df_list: + if len(df.dropna()) > 1: + final_dfs.append(df.reset_index(drop=False)) + + # Merge all data frames + final_df = reduce(lambda left, right: + pd.merge(left, right, on=['index'], how='outer'), + final_dfs) + + # Remove appended iteration markers + final_df['index'] = (final_df['index'].apply( + lambda x: x.split('_')[0])) + + final_df = final_df.rename(columns={'index': 'Step'}) + result = (final_df, True) + + else: + final_df = df_list[0] + result = (final_df, False) + + return result diff --git a/sandag_abm/src/main/emme/toolbox/validation/validation.py b/sandag_abm/src/main/emme/toolbox/validation/validation.py new file mode 100644 index 0000000..13ae759 --- /dev/null +++ b/sandag_abm/src/main/emme/toolbox/validation/validation.py @@ -0,0 +1,290 @@ +""" +Created on March 2020 + +@author: cliu +""" + +TOOLBOX_ORDER = 105 + +import inro.modeller as _m +import traceback as _traceback +import inro.emme.database.emmebank as _eb +import inro.emme.desktop.app as _app +import inro.emme.core.exception as _except +from collections import OrderedDict +import os +import pandas as pd +import openpyxl +from functools import reduce + + +gen_utils = _m.Modeller().module("sandag.utilities.general") +dem_utils = _m.Modeller().module("sandag.utilities.demand") + + +format = lambda x: ("%.6f" % x).rstrip('0').rstrip(".") +id_format = lambda x: str(int(x)) + +class validation(_m.Tool(), gen_utils.Snapshot): + + main_directory = _m.Attribute(str) + base_scenario_id = _m.Attribute(int) + traffic_emmebank = _m.Attribute(str) + #transit_emmebank = _m.Attribute(str) + attributes = _m.Attribute(str) + + tool_run_msg = "" + + def __init__(self): + project_dir = os.path.dirname(_m.Modeller().desktop.project.path) + self.main_directory = os.path.dirname(project_dir) + self.base_scenario_id = 100 + self.traffic_emmebank = os.path.join(project_dir, "Database", "emmebank") + #self.transit_emmebank = os.path.join(project_dir, "Database_transit", "emmebank") + self.attributes = ["main_directory", "traffic_emmebank", "transit_emmebank","base_scenario_id"] + + def page(self): + pb = _m.ToolPageBuilder(self) + pb.title = "Validation Procedure" + pb.description = """ +Export traffic flow to Excel files for base year validation.""" + pb.branding_text = "- SANDAG - Validation" + if self.tool_run_msg != "": + pb.tool_run_status(self.tool_run_msg_status) + + pb.add_select_file('main_directory', 'directory', + title='Select main directory') + + pb.add_select_file('traffic_emmebank', 'file', + title='Select traffic emmebank') + #pb.add_select_file('transit_emmebank', 'file', + # title='Select transit emmebank') + return pb.render() + + def run(self): + self.tool_run_msg = "" + try: + results = self(self.main_directory, self.traffic_emmebank, self.base_scenario_id) + #results = self(self.main_directory, self.traffic_emmebank, self.transit_emmebank, self.base_scenario_id) + run_msg = "Export completed" + self.tool_run_msg = _m.PageBuilder.format_info(run_msg) + except Exception as error: + self.tool_run_msg = _m.PageBuilder.format_exception( + error, _traceback.format_exc(error)) + raise + @_m.logbook_trace("Export network data for base year Validation", save_arguments=True) + + def __call__(self, main_directory, traffic_emmebank, base_scenario_id): + #def __call__(self, main_directory, traffic_emmebank, transit_emmebank, base_scenario_id): + print "in validation module" + attrs = { + "main_directory": main_directory, + "traffic_emmebank": str(traffic_emmebank), + #"transit_emmebank": str(transit_emmebank), + "base_scenario_id": base_scenario_id, + "self": str(self) + } + + gen_utils.log_snapshot("Validation procedure", str(self), attrs) + + traffic_emmebank = _eb.Emmebank(traffic_emmebank) + #transit_emmebank = _eb.Emmebank(transit_emmebank) + export_path = os.path.join(main_directory, "analysis/validation") + transitbank_path = os.path.join(main_directory, "emme_project/Database_transit/emmebank") + source_file = os.path.join(export_path, "source_EMME.xlsx") + df = pd.read_excel(source_file, header=None, sheet_name='raw') + writer = pd.ExcelWriter(source_file, engine='openpyxl') + book = openpyxl.load_workbook(source_file) + writer.book = book + writer.sheets = dict((ws.title, ws) for ws in book.worksheets) + + #periods = ["EA"] + periods = ["EA", "AM", "MD", "PM", "EV"] + + period_scenario_ids = OrderedDict((v, i) for i, v in enumerate(periods, start=int(base_scenario_id) + 1)) + + #-------export tranffic data-------- + dfHwycov = pd.read_excel(source_file, sheetname='raw', usecols ="A") + for p, scen_id in period_scenario_ids.iteritems(): + base_scenario = traffic_emmebank.scenario(scen_id) + + #create and calculate @trk_non_pce + create_attribute = _m.Modeller().tool( + "inro.emme.data.extra_attribute.create_extra_attribute") + net_calculator = _m.Modeller().tool( + "inro.emme.network_calculation.network_calculator") + try: + att = create_attribute("LINK", "@trk_non_pce", "total trucs in non-Pce", 0, overwrite=True, scenario = base_scenario) + except: #if "@trk_non_pce" has been created + pass + cal_spec = {"result": att.id, + "expression": "@trk_l_non_pce+@trk_m_non_pce+@trk_h_non_pce", + "aggregation": None, + "selections": {"link": "mode=d"}, + "type": "NETWORK_CALCULATION" + } + net_calculator(cal_spec, scenario = base_scenario) + + network = base_scenario.get_partial_network(["LINK"], include_attributes=True) + + df, dftr, dfsp = self.export_traffic(export_path, traffic_emmebank, scen_id, network, source_file, p, dfHwycov) + dfsp[p + "_Speed"] = dfsp[p + "_Speed"].astype(int) + if p == "EA": + df_total = df + dftr_total = dftr + dfsp_total = dfsp + else: + df_total = df_total.join(df[p + "_Flow"]) + dftr_total = dftr_total.join(dftr[p + "_TruckFlow"]) + dfsp_total = dfsp_total.join(dfsp[p + "_Speed"]) + + df_total.to_excel(writer, sheet_name='raw', header=True, index=False, startcol=0, startrow=0) + dftr_total.to_excel(writer, sheet_name='raw', header=True, index=False, startcol=7, startrow=0) + dfsp_total.to_excel(writer, sheet_name='raw', header=True, index=False, startcol=14, startrow=0) + writer.save() + + #----------------------------------export transit data---------------------------------- + + desktop = _m.Modeller().desktop + data_explorer = desktop.data_explorer() + + try: + data_explorer.add_database(transitbank_path) + except: + pass #if transit database already included in the project + all_databases = data_explorer.databases() + for database in all_databases: + if "transit" in database.name(): + database.open() + break + for p, scen_id in period_scenario_ids.iteritems(): + scen = database.scenario_by_number(scen_id) + data_explorer.replace_primary_scenario(scen) + self.export_transit(export_path, desktop, p) + + # -----------------close or remove transit databack from the project----------------- + database.close() + if "T:" not in main_directory: + data_explorer.remove_database(database) + all_databases = data_explorer.databases() + for database in all_databases: + if "transit" not in database.name(): + database.open() + break + + #------Combine into one datafram and write out + routeDict = {'c':23, 'l':24, 'y':25, 'r':26, 'p':27, 'e':28, 'b':29} + filenames = [] + for p in periods: + file = os.path.join(export_path, "transit_" + p + ".csv") + filenames.append(file) + + df_detail = [] + df_board = [] + df_passMile = [] + + for f in filenames: + df_detail.append(pd.read_csv(f)) + + pnum = 0 + for datafm in df_detail: + datafm['route'] = datafm.apply(lambda row: str(int(row.Line/1000))+row.Mode, axis = 1) + df_board.append(datafm.groupby(['route'])['Pass.'].agg('sum').reset_index()) + df_board[pnum].rename(columns = {'Pass.':periods[pnum]+'_Board'}, inplace=True) + + df_passMile.append(datafm.groupby(['route'])['Pass. dist.'].agg('sum').reset_index()) + df_passMile[pnum].rename(columns = {'Pass. dist.':periods[pnum]+'_PsgrMile'}, inplace=True) + + pnum += 1 + + frame1 = reduce(lambda x,y: pd.merge(x,y, on='route', how='outer'), df_board ) + frame2 = reduce(lambda x,y: pd.merge(x,y, on='route', how='outer'), df_passMile ) + frame = reduce(lambda x,y: pd.merge(x,y, on='route', how='outer'), [frame1,frame2]) + + idx = 1 + frame.insert(loc=idx, column='mode_transit_route_id', value="") + frame['mode_transit_route_id'] = frame['route'].apply(lambda x: routeDict[x[-1]]) + frame['route'] = frame['route'].apply(lambda x: int(x[:-1])) + + writer = pd.ExcelWriter(source_file, engine='openpyxl') + book = openpyxl.load_workbook(source_file) + writer.book = book + writer.sheets = dict((ws.title, ws) for ws in book.worksheets) + frame.to_excel(writer, sheet_name='transit_general', header=True, index=False, startcol=1, startrow=0) + writer.save() + + for p in periods: + file = os.path.join(export_path, "transit_" + p + ".csv") + os.remove(file) + + @_m.logbook_trace("Export traffic load data by period - validaton") + def export_traffic(self, export_path, traffic_emmebank, scen_id, network, filename, period, dfHwycov): + def get_network_value(attrs, emmeAttrName, headerStr, df): + reverse_link = link.reverse_link + key, att = attrs[0] # expected to be the link id + values = [id_format(link[att])] + reverse_link = link.reverse_link + for key, att in attrs[1:]: + if key == "AN": + values.append(link.i_node.id) + elif key == "BN": + values.append(link.j_node.id) + elif key.startswith("BA"): + print "line 148 key, att", key, att + name, default = att + if reverse_link and (abs(link["@tcov_id"]) == abs(reverse_link["@tcov_id"])): + values.append(format(reverse_link[name])) + else: + values.append(default) + elif att.startswith("#"): + values.append('"%s"' % link[att]) + else: + values.append(format(link[emmeAttrName])) + df = df.append({'TCOVID': values[0], period + headerStr: values[1]}, ignore_index=True) + df['TCOVID'] = df['TCOVID'].astype(float) + df[period + headerStr] = df[period + headerStr].astype(float) + return df + + # only the original forward direction links and auto links only + hwyload_attrs = [("TCOVID", "@tcov_id"), (period + "_Flow", "@non_pce_flow")] + trkload_attrs = [("TCOVID", "@tcov_id"), (period + "_TruckFlow", "@trk_non_pce")] + speedload_attrs = [("TCOVID", "@tcov_id"), (period + "_Speed", "@speed")] + df = pd.DataFrame(columns=['TCOVID', period + "_Flow"]) + dftr = pd.DataFrame(columns=['TCOVID', period + "_TruckFlow"]) + dfsp = pd.DataFrame(columns=['TCOVID', period + "_Speed"]) + print "scen_id", scen_id + auto_mode = network.mode("d") + scenario = traffic_emmebank.scenario(scen_id) + links = [l for l in network.links() if (auto_mode in l.modes or (l.reverse_link and auto_mode in l.reverse_link.modes))] + #links = [l for l in network.links() if l["@tcov_id"] > 0 and (auto_mode in l.modes or (l.reverse_link and auto_mode in l.reverse_link.modes))] + links.sort(key=lambda l: l["@tcov_id"]) + + for link in links: + if link["@tcov_id"] in dfHwycov['TCOVID'].tolist(): + reverse_link = link.reverse_link + df = get_network_value(hwyload_attrs, '@non_pce_flow', "_Flow", df) + dftr = get_network_value(trkload_attrs, '@trk_non_pce', "_TruckFlow", dftr) + dfsp = get_network_value(speedload_attrs, '@speed', "_Speed", dfsp) + return df, dftr, dfsp + + @_m.logbook_trace("Export transit load data by period - validaton") + def export_transit(self, export_path, desktop, p): + project_table_db = desktop.project.data_tables() + ws_path = ["General", "Results Analysis", "Transit", "Summaries", "Summary by line"] + root_ws_f = desktop.root_worksheet_folder() + table_item = root_ws_f.find_item(ws_path) + transit_table = table_item.open() + + #for i in delete_table_list: + # transit_table.delete_column(i) + transit_dt = transit_table.save_as_data_table("Transit_Summary", overwrite=True) + transit_table.close() + + transit_data = transit_dt.get_data() + project_path = r'T:\ABM\ABM_FY19\model_runs\ABM2Plus\SenTests4TAC' + transit_filepath = os.path.join(export_path, "transit_"+ p +".csv") + transit_data.export_to_csv(transit_filepath, separator=",") + + @_m.method(return_type=unicode) + def tool_run_msg_status(self): + return self.tool_run_msg \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/SandagCommon.rsc b/sandag_abm/src/main/gisdk/SandagCommon.rsc new file mode 100644 index 0000000..ac345f1 --- /dev/null +++ b/sandag_abm/src/main/gisdk/SandagCommon.rsc @@ -0,0 +1,405 @@ +//**************************************************************** +//**************************************************************** +//Common Macros +// +//Find a string in a text file +//read properties +//Export Matrix to CSV +//Export Matrix +//Matrix Size +//Create Matrix +//Aggregate Matrices +//Go GetMatrixCoreNames +//Get SL Query # +//close all +//CloseViews +//date and time +//SDdeletefile +//SDcopyfile +//SDrenamefile +//HwycadLog +//ForecastYearStr +//ForecastYearInt +//DeleteInterimFiles +//FileCheckDelete +//**************************************************************** +//**************************************************************** +Macro "find String"(file,key) +//file a string in a text file +//file--text file name; key--string to be found in text file +//return 0 is string found, otherwise return 1 +//wsu 6-20-2014 + shared path, path_study + result=1 + +// Get file name + dif2=GetDirectoryInfo(path+"\\"+file, "file") + if dif2.length>0 then do //use scenario file + fptr=openfile(path+"\\"+file,"r") + end + else do //use study file from data directory + fptr=openfile(path_study+"\\data\\"+file,"r") + end + + while not FileAtEOF(fptr) do + pos = PositionFrom(,ReadLine(fptr),key) + if pos>0 then do + result=0 + end + end + CloseFile(fptr) + Return(result) +EndMacro + +Macro "read properties"(file,key,ctype) + //ctype as string - Character Type - Valid "I" or anything else + //macro only reads integers and strings + //reads property as string and returns either an integer or a string + + shared path, path_study + +// Get file name + dif2=GetDirectoryInfo(path+"\\"+file, "file") + if dif2.length>0 then do //use scenario file + fptr=openfile(path+"\\"+file,"r") + end + else do //use study file from data directory + fptr=openfile(path_study+"\\data\\"+file,"r") + end + +// Search key in properties file + a = ReadArray(fptr) + for k=1 to a.length do + // search for the key (line number is stored as k value) + pos1 = position(a[k],key) + if pos1 =1 then do + // gets the integer on the rightside of "=" + keyword=ParseString(a[k], "=") + keyvaltrim=trim(keyword[2]) + if ctype = "I" then do // integer + keyval=S2I(keyvaltrim) + end + else do // if not I then it's a string + keyval = keyvaltrim // gets the string on the rightside of "=" + end + end + end + CloseFile(fptr) + Return(keyval) +EndMacro + +Macro "read properties array"(file,key,ctype) + //this Macro is to read an array property,index is 1-based. + shared path, path_study + + pStr=RunMacro("read properties",file,key,ctype) + pStr=trim(pStr) + pArray=ParseString(pStr, ",") + Return(pArray) +EndMacro + +Macro "Export Matrix to CSV" (path,filename,corename,filenameout) + m = OpenMatrix(path+"\\"+filename, "True") + mc = CreateMatrixCurrency(m,corename,,,) + rows = GetMatrixRowLabels(mc) + ExportMatrix(mc, rows, "Rows", "CSV", path+"\\"+filenameout, ) + return(1) +EndMacro + +Macro "Export Matrix" (path,filename,corename,filenameout,outputtype) + //path as string - path="T:\\transnet2\\devel\\sr12\\sr12_byear\\byear" + //filename as string - must be a matrix - filename="SLAgg.mtx" + //corename as string - corename="DAN" + //filenameout as string - filenameout="SLAgg.csv" + //outputtype as string - ("dBASE", "FFA", "FFB" or "CSV") + + m = OpenMatrix(path+"\\"+filename, "True") + mc = CreateMatrixCurrency(m,corename,,,) + rows = GetMatrixRowLabels(mc) + ExportMatrix(mc, rows, "Rows", outputtype, path+"\\"+filenameout, ) + return(1) +EndMacro + +Macro "Matrix Size" (path, filename, corename) + //gets the size (number of zones) in the matrix - useful for sr11 vs sr12 and for split zones + m = OpenMatrix(path+"\\"+filename, "True") + base_indicies = GetMatrixBaseIndex(m) + mc = CreateMatrixCurrency(m, corename, base_indicies[1], base_indicies[2], ) + v = GetMatrixVector(mc, {{"Marginal", "Row Count"}}) + vcount = VectorStatistic(v, "Count", ) + return(vcount) +EndMacro + +Macro "Create Matrix" (path, filename, label, corenames, zone) + Opts = null + Opts.[File Name] = (path+"\\"+filename) + Opts.Label = label + Opts.Type = "Float" + Opts.Tables = corenames + Opts.[Column Major] = "No" + Opts.[File Based] = "Yes" + Opts.Compression = 0 + m = CreateMatrixFromScratch(label, zone, zone, Opts) + return(1) +EndMacro + +Macro "Aggregate Matrices" (path, xref, xrefcol1, xrefcol2, mtx, corenm, aggmtx) + // Aggregate Matrix Options + m = OpenMatrix(path+"\\"+mtx, "True") + base_indicies = GetMatrixBaseIndex(m) + Opts = null + Opts.Input.[Matrix Currency] = {path+"\\"+mtx, corenm, base_indicies[1], base_indicies[2]} + Opts.Input.[Aggregation View] = {xref, "xref"} + Opts.Global.[Row Names] = {"xref."+xrefcol1, "xref."+xrefcol2} + Opts.Global.[Column Names] = {"xref."+xrefcol1, "xref."+xrefcol2} + Opts.Output.[Aggregated Matrix].Label = "AggMtx"+"_"+corenm + Opts.Output.[Aggregated Matrix].Compression = 1 + Opts.Output.[Aggregated Matrix].[File Name] = path+"\\"+aggmtx + + ok = RunMacro("TCB Run Operation", 1, "Aggregate Matrix", Opts, ) + return(ok) +EndMacro + +Macro "Go GetMatrixCoreNames" (path, matrix) + m = OpenMatrix(path+"\\"+matrix, ) + core_names=GetMatrixCoreNames(m) + return(core_names) +EndMacro + +Macro "Get SL Query # from QRY" (path) + + selinkqry_file="\\selectlink_query.qry" + fptr_from = OpenFile(path + selinkqry_file, "r") + qry_array = readarray(fptr_from) + // query = 0 + query_list = null + + for j = 1 to qry_array.length do + line = qry_array[j] + p1 = Position(line, "\") + p2 = Position(line, "\<\/name\>") + if p1 > 0 & p2 > 0 then do + start = p1 + 6 + name_len = p2 - start + name = Substring(line, start, name_len) + query_list = query_list + {name} + end + // if Position(qry_array[j], "\") >0 then query = query + 1 + end + return(query_list) +EndMacro + +Macro "close all" + maps = GetMaps() + if maps <> null then do + for k = 1 to maps[1].length do + SetMapSaveFlag(maps[1][k],"False") + end + end + RunMacro("G30 File Close All") + mtxs = GetMatrices() + if mtxs <> null then do + handles = mtxs[1] + for k = 1 to handles.length do + handles[k] = null + end + end + views = GetViews() + if views <> null then do + handles = views[1] + for k = 1 to handles.length do + handles[k] = null + end + end +EndMacro + +Macro "CloseViews" + vws = GetViewNames() + for i = 1 to vws.length do + CloseView(vws[i]) + end +EndMacro + +// returns a nicely formatted day and time +Macro "date and time" + date_arr = ParseString(GetDateAndTime(), " ") + day = date_arr[1] + mth = date_arr[2] + num = date_arr[3] + time = Left(date_arr[4], StringLength(date_arr[4])-3) + year = SubString(date_arr[5], 1, 4) + today = mth + "/" + num + "/" + year + " " + time + //showmessage(today) + Return(today) +EndMacro + +Macro "SDdeletefile"(arr) + file=arr[1] + dif2=GetDirectoryInfo(file,"file") + if dif2.length>0 then deletefile(file) + ok=1 + quit: + return(ok) +EndMacro + +Macro "SDcopyfile"(arr) + file1=arr[1] + file2=arr[2] + dif2=GetDirectoryInfo(file2,"file") + if dif2.length>0 then deletefile(file2) + dif2=GetDirectoryInfo(file1,"file") + if dif2.length>0 then copyfile(file1,file2) + ok=1 + quit: + return(ok) +EndMacro + +Macro "SDrenamefile"(arr) + file1=arr[1] + file2=arr[2] + dif1=GetDirectoryInfo(file2,"file") + if dif1.length>0 then deletefile(file2) + dif2=GetDirectoryInfo(file1,"file") + if dif2.length>0 then RenameFile(file1, file2) + ok=1 + quit: + return(ok) +EndMacro + +Macro "HwycadLog"(arr) + shared path + fprlog=null + log1=arr[1] + log2=arr[2] + dif2=GetDirectoryInfo(path+"\\hwycadx.log","file") + if dif2.length>0 then fprlog=OpenFile(path+"\\hwycadx.log","a") + else fprlog=OpenFile(path+"\\hwycadx.log","w") + mytime=GetDateAndTime() + writeline(fprlog,mytime+", "+log1+", "+log2) + CloseFile(fprlog) + fprlog = null + return() +EndMacro + +Macro "ForecastYearStr" + shared path_study,path + fptr = OpenFile(path+"\\year", "r") + strYear = ReadLine(fptr) + closefile(fptr) + return(strYear) +EndMacro + +Macro "ForecastYearInt" + //usage: myyear=RunMacro("ForecastYearInt") + shared path_study,path + fptr = OpenFile(path+"\\year", "r") + strFyear = ReadLine(fptr) + closefile(fptr) + intFyear=S2I(strFyear) + return(intFyear) +EndMacro + +Macro "DeleteInterimFiles" (path, FileNameArray,RscName,MacroName,FileDescription) + RunMacro("HwycadLog",{RscName+": "+MacroName,"SDdeletefile, "+FileDescription}) + for i = 1 to FileNameArray.length do //delete existing files + ok=RunMacro("SDdeletefile",{path+"\\"+FileNameArray[i]}) if !ok then goto quit + end + quit: + return(ok) +EndMacro + +Macro "FileCheckDelete" (path,filename) + //usage: RunMacro("FileCheckDelete",path,filename) where path and filename are strings + di = GetDirectoryInfo(path+"\\"+filename, "File") + if di.length > 0 then do + ok=RunMacro("SDdeletefile",{path+"\\"+filename}) + return(ok) + end +EndMacro + +// Macro "getpathdirectory" doesn't allow the selected path with different path_study. +Macro "GetPathDirectory" + shared path,path_study,scr + opts={{"Initial Directory", path_study}} + tmp_path=choosedirectory("Choose an alternative directory in the same study area", opts) + strlen=len(tmp_path) + for i = 1 to strlen do + tmp=right(tmp_path,i) + tmpx=left(tmp,1) + if tmpx="\\" then goto endfor + end + endfor: + strlenx=strlen-i + tmppath_study=left(tmp_path,strlenx) + if path_study=tmppath_study then do + path=tmp_path + tmp_flag=0 + for i=1 to scr.length do + if scr[i]=path then do + tmp_flag=1 + i=scr.length+1 + end + else i=i+1 + end + if tmp_flag=0 then do + tmp = CopyArray(scr) + tmp = tmp + {tmp_path} + scr = CopyArray(tmp) + end + //showmessage("write description of the alternative in the head file") + //x=RunProgram("notepad "+path+"\\head",) + mytime=GetDateAndTime() + fptr=openfile(path+"\\tplog","a") + WriteLine(fptr, mytime) + closefile(fptr) + //showmessage("type in the reason why you are doing the model run in tplog") + //x=RunProgram("notepad "+path+"\\tplog",) + end + else do + path=null + msg1="The alternative directory selected is invalid because it has different study area! " + msg2="Please select again within the same study area " + msg3=" or use the Browse button to select a different study area." + showMessage(msg1+msg2+path_study+msg3) + end +EndMacro +/*********************************************************************************************************************************** +* +* Run Program +* Runs the program for a set of control files +* +***********************************************************************************************************************************/ + +Macro "Run Program" (scenarioDirectory, executableString, controlString) + + + //drive letter + path = SplitPath(scenarioDirectory) + + //open the batch file to run + fileString = scenarioDirectory+"\\programs\\source.bat" + ptr = OpenFile(fileString, "w") + WriteLine(ptr,path[1]) + WriteLine(ptr,"cd "+scenarioDirectory ) + + runString = "call "+executableString + " " + controlString + WriteLine(ptr,runString) + + //write the return code check + failString = "IF NOT ERRORLEVEL = 0 ECHO "+controlString+" > failed.txt" + WriteLine(ptr,failString) + + CloseFile(ptr) + status = RunProgram(fileString, {{"Minimize", "True"}}) + + info = GetFileInfo(scenarioDirectory+"\\failed.txt") + if(info != null) then do + ret_value=0 + goto quit + end + + Return(1) + quit: + Return( RunMacro("TCB Closing", ret_value, True ) ) +EndMacro + diff --git a/sandag_abm/src/main/gisdk/TC2OMX.rsc b/sandag_abm/src/main/gisdk/TC2OMX.rsc new file mode 100644 index 0000000..09fa7cb --- /dev/null +++ b/sandag_abm/src/main/gisdk/TC2OMX.rsc @@ -0,0 +1,69 @@ +Macro "TC to OMX" + + p="T:\\ABM\\ActivitySim\\SANDAG_ActivitySim\\data\\skims" + + files = GetDirectoryInfo(RunMacro("FormPath",{p,"*"}),"All") + for i = 1 to files.length do + f = RunMacro("FormPath",{p,files[i][1]}) + subs = ParseString(f,".", {{"Include Empty",True}}) + if files[i][2] = "file" then do + if subs[2]="mtx" then do + RunMacro("ExportMatrix",subs[1]+".mtx") + end + end + end +EndMacro + +Macro "ExportMatrix" (matrix) + subs = ParseString(matrix,".", {{"Include Empty",True}}) + m = OpenMatrix(matrix, "True") + mc = CreateMatrixCurrency(m,,,,) + CopyMatrix(mc, { + {"File Name", subs[1]+".omx"}, + {"OMX", "True"} + } + ) +EndMacro + +Macro "FormPath" (path_elements) + if TypeOf(path_elements) <> "array" then do + ShowMessage("Must form a path out of a list of elements, not: " + TypeOf(path_elements)) + ShowMessage(2) + end + //path_elements is an array of elements + path = "" + for i = 1 to path_elements.length do + //change / to \ + p = RunMacro("NormalizePath",path_elements[i]) + if Right(p,1) = "\\" then do + if Len(p) > 1 then do + p = Substring(p,1,Len(p)-1) + end + else do + p = "" + end + end + if Left(p,1) = "\\" then do + if Len(p) > 1 then do + p = Substring(p,2,Len(p)) + end + else do + p = "" + end + end + if path = "" then do + path = p + end + else do + path = path + "\\" + p + end + end + return(path) +EndMacro + +Macro "NormalizePath" (path) + if Len(path) > 1 and path[2] = ":" then do + path = Lower(path[1]) + Right(path,Len(path)-1) + end + return(Substitute(path,"/","\\",)) +EndMacro \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/TruckModel.rsc b/sandag_abm/src/main/gisdk/TruckModel.rsc new file mode 100644 index 0000000..05cda11 --- /dev/null +++ b/sandag_abm/src/main/gisdk/TruckModel.rsc @@ -0,0 +1,1504 @@ +/********************************************************************************************************** +Runs truck model +About: + Script to run the SANDAG Truck Model in TransCAD + Study Area: County of San Diego, California + TransCAD version 4.8 Build 545 + Author: Parsons Brinckerhoff (R. Moeckel, S. Gupta, C. Frazier) + Developed: June to December 2008 + +Modifications: + 1) Added truck toll diversion model to go from three truck types + to six truck types ({lhd/mhd/hhd} * {toll/non-toll}) + Ben Stabler, stabler@pbworld.com, 12/02/10 + + 2) Modified to integrate with SANDAG ABM + Amar Sarvepalli, sarvepalli@pbworld.com, 09/06/12 + + 3) Modified to remove truck skimming; added truck skims to hwyskim_vot.rsc + JEF joel.freedman@rsginc.com, 5/10/2015 + +Steps: + 1) Generates standard truck trip and special (military) truck trips + 2) Gets regional truck trips, IE trips, EI trips and EE trips and balances truck trips + 3) Distributes truck trips with congested skims and splits by time of day + 4) Applies truck toll diversion model with free-flow toll and non-toll skims + + Note: truck trip generation and free-flow skims are run only for the first iteration + + + +**********************************************************************************************************/ +Macro "truck model"(properties, iteration) + shared path, inputDir, outputDir, inputTruckDir + + // read properties from sandag_abm.properties in /conf folder + properties = "\\conf\\sandag_abm.properties" + startFromIteration = s2i(RunMacro("read properties",properties,"RunModel.startFromIteration", "S")) + + // Generate trips and free-flow truck skims for the first iteration + if (iteration = startFromIteration) then do + // Generate daily truck trips + RunMacro("HwycadLog",{"TruckModel.rsc: truckmodel","truck-tripgen"}) + ok = RunMacro("truck-tripgen",properties) + if !ok then goto quit + end + + // Distribute daily truck trips and split them by time period + RunMacro("HwycadLog",{"TruckModel.rsc: truckmodel","trkDistribution,(properties)"}) + ok = RunMacro("trkDistribution",properties) + if !ok then goto quit + + // Apply toll-diversion model + RunMacro("HwycadLog",{"TruckModel.rsc: truckmodel","trk toll diversion model"}) + ok = RunMacro("trk toll diversion model") + if !ok then goto quit + + run_ok = 1 + RunMacro("close all") + Return(run_ok) + + quit: + RunMacro("close all") + Return(ok) +EndMacro + + + +/********************************************************************************************************** +Generates daily truck trips (standard and special generations) + +Inputs: + sandag.properties + +Outputs: + output\gmTruckDataBalanced.bin + output\regionalEEtrips.csv + +**********************************************************************************************************/ +Macro "truck-tripgen"(properties) + shared path, inputDir, outputDir, mxzone + dim arrInterimYear[3] + + strFyear = RunMacro("read properties",properties,"truck.FFyear","S") + intFyear = StringToInt(strFyear) + arrInterimYear=RunMacro("InterimYearCheck",properties,intFyear) + + RunMacro("trkStdTripGen",strFyear,intFyear,arrInterimYear,properties) + RunMacro("trkSpecialGen",strFyear,intFyear,arrInterimYear) + RunMacro("trkBalance",strFyear,intFyear,arrInterimYear) + run_ok=1 + + exit: + RunMacro("close all") + Return(run_ok) +EndMacro + + + + +/********************************************************************************************************** +Produces standard truck trips + +Inputs: + input\mgra13_based_input2010.csv + input\TruckTripRates.csv + output\hhByTaz.csv.csv + output\empByTaz.csv.csv + + (optional, used for interpolation) + input\hhByTaz.csv + input\hhByTaz.csv + input\empByTaz.csv + input\empByTaz.csv + + (optional, used only for landuse override) + input\lu.csv + output\EmpDistLUovrAgg.csv + output\hhluagg.csv + +Outputs: + output\gmTruckDataII.csv + +**********************************************************************************************************/ +Macro "trkStdTripGen" (strFyear,intFyear,arrInterimYear,properties) + shared path, inputDir, outputDir, mxzone + booInterimYear = arrInterimYear[1] + + // Creates household and employment data by taz from mgra data + RunMacro("Create hh and emp by taz") + + //-------------------------------------------------- + //This section checks available data and interpolates if doesn't exist + //-------------------------------------------------- + // Do interpolate = True + if booInterimYear = 2 then do + prevYear = arrInterimYear[2] + nextYear = arrInterimYear[3] + end + + // Override landuse data if option is "True" + check_luOverride = RunMacro("read properties",properties,"truck.luOverRide", "S") + if check_luOverride = "True" then do + RunMacro("EmploymentLUOverride") + RunMacro("EmploymentDistLUOverride") + RunMacro("HouseholdLUOverride") + end + + + // If data is not available then interpolate from closest available years + if booInterimYear = 2 then do + // Copy prev and next year data files to output directory + ok=RunMacro("SDcopyfile",{inputDir+"\\hhByTaz"+I2S(prevYear)+".csv",outputDir+"\\hhByTaz_prev.csv"}) + ok=RunMacro("SDcopyfile",{inputDir+"\\hhByTaz"+I2S(nextYear)+".csv",outputDir+"\\hhByTaz_next.csv"}) + ok=RunMacro("SDcopyfile",{inputDir+"\\empByTaz"+I2S(prevYear)+".csv",outputDir+"\\empByTaz_prev.csv"}) + ok=RunMacro("SDcopyfile",{inputDir+"\\empByTaz"+I2S(nextYear)+".csv",outputDir+"\\empByTaz_next.csv"}) + + // Interpolate data from prev and next years + ok=RunMacro("Interpolate",{"hhByTaz_prev.csv","hhByTaz_next.csv","hhByTaz.csv",intFyear,prevYear,nextYear}) + ok=RunMacro("Interpolate",{"empByTaz_prev.csv","empByTaz_next.csv","empByTaz.csv",intFyear,prevYear,nextYear}) + + // Delete prev and next year data files + ok=RunMacro("SDdeletefile",{outputDir+"\\hhByTaz_prev.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\hhByTaz_next.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\empByTaz_prev.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\empByTaz_next.csv"}) + end + + // join data and parameter tables + empView = Opentable("Employment", "CSV", {outputDir+"\\empByTaz.csv"}) + hhView = Opentable("HouseHolds", "CSV", {outputDir+"\\hhByTaz.csv"}) + + + //-------------------------------------------------- + // This section overrides LU for employment and households + //-------------------------------------------------- + if check_luOverride = "True" then do + + //LU override file for Employment + empAggDistLUovr_filecsv = outputDir+"\\EmpDistLUovrAgg.csv" + di = GetDirectoryInfo(empAggDistLUovr_filecsv, "File") + + // Export employment by TAZ to binary file and get zones + ExportView("Employment|", "FFB", outputDir+"\\empByTaz.BIN", null, ) + vwEmpBin = Opentable("EmploymentByZoneBin", "FFB", {outputDir+"\\empByTaz.BIN"}) + vwEmpDistLUovrAgg = Opentable("EmploymentDistributionOverride", "CSV", {empAggDistLUovr_filecsv}) + vectZonerecords = GetRecordCount(vwEmpDistLUovrAgg, null) + vectZone = GetDataVectors(vwEmpDistLUovrAgg+"|",{"zone"},) + + // Convert real to string zones + for i = 1 to vectZonerecords do + strZone = RealToString(vectZone[1][i]) + rh = LocateRecord("EmploymentByZoneBin|","TAZ",{strZone},{{"Exact", "True"}}) + x = GetView() + DeleteRecord("EmploymentByZoneBin", rh) + end + + // Get data from all fields in EmpDistLUovrAgg file + fldsEmpDistLUovrAgg = GetFields(vwEmpDistLUovrAgg, "All") + vectEMPovr = GetDataVectors(vwEmpDistLUovrAgg+"|",fldsEmpDistLUovrAgg[1],) + + // Write fields to employment by TAZ + for i = 1 to vectZonerecords do + rh = AddRecord(vwEmpBin, { + {"TAZ", R2I(vectEMPovr[1][i])}, + {"First TAZ", R2I(vectEMPovr[2][i])}, + {fldsEmpDistLUovrAgg[1][3], vectEMPovr[3][i]}, + {fldsEmpDistLUovrAgg[1][4], vectEMPovr[4][i]}, + {fldsEmpDistLUovrAgg[1][5], vectEMPovr[5][i]}, + {fldsEmpDistLUovrAgg[1][6], vectEMPovr[6][i]}, + {fldsEmpDistLUovrAgg[1][7], vectEMPovr[7][i]}, + {fldsEmpDistLUovrAgg[1][8], vectEMPovr[8][i]}, + {fldsEmpDistLUovrAgg[1][9], vectEMPovr[9][i]}, + {fldsEmpDistLUovrAgg[1][10], vectEMPovr[10][i]}, + {fldsEmpDistLUovrAgg[1][11], vectEMPovr[11][i]} + }) + end + + // LU override file for Households + HHLUagg_filecsv = outputDir+"\\hhluagg.csv" + di = GetDirectoryInfo(HHLUagg_filecsv, "File") + + // Export households by TAZ to binary file and get zones + ExportView(hhView+"|", "FFB", outputDir+"\\hhByTaz.BIN", null, ) + vwHHBin = Opentable("HouseholdsByZoneBin", "FFB", {outputDir+"\\HHByTaz.BIN"}) + vwHHLUagg = Opentable("HouseholdsOverride", "CSV", {HHLUagg_filecsv}) + vectHHZoneRecords = GetRecordCount(vwHHLUagg, null) + vectHHZone = GetDataVectors(vwHHLUagg+"|",{"TAZ"},) + + // Convert real to string zones + for i = 1 to vectHHZoneRecords do + strZone = RealToString(vectHHZone[1][i]) + rh = LocateRecord("HouseholdsByZoneBin|","TAZ",{strZone},{{"Exact", "True"}}) + DeleteRecord("HouseholdsByZoneBin", rh) + end + + // Get data from all fields in hhluagg file + fldsHHLUAgg = GetFields(vwHHLUagg, "All") + vectHHovr = GetDataVectors(vwHHLUagg+"|",fldsHHLUAgg[1],) + + // Write fields to households by TAZ + for i = 1 to vectHHZoneRecords do + rh = AddRecord(vwHHBin, { + {"TAZ", R2I(vectHHovr[1][i])}, + {"First TAZ", R2I(vectHHovr[2][i])}, + {fldsHHLUAgg[1][3], vectHHovr[3][i]} + }) + end + end + + + //-------------------------------------------------- + // This section applies truck trip production and attraction rates by truck type + //-------------------------------------------------- + // Open truck data file + viewtripRates = Opentable("TruckTripRates", "CSV", {inputDir+"\\TruckTripRates.csv"}) + + // Join all data + jv1 = Joinviews("JV1", hhView+".ZONE", empView+".ZONE",) + jv9 = Joinviews("JV9", jv1+"."+hhView+".TruckRegionType", viewtripRates+".RegionType",) + Setview(jv9) + + // Compute lhd truck productions "AGREMPN","CONEMPN","RETEMPN","GOVEMPN","MANEMPN","UTLEMPN","WHSEMPN","OTHEMPN"} + lhd_p = CreateExpression(jv9, "LHD_ProductionsTemp", "Nz(emp_agmin + emp_cons) * [TG_L_Ag/Min/Constr] + Nz(emp_retrade) * TG_L_Retail + Nz(emp_gov) * TG_L_Government + Nz(emp_mfg) * TG_L_Manufacturing + Nz(emp_twu) * [TG_L_Transp/Utilities]", ) + lhd_p = CreateExpression(jv9, "LHD_Productions", "Nz(LHD_ProductionsTemp) + Nz(emp_whtrade) * TG_L_Wholesale + Nz(emp_other) * TG_L_Other + Nz(HH) * TG_L_Households", ) + + // Compute lhd truck attractions + lhd_a = CreateExpression(jv9, "LHD_AttractionsTemp", "(emp_agmin + emp_cons) * [TA_L_Ag/Min/Constr] + emp_retrade * TA_L_Retail + emp_gov * TA_L_Government + emp_mfg * TA_L_Manufacturing + emp_twu * [TA_L_Transp/Utilities] + emp_whtrade * TA_L_Wholesale", ) + lhd_a = CreateExpression(jv9, "LHD_Attractions", "Nz(LHD_AttractionsTemp) + Nz(emp_other) * TA_L_Other + Nz(HH) * TA_L_Households", ) + + // Compute mhd truck productions + mhd_p = CreateExpression(jv9, "MHD_ProductionsTemp", "(emp_agmin + emp_cons) * [TG_M_Ag/Min/Constr] + emp_retrade * TG_M_Retail + emp_gov * TG_M_Government + emp_mfg * TG_M_Manufacturing + emp_twu * [TG_M_Transp/Utilities] + emp_whtrade * TG_M_Wholesale ", ) + mhd_p = CreateExpression(jv9, "MHD_Productions", "Nz(MHD_ProductionsTemp) + Nz(emp_other) * TG_M_Other + Nz(HH) * TG_M_Households", ) + + // Compute mhd truck attractions + mhd_a = CreateExpression(jv9, "MHD_AttractionsTemp", "(emp_agmin + emp_cons) * [TA_M_Ag/Min/Constr] + emp_retrade * TA_M_Retail + emp_gov * TA_M_Government + emp_mfg * TA_M_Manufacturing + emp_twu * [TA_M_Transp/Utilities] + emp_whtrade * TA_M_Wholesale", ) + mhd_a = CreateExpression(jv9, "MHD_Attractions", "Nz(MHD_AttractionsTemp) + Nz(emp_other) * TA_M_Other + Nz(HH) * TA_M_Households", ) + + // Compute hhd truck productions + hhd_p = CreateExpression(jv9, "HHD_ProductionsTemp", "(emp_agmin + emp_cons) * [TG_H_Ag/Min/Constr] + emp_retrade * TG_H_Retail + emp_gov * TG_H_Government + emp_mfg * TG_H_Manufacturing + emp_twu * [TG_H_Transp/Utilities] + emp_whtrade * TG_H_Wholesale ", ) + hhd_p = CreateExpression(jv9, "HHD_Productions", "Nz(HHD_ProductionsTemp) + Nz(emp_other) * TG_H_Other + Nz(HH) * TG_H_Households", ) + + // Compute hhd truck attractions + hhd_a = CreateExpression(jv9, "HHD_AttractionsTemp", "(emp_agmin + emp_cons) * [TA_H_Ag/Min/Constr] + emp_retrade * TA_H_Retail + emp_gov * TA_H_Government + emp_mfg * TA_H_Manufacturing + emp_twu * [TA_H_Transp/Utilities] + emp_whtrade * TA_H_Wholesale", ) + hhd_a = CreateExpression(jv9, "HHD_Attractions", "Nz(HHD_AttractionsTemp) + Nz(emp_other) * TA_H_Other + Nz(HH) * TA_H_Households", ) + + // Export the productions and attractions to csv file + RunMacro("HwycadLog",{"TruckModel.rsc: trkStdGen","ExportView P&A"}) + ExportView(jv9+"|", "CSV", outputDir+"\\gmTruckDataII.csv", {hhView+".ZONE", "LHD_Productions", "LHD_Attractions", "MHD_Productions", "MHD_Attractions", "HHD_Productions", "HHD_Attractions"}, {{"CSV Header"}}) + + + // Close all and delete temp files + RunMacro("close all") + ok=RunMacro("SDdeletefile",{outputDir+"\\hhdata.csv"}) + if!ok then goto exit + ok=RunMacro("SDdeletefile",{outputDir+"\\emp.csv"}) + if!ok then goto exit + + run_ok=1 + exit: + RunMacro("close all") + Return(run_ok) +EndMacro + + + +/********************************************************************************************************** +Creates households by taz and employment by taz files to use in the truck trip generation model + +Inputs: + sandag.properties + input\mgra13_based_input2012.csv + +Outputs: + output\empByTaz.csv + output\hhByTaz.csv + +**********************************************************************************************************/ +Macro "Create hh and emp by taz" + shared path, inputDir, outputDir, mxzone , scenarioYear + mgraDataFile = "mgra13_based_input"+scenarioYear+".csv" + empbytaz = "empByTaz.csv" + hhbytaz = "hhByTaz.csv" + + RunMacro("SDcopyfile",{inputDir+"\\"+mgraDataFile,outputDir+"\\"+mgraDataFile}) + mgraView = OpenTable("MGRA View", "CSV", {outputDir+"\\"+mgraDataFile}, {{"Shared", "True"}}) + + // Get data fields into vectors + mgra = GetDataVector(mgraView+"|", "mgra", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + taz = GetDataVector(mgraView+"|", "TAZ", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + hh = GetDataVector(mgraView+"|", "hh", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_ag = GetDataVector(mgraView+"|", "emp_ag", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_non_bldg_prod = GetDataVector(mgraView+"|", "emp_const_non_bldg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_non_bldg_office = GetDataVector(mgraView+"|", "emp_const_non_bldg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_utilities_prod = GetDataVector(mgraView+"|", "emp_utilities_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_utilities_office = GetDataVector(mgraView+"|", "emp_utilities_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_bldg_prod = GetDataVector(mgraView+"|", "emp_const_bldg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_bldg_office = GetDataVector(mgraView+"|", "emp_const_bldg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_mfg_prod = GetDataVector(mgraView+"|", "emp_mfg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_mfg_office = GetDataVector(mgraView+"|", "emp_mfg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_whsle_whs = GetDataVector(mgraView+"|", "emp_whsle_whs", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_trans = GetDataVector(mgraView+"|", "emp_trans", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_retail = GetDataVector(mgraView+"|", "emp_retail", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_prof_bus_svcs = GetDataVector(mgraView+"|", "emp_prof_bus_svcs", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_prof_bus_svcs_bldg_maint = GetDataVector(mgraView+"|", "emp_prof_bus_svcs_bldg_maint", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_ed_k12 = GetDataVector(mgraView+"|", "emp_pvt_ed_k12", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_ed_post_k12_oth = GetDataVector(mgraView+"|", "emp_pvt_ed_post_k12_oth", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_health = GetDataVector(mgraView+"|", "emp_health", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_personal_svcs_office = GetDataVector(mgraView+"|", "emp_personal_svcs_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_amusement = GetDataVector(mgraView+"|", "emp_amusement", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_hotel = GetDataVector(mgraView+"|", "emp_hotel", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_restaurant_bar = GetDataVector(mgraView+"|", "emp_restaurant_bar", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_personal_svcs_retail = GetDataVector(mgraView+"|", "emp_personal_svcs_retail", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_religious = GetDataVector(mgraView+"|", "emp_religious", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_hh = GetDataVector(mgraView+"|", "emp_pvt_hh", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_ent = GetDataVector(mgraView+"|", "emp_state_local_gov_ent", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_fed_non_mil = GetDataVector(mgraView+"|", "emp_fed_non_mil", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_fed_mil = GetDataVector(mgraView+"|", "emp_fed_mil", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_blue = GetDataVector(mgraView+"|", "emp_state_local_gov_blue", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_white = GetDataVector(mgraView+"|", "emp_state_local_gov_white", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_total = GetDataVector(mgraView+"|", "emp_total", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + + + // Combine employment fields that match to the truck trip rate classification + TOTEMP = emp_total // Total employment + emp_agmin = emp_ag // Agriculture + Mining + emp_cons = emp_const_bldg_prod + emp_const_bldg_office // Construction + emp_retrade = emp_retail + emp_personal_svcs_retail // Retail + emp_gov = emp_state_local_gov_ent + emp_state_local_gov_blue + emp_state_local_gov_white + emp_fed_non_mil + emp_fed_mil // Government + emp_mfg = emp_mfg_prod + emp_mfg_office // Manufacturing + emp_twu = emp_trans + emp_utilities_office + emp_utilities_prod // Transportation + Utilities + emp_whtrade = emp_whsle_whs // Wholesale + emp_other = TOTEMP - (emp_agmin +emp_cons+ emp_retrade + emp_gov + emp_mfg + emp_twu + emp_whtrade) // Other + + + // Add fields employment by taz + strct = GetTableStructure(mgraView) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + strct = strct + {{"emp_agmin" , "Float", 8, 4, "True", , , , , , , null}} + strct = strct + {{"emp_cons" , "Float", 8, 4, "True", , , , , , , null}} + strct = strct + {{"emp_retrade" , "Float", 8, 0, "True", , , , , , , null}} + strct = strct + {{"emp_gov" , "Float", 8, 0, "True", , , , , , , null}} + strct = strct + {{"emp_mfg" , "Float", 8, 0, "True", , , , , , , null}} + strct = strct + {{"emp_twu" , "Float", 8, 0, "True", , , , , , , null}} + strct = strct + {{"emp_whtrade" , "Float", 8, 0, "True", , , , , , , null}} + strct = strct + {{"emp_other" , "Float", 8, 4, "True", , , , , , , null}} + ModifyTable(mgraView, strct) + + ExportView(mgraView+"|","FFB",outputDir+"\\temp.bin",{"MGRA","TAZ","HH","TruckRegionType","emp_agmin","emp_cons","emp_retrade","emp_gov","emp_mfg","emp_twu","emp_whtrade","emp_other"},) + MgraTazView = OpenTable("MGRA View", "FFB", {outputDir+"\\temp.bin"},) + + // Set data into new fields + SetDataVectors(MgraTazView+"|",{{"emp_agmin" ,emp_agmin }, + {"emp_cons" ,emp_cons }, + {"emp_retrade",emp_retrade}, + {"emp_gov" ,emp_gov }, + {"emp_mfg" ,emp_mfg }, + {"emp_twu" ,emp_twu }, + {"emp_whtrade",emp_whtrade}, + {"emp_other" ,emp_other }},) + + // Aggregate employment fields by taz + emp = AggregateTable("employment", MgraTazView+"|","FFB", outputDir+"\\emp_temp.bin","TAZ", { + {"TruckRegionType","avg","TruckRegionType"}, + {"emp_agmin" ,"sum","emp_agmin" }, + {"emp_cons" ,"sum","emp_cons" }, + {"emp_retrade" ,"sum","emp_retrade" }, + {"emp_gov" ,"sum","emp_gov" }, + {"emp_mfg" ,"sum","emp_mfg" }, + {"emp_twu" ,"sum","emp_twu" }, + {"emp_whtrade" ,"sum","emp_whtrade" }, + {"emp_other" ,"sum","emp_other" } + },null) + + emp_view = OpenTable("emp_view", "FFB", {outputDir+"\\emp_temp.bin"},) + RenameField(emp_view+".Avg TruckRegionType", "TruckRegionType") + + // Create a temp file with all zones (internal + external zones) from the highway network file + db_file = outputDir+"\\hwy.dbd" + {node_lyr,} = RunMacro("TCB Add DB Layers", db_file,,) + SetLayer(node_lyr) + n= SelectByQuery("Zones", "Several", "Select * where ID <= "+ String(mxzone),) + zones = GetDataVector(node_lyr+"|Zones", "ID",{{"Sort Order", {{"ID", "Ascending"}}}}) + + // Create a temp file with all zones + all_vw = CreateTable("allzones", outputDir+"\\temp_zones.bin", "FFB",{ + {"ZONE", "Integer", 8, null, "Yes"}}) + SetView(all_vw) + for i = 1 to zones.length do + rh = AddRecord(all_vw, {{"ZONE", zones[i]}}) + end + + join_vw = JoinViews("joined_view1", all_vw+".ZONE",emp_view+".TAZ",) + ExportView(join_vw+"|","CSV",outputDir+"\\"+empbytaz,,) + CloseView(join_vw) + + + // Aggregate households by taz + hh = AggregateTable("households", MgraTazView+"|","FFB", outputDir+"\\hh_temp.bin","TAZ", { + {"TruckRegionType","avg","TruckRegionType"}, + {"HH" ,"sum","HH"} + },null) + + hh_view = OpenTable("hh_temp", "FFB", {outputDir+"\\hh_temp.bin"},) + RenameField(hh_view+".Avg TruckRegionType", "TruckRegionType") + join_vw = JoinViews("joined_view1", all_vw+".ZONE",hh_view+".TAZ",) + ExportView(join_vw+"|","CSV",outputDir+"\\"+hhbytaz,,) + + RunMacro("close all") + + DeleteFile(outputDir+"\\temp_zones.bin") + DeleteFile(outputDir+"\\emp_temp.bin") + DeleteFile(outputDir+"\\hh_temp.bin") +EndMacro + + + +/********************************************************************************************************** +Creates household override file from a land use file LU.CSV + +Inputs: + input\lu.csv + +Outputs: + output\hhlu.csv + output\hhluagg.csv + +**********************************************************************************************************/ +Macro "HouseholdLUOverride" + // Creates Household Override file from a Land Use based LU.csv + shared path, inputDir, outputDir + RunMacro("TCB Init") + + // Copy LU.csv, Open Copy, and Rename Fields - no header line in lu.csv + ok=RunMacro("SDcopyfile",{inputDir+"\\lu.csv",outputDir+"\\hhlu.csv"}) if!ok then goto quit + vwHHLUovr = Opentable("HHLUOverride", "CSV",{outputDir+"\\hhlu.csv"}) + RenameField(vwHHLUovr+".FIELD_1", "TAZ") + RenameField(vwHHLUovr+".FIELD_2", "RateType") + RenameField(vwHHLUovr+".FIELD_3", "LUCode") + RenameField(vwHHLUovr+".FIELD_4", "HH") + Setview(vwHHLUovr) + + // Select HH's From LU.csv + // Ratetype=DU=1 + qry1 = "Select * where RateType = 1" + DUqry = SelectByQuery("HHSelection", "Several", qry1,) + + // Aggregate HH's to TAZ Level (might have SF & MF as separate codes) + RunMacro("HwycadLog",{"TruckModel.rsc: HouseholdLUOverride","AggregateTable"}) + aggtable = AggregateTable("AggHHLUOvr","HHLUOverride|HHSelection", "CSV", outputDir+"\\hhluagg.csv", "TAZ", { + {"TAZ","dominant"}, + {"HH","sum", } + }, {"Missing as zero"}) + + done: + RunMacro("close all") + Return( RunMacro("TCB Closing", 1, "FALSE" ) ) + + quit: + RunMacro("close all") + Return( RunMacro("TCB Closing", 0, "FALSE" ) ) +EndMacro + + +/********************************************************************************************************** +Creates Employment Override File from a land use file LU.CSV + +Inputs: + input\lu.csv + input\emplbylu.csv + input\Zone_sphere.csv + input\emp_lu_ksf.csv + input\emp_lu_rm.csv + input\emp_lu_site.csv + +Outputs: + output\EmpLUovr.bin" + output\EmpLUovr.csv" +**********************************************************************************************************/ +Macro "EmploymentLUOverride" + shared path,inputDir, outputDir + + // Remove dcc & dcb files if already exist + ok=RunMacro("SDdeletefile",{inputDir+"\\emplbylu.dcc"}) + if!ok then goto quit + ok=RunMacro("SDdeletefile",{inputDir+"\\Zone_sphere.dcc"}) + if!ok then goto quit + ok=RunMacro("SDdeletefile",{inputDir+"\\emp_lu_ksf.dcc"}) + if!ok then goto quit + ok=RunMacro("SDdeletefile",{inputDir+"\\emp_lu_site.dcc"}) + if!ok then goto quit + ok=RunMacro("SDdeletefile",{inputDir+"\\lu.dcc"}) + if!ok then goto quit + ok=RunMacro("SDdeletefile",{outputDir+"\\EmpLUovr.dcb"}) + if!ok then goto quit + ok=RunMacro("SDdeletefile",{outputDir+"\\EmpLUovr.dcc"}) + if!ok then goto quit + + // Open data files and LU.CSV + vwEmpbyLU = Opentable("EmploymentByLU", "CSV", {inputDir+"\\emplbylu.csv"}) + vwZoneSphere = Opentable("XREF_ZoneSphere","CSV", {inputDir+"\\Zone_sphere.csv"}) + vwAcreToKSF = Opentable("Conv_Acre_KSF", "CSV", {inputDir+"\\emp_lu_ksf.csv"}) + vwAcreToRM = Opentable("Conv_Acre_RM", "CSV", {inputDir+"\\emp_lu_rm.csv"}) + vwEmpSite = Opentable("SiteEmploymentbySphere", "CSV", {inputDir+"\\emp_lu_site.csv"}) + vwLUovr = Opentable("LUOverride", "CSV", {inputDir+"\\lu.csv"}) + + // Rename fields for LU.CSV - no header line in file + RenameField(vwLUovr+".FIELD_1", "TAZ") + RenameField(vwLUovr+".FIELD_2", "RateType") + RenameField(vwLUovr+".FIELD_3", "LUCode") + RenameField(vwLUovr+".FIELD_4", "Amt") + + // Join data files to LU.CSV + Setview(vwLUovr) + jvwLUovrSphere = Joinviews("jvwLUovrSphere", vwLUovr+".TAZ", vwZoneSphere+".Zone",) + jvwLUovrSphereEmp = Joinviews("jvwLUovrSphereEmp", jvwLUovrSphere+".LUCode", vwEmpbyLU+".LU",) + jvwLUovrSphereEmpKSF = Joinviews("jvwLUovrSphereEmpKSF", jvwLUovrSphereEmp+".LUCode", vwAcreToKSF+".LU",) + jvwLUovrSphereEmpKSFSite = Joinviews("jvwLUovrSphereEmpKSFSite", jvwLUovrSphereEmpKSF+".LUCode", vwEmpSite+".LU",) + jvwLUovrSphereEmpKSFSiteRM = Joinviews("jvwLUovrSphereEmpKSFSiteRM", jvwLUovrSphereEmpKSFSite+".LUCode", vwAcreToRM+".LU",) + + // Set Output Files + empLUovr_file = outputDir+"\\EmpLUovr.BIN" + empLUovr_filecsv = outputDir+"\\EmpLUovr.csv" + + // Export Joined View and Add Employment Fields + Setview(jvwLUovrSphereEmpKSFSiteRM) + ExportView(jvwLUovrSphereEmpKSFSiteRM+"|", "FFB", empLUovr_file, null, { + {"Additional Fields",{ {"empbyacres", "Real", 16, 4, },{"empdirect", "Real", 16, 4, },{"empbysite", "Real", 16, 4, },{"empbyksf", "Real", 16, 4, },{"empbyrm", "Real", 16, 4, },{"emp", "Real", 16, 4, }} }, + } ) + + // Apply Acre Based Employment Rates + // RateType=2=Acre + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"empbyacres"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if (Sphere=1404 and RateType=2) then nz(sph1404acre*Amt) else if (Sphere=1441 and RateType=2) then nz(sph1441acre*Amt) else if (Sphere>=1900 and RateType=2) then nz(sph1900acre*Amt) else if RateType=2 then nz(sphOtheracre*Amt)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + + // Add Directly Entered Employment + // RateType=3=Employee + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"empdirect"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if RateType=3 then nz(Amt)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + + // Apply Site Based Employment Rates + // RateType=4=Site + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"empbysite"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if (Sphere=1404 and RateType=4) then nz(sph1404site*Amt) else if (Sphere=1441 and RateType=4) then nz(sph1441site*Amt) else if (Sphere>=1900 and RateType=4) then nz(sph1900site*Amt) else if RateType=4 then nz(sphOthersite*Amt)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + + // Convert KSF to Acres and Apply Acre Based Employment Rates + // RateType=6=KSF + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"empbyksf"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if (Sphere=1404 and RateType=6) then nz(sph1404acre*Amt*ksf2acre) else if (Sphere=1441 and RateType=6) then nz(sph1441acre*Amt*ksf2acre)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"empbyksf"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if (Sphere>=1900 and RateType=6) then nz(sph1900acre*Amt*ksf2acre) else if RateType=6 then nz(sphOtheracre*Amt*ksf2acre)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + + // Convert KSF to Acres and Apply Acre Based Employment Rates + // RateType=7=Hotel Room + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"empbyRM"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if (Sphere=1404 and RateType=7) then nz(sph1404acre*Amt*rm2acre) else if (Sphere=1441 and RateType=7) then nz(sph1441acre*Amt*rm2acre)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"empbyRM"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if (Sphere>=1900 and RateType=7) then nz(sph1900acre*Amt*rm2acre) else if RateType=7 then nz(sphOtheracre*Amt*rm2acre)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + + // Combine Acre, KSF, and Site Employment into EMP Field + Opts = null + Opts.Input.[Dataview Set] = {empLUovr_file, "jvwLUovrSphereEmpKSFSiteRM"} + Opts.Global.Fields = {"emp"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"nz(empbyacres)+nz(empdirect)+nz(empbysite)+nz(empbyksf)+nz(empbyrm)"} + ret_value = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ret_value then goto quit + + // Export Employment Override File + RunMacro("HwycadLog",{"TruckModel.rsc: EmploymentLUOverride","ExportView"}) + CloseView(jvwLUovrSphereEmpKSFSiteRM) + jvwLUovrSphereEmpKSFSiteRM=opentable("jvwLUovrSphereEmpKSFSiteRM", "FFB", {empLUovr_file,}) + Setview(jvwLUovrSphereEmpKSFSiteRM) + ExportView(jvwLUovrSphereEmpKSFSiteRM+"|", "CSV", empLUovr_filecsv, + {"TAZ","RateType","LUCode","Amt","emp"}, + { + {"CSV Header", "False"}, + {"CSV Drop Quotes", "True"} + } ) + + done: + RunMacro("close all") + Return( RunMacro("TCB Closing", 1, "FALSE" ) ) + + quit: + RunMacro("close all") + Return( RunMacro("TCB Closing", 0, "FALSE" ) ) +EndMacro + + +/********************************************************************************************************** +Takes employment override file and creates employment distribution to employment categories + +Inputs: + output\EmpLUovr.csv" + input\empldistbylu.csv + +Outputs: + output\EmpDistLUovrAgg.csv + output\EmpDistLUovr.csv" + +**********************************************************************************************************/ +Macro "EmploymentDistLUOverride" + shared path,inputDir, outputDir + RunMacro("TCB Init") + + // Open Employment Override and Employment Distribution Files + empLUovr_filecsv = outputDir+"\\EmpLUovr.csv" + vwEmpLUovr=opentable("EmploymentLUoverride", "CSV", {empLUovr_filecsv,}) + vwEmpDistbyLU = Opentable("EmploymentDistribution", "CSV", {inputDir+"\\empldistbylu.csv"}) + + // Join Files + Setview(vwEmpLUovr) + jvwEmpLUovrDist = Joinviews("EmploymentOverrideWithDistribution", vwEmpLUovr+".LUCode", vwEmpDistbyLU+".plu",) + + // Set Output Files + empAggDistLUovr_filecsv = outputDir+"\\EmpDistLUovrAgg.csv" + empDistLUovr_filecsv = outputDir+"\\EmpDistLUovr.csv" + + // Calculate Employment Distribution + expZone = CreateExpression(jvwEmpLUovrDist, "zone", "TAZ", ) + expEmp_mil = CreateExpression(jvwEmpLUovrDist, "emp_mil", "Nz(emp*mil)", ) + expEmp_agmin = CreateExpression(jvwEmpLUovrDist, "emp_agmin", "Nz(emp*ag)", ) + expEmp_cons = CreateExpression(jvwEmpLUovrDist, "emp_cons", "Nz(emp*con)", ) + expEmp_mfg = CreateExpression(jvwEmpLUovrDist, "emp_mfg", "Nz(emp*mfg)", ) + expEmp_whtrade = CreateExpression(jvwEmpLUovrDist, "emp_whtrade", "Nz(emp*whtrade)", ) + expEmp_retrade = CreateExpression(jvwEmpLUovrDist, "emp_retrade", "Nz(emp*retrade)", ) + expEmp_twu = CreateExpression(jvwEmpLUovrDist, "emp_twu", "Nz(emp*twu)", ) + expEmp_fre = CreateExpression(jvwEmpLUovrDist, "emp_fre", "Nz(emp*fre)", ) + expEmp_info = CreateExpression(jvwEmpLUovrDist, "emp_info", "Nz(emp*info)", ) + expEmp_pbs = CreateExpression(jvwEmpLUovrDist, "emp_pbs", "Nz(emp*pbs)", ) + expEmp_lh = CreateExpression(jvwEmpLUovrDist, "emp_lh", "Nz(emp*lh)", ) + expEmp_os = CreateExpression(jvwEmpLUovrDist, "emp_os", "Nz(emp*os)", ) + expEmp_edhs = CreateExpression(jvwEmpLUovrDist, "emp_edhs", "Nz(emp*edhs)", ) + expEmp_gov = CreateExpression(jvwEmpLUovrDist, "emp_gov", "Nz(emp*gov)", ) + expEmp_sedw = CreateExpression(jvwEmpLUovrDist, "emp_sedw", "Nz(emp*sedw)", ) + expEmp_civ = CreateExpression(jvwEmpLUovrDist, "emp_civ", "emp_agmin + emp_cons + emp_mfg + emp_whtrade + emp_retrade + emp_twu + emp_fre + emp_info + emp_pbs + emp_lh + emp_os + emp_edhs + emp_gov + emp_sedw", ) + + // Export employment distribution before aggregation + ExportView(jvwEmpLUovrDist+"|", "CSV", empDistLUovr_filecsv, {"zone", "emp", "emp_civ", "emp_mil", "emp_agmin", "emp_cons", "emp_mfg", "emp_whtrade", "emp_retrade", "emp_twu", "emp_fre", "emp_info", "emp_pbs", "emp_lh", "emp_os", "emp_edhs", "emp_gov", "emp_sedw"}, {{"CSV Header", "True"},{"CSV Drop Quotes", "True"}}) + + // Aggregate employment distribution by LU Code by TAZ to employment distribution by TAZ + RunMacro("HwycadLog",{"TruckModel.rsc: EmploymentDistLUOverride","AggregateTable"}) + vwEmpDistLUovr=opentable("DistributedEmploymentOverride", "CSV", {empDistLUovr_filecsv,}) + Setview(vwEmpDistLUovr) + AggAll = CreateSet("AggregatedZones") + SelectAll(AggAll) + sets_list = GetSets(vwEmpDistLUovr) + aggtable = AggregateTable("ZoneAggEmpDistLUOvr","DistributedEmploymentOverride|AggregatedZones", "CSV", empAggDistLUovr_filecsv, "zone", { + {"zone","dominant"}, + {"emp_agmin","sum", }, + {"emp_cons","sum", }, + {"emp_retrade","sum", }, + {"emp_gov","sum", }, + {"emp_mfg","sum", }, + {"emp_twu","sum", }, + {"emp_whtrade","sum", }, + {"emp_os","sum", }, + {"emp_sedw","sum", } + }, {"Missing as zero"}) + + done: + RunMacro("close all") + Return( RunMacro("TCB Closing", 1, "FALSE" ) ) + + quit: + RunMacro("close all") + Return( RunMacro("TCB Closing", 0, "FALSE" ) ) +EndMacro + + +/********************************************************************************************************** +Checks whether data is available for forecast year and if not then interpolates from closet available years + +Inputs: + forecast year + +Outputs: + returns an array {availability of data, previous data year, next data year} +**********************************************************************************************************/ +Macro "InterimYearCheck" (properties,intFyear) + dim arrInterimYear[3] + + // Reads all years for which data is available + DFyear =RunMacro("read properties",properties,"truck.DFyear","S") + + // Lists data year with delimiter "," + arrAllDFyears = ParseString(DFyear, ",") + for i = 1 to arrAllDFyears.length do + intTargetYear = s2i(trim(arrAllDFyears[i])) + if i < arrAllDFyears.length then do + intNextTargetYear = s2i(trim(arrAllDFyears[i+1])) + end + + // Forecast year has data available + if intFyear = intTargetYear then do + // Do interpolate = False + arrInterimYear[1]=1 + end + + // Forecast year has no data + else do + // Check for previous and next closest years + if (intFyear > intTargetYear & intFyear < intNextTargetYear) then do + // Do interpolate = True + arrInterimYear[1] = 2 + // Gets previous closest year + arrInterimYear[2] = intTargetYear + // Gets next closest year + arrInterimYear[3] = intNextTargetYear + end + end + end + + Return(arrInterimYear) +EndMacro + + + +/********************************************************************************************************** +Adds trucks generated by special generators, such as military sites, mail to/from airport, cruise ships, etc + +Inputs: + input\specialGenerators.csv + output\gmTruckDataII.csv + +Outputs: + output\gmTruckDataIISP.csv + +**********************************************************************************************************/ +Macro "trkSpecialGen" (strFyear,intFyear,arrInterimYear) + shared path, inputDir, outputDir + + booInterimYear = arrInterimYear[1] + // 1 = Forecast year, 2 = Interim year and needs interpolation + if booInterimYear = 2 then do + prevYear = arrInterimYear[2] + nextYear = arrInterimYear[3] + end + + // Open truck trips and truck special generators + baseTrucks = Opentable("TruckGeneration", "CSV", {outputDir+"\\gmTruckDataII.csv"}) + specGenerators = Opentable("SpecGenMilit", "CSV",{inputDir+"\\specialGenerators.csv"}) + jv1 = Joinviews("JV1", baseTrucks+".ZONE", specGenerators+".TAZ", ) + Setview(jv1) + + // Forecast year has data available + if booInterimYear = 1 then do + col_name="Y"+strFyear + lhd_a = CreateExpression(jv1, "LHD_Attr", "LHD_Attractions + Nz("+col_name+" * trkAttraction * lhdShare)", ) + lhd_p = CreateExpression(jv1, "LHD_Prod", "LHD_Productions + Nz("+col_name+" * trkProduction * lhdShare)", ) + mhd_a = CreateExpression(jv1, "MHD_Attr", "MHD_Attractions + Nz("+col_name+" * trkAttraction * mhdShare)", ) + mhd_p = CreateExpression(jv1, "MHD_Prod", "MHD_Productions + Nz("+col_name+" * trkProduction * mhdShare)", ) + hhd_a = CreateExpression(jv1, "HHD_Attr", "HHD_Attractions + Nz("+col_name+" * trkAttraction * hhdShare)", ) + hhd_p = CreateExpression(jv1, "HHD_Prod", "HHD_Productions + Nz("+col_name+" * trkProduction * hhdShare)", ) + RunMacro("HwycadLog",{"TruckModel.rsc: trkSpecialGen","ExportView P&A + Special Generators"}) + ExportView(jv1+"|", "CSV", outputDir+"\\gmTruckDataIISP.csv", {baseTrucks+".ZONE", "LHD_Prod", "LHD_Attr", "MHD_Prod", "MHD_Attr", "HHD_Prod", "HHD_Attr"}, {{"CSV Header"}}) + end + + // If data is not available then interpolate from closest available years + else do + // Get previous and next closest year + dim IY_Year[2] + IY_Year[1] = prevYear + IY_Year[2] = nextYear + + for j = 1 to 2 do + view="jv"+I2S(j) + Setview(view) + col_name="Y"+I2S(IY_Year[j]) + lhd_a = CreateExpression(view, "LHD_Attr", "LHD_Attractions + Nz("+col_name+" * trkAttraction * lhdShare)", ) + lhd_p = CreateExpression(view, "LHD_Prod", "LHD_Productions + Nz("+col_name+" * trkProduction * lhdShare)", ) + mhd_a = CreateExpression(view, "MHD_Attr", "MHD_Attractions + Nz("+col_name+" * trkAttraction * mhdShare)", ) + mhd_p = CreateExpression(view, "MHD_Prod", "MHD_Productions + Nz("+col_name+" * trkProduction * mhdShare)", ) + hhd_a = CreateExpression(view, "HHD_Attr", "HHD_Attractions + Nz("+col_name+" * trkAttraction * hhdShare)", ) + hhd_p = CreateExpression(view, "HHD_Prod", "HHD_Productions + Nz("+col_name+" * trkProduction * hhdShare)", ) + RunMacro("HwycadLog",{"TruckModel.rsc: trkSpecialGen","ExportView P&A + Special Generators"}) + ExportView(view+"|", "CSV", outputDir+"\\gmTruckDataIISP"+I2S(IY_Year[j])+".csv", {"ZONE", "LHD_Prod", "LHD_Attr", "MHD_Prod", "MHD_Attr", "HHD_Prod", "HHD_Attr"}, {{"CSV Header"}}) + Closeview(view) + jv2 = Joinviews("JV2", baseTrucks+".ZONE", specGenerators+".TAZ", ) + end + + ok=RunMacro("Interpolate",{"gmTruckDataIISP"+I2S(prevYear)+".csv","gmTruckDataIISP"+I2S(nextYear)+".csv","gmTruckDataIISP.csv",intFyear,prevYear,nextYear}) + end + +EndMacro + + +/********************************************************************************************************** +Balances total production and attraction for lhd, mhd, hhd, ei and ie trips + +Inputs: + input\specialGenerators.csv + output\gmTruckDataII.csv + + inputTruckDir\regionalEItrips.csv + inputTruckDir\regionalEItrips.csv + inputTruckDir\regionalIEtrips.csv + inputTruckDir\regionalIEtrips.csv + inputTruckDir\regionalEEtrips.csv + inputTruckDir\regionalEEtrips.csv + +Outputs: + output\gmTruckDataBalanced.bin + +**********************************************************************************************************/ +Macro "trkBalance" (strFyear,intFyear,arrInterimYear) + shared path, inputDir, outputDir, inputTruckDir + + // Check if interim year and interpolate trip files if it is + booInterimYear = arrInterimYear[1] + + // 1 = Forecast year, 2 = Interim year and needs interpolation + if booInterimYear = 2 then do + prevYear = arrInterimYear[2] + nextYear = arrInterimYear[3] + + // copy files to scenario directory + ok=RunMacro("SDcopyfile",{inputTruckDir+"\\regionalEItrips"+I2S(prevYear)+".csv",outputDir+"\\regionalEItrips_prev.csv"}) + ok=RunMacro("SDcopyfile",{inputTruckDir+"\\regionalEItrips"+I2S(nextYear)+".csv",outputDir+"\\regionalEItrips_next.csv"}) + ok=RunMacro("SDcopyfile",{inputTruckDir+"\\regionalIEtrips"+I2S(prevYear)+".csv",outputDir+"\\regionalIEtrips_prev.csv"}) + ok=RunMacro("SDcopyfile",{inputTruckDir+"\\regionalIEtrips"+I2S(nextYear)+".csv",outputDir+"\\regionalIEtrips_next.csv"}) + ok=RunMacro("SDcopyfile",{inputTruckDir+"\\regionalEEtrips"+I2S(prevYear)+".csv",outputDir+"\\regionalEEtrips_prev.csv"}) + ok=RunMacro("SDcopyfile",{inputTruckDir+"\\regionalEEtrips"+I2S(nextYear)+".csv",outputDir+"\\regionalEEtrips_next.csv"}) + + // Call Macro Interpolate //arr = {"previous year data file","next year data file","new year data file name(macro will create this)} + ok=RunMacro("Interpolate",{"regionalEItrips_prev.csv","regionalEItrips_next.csv","regionalEItrips.csv",intFyear,prevYear,nextYear}) + ok=RunMacro("Interpolate",{"regionalIEtrips_prev.csv","regionalIEtrips_next.csv","regionalIEtrips.csv",intFyear,prevYear,nextYear}) + ok=RunMacro("Interpolate",{"regionalEEtrips_prev.csv","regionalEEtrips_next.csv","regionalEEtrips.csv",intFyear,prevYear,nextYear}) + + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEItrips_prev.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEItrips_next.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalIEtrips_prev.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalIEtrips_next.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEEtrips_prev.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEEtrips_next.csv"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEItrips_prev.dcc"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEItrips_next.dcc"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalIEtrips_prev.dcc"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalIEtrips_next.dcc"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEEtrips_prev.dcc"}) + ok=RunMacro("SDdeletefile",{outputDir+"\\regionalEEtrips_next.dcc"}) + end + + // If not interim year then copy EE to output folder + if booInterimYear = 1 then do + RunMacro("SDcopyfile",{inputTruckDir+"\\regionalEEtrips"+strFyear+".csv",outputDir+"\\regionalEEtrips.csv"}) + end + // Balance each truck type (except EE [external-external], which is already balanced) + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalance","Balance LHD"}) + RunMacro("trkBalanceOneType", "LHD") + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalance","Balance MHD"}) + RunMacro("trkBalanceOneType", "MHD") + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalance","Balance HHD"}) + RunMacro("trkBalanceOneType", "HHD") + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalance","Balance EI"}) + RunMacro("trkBalanceRegionalTrucks", "EI", strFyear,booInterimYear) + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalance","Balance IE"}) + RunMacro("trkBalanceRegionalTrucks", "IE", strFyear,booInterimYear) + + // Combine single balanced files + vw1 = Opentable("BALANCE_LHD", "FFB", {outputDir+"\\gmTruckDataBal_LHD.bin",}) + vw2 = Opentable("BALANCE_MHD", "FFB", {outputDir+"\\gmTruckDataBal_MHD.bin",}) + vw3 = Opentable("BALANCE_HHD", "FFB", {outputDir+"\\gmTruckDataBal_HHD.bin",}) + vw4 = Opentable("BALANCE_EI", "FFB", {outputDir+"\\regionalEItripsBalanced.bin",}) + RenameField("BALANCE_EI.HHD_Attr" ,"EI_Attr") + RenameField("BALANCE_EI.EItrucks" ,"EI_Prod") + + Opts = null + Opts.Input.[Dataview Set] = {outputDir+"\\regionalEItripsBalanced.bin" , vw4} + Opts.Global.Fields = {"EI_Prod"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if EI_Prod=null then 0.00 else EI_Prod"} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + + vw5 = Opentable("BALANCE_IE", "FFB", {outputDir+ "\\regionalIEtripsBalanced.bin",}) + RenameField("BALANCE_IE.IEtrucks" ,"IE_Attr") + RenameField("BALANCE_IE.HHD_Prod" ,"IE_Prod") + Opts = null + Opts.Input.[Dataview Set] = {outputDir+ "\\regionalIEtripsBalanced.bin" , vw5} + Opts.Global.Fields = {"IE_Attr"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"if IE_Attr=null then 0.00 else IE_Attr"} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + + jv1 = Joinviews("JV1", vw1 + ".ID1", vw2 + ".ID1",) + jv2 = Joinviews("JV2", jv1 + ".BALANCE_LHD.ID1", vw3 + ".ID1",) + jv3 = Joinviews("JV3", jv2 + ".BALANCE_LHD.ID1", vw4 + ".ID1",) + jv4 = Joinviews("JV4", jv3 + ".BALANCE_LHD.ID1", vw5 + ".ID1",) + RenameField("BALANCE_LHD.ID1", "ID") + + Setview(jv4) + n = SelectByQuery("notzeros", "several", "Select * where ID <> 0",) + + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalance","ExportView - Combined Balanced Flow"}) + ExportView("JV4|notzeros", "FFB", outputDir+"\\gmTruckDataBalanced.bin", {"ID","LHD_Prod", "LHD_Attr", "MHD_Prod", "MHD_Attr", "HHD_Prod", "HHD_Attr", "IE_Prod", "IE_Attr", "EI_Prod","EI_Attr"},) + + Closeview(jv1) + Closeview(jv2) + Closeview(jv3) + Closeview(jv4) + Closeview(vw1) + Closeview(vw2) + Closeview(vw3) + Closeview(vw4) + Closeview(vw5) +EndMacro + + +/********************************************************************************************************** +Balances total production and attraction for truck type (type = lhd, mhd or hhd) + +Inputs: + output\gmTruckDataIISP.csv + +Outputs: + output\gmTruckDataBal_lhd.bin + output\gmTruckDataBal_mhd.bin + output\gmTruckDataBal_hhd.bin +**********************************************************************************************************/ +Macro "trkBalanceOneType" (type) + shared path, inputDir, outputDir + + RunMacro("TCB Init") + + Opts = null + Opts.Input.[Data View Set] = {outputDir+"\\gmTruckDataIISP.csv", "gmTruckDataIISP"} + Opts.Field.[Vector 1] = {"[gmTruckDataIISP]." + type + "_Prod"} + Opts.Field.[Vector 2] = {"[gmTruckDataIISP]." + type + "_Attr"} + Opts.Global.[Holding Method] = {"Weighted Sum"} + Opts.Global.[Percent Weight] = {50} + Opts.Global.[Sum Weight] = {100} + Opts.Global.[Store Type] = 1 + Opts.Output.[Output Table] = outputDir+"\\gmTruckDataBal_" + type + ".bin" + + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalanceOneType", "Balance "+type}) + ok=RunMacro("TCB Run Procedure", "Balance", Opts, &Ret) +EndMacro + + +/********************************************************************************************************** +Balances EI trips where sum of E is fixed and I of truck attraction is adjusted or +IE trips where sum of E is fixed and I of truck production is adjusted + +Inputs: + output\regionalIEtrips.csv + output\regionalEItrips.csv + inputTruckDir\regionalIEtrips.csv + inputTruckDir\regionalIEtrips.csv + inputTruckDir\regionalEItrips.csv + inputTruckDir\regionalEItrips.csv + output\gmTruckDataBal_HHD.bin + +Outputs: + output\regionaltripsBalanced.bin + +**********************************************************************************************************/ +Macro "trkBalanceRegionalTrucks" (direction,strFyear,booInterimYear) + shared path, inputDir, outputDir, inputTruckDir + + // Not an interim year, read regional trips from inputTruckDir + if booInterimYear=1 then do + strPathRegTrips=inputTruckDir+"\\regional"+direction+"trips"+strFyear+".csv" + end + + //Interim year, read regional trips from output directory + else do + strPathRegTrips=outputDir+"\\regional"+direction+"trips.csv" + end + + Opts = null + if direction = "EI" then do + Opts.Input.[Data Set] = {{outputDir+"\\gmTruckDataBal_HHD.bin", strPathRegTrips, "ID1", "fromZone"}, "BALANCE_HHD+regionalEItrips"+strFyear} + Opts.Input.[Data View] = {{outputDir+"\\gmTruckDataBal_HHD.bin", strPathRegTrips, "ID1", "fromZone"}, "BALANCE_HHD+regionalEItrips"+strFyear} + end + else do + Opts.Input.[Data Set] = {{outputDir+"\\gmTruckDataBal_HHD.bin", strPathRegTrips, "ID1", "toZone"}, "BALANCE_HHD+regionalIEtrips"+strFyear} + Opts.Input.[Data View] = {{outputDir+"\\gmTruckDataBal_HHD.bin", strPathRegTrips, "ID1", "toZone"}, "BALANCE_HHD+regionalIEtrips"+strFyear} + end + + Opts.Input.[V1 Holding Sets] = {} + Opts.Input.[V2 Holding Sets] = {} + if direction = "EI" then do + Opts.Field.[Vector 1] = {"[BALANCE_HHD+regionalEItrips"+strFyear+"].HHD_Attr"} + Opts.Field.[Vector 2] = {"[BALANCE_HHD+regionalEItrips"+strFyear+"].EITrucks"} + end + else do + Opts.Field.[Vector 1] = {"[BALANCE_HHD+regionalIEtrips"+strFyear+"].HHD_Prod"} + Opts.Field.[Vector 2] = {"[BALANCE_HHD+regionalIEtrips"+strFyear+"].IETrucks"} + end + + Opts.Global.Pairs = 1 + Opts.Global.[Holding Method] = {2} + Opts.Global.[Percent Weight] = {50} + Opts.Global.[Sum Weight] = {100} + Opts.Global.[V1 Options] = {1} + Opts.Global.[V2 Options] = {1} + Opts.Global.[Store Type] = 1 + Opts.Output.[Output Table] = outputDir+"\\regional"+direction+"tripsBalanced.bin" + + RunMacro("HwycadLog",{"TruckModel.rsc: trkBalanceRegionalTrucks","Balance "+direction}) + RunMacro("TCB Run Procedure", 1, "Balance", Opts) +EndMacro + + + +/********************************************************************************************************** +Distributes truck lhd, mhd, hhd, ie and ei truck trips + +Inputs: + output\gmTruckDataBalanced.bin + output\regionalEEtrips.csv + output\imptrk_EA.mtx + output\imptrk_AM.mtx + output\imptrk_MD.mtx + output\imptrk_PM.mtx + output\imptrk_EV.mtx + +Outputs: + output\distributionMatricesTruck.mtx + outputDir\regionalEEtrips.mtx + outputDir\dailyDistributionMatricesTruckAll.mtx + outputDir\dailyDistributionMatricesTruckEA.mtx + outputDir\dailyDistributionMatricesTruckAM.mtx + outputDir\dailyDistributionMatricesTruckMD.mtx + outputDir\dailyDistributionMatricesTruckPM.mtx + outputDir\dailyDistributionMatricesTruckEV.mtx + +**********************************************************************************************************/ + +Macro "trkDistribution" (properties) + shared path, inputDir, outputDir + + // Get forecast year + strFyear=RunMacro("read properties",properties,"truck.FFyear","S") + + //-------------------------------------------------- + // This section does the truck trip distribution + //-------------------------------------------------- + // Use mid-day (md) truck skim for distribution + periods = {"_EA", "_AM", "_MD", "_PM", "_EV"} + p = 3 + md_truck_skim = outputDir +"\\imptrk"+periods[p]+".mtx" + md_truck_FF = "*SCST"+periods[p] + md_truck_IM = "*STM"+periods[p]+" (Skim)" + md_truck_KF = "*STM"+periods[p]+" (Skim)" + + // Open md truck skims + Opts.Input.[FF Matrix Currencies] = {{md_truck_skim, md_truck_FF,,},{md_truck_skim, md_truck_FF,,}, {md_truck_skim, md_truck_FF,,}, {md_truck_skim, md_truck_FF,,},{md_truck_skim, md_truck_FF,,}} + Opts.Input.[Imp Matrix Currencies] = {{md_truck_skim, md_truck_IM,,},{md_truck_skim, md_truck_IM,,}, {md_truck_skim, md_truck_IM,,}, {md_truck_skim, md_truck_IM,,},{md_truck_skim, md_truck_IM,,}} + Opts.Input.[KF Matrix Currencies] = {{md_truck_skim, md_truck_KF,,},{md_truck_skim, md_truck_KF,,}, {md_truck_skim, md_truck_KF,,}, {md_truck_skim, md_truck_KF,,},{md_truck_skim, md_truck_KF,,}} + + // Open truck trips + Opts.Input.[PA View Set] = {outputDir+"\\gmTruckDataBalanced.bin", "gmTruckDataBalanced"} + + // Set gravity model settings + Opts.Input.[FF Tables] = {{outputDir+"\\gmTruckDataBalanced.bin"}, {outputDir+"\\gmTruckDataBalanced.bin"}, {outputDir+"\\gmTruckDataBalanced.bin"}, {outputDir+"\\gmTruckDataBalanced.bin"}, {outputDir+"\\gmTruckDataBalanced.bin"}} + Opts.Field.[Prod Fields] = {"gmTruckDataBalanced.LHD_Prod", "gmTruckDataBalanced.MHD_Prod", "gmTruckDataBalanced.HHD_Prod", "gmTruckDataBalanced.IE_Prod", "gmTruckDataBalanced.EI_Prod"} + Opts.Field.[Attr Fields] = {"gmTruckDataBalanced.LHD_Attr", "gmTruckDataBalanced.MHD_Attr", "gmTruckDataBalanced.HHD_Attr", "gmTruckDataBalanced.IE_Attr", "gmTruckDataBalanced.EI_Attr"} + Opts.Field.[FF Table Fields] = {"gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID"} + Opts.Field.[FF Table Times] = {"gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID", "gmTruckDataBalanced.ID"} + Opts.Global.[Purpose Names] = {"lhd", "mhd", "hhd", "IE", "EI"} + Opts.Global.Iterations = {100, 100, 100, 100, 100} + Opts.Global.Convergence = {0.01, 0.01, 0.01, 0.01, 0.01} + Opts.Global.[Constraint Type] = {"Double", "Double", "Double", "Columns", "Rows"} + Opts.Global.[Fric Factor Type] = {"Exponential", "Exponential", "Exponential", "Exponential", "Exponential"} + Opts.Global.[A List] = {1, 1, 1, 1, 1} + Opts.Global.[B List] = {0.3, 0.3, 0.3, 0.3, 0.3} + Opts.Global.[C List] = {0.045, 0.03, 0.03, 0.03, 0.03} + Opts.Flag.[Use K Factors] = {0, 0, 0, 0, 0} + Opts.Output.[Output Matrix].Label = "Distribution Matrix" + Opts.Output.[Output Matrix].Compression = 1 + Opts.Output.[Output Matrix].[File Name] = outputDir + "\\distributionMatricesTruck.mtx" + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","Gravity"}) + RunMacro("TCB Run Procedure", 1, "Gravity", Opts) + + + //-------------------------------------------------- + // Adds IE, EI and EE trips to the truck trips by type + //-------------------------------------------------- + // Create EE trip matrix + viewEE = Opentable("EEtrips", "CSV", {outputDir + "\\regionalEEtrips.csv"}) + matrixEE = CreateMatrixFromView("EEmatrix", "EEtrips|", "fromZone", "toZone", {"EEtrucks"}, {{"File Name", outputDir + "\\regionalEEtrips.mtx"}, {"Type", "Float"}, {"Sparse", "No"}, {"Column Major", "No"}, {"File Based", "Yes"}}) + Closeview(viewEE) + + // Split truck trips by type + trkShare = {0.307, 0.155, 0.538} + trkTypes = {"lhd", "mhd", "hhd"} + + Opts = null + Opts.Input.[Matrix Currencies] = {{outputDir + "\\distributionMatricesTruck.mtx", "lhd", "Row ID's", "Col ID's"}, + {outputDir + "\\distributionMatricesTruck.mtx", "mhd", "Row ID's", "Col ID's"}, + {outputDir + "\\distributionMatricesTruck.mtx", "hhd", "Row ID's", "Col ID's"}, + {outputDir + "\\distributionMatricesTruck.mtx", "IE", "Row ID's", "Col ID's"}, + {outputDir + "\\distributionMatricesTruck.mtx", "EI", "Row ID's", "Col ID's"}, + {outputDir + "\\regionalEEtrips.mtx", "EEtrucks", "fromZone", "toZone"}} + Opts.Global.Operation = "Union" + Opts.Output.[Combined Matrix].Label = "Union Combine" + Opts.Output.[Combined Matrix].Compression = 1 + Opts.Output.[Combined Matrix].[File Name] = outputDir + "\\dailyDistributionMatricesTruckAll.mtx" + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","Combine Matrix Files"}) + RunMacro("TCB Run Operation", 1, "Combine Matrix Files", Opts) + + + // Aportion and add IE, EI and EE trips to LHD, MHD and HHD + for i = 1 to trkTypes.length do + Opts = null + Opts.Input.[Matrix Currency] = {outputDir + "\\dailyDistributionMatricesTruckAll.mtx", trkTypes[i], "Rows", "Columns"} + Opts.Input.[Core Currencies] = {{outputDir + "\\dailyDistributionMatricesTruckAll.mtx",trkTypes[i], "Rows", "Columns"}, + {outputDir + "\\dailyDistributionMatricesTruckAll.mtx","EI", "Rows", "Columns"}, + {outputDir + "\\dailyDistributionMatricesTruckAll.mtx","IE", "Rows", "Columns"}, + {outputDir + "\\dailyDistributionMatricesTruckAll.mtx","EEtrucks", "Rows", "Columns"}} + Opts.Global.Method = 7 + Opts.Global.[Cell Range] = 2 + Opts.Global.[Matrix K] = {1, trkShare[i], trkShare[i], trkShare[i]} + Opts.Global.[Force Missing] = "No" + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","Fill Matrices"}) + ok = RunMacro("TCB Run Operation", 1, "Fill Matrices", Opts) + end + + // Drop IE matrix core + Opts = null + Opts.input.[Input Matrix] = outputDir + "\\dailyDistributionMatricesTruckAll.mtx" + Opts.global.[Drop Core] = {"IE"} + RunMacro("TCB Run Operation", 1, "Drop Matrix Core", Opts) + + // Drop EI matrix core + Opts = null + Opts.input.[Input Matrix] = outputDir + "\\dailyDistributionMatricesTruckAll.mtx" + Opts.global.[Drop Core] = {"EI"} + RunMacro("TCB Run Operation", 1, "Drop Matrix Core", Opts) + + // Drop EE matrix core + Opts = null + Opts.input.[Input Matrix] = outputDir + "\\dailyDistributionMatricesTruckAll.mtx" + Opts.global.[Drop Core] = {"EEtrucks"} + RunMacro("TCB Run Operation", 1, "Drop Matrix Core", Opts) + + + //-------------------------------------------------- + // Set intrazonal truck trips to 0. Note: intrazonal truck trips are not necessarily 0 in reality, but they are + // not simulated in this model. Having an undefined value for intrazonal trips provides problems in the emission + // estimation of the EMFAC2007 model. Therefore, intrazonals are artificially set to 0. + //-------------------------------------------------- + Opts = null + Opts.Input.[Matrix Currency] = {outputDir + "\\dailyDistributionMatricesTruckAll.mtx", "lhd", "Rows", "Columns"} + Opts.Global.Method = 1 + Opts.Global.Value = 0 + Opts.Global.[Cell Range] = 3 + Opts.Global.[Matrix Range] = 3 + Opts.Global.[Matrix List] = {"lhd", "mhd", "hhd"} + ok = RunMacro("TCB Run Operation", 1, "Fill Matrices", Opts) + if !ok then goto quit + + // Split into time of day + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","splitIntoTimeOfDay, EA"}) + RunMacro("splitIntoTimeOfDay", 1) // EA Off-peak + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","splitIntoTimeOfDay, AM"}) + RunMacro("splitIntoTimeOfDay", 2) // AM Peak + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","splitIntoTimeOfDay, MD"}) + RunMacro("splitIntoTimeOfDay", 3) // MD Off-peak + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","splitIntoTimeOfDay, PM"}) + RunMacro("splitIntoTimeOfDay", 4) // PM Peak + RunMacro("HwycadLog",{"TruckModel.rsc: trkDistribution","splitIntoTimeOfDay, EV"}) + RunMacro("splitIntoTimeOfDay", 5) // EV Off-peak + + run_ok=1 + Return(run_ok) + + quit: + Return(ok) +EndMacro + + +/********************************************************************************************************** +Splits daily truck trips to five periods EA, AM, MD, PM and EV + +Inputs: + outputDir\dailyDistributionMatricesTruckAll.mtx + timeShare = {0.1018, 0.1698, 0.4284, 0.1543, 0.1457} + borderTimeShare = {0.0188, 0.1812, 0.4629, 0.2310, 0.1061} + +Outputs: + outputDir\dailyDistributionMatricesTruckEA.mtx + outputDir\dailyDistributionMatricesTruckAM.mtx + outputDir\dailyDistributionMatricesTruckMD.mtx + outputDir\dailyDistributionMatricesTruckPM.mtx + outputDir\dailyDistributionMatricesTruckEV.mtx + +**********************************************************************************************************/ +Macro "splitIntoTimeOfDay" (period) + shared path, inputDir, outputDir + + // Split lhd, mhd and hhd truck trips into time-of-day periods + periodName = {"EA","AM","MD","PM","EV"} + mode = {"lhd", "mhd", "hhd"} + timeShare = {0.1018, 0.1698, 0.4284, 0.1543, 0.1457} // share of truck trips per time period for all zones except border crossings + borderTimeShare = {0.0188, 0.1812, 0.4629, 0.2310, 0.1061} // share of truck trips per time period for border crossings + dim borderCorrection[timeShare.length] // correct values at border after multiplication with timeShare + for i = 1 to borderCorrection.length do + borderCorrection[i] = borderTimeShare[i] / timeShare[i] + end + + // Copy original matrix into time-of-day matrix + mat = OpenMatrix(outputDir + "\\dailyDistributionMatricesTruckAll.mtx", ) + mc = CreateMatrixCurrency(mat, "lhd", "Rows", "Columns", ) + newFile = outputDir + "\\dailyDistributionMatricesTruck" + periodName[period] + ".mtx" + label = "Truck Table " + periodName[period] + " Peak" + new_mat = CopyMatrix(mc, {{"File Name", newFile}, {"Label", label}, {"File Based", "Yes"}}) + + // Multiply entire matrix with time-of-day share + Opts = null + Opts.Input.[Matrix Currency] = {newFile, "lhd", "Rows", "Columns"} + Opts.Global.Method = 5 + Opts.Global.Value = timeShare[period] + Opts.Global.[Cell Range] = 2 + Opts.Global.[Matrix Range] = 3 + Opts.Global.[Matrix List] = {"lhd", "mhd", "hhd"} + RunMacro("HwycadLog",{"TruckModel.rsc: splitIntoTimeOfDay","Fill Matrices"}) + ok = RunMacro("TCB Run Operation", 1, "Fill Matrices", Opts) + if !ok then goto quit + + // Correct time-of-day share for destination zones 1 through 5 (border zones) + for i = 1 to mode.length do + mat = OpenMatrix(newFile,) + mc = CreateMatrixCurrency(mat, mode[i], "Rows", "Columns", ) + cols = {"1", "2", "3", "4", "5"} + operation = {"Multiply", borderCorrection[period]} + FillMatrix(mc, null, cols, operation, ) + + mat = OpenMatrix(newFile,) + mc = CreateMatrixCurrency(mat, mode[i], "Rows", "Columns", ) + rows = {"1", "2", "3", "4", "5"} + operation = {"Multiply", borderCorrection[period]} + FillMatrix(mc, rows, null, operation, ) + end + + run_ok=1 + Return(run_ok) + + quit: + Return(ok) +EndMacro + + + + +/********************************************************************************************************** + Truck Toll Diversion Model + Splits Truck Demand to Non-Toll and Toll + called after truck model but before combine trktrips + Ben Stabler, stabler@pbworld.com, 12/02/10 + +Inputs: + Each skim matrix is suffixed with xx, yy where: + xx is mode indicating following truck types: + lhdn, mhdn, hhdn, lhdt, mhdt, and hhdt + + yy is period, as follows: + EA: Early AM + AM: AM peak + MD: Midday + PM: PM peak + EV: Evening + + output\impXXYY.mtx + outputDir\dailyDistributionMatricesTruckYY.mtx + +Outputs: + Adds toll and non-toll cores to + outputDir\dailyDistributionMatricesTruckYY.mtx + +**********************************************************************************************************/ +Macro "trk toll diversion model" + shared path, inputDir, outputDir + RunMacro("TCB Init") + + // Toll diversion curve settings + nest_param = 10 + vot = 0.02 //(minutes/cent) + + periodName = {"EA","AM","MD","PM","EV"} // must be consistent with filename arrays below + trkTypes = {"lhd", "mhd", "hhd"} // truck types + trkTollFactor = {1, 1.03, 2.33} // truck toll factor + + // Loop by time period + for period = 1 to periodName.length do + + // Open truck trips + fileNameTruck = outputDir + "\\dailyDistributionMatricesTruck" + periodName[period] + ".mtx" + m = OpenMatrix(fileNameTruck,) + + // Loop by truck class + for trkType = 1 to trkTypes.length do + nontollmtx=outputDir+"\\imp"+trkTypes[trkType]+"n_"+periodName[period]+".mtx" // non-toll skims + tollmtx=outputDir+"\\imp"+trkTypes[trkType]+"t_"+periodName[period]+".mtx" // toll skims + + // Check and if exist, drop toll and non-toll matrix cores by truck type + coreNames = GetMatrixCoreNames(m) + for c = 1 to coreNames.length do + if (coreNames[c] = trkTypes[trkType] + "t") then DropMatrixCore(m, trkTypes[trkType] + "t") + if (coreNames[c] = trkTypes[trkType] + "n") then DropMatrixCore(m, trkTypes[trkType] + "n") + end + + // Add toll and non-toll matrix + AddMatrixCore(m, trkTypes[trkType] + "t") + AddMatrixCore(m, trkTypes[trkType] + "n") + + // Diversion curve (time is in minutes, cost is in cents) + utility = "(([impedance truck].[*STM_"+periodName[period]+" (Skim)] - [impedance truck toll].[*STM_"+periodName[period]+" (Skim)]) - " + + String(vot) + " * " + "[impedance truck toll].["+trkTypes[trkType]+"t - "+"ITOLL2_"+periodName[period]+"] * " + String(trkTollFactor[trkType]) + " ) / " + String(nest_param) + + expression = "if([impedance truck toll].["+trkTypes[trkType]+"t - "+"ITOLL2_"+periodName[period]+"]!=0) then ( 1 / ( 1 + exp(-" + utility + ") ) ) else [impedance truck toll].["+trkTypes[trkType]+"t - "+"ITOLL2_"+periodName[period]+"]" + + // Calculate toll matrix + Opts = null + Opts.Input.[Matrix Currency] = {fileNameTruck, trkTypes[trkType] + "t", "Rows", "Columns"} + Opts.Input.[Formula Currencies] = {{nontollmtx, "*STM_"+periodName[period]+" (Skim)", "Origin", "Destination"}, {tollmtx, "*STM_"+periodName[period]+" (Skim)", "Origin", "Destination"}} + Opts.Global.Method = 11 + Opts.Global.[Cell Range] = 2 + Opts.Global.[Expression Text] = "[" + trkTypes[trkType] + "] * " + expression + Opts.Global.[Formula Labels] = {"impedance truck", "impedance truck toll"} + Opts.Global.[Force Missing] = "Yes" + ok = RunMacro("TCB Run Operation", "Fill Matrices", Opts) + if !ok then goto quit + + // Calculate non-toll matrix + mc_n = CreateMatrixCurrency(m, trkTypes[trkType] + "n", "Rows", "Columns",) + mc_t = CreateMatrixCurrency(m, trkTypes[trkType] + "t", "Rows", "Columns",) + mc = CreateMatrixCurrency(m, trkTypes[trkType], "Rows", "Columns",) + mc_n := mc - mc_t + end + end + + //return 1 if macro completed + run_ok = 1 + Return(run_ok) + + quit: + Return(ok) + +EndMacro + + +/********************************************************************************************************** +Used to gerenarte data for the forecast years from the years where data is avaialble +Interpolates data from the closest previous year and next years +All files are from read and written to output directory + +Inputs: + output\file.csv + output\file.csv + +Outputs: + output\file.csv + +**********************************************************************************************************/ +Macro "Interpolate" (arr) + shared outputDir + prevfile= arr[1] + nextfile= arr[2] + newfile = arr[3] + Fyear = arr[4] + prevYear= arr[5] + nextYear= arr[6] + + newview = ParseString(newfile, ".") // Get file name and use it as view name + pview = ParseString(prevfile, ".") // Get file name + nview = ParseString(nextfile, ".") // Get file name + + // Delete dictionary files if exist + di = GetDirectoryInfo(outputDir+"\\"+pview[1]+".dcc", "File") + if di.length > 0 then do + ok=RunMacro("SDdeletefile",{outputDir+"\\"+pview[1]+".dcc"}) + end + di = GetDirectoryInfo(outputDir+"\\"+nview[1]+".dcc", "File") + if di.length > 0 then do + ok=RunMacro("SDdeletefile",{outputDir+"\\"+nview[1]+".dcc"}) + end + di = GetDirectoryInfo(outputDir+"\\"+newview[1]+".dcc", "File") + if di.length > 0 then do + ok=RunMacro("SDdeletefile",{outputDir+"\\"+newview[1]+".dcc"}) + end + + // Open previous year data + prevview = Opentable("prevview", "CSV", {outputDir+"\\"+prevfile,}) + + // Open next year data + nextview = Opentable("nextview", "CSV", {outputDir+"\\"+nextfile,}) + + // Number of zones (assuming both prev and next year contain same number of zones) + zones = GetRecordCount(prevview, null) + + // Get data table structure + str = GetTableStructure(prevview) + dim pfieldName[str.length],nfieldName[str.length] + for i =1 to str.length do + pfieldName[i] = prevview+"."+str[i][1] // gets field names from previous year data + nfieldName[i] = nextview+"."+str[i][1] // gets field names from previous year data + end + + // Get fields from previous and next years + prevf = GetDataVectors(prevview+"|",pfieldName,) + nextf = GetDataVectors(nextview+"|",nfieldName,) + + // Create a Fyear table and do interpolation + view = CreateTable(newview[1], outputDir+"\\"+ newfile, "CSV", str) + SetView(view) + + // Interpolate and set values for Fyear + for i = 1 to zones do // row loop + dim v[str.length] // array to hold new field computation + v[1] = {str[1][1], prevf[1][i]} // fill new fields, first field is zone and no interpolation + + for j = 1 to str.length do // field loop + // interpolate + v[j] = {str[j][1] , (prevf[j][i]+((Fyear-prevYear)*((nextf[j][i]-prevf[j][i])/(nextYear-prevYear))))} + end + rh = AddRecord(view,v) + end + + // Close all opened views + vws = GetViewNames() + for p = 1 to vws.length do + CloseView(vws[p]) + end +EndMacro + diff --git a/sandag_abm/src/main/gisdk/Utilities.rsc b/sandag_abm/src/main/gisdk/Utilities.rsc new file mode 100644 index 0000000..7fcefcc --- /dev/null +++ b/sandag_abm/src/main/gisdk/Utilities.rsc @@ -0,0 +1,568 @@ +Macro "ModifyOptionsOption" (options_array,option_key,key,value) + spec = options_array.(option_key) + spec.(key) = value +EndMacro + +Macro "CloseAll" + // close all files in workspace + map_arr=GetMaps() + if ArrayLength(map_arr)>0 then do + open_maps=ArrayLength(map_arr[1]) + for mm=1 to open_maps do + CloseMap(map_arr[1][mm]) + end + end + + On NotFound goto no_more_eds + still_more_eds: + CloseEditor() + goto still_more_eds + + no_more_eds: + On NotFound default + + view_arr=GetViews() + if ArrayLength(view_arr)>0 then do + On NotFound goto cont_views + open_views=ArrayLength(view_arr[1]) + for vv=1 to open_views do + CloseView(view_arr[1][vv]) + cont_views: + end + end +endMacro + +Macro "IsMapOpen" (map) + maps = GetMapNames() + for i = 1 to maps.length do + if maps[i] = map then do + return(True) + end + end + return(False) +EndMacro + +Macro "IsViewOpen" (view) + views = GetViewNames() + for i = 1 to views.length do + if views[i] = view then do + return(True) + end + end + return(False) +EndMacro + +Macro "SafeDeleteFile" (file) + //just ignores any errors + if GetFileInfo(file) <> null then do + On Error goto safe_delete_error + DeleteFile(file) + safe_delete_error: + On Error default + end +EndMacro + +Macro "DeleteFiles" (path) + files = GetDirectoryInfo(path,"All") + for i = 1 to files.length do + DeleteFile(RunMacro("FormPath",{path,files[i][1]})) + end +EndMacro + +Macro "SafeDeleteFiles" (path) + files = GetDirectoryInfo(path,"All") + for i = 1 to files.length do + RunMacro("SafeDeleteFile",RunMacro("FormPath",{path,files[i][1]})) + end +EndMacro + +Macro "SafeDeleteDatabase" (database_file) + //just ignores any errors + On Error goto safe_delete_database_error + On NotFound goto safe_delete_database_error + DeleteDatabase(file) + safe_delete_database_error: + On Error default + On NotFound default +EndMacro + +Macro "NormalizePath" (path) + if Len(path) > 1 and path[2] = ":" then do + path = Lower(path[1]) + Right(path,Len(path)-1) + end + return(Substitute(path,"/","\\",)) +EndMacro + +Macro "FormPath" (path_elements) + if TypeOf(path_elements) <> "array" then do + ShowMessage("Must form a path out of a list of elements, not: " + TypeOf(path_elements)) + ShowMessage(2) + end + //path_elements is an array of elements + path = "" + for i = 1 to path_elements.length do + //change / to \ + p = RunMacro("NormalizePath",path_elements[i]) + if Right(p,1) = "\\" then do + if Len(p) > 1 then do + p = Substring(p,1,Len(p)-1) + end + else do + p = "" + end + end + if Left(p,1) = "\\" then do + if Len(p) > 1 then do + p = Substring(p,2,Len(p)) + end + else do + p = "" + end + end + if path = "" then do + path = p + end + else do + path = path + "\\" + p + end + end + return(path) +EndMacro + +Macro "CreateMapForDatabase" (database_file,map_name) + linfo=GetDBInfo(database_file) + scope=linfo[1] + maps = GetMapNames() + map_name_not_ok = true + while map_name_not_ok do + map_name_not_ok = false + for i = 1 to maps.length do + if maps[i] = map_name then do + map_name = map_name + " " + map_name_not_ok = true + end + end + end + map=createMap(map_name,{{"Scope", scope},{"Auto Project","True"}}) + SetMapUnits("Miles") +EndMacro + +Macro "OpenDatabaseInMap" (database_file,map) + info=GetDBInfo(database_file) + map_made = False + if map <> null then do + map_made = RunMacro("IsMapOpen",map) + end + else do + map = info[2] + end + if not map_made then do + RunMacro("CreateMapForDatabase",database_file,map) + end + NewLayer=GetDBLayers(database_file) + layer = AddLayer(map,NewLayer[1],database_file,NewLayer[1]) + if NewLayer.length = 2 then do + //assumes it is a network file, and hides the nodes and adds the lines + SetLayerVisibility(map + "|" + layer,"False") + AddLayer(map,NewLayer[2],database_file,NewLayer[2]) + end + return(map) +EndMacro + +Macro "OpenDatabase" (database_file) + return(RunMacro("OpenDatabaseInMap",database_file,)) +EndMacro + +Macro "OpenRouteSystemInMap" (route_system_file,map) + info = GetRouteSystemInfo(route_system_file) + map_made = False + if map <> null then do + map_made = RunMacro("IsMapOpen",map) + end + else do + map = info[3].Label + end + if not map_made then do + RunMacro("CreateMapForDatabase",info[1],map) + end + RunMacro("Set Default RS Style",AddRouteSystemLayer(map,info[3].Label,route_system_file,),"TRUE","FALSE") + return(map) +EndMacro + +Macro "OpenRouteSystem" (route_system_file) + return(RunMacro("OpenRouteSystemInMap",route_system_file,)) +EndMacro + +Macro "CleanRecordValuesOptionsArray" (options_array,view_name) + for i = 1 to options_array.length do + options_array[i][1] = Substitute(options_array[i][1],view_name + ".","",) + end +EndMacro + +Macro "FormFieldSpec" (view,field) + //don't think the following is necessary + //issue_chars = {":"} + //fix = False + //for i = 1 to issue_chars.length do + // if Position(field,issue_chars[i]) > 0 then do + // fix = True + // end + //end + //if fix then do + // field = "[" + field + "]" + //end + return(view + "." + field) +EndMacro + +Macro "ToString" (value) + type = TypeOf(value) + if type = "string" then do + return(value) + end + else if type = "int" then do + return(i2s(value)) + end + else if type = "double" then do + return(r2s(value)) + end + else if type = "null" then do + return("") + end + ShowMessage("Type " + type + " not supported by ToString method") +EndMacro + +Macro "GetArrayIndex" (array,value) + //returns the index of value in array, or 0 if it is not found + type = TypeOf(value) + for i = 1 to array.length do + if TypeOf(array[i]) = type and array[i] = value then do + return(i) + end + end + return(0) +EndMacro + +Macro "ArraysEqual" (array1,array2) + if array1.length <> array2.length then do + return(False) + end + for i = 1 to array1.length do + if TypeOf(array1[i]) = "array" then do + if TypeOf(array2[i]) = "array" then do + if not RunMacro("ArraysEqual",array1[i],array2[i]) then do + return(False) + end + end + else do + return(False) + end + end + else if TypeOf(array2[i]) = "array" then do + return(False) + end + else do + if array1[i] <> array2[i] then do + return(False) + end + end + end + return(True) +EndMacro + +Macro "GetDatabaseColumns" (database_file,layer_name) + columns = null + if database_file <> null and GetFileInfo(database_file) <> null then do + current_layer = GetLayer() + current_view = GetView() + lyr = AddLayerToWorkspace("__temp__",database_file,layer_name,{{"Shared","True"}}) + layer_in_use = lyr <> "__temp__" + SetLayer(lyr) + v = GetView() + info = GetTableStructure(v) + for i = 1 to info.length do + columns = columns + {info[i][1]} + end + if not layer_in_use then do + DropLayerFromWorkspace(lyr) + end + if current_layer <> null then do + SetLayer(current_layer) + end + if current_view <> null then do + SetView(current_view) + end + end + return(columns) +EndMacro + +//same as built in TC function, but with error checking for escape and for if a file is in use +Macro "ChooseFileName" (file_types,title,options) + on escape do + fname = null + goto cfn_done + end + openfile: + fname = ChooseFileName(file_types,title,options) + if FileCheckUsage({fname},) then do + ShowMessage("File already in use. Please choose again.") + goto openfile + end + cfn_done: + on escape default + return(fname) +EndMacro + +Macro "RunProgram" (program_with_arguments,working_directory) //can't get output file to work right now..boo hoo + wd = "" + if working_directory <> null then do + wd = " /D" + working_directory + end + RunProgram("cmd /s /c \"start \"cmd\" " + wd + " /WAIT " + program_with_arguments + "\"",) +EndMacro + +Macro "AddElementToSortedArraySet" (array,element) + index = array.length + 1 + not_done = True + for i = 1 to array.length do + if not_done then do + if element = array[i] then do + index = -1 + not_done = False + end + else if element < array[i] then do + index = i + not_done = False + end + end + end + if index > 0 then do + array = InsertArrayElements(array,index,{element}) + end + return(array) +EndMacro + +Macro "ClearAndDeleteDirectory" (path) + //this doesn't do any error handling + info = GetDirectoryInfo(RunMacro("FormPath",{path,"*"}),"All") + for i = 1 to info.length do + f = RunMacro("FormPath",{path,info[i][1]}) + if info[i][2] = "file" then do + DeleteFile(f) + end + else if info[i][2] = "directory" then do + RunMacro("ClearAndDeleteDirectory",f) + end + end + RemoveDirectory(path) +EndMacro + +Macro "ReadPropertiesFile" (properties_file) + props = null + f = OpenFile(properties_file,"r") + while not FileAtEOF(f) do + line = Trim(ReadLine(f)) + if Len(line) > 0 then do + subs = ParseString(line,"=", {{"Include Empty",True}}) + key = subs[1] + value = JoinStrings(Subarray(subs,2,subs.length-1),"=") + props.(Trim(key)) = Trim(value) + end + end + CloseFile(f) + return(props) +EndMacro + +Macro "DetokenizePropertyValues" (properties,token_map) + for i = 1 to properties.length do + value = token_map[i][2] + for j = 1 to token_map.length do + value = Substitute(value,token_map[i][1],token_map[i][2],) + end + token_map[i][2] = value + end +EndMacro + +Macro "ComputeAreaBufferOverlayPercentages" (area_layer_file,centroid_layer_file,centroid_query,area_taz_field,node_taz_field,buffer_size) + //assumes node layer holds centroids from area layer, and bases its buffer around this + //returns array of percentage arrays, each holding {centroid_taz,overlay_taz,percentage} + omap_name = GetMap() + olayer_name = GetLayer() + oview_name = GetView() + + map = RunMacro("OpenDatabase",area_layer_file) + RunMacro("OpenDatabaseInMap",centroid_layer_file,map) + node_layer = GetMapLayers(map,"Point") + node_layer = node_layer[1][1] + area_layer = GetMapLayers(map,"Area") + area_layer = area_layer[1][1] + + SetLayer(node_layer) + centroid_selection = "centroids" + SelectByQuery(centroid_selection,"Several",centroid_query) + node_ids = GetSetIDs(node_layer + "|" + centroid_selection) + node_to_taz = null + for i = 1 to node_ids.length do + node_id = node_ids[i] + value = GetRecordValues(node_layer,IDToRecordHandle(node_id),{node_taz_field}) + node_to_taz.(i2s(node_id)) = value[1][2] + end + + percentages = null + temp_dir = GetFileInfo(area_layer_file) + temp_dir = Substring(area_layer_file,1,Len(area_layer_file) - Len(temp_dir[1])) + intersection_file = "temp_buffers.dbd" + percentages_file = "tempintersect" + temp_intersection_file = RunMacro("FormPath",{temp_dir,intersection_file}) + temp_percentages_file = RunMacro("FormPath",{temp_dir,percentages_file}) + EnableProgressBar("Calculating Area Buffer Percentages (buffer = " + r2s(buffer_size) + ")", 1) // Allow only a single progress bar + CreateProgressBar("", "True") + + nlen = node_ids.length + //for i = 1 to nlen do + for i = 1 to 20 do + node_id = node_ids[i] + node_taz = node_to_taz.(i2s(node_id)) + stat = UpdateProgressBar("Zone: " + i2s(node_taz), r2i(i/nlen*100)) + if stat = "True" then do + percentages = null + goto quit_loop + end + SetLayer(node_layer) + SelectByQuery("centroid","Several","SELECT * WHERE id=" + i2s(node_id)) + CreateBuffers(temp_intersection_file,"buffers",{"centroid"},"Value",{buffer_size},{{"Interior","Separate"},{"Exterior","Separate"}}) + + NewLayer = GetDBLayers(temp_intersection_file) + intersection_layer = AddLayer(map,"inter",temp_intersection_file,NewLayer[1]) + SetLayer(area_layer) + n = SelectByVicinity("subtaz","several",node_layer+"|centroid",buffer_size,{{"Inclusion","Intersecting"}}) + if n > 0 then do + ComputeIntersectionPercentages({intersection_layer, area_layer + "|subtaz"}, temp_percentages_file + ".bin",) + t = OpenTable("int_table", "FFB", {temp_percentages_file + ".bin"},) + tbar = t + "|" + rh = GetFirstRecord(tbar,) + while rh <> null do + vals = GetRecordValues(t,rh,{"Area_1", "Area_2","Percent_2"}) + if vals[1][2] = 1 and vals[2][2] <> 0 then do + value = GetRecordValues(area_layer,IDToRecordHandle(vals[2][2]),{area_taz_field}) + area_taz = node_to_taz.(i2s(value[1][2])) + percentages = percentages + {{node_taz,area_taz,vals[3][2]}} + end + rh = GetNextRecord(t+"|",,) + end + CloseView(t) + end + DropLayer(map,intersection_layer) + end + + quit_loop: + DestroyProgressBar() + CloseMap(map) + if omap_name <> null then do + SetMap(omap_name) + if olayer_name <> null then do + SetLayer(olayer_name) + end + end + if oview_name <> null then do + SetView(oview_name) + end + DeleteDatabase(temp_intersection_file) + DeleteFile(temp_percentages_file + ".bin") + DeleteFile(temp_percentages_file + ".BX") + DeleteFile(temp_percentages_file + ".dcb") + + return(percentages) +EndMacro + +Macro "ExportBintoCSV"(input_file_base, output_file_base) + + view = OpenTable("Binary Table","FFB",{input_file_base+".bin",}, {{"Shared", "True"}}) + SetView(view) + ExportView(view+"|", "CSV", output_file_base+".csv",,{{"CSV Header", "True"}, {"Force Numeric Type", "double"}}) + CloseView(view) + ok=1 + quit: + return(ok) +EndMacro + + +Macro "ComputeAreaOverlayPercentages" (area_layer_file,overlay_layer_file,area_id_field,overlay_id_field) + //returns percentage array, each element holding {area_id,overlay_id,% of overlay in area} + omap_name = GetMap() + olayer_name = GetLayer() + oview_name = GetView() + + map = RunMacro("OpenDatabase",area_layer_file) + area_layer = GetMapLayers(map,"Area") + area_layer = area_layer[1][1] + RunMacro("OpenDatabaseInMap",overlay_layer_file,map) + overlay_layer = GetMapLayers(map,"Area") + if overlay_layer[1][1] = area_layer then do + overlay_layer = overlay_layer[1][2] + end + else do + overlay_layer = overlay_layer[1][1] + end + + area_ids = GetSetIDs(area_layer + "|") + + percentages = null + temp_dir = GetFileInfo(area_layer_file) + temp_dir = Substring(area_layer_file,1,Len(area_layer_file) - Len(temp_dir[1])) + percentages_file = "tempintersect" + temp_percentages_file = RunMacro("FormPath",{temp_dir,percentages_file}) + EnableProgressBar("Calculating Area Intersections", 1) // Allow only a single progress bar + CreateProgressBar("", "True") + + nlen = area_ids.length + for i = 1 to nlen do + area_id = area_ids[i] + stat = UpdateProgressBar("Area id: " + i2s(area_id), r2i(i/nlen*100)) + if stat = "True" then do + percentages = null + goto quit_loop + end + SetLayer(area_layer) + SelectByQuery("select","Several","SELECT * WHERE id=" + i2s(area_id)) + area_sid = GetRecordValues(area_layer,IDToRecordHandle(area_id),{area_id_field}) + area_sid = area_sid[1][2] + SetLayer(overlay_layer) + n = SelectByVicinity("subtaz","several",area_layer+"|select",0,{{"Inclusion","Intersecting"}}) + if n > 0 then do + ComputeIntersectionPercentages({area_layer+"|select",overlay_layer + "|subtaz"}, temp_percentages_file + ".bin",) + t = OpenTable("int_table", "FFB", {temp_percentages_file + ".bin"},) + tbar = t + "|" + rh = GetFirstRecord(tbar,) + while rh <> null do + vals = GetRecordValues(t,rh,{"Area_1", "Area_2","Percent_2"}) + if vals[1][2] > 0 and vals[2][2] <> 0 and vals[3][2] > 0.0 then do + value = GetRecordValues(overlay_layer,IDToRecordHandle(vals[2][2]),{overlay_id_field}) + percentages = percentages + {{area_sid,value[1][2],vals[3][2]}} + end + rh = GetNextRecord(t+"|",,) + end + CloseView(t) + end + end + + quit_loop: + DestroyProgressBar() + CloseMap(map) + if omap_name <> null then do + SetMap(omap_name) + if olayer_name <> null then do + SetLayer(olayer_name) + end + end + if oview_name <> null then do + SetView(oview_name) + end + DeleteFile(temp_percentages_file + ".bin") + DeleteFile(temp_percentages_file + ".BX") + DeleteFile(temp_percentages_file + ".dcb") + + return(percentages) +EndMacro + + + diff --git a/sandag_abm/src/main/gisdk/commVehDist.rsc b/sandag_abm/src/main/gisdk/commVehDist.rsc new file mode 100644 index 0000000..5afba39 --- /dev/null +++ b/sandag_abm/src/main/gisdk/commVehDist.rsc @@ -0,0 +1,106 @@ +/************************************************************** + CommVehTOD.rsc + + TransCAD Macro used to run truck commercial vehicle distribution model. The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. + + A simple gravity model is used to distribute the truck trips. A blended travel time is used as the impedance measure, + specifically the weighted average of the AM travel time (one-third weight) and the midday travel time (two-thirds weight). + + Input: (1) Level-of-service matrices for the AM peak period (6 am to 10 am) and midday period (10 am to 3 pm) + which contain truck-class specific estimates of congested travel time (in minutes) + (2) Trip generation results in ASCII format with the following fields + (a) TAZ: zone number; + (b) PROD: very small truck trip productions; + (c) ATTR: very small truck trip attractions; + (4) A table of friction factors in ASCII format with the following fields (each 12 columns wide): (a) + impedance measure (blended travel time); (b) friction factors for very small trucks; + + Output: (1) A production/attraction trip table matrix of daily class-specific truck trips for very small trucks. + (2) A blended travel time matrix + + See also: (1) CommVehGen.rsc, which applies the generation model. + (2) CommVehTOD.rsc, which applies diurnal factors to the daily trips generated here. + + authors: jef (2012 03 11) dto (2011 09 08); dto (2010 08 31); cp (date unknown) + + +**************************************************************/ +Macro "Commercial Vehicle Distribution" + + shared path, inputDir, outputDir + + /* testing + RunMacro("TCB Init") + scenarioDirectory = "d:\\projects\\SANDAG\\AB_Model\\commercial_vehicles" + */ + + tazCommTripFile = "tazCommVeh.csv" + amMatrixName = "impcvn_AM.mtx" + amTableName = "*STM_AM (Skim)" + mdMatrixName = "impcvn_MD.mtx" + mdTableName = "*STM_MD (Skim)" + + frictionTable = "commVehFF.csv" + pa_tb = outputDir+"\\"+tazCommTripFile + ff_tb = inputDir+"\\"+frictionTable + + //outputs + blendMatrixName = "blendMatrix.mtx" + commVehTripTable = "commVehTrips.mtx" + + //create blended skim + amMatrix = OpenMatrix(outputDir + "\\"+amMatrixName, ) + amMC = CreateMatrixCurrency(amMatrix, amTableName, "Origin", "Destination", ) + mdMatrix = OpenMatrix(outputDir + "\\"+mdMatrixName, ) + mdMC = CreateMatrixCurrency(mdMatrix, mdTableName, "Origin", "Destination", ) + + blendMatrix = CopyMatrix(amMC, {{"File Name", outputDir+"\\"+blendMatrixName}, + {"Label", "AMMDBlend"}, + {"Table", amTableName}, + {"File Based", "Yes"}}) + + blendMC = CreateMatrixCurrency(blendMatrix, amTableName, "Origin", "Destination", ) + + blendMC := 0.3333*amMC + 0.6666*mdMC + + //prevent intrazonal + EvaluateMatrixExpression(blendMC, "99999", null, null,{{"Diagonal","true"}} ) + + + ff_vw = RunMacro("TCB OpenTable",,, {ff_tb}) + ok = (ff_vw <> null) if !ok then goto quit + + pa_vw = RunMacro("TCB OpenTable",,, {pa_tb}) + ok = (pa_vw <> null) if !ok then goto quit + + //Gravity Application + Opts = null + Opts.Input.[PA View Set] = {pa_tb} + Opts.Field.[Prod Fields] = {pa_vw + ".PROD"} + Opts.Field.[Attr Fields] = {pa_vw + ".ATTR"} + Opts.Input.[FF Matrix Currencies] = {{outputDir + "\\" + blendMatrixName, amTableName, "Origin", "Destination"}} + Opts.Input.[Imp Matrix Currencies] = {{outputDir + "\\" + blendMatrixName, amTableName, "Origin", "Destination"}} + Opts.Input.[FF Tables] = {{ff_tb}} + Opts.Input.[KF Matrix Currencies] = {{outputDir + "\\" +blendMatrixName, amTableName, "Origin", "Destination"}} + Opts.Field.[FF Table Fields] = {ff_vw +".FF"} + Opts.Field.[FF Table Times] = {ff_vw +".TIME"} + Opts.Global.[Purpose Names] = {"CommVeh"} + Opts.Global.Iterations = {50} + Opts.Global.Convergence = {0.1} + Opts.Global.[Constraint Type] = {"Double"} + Opts.Global.[Fric Factor Type] = {"Table"} + Opts.Global.[A List] = {1} + Opts.Global.[B List] = {0.3} + Opts.Global.[C List] = {0.005} + Opts.Flag.[Use K Factors] = {0} + Opts.Output.[Output Matrix].Label = "Output Matrix" + Opts.Output.[Output Matrix].[File Name] = outputDir + "\\" +commVehTripTable + ok = RunMacro("TCB Run Procedure", "Gravity", Opts) + + + RunMacro("close all") + quit: + Return(ok) + +EndMacro diff --git a/sandag_abm/src/main/gisdk/commVehDiversion.rsc b/sandag_abm/src/main/gisdk/commVehDiversion.rsc new file mode 100644 index 0000000..ba1c928 --- /dev/null +++ b/sandag_abm/src/main/gisdk/commVehDiversion.rsc @@ -0,0 +1,71 @@ +Macro "cv toll diversion model" + shared path, inputDir, outputDir +/* RunMacro("TCB Init") + //inputs + path = "D:\\projects\\sandag\\series13\\2012_test" + inputDir = path+"\\input" + outputDir = path+"\\output" + scenarioDirectory = "D:\\projects\\SANDAG\\series13\\2012_test" +*/ + // Toll diversion curve settings + nest_param = 10 + vot = 0.02 //(minutes/cent), currently $0.50 a minute + + periodName = {"EA","AM","MD","PM","EV"} // must be consistent with filename arrays below + //periodName = {"AM"} // must be consistent with filename arrays below + cvTollFactor = 1 // cv toll factor + + // Loop by time period + for period = 1 to periodName.length do + + // Open cv trips + fileNameCV = outputDir + "\\commVehTODTrips.mtx" + m = OpenMatrix(fileNameCV,) + + nontollmtx=outputDir+"\\impcv"+"n_"+periodName[period]+".mtx" // non-toll commercial vehicle skims + tollmtx=outputDir+"\\impcv"+"t_"+periodName[period]+".mtx" // toll commercial vehicle skims + OpenMatrix(nontollmtx,) + OpenMatrix(tollmtx,) + + // Add toll and non-toll matrix + AddMatrixCore(m, periodName[period]+ " Toll") + AddMatrixCore(m, periodName[period]+ " NonToll") + + // Diversion curve (time is in minutes, cost is in cents) + // First scale the toll cost since the cost is scaled for SR125 + tollCost = "[Output Matrix:1].[cvt - ITOLL2_"+ + periodName[period]+"]" + utility = "(([Output Matrix].[*STM_"+periodName[period]+" (Skim)] - [Output Matrix:1].[*STM_"+periodName[period]+" (Skim)]) - " + + String(vot) + " * " + tollCost + " * " + String(cvTollFactor) + " ) / " + String(nest_param) + + expression = "if(" + tollCost + "!=0) then ( 1 / ( 1 + exp(-" + utility + ") ) ) else " + tollCost + + // Calculate toll matrix + Opts = null + Opts.Input.[Matrix Currency] = {fileNameCV, periodName[period]+ " Toll", "Row ID's", "Col ID's"} + Opts.Input.[Formula Currencies] = {{nontollmtx, "*CVCST_"+periodName[period], "Origin", "Destination"}, {tollmtx, "*CVCST_"+periodName[period], "Origin", "Destination"}} + Opts.Global.Method = 11 + Opts.Global.[Cell Range] = 2 + Opts.Global.[Expression Text] = "[" + periodName[period] + " Trips] * " + expression + Opts.Global.[Formula Labels] = {"Output Matrix", "Output Matrix:1"} + Opts.Global.[Force Missing] = "Yes" + ok = RunMacro("TCB Run Operation", "Fill Matrices", Opts) + if !ok then goto quit + + // Calculate non-toll matrix + mc_n = CreateMatrixCurrency(m, periodName[period]+ " NonToll", "Row ID's", "Col ID's",) + mc_t = CreateMatrixCurrency(m, periodName[period]+ " Toll", "Row ID's", "Col ID's",) + mc = CreateMatrixCurrency(m, periodName[period]+ " Trips" , "Row ID's", "Col ID's",) + mc_n := mc - mc_t + + end + + //return 1 if macro completed + run_ok = 1 + Return(run_ok) + + quit: + Return(ok) + +EndMacro + \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/commVehGen.rsc b/sandag_abm/src/main/gisdk/commVehGen.rsc new file mode 100644 index 0000000..ccb8239 --- /dev/null +++ b/sandag_abm/src/main/gisdk/commVehGen.rsc @@ -0,0 +1,184 @@ +/************************************************************** + CommVehGen.rsc + + TransCAD Macro used to run truck trip generation model. The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. + + Linear regression models generate trip ends, balancing attractions to productions. + + Input: (1) MGRA file in CSV format with the following fields: (a) TOTEMP, total employment (same regardless + of classification system); (b) RETEMPN, retail trade employment per the NAICS classification system; + (c) FPSEMPN, financial and professional services employment per the NAICS classification system; (d) + HEREMPN, health, educational, and recreational employment per the NAICS classification system; (e) + OTHEMPN, other employment per the NAICS classification system; (f) AGREMPN, agricultural employment + per the NAICS classificatin system; (g) MWTEMPN, manufacturing, warehousing, and transportation + emp;loyment per the NAICS classification system; and, (h) TOTHH, total households. + + Output: (1) An ASCII file containing the following fields: (a) zone number; (b) very small truck trip productions; + (c) very small truck trip attractions + + See also: (1) TruckTripDistribution.job, which applies the distribution model. + (2) TruckTimeOfDay.job, which applies diurnal factors to the daily trips generated here. + (3) TruckTollChoice.job, which applies a toll/no toll choice model for trucks. + + version: 0.1 + authors: dto (2010 08 31); jef (2012 03 07) + + 5-2013 wsu fixed indexing bug + 7-2013 jef reduced truck rate for military employment to 0.3 + 8-2014 wsu reduced truck rate for military employment to 0.15 + +**************************************************************/ +Macro "Commercial Vehicle Generation" + + shared path, inputDir, outputDir ,scenarioYear + + mgraCommTripFile = "mgraCommVeh.csv" + tazCommTripFile = "tazCommVeh.csv" + + writeMgraData = true + calibrationFactor = 1.4 + + // read in the mgra data in CSV format + mgraView = OpenTable("MGRA View", "CSV", {inputDir+"\\mgra13_based_input"+scenarioYear+".csv"}, {{"Shared", "True"}}) + + mgra = GetDataVector(mgraView+"|", "mgra", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + taz = GetDataVector(mgraView+"|", "TAZ", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + hh = GetDataVector(mgraView+"|", "hh", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_ag = GetDataVector(mgraView+"|", "emp_ag", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_non_bldg_prod = GetDataVector(mgraView+"|", "emp_const_non_bldg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_non_bldg_office = GetDataVector(mgraView+"|", "emp_const_non_bldg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_utilities_prod = GetDataVector(mgraView+"|", "emp_utilities_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_utilities_office = GetDataVector(mgraView+"|", "emp_utilities_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_bldg_prod = GetDataVector(mgraView+"|", "emp_const_bldg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_bldg_office = GetDataVector(mgraView+"|", "emp_const_bldg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_mfg_prod = GetDataVector(mgraView+"|", "emp_mfg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_mfg_office = GetDataVector(mgraView+"|", "emp_mfg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_whsle_whs = GetDataVector(mgraView+"|", "emp_whsle_whs", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_trans = GetDataVector(mgraView+"|", "emp_trans", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_retail = GetDataVector(mgraView+"|", "emp_retail", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_prof_bus_svcs = GetDataVector(mgraView+"|", "emp_prof_bus_svcs", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_prof_bus_svcs_bldg_maint = GetDataVector(mgraView+"|", "emp_prof_bus_svcs_bldg_maint", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_ed_k12 = GetDataVector(mgraView+"|", "emp_pvt_ed_k12", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_ed_post_k12_oth = GetDataVector(mgraView+"|", "emp_pvt_ed_post_k12_oth", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_health = GetDataVector(mgraView+"|", "emp_health", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_personal_svcs_office = GetDataVector(mgraView+"|", "emp_personal_svcs_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_amusement = GetDataVector(mgraView+"|", "emp_amusement", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_hotel = GetDataVector(mgraView+"|", "emp_hotel", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_restaurant_bar = GetDataVector(mgraView+"|", "emp_restaurant_bar", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_personal_svcs_retail = GetDataVector(mgraView+"|", "emp_personal_svcs_retail", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_religious = GetDataVector(mgraView+"|", "emp_religious", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_hh = GetDataVector(mgraView+"|", "emp_pvt_hh", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_ent = GetDataVector(mgraView+"|", "emp_state_local_gov_ent", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_fed_non_mil = GetDataVector(mgraView+"|", "emp_fed_non_mil", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_fed_mil = GetDataVector(mgraView+"|", "emp_fed_mil", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_blue = GetDataVector(mgraView+"|", "emp_state_local_gov_blue", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_white = GetDataVector(mgraView+"|", "emp_state_local_gov_white", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_total = GetDataVector(mgraView+"|", "emp_total", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + + RETEMPN = emp_retail + emp_personal_svcs_retail + FPSEMPN = emp_prof_bus_svcs + HEREMPN = emp_health + emp_pvt_ed_k12 + emp_pvt_ed_post_k12_oth + emp_amusement + AGREMPN = emp_ag + MWTEMPN = emp_const_non_bldg_prod + emp_const_bldg_prod + emp_mfg_prod + emp_trans + MILITARY = emp_fed_mil + TOTEMP = emp_total + OTHEMPN = TOTEMP - (RETEMPN + FPSEMPN + HEREMPN + AGREMPN + MWTEMPN + MILITARY) + TOTHH = hh + + verySmallP = calibrationFactor * (0.95409 * RETEMPN + 0.54333 * FPSEMPN + 0.50769 * HEREMPN + + 0.63558 * OTHEMPN + 1.10181 * AGREMPN + 0.81576 * MWTEMPN + + 0.15000 * MILITARY + + 0.1 * TOTHH) + + + // Wu added this section for military CTM trips adjustment to match military gate counts + properties = "\\conf\\sandag_abm.properties" + militaryCtmAdjustment = RunMacro("read properties",properties,"RunModel.militaryCtmAdjustment", "S") + if militaryCtmAdjustment = "true" then do + mgraView_m = OpenTable("Military MGRA View", "CSV", {inputDir+"\\cvm_military_adjustment.csv"}, {{"Shared", "True"}}) + //base_id = GetDataVector(mgraView_m+"|", "ID", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + //base_name = GetDataVector(mgraView_m+"|", "base", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + //taz_m = GetDataVector(mgraView_m+"|", "TAZ", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + //mgra_m = GetDataVector(mgraView_m+"|", "mgra", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + base_id = GetDataVector(mgraView_m+"|", "ID",) + base_name = GetDataVector(mgraView_m+"|", "base",) + taz_m = GetDataVector(mgraView_m+"|", "TAZ",) + mgra_m = GetDataVector(mgraView_m+"|", "mgra",) + scale = GetDataVector(mgraView_m+"|", "scale", {{"Type", {{"scale", "Float"}}}} ) + + //scale verySmallP and verySmallA: why is his called verySmallP and verySmallA??? + for i = 1 to mgra.length do + for j = 1 to mgra_m.length do + if mgra[i] = mgra_m[j] then do + verySmallP[i]=verySmallP[i]*scale[j] + end + end + end + end + + verySmallA = verySmallP + + if writeMgraData = true then do + //create a table with the mgra trips + truckTripsMgra = CreateTable("truckTripsMgra",outputDir+"\\"+mgraCommTripFile, "CSV", { + {"MGRA", "Integer", 8, null, }, + {"PROD", "Real", 12, 4, }, + {"ATTR", "Real", 12, 4, } + }) + end + + //create a table with the taz trips + truckTripsTaz= CreateTable("truckTripsTaz",outputDir+"\\"+tazCommTripFile, "CSV", { + {"TAZ", "Integer", 8, null, }, + {"PROD", "Real", 12, 4, }, + {"ATTR", "Real", 12, 4, } + }) + + //now aggregate by TAZ + maxTaz = 0 + for i=1 to taz.length do + if taz[i] > maxTaz then maxTaz = taz[i] + end + + //arrays for holding productions and attractions by TAZ + dim tazProd[maxTaz] + dim tazAttr[maxTaz] + + //initialize arrays to 0 + for i = 1 to tazProd.length do + tazProd[i]=0 + tazAttr[i]=0 + end + + //aggregate mgra to taz arrays + for i = 1 to mgra.length do + + tazNumber = taz[i] + tazProd[tazNumber] = tazProd[tazNumber] + verySmallP[i] + tazAttr[tazNumber] = tazAttr[tazNumber] + verySmallA[i] + + if writeMgraData = true then do + AddRecord("truckTripsMgra", { + {"MGRA", mgra[i]}, + {"PROD", verySmallP[i]}, + {"ATTR", verySmallA[i]} + }) + end + end + + if writeMgraData = true then CloseView(truckTripsMgra) + + //add taz data to table + for i = 1 to maxTaz do + + AddRecord("truckTripsTaz", { + {"TAZ", i}, + {"PROD", tazProd[i]}, + {"ATTR", tazAttr[i]} + }) + end + + RunMacro("close all") + Return(1) +EndMacro diff --git a/sandag_abm/src/main/gisdk/commVehTOD.rsc b/sandag_abm/src/main/gisdk/commVehTOD.rsc new file mode 100644 index 0000000..9b1a459 --- /dev/null +++ b/sandag_abm/src/main/gisdk/commVehTOD.rsc @@ -0,0 +1,122 @@ +/************************************************************** + CommVehTOD.rsc + + TransCAD Macro used to run truck commercial vehicle time-of-day factoring. The very small truck generation model is based on the Phoenix + four-tire truck model documented in the TMIP Quick Response Freight Manual. + + The diurnal factors are taken from the BAYCAST-90 model with adjustments made during calibration to the very + small truck values to better match counts. + + Input: A production/attraction format trip table matrix of daily very small truck trips. + + Output: Five, time-of-day-specific trip table matrices containing very small trucks. + + See also: (1) CommVehGen.rsc, which applies the generation model. + (2) CommVehDist.rsc, which applies the distribution model. + + authors: jef (2012 03 11) dto (2011 09 08); dto (2010 08 31); cp (date unknown) + + +**************************************************************/ +Macro "Commercial Vehicle Time Of Day" (scenarioDirectory) + shared path, inputDir, outputDir + +/* + RunMacro("TCB Init") + + //inputs + scenarioDirectory = "d:\\projects\\SANDAG\\AB_Model\\commercial_vehicles" +*/ + + commVehTripTable = "commVehTrips.mtx" + + //outputs + commVehTODTable = "commVehTODTrips.mtx" + + //open input table + dailyMatrix = OpenMatrix(outputDir + "\\"+commVehTripTable, ) + dailyMC = CreateMatrixCurrency(dailyMatrix, "CommVeh", ,, ) + + //create transposed daily trip table + tmat = TransposeMatrix(dailyMatrix, {{"File Name", outputDir + "\\"+commVehTripTable+"t"}, + {"Label", "commVehT"}, + {"Type", "Double"}, + {"Sparse", "No"}, + {"Column Major", "No"}, + {"File Based", "No"}}) + + transMC = CreateMatrixCurrency(tmat, "commVeh", ,, ) + + //create output matrix + todMatrix = CopyMatrix(dailyMC, {{"File Name", outputDir+"\\"+commVehTODTable}, + {"Label", "CommVehTOD"}, + {"File Based", "Yes"}}) + + Opts = null + Opts.Input.[Input Matrix] =outputDir+"\\"+commVehTODTable + Opts.Input.[New Core] = "OD Trips" + ok = RunMacro("TCB Run Operation", "Add Matrix Core", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[Input Matrix] = outputDir+"\\"+commVehTODTable + Opts.Input.[New Core] = "EA Trips" + ok = RunMacro("TCB Run Operation", "Add Matrix Core", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[Input Matrix] = outputDir+"\\"+commVehTODTable + Opts.Input.[New Core] = "AM Trips" + ok = RunMacro("TCB Run Operation", "Add Matrix Core", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[Input Matrix] = outputDir+"\\"+commVehTODTable + Opts.Input.[New Core] = "MD Trips" + ok = RunMacro("TCB Run Operation", "Add Matrix Core", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[Input Matrix] = outputDir+"\\"+commVehTODTable + Opts.Input.[New Core] = "PM Trips" + ok = RunMacro("TCB Run Operation", "Add Matrix Core", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[Input Matrix] = outputDir+"\\"+commVehTODTable + Opts.Input.[New Core] = "EV Trips" + ok = RunMacro("TCB Run Operation", "Add Matrix Core", Opts) + if !ok then goto quit + + odMC = CreateMatrixCurrency(todMatrix, "OD Trips", ,, ) + eaMC = CreateMatrixCurrency(todMatrix, "EA Trips", ,, ) + amMC = CreateMatrixCurrency(todMatrix, "AM Trips", ,, ) + mdMC = CreateMatrixCurrency(todMatrix, "MD Trips", ,, ) + pmMC = CreateMatrixCurrency(todMatrix, "PM Trips", ,, ) + evMC = CreateMatrixCurrency(todMatrix, "EV Trips", ,, ) + + odMC := (0.5 * dailyMC) + (0.5 * transMC) + + // - early AM + eaMC := 0.0235 * odMC + + + // - AM peak + amMC := 0.1000 * odMC + + + // - midday + mdMC := 0.5080 * odMC + + // - PM peak + pmMC := 0.1980 * odMC + + + // - evening + evMC := 0.1705 * odMC + + RunMacro("close all") + quit: + Return(ok) + +EndMacro diff --git a/sandag_abm/src/main/gisdk/create_LUZ_Skims.rsc b/sandag_abm/src/main/gisdk/create_LUZ_Skims.rsc new file mode 100644 index 0000000..9c74141 --- /dev/null +++ b/sandag_abm/src/main/gisdk/create_LUZ_Skims.rsc @@ -0,0 +1,254 @@ +/* + Create landuse skims(LUZ skims): + +About: + Creates LUZ skims from the following TAZ skims including length, time, and cost: + impdat_AM.mtx (Length (Skim), *STM_AM (Skim), dat_AM – itoll_AM) + impdat_MD.mtx (Length (Skim), *STM_MD (Skim), dat_MD – itoll_MD) + impmhdt_AM.mtx (Length (Skim), *STM_AM (Skim), mhdt – ITOLL2_AM) + impmhdt_MD.mtx (Length (Skim), *STM_MD (Skim), mhdt – ITOLL2_MD) + +Inputs: + 1) luzToTazSeries13.xls (Luz to TAZ reference) + 2) ExternalZones.xls (Luz internal to external reference) + 3) impdat_AM.mtx + 4) impdat_MD.mtx + 5) impmhdt_AM.mtx + 6) impmhdt_MD.mtx + +Outputs: + 1) impdat_AM.mtx (csv) + 2) impdat_MD.mtx (csv) + 3) impmhdt_AM.mtx (csv) + 4) impmhdt_MD.mtx (csv) + + +*/ + +Macro "Create LUZ Skims" + + shared path, inputDir, outputDir + + // Input Files + ext_luz_excel = inputDir+"\\ExternalZones.xls" + luz_taz_excel = inputDir+"\\luzToTazSeries13.xls" + + // Temp files + ext_luz_file = outputDir+"\\ExternalZones.bin" + luz_taz_file = outputDir+"\\luzToTazSeries13.bin" + tempfile = outputDir+"\\temp_luz.bin" + luzskims_bin = outputDir+"\\temp_luz_export.bin" + + // Convert excel to bin file + ExportExcel(ext_luz_excel, "FFB", ext_luz_file, ) + ExportExcel(luz_taz_excel, "FFB", luz_taz_file, ) + + // Open tables + luztaz_view = Opentable("luztaz", "FFB", {luz_taz_file}) + ext_luz_view = Opentable("luzIE", "FFB", {ext_luz_file}) + + /* ------------------------------------------------------------------------------------------------ + // Step 0: Prepares input and output files + --------------------------------------------------------------------------------------------------*/ + // Create list of LUZ I+E zones + LUZ_I = V2A(GetDataVector(luztaz_view+"|","luz_id",)) + LUZ_E = V2A(GetDataVector(ext_luz_view+"|","External LUZ",{{"Sort Order", {{"External LUZ", "Ascending"}}}})) + LUZ_IE = LUZ_I + LUZ_E + + // Get the maximum internal zone + max_LUZ_I = ArrayMax(LUZ_I) + min_LUZ_E = ArrayMin(LUZ_E) + max_LUZ_E = ArrayMax(LUZ_E) + + // Write the list to a file (temp luz zonal file) + luz_vw = CreateTable("luz", tempfile, "FFB",{ + {"luz_id", "Integer", 8, null, "Yes"}}) + SetView(view) + for r = 1 to LUZ_IE.length do + rh = AddRecord(luz_vw, { + {"luz_id", LUZ_IE[r]} + }) + end + + + period = {"AM","MD"} + vehicle = {"dat","mhdt"} + + for v =1 to vehicle.length do + for p= 1 to period.length do + + /* ------------------------------------------------------------------------------------------------ + //Step 1: Create matrix with LUZ internal and external Zones + --------------------------------------------------------------------------------------------------*/ + // Input taz skim + tazskims = outputDir+"\\imp"+vehicle[v]+"_"+period[p]+".mtx" + + // Output luz skim (mtx and csv files) + luzskims = outputDir+"\\luz_imp"+vehicle[v]+"_"+period[p]+".mtx" + luzskims_csv = outputDir+"\\luz_imp"+vehicle[v]+"_"+period[p]+".csv" + + // List of cores (same core names for inputs and outputs) + m = OpenMatrix(tazskims, ) + coreNames = GetMatrixCoreNames(m) + coreNames = Subarray(coreNames,2,3) // Only the distance, time, & toll skims + + // Open the temp luz zonal file + luz_view = Opentable("luz", "FFB", {tempfile}) + + // Create output matrix file with both LUZ internal & external zones + luz_mat =CreateMatrix({luz_view+"|", "luz_id", "All"}, + {luz_view+"|", "luz_id", "All"}, + {{"File Name", luzskims}, {"Type", "Float"}, {"Tables",coreNames}}) + + // Create LUZ II, IE/EI and EE indices + SetView(luz_view) + set_i = SelectByQuery("Internal", "Several", "Select * where luz_id <= "+ String(max_LUZ_I),) + Internal = CreateMatrixIndex("Internal", luz_mat, "Both", luz_view +"|Internal", "luz_id", "luz_id" ) + + set_e = SelectByQuery("External", "Several", "Select * where (luz_id >= "+ String(min_LUZ_E) +" & luz_id <= "+ String(max_LUZ_E)+")",) + External = CreateMatrixIndex("External", luz_mat, "Both", luz_view +"|External", "luz_id", "luz_id" ) + CloseView(luz_view) + + // Create luz currencies for II, EI and IE (each array has 3 currencies; one of each core) + mc_luz_II = CreateMatrixCurrencies(luz_mat,"Internal","Internal",) + mc_luz_EI = CreateMatrixCurrencies(luz_mat,"External","Internal",) + mc_luz_IE = CreateMatrixCurrencies(luz_mat,"Internal","External",) + mc_luz_EE = CreateMatrixCurrencies(luz_mat,"External","External",) + + /* ------------------------------------------------------------------------------------------------ + // Step 2: Create LUZ internal skims from TAZ skims + --------------------------------------------------------------------------------------------------*/ + // Create aggregate tables for each selected cores + for c = 1 to coreNames.length do + + // Create currency in the input file + mc = CreateMatrixCurrency(m, coreNames[c], , , ) + row_names = {"luztaz.taz", "luztaz.luz_id"} + col_names = {"luztaz.taz", "luztaz.luz_id"} + + // Create LUZ internal skims + tempLuzMtx = outputDir+"\\temp"+vehicle[v]+period[p]+"_"+String(c)+".mtx" + AggregateMatrix(mc, row_names, col_names, + {{"File Name", tempLuzMtx}, + {"Label", "LUZ"+coreNames[c]}, + {"File Based", "Yes"}}) + + // Add the aggregate table to the internal zones in the new core + mat = OpenMatrix(tempLuzMtx, ) + mc_temp = CreateMatrixCurrency(mat, coreNames[c], , , ) + mc_luz_II.(coreNames[c]):= mc_temp + + // Get the internal zones to the corresponding + intZones = GetDataVector(ext_luz_view+"|","Internal Cordon LUZ",) + extZones = GetDataVector(ext_luz_view+"|","External LUZ",) + distance = GetDataVector(ext_luz_view+"|","Miles to be Added to Cordon Point",) + time = GetDataVector(ext_luz_view+"|","Minutes to be Added to Cordon Point",) + + // Add the EI and IE mat values based on cordon data + for e = 1 to extZones.length do + // Get mat values for the corresponding internal zones + vec_EI = GetMatrixVector(mc_temp, {{"Row",intZones[e]}}) + vec_IE = GetMatrixVector(mc_temp, {{"Column",intZones[e]}}) + + // Add cordon time, distance (depending on the core) + if (c = 1) then do // length + vec_EI = vec_EI + distance[e] + vec_IE = vec_IE + distance[e] + end + if (c = 2) then do // time + vec_EI = vec_EI + time[e] + vec_IE = vec_IE + time[e] + end + + // Set vectors to the matrix + SetMatrixVector(mc_luz_EI.(coreNames[c]), vec_EI, {{"Row",extZones[e]}}) + SetMatrixVector(mc_luz_IE.(coreNames[c]), vec_IE, {{"Column",extZones[e]}}) + end // ext zones + + // EE values are filled based on II, and IE values + for i = 1 to extZones.length do + for j = 1 to extZones.length do + // Get II value if Intrazonal + if i=j then do + II_val = GetMatrixValue(mc_luz_II.(coreNames[c]), String(intZones[i]),String(intZones[j])) + SetMatrixValue(mc_luz_EE.(coreNames[c]),String(extZones[i]),String(extZones[j]),II_val) + end + else do + IE_val = GetMatrixValue(mc_luz_IE.(coreNames[c]), String(intZones[i]),String(extZones[j])) + if (c=1) then IE_val = IE_val + distance[i] + if (c=2) then IE_val = IE_val + time[i] + SetMatrixValue(mc_luz_EE.(coreNames[c]),String(extZones[i]),String(extZones[j]),IE_val) + end // if + end // j loop + end // i loop + end // cores + + /* ------------------------------------------------------------------------------------------------ + // Step 3: Export to CSV file + --------------------------------------------------------------------------------------------------*/ + // Export matrix values to a temp bin file + SetMatrixIndex(luz_mat, "All", "All") + CreateTableFromMatrix(luz_mat, luzskims_bin, "FFB", {{"Complete", "Yes"}}) + + // Add header and then export to csv file + export_vw = OpenTable("luztaz", "FFB", {luzskims_bin}) + strct = GetTableStructure(export_vw) + for s = 1 to strct.length do + strct[s] = strct[s] + {strct[s][1]} + end + + // Rename to first and second columns to Origin and Destination + strct[1][1] = "origin LUZ" + strct[2][1] = "destination LUZ" + ModifyTable(export_vw, strct) + + // Export to CSV file + ExportView(export_vw+"|", "CSV", luzskims_csv, null,{{"CSV Header", "True"}}) + CloseView(export_vw) + + end // time period + end // vehicle + + + /* ------------------------------------------------------------------------------------------------ + // Step 4: Close all views and delete temp files + --------------------------------------------------------------------------------------------------*/ + vws = GetViewNames() + if vws<> null then do + for w = 1 to vws.length do + CloseView(vws[w]) + end + end + + // Close matrices + mtxs = GetMatrices() + if mtxs <> null then do + handles = mtxs[1] + for m = 1 to handles.length do + handles[m] = null + end + end + + // Close rest + RunMacro("G30 File Close All") + + // Delete temp matrices + for v =1 to vehicle.length do + for p= 1 to period.length do + for c = 1 to coreNames.length do + DeleteFile(outputDir+"\\temp"+vehicle[v]+period[p]+"_"+String(c)+".mtx") + end + // Also delete tcad headers for the CSV file (as the csv files have headers) + DeleteFile(outputDir+"\\luz_imp"+vehicle[v]+"_"+period[p]+".DCC") + end + end + + // Delete temp luz files + delFiles = {"temp_luz.bin","temp_luz.BX","temp_luz.DCB","luzToTazSeries13.bin","luzToTazSeries13.DCB", + "ExternalZones.bin","ExternalZones.DCB","temp_luz_export.bin","temp_luz_export.DCB"} + for d =1 to delFiles.length do + info = GetFileInfo(outputDir+"\\"+delFiles[d]) + if info[1] <> null then DeleteFile(outputDir+"\\"+delFiles[d]) + end + +EndMacro \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/createhwynet.rsc b/sandag_abm/src/main/gisdk/createhwynet.rsc new file mode 100644 index 0000000..b6c5cf5 --- /dev/null +++ b/sandag_abm/src/main/gisdk/createhwynet.rsc @@ -0,0 +1,2509 @@ +//******************************************************************** +//procedure to import e00 file to geo dbd file +//create highway network +//written on 4/19/01 +//macro "import highway layer", macro"fill oneway streets", +//macro "createhwynet1" +// +//input files: hwycov.e00 - hwy line layer ESRI exchange file +//output files: hwy.dbd - hwy line geographic file +// hwycad.log- a log file +// hwycad.err - error file with error info +//Oct 08, 2010: Added Lines 164-186, Create a copy of Toll fields +//Oct 08, 2010: Added Lines 284-287 Build Highway Network with ITOLL fields +//April 22, 2014: Wu checked all SR125 related changes are included +//Feb 02, 2016: Added reliability fields +//******************************************************************** + +macro "run create hwy" + shared path,inputDir,outputDir,mxzone + +/* exported highway layer is copied manually to the output folder (I15 SB toll entry/exit links are modified by RSG) + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","import highway layer"}) + ok=RunMacro("import highway layer") + if !ok then goto quit +*/ + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","copy highway database"}) + ok=RunMacro("copy database") + if !ok then goto quit + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","fill oneway streets"}) + ok=RunMacro("fill oneway streets") + if !ok then goto quit + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","add TOD attributes"}) + ok=RunMacro("add TOD attributes") + if !ok then goto quit + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","calculate distance to/from major interchange"}) + ok=RunMacro("DistanceToInterchange") + if !ok then goto quit + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","add reliability fields"}) + ok=RunMacro("add reliability fields") + if !ok then goto quit + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","add preload attributes"}) + ok=RunMacro("add preload attributes") + if !ok then goto quit + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","Code VDF fields"}) + ok=RunMacro("Code VDF fields") + if !ok then goto quit + + RunMacro("HwycadLog",{"createhwynet.rsc: run create hwy","create hwynet"}) + ok=RunMacro("create hwynet") + if !ok then goto quit + + quit: + return(ok) +EndMacro + +/********************************************************************************************************** + import e00 file + if numofzone=tdz then e00file=hwycovtdz.e00, hwytdz.dbd + else e00file=hwy.e00, hwy.dbd + + Inputs: + input\turns.csv + input\turns.DCC + input\hwycov.e00 + + Outputs: + output\turns.dbf + output\hwytmp.dbd + output\hwy.dbd + +**********************************************************************************************************/ +macro "import highway layer" + shared path, inputDir,outputDir + ok=0 + + RunMacro("close all") + + di=GetDirectoryInfo(path + "\\tchc1.err","file") + if di.length>0 then do + ok=0 + RunMacro("TCB Error","chech tchc1.err file!") + goto exit + end + + di=GetDirectoryInfo(path + "\\tchc.err","file") + if di.length>0 then do + ok=0 + RunMacro("TCB Error","chech tchc.err file!") + goto exit + end + + di=GetDirectoryInfo(inputDir + "\\turns.csv","file") + if di.length=0 then do + ok=0 + RunMacro("TCB Error","turns.csv does not exist!") + goto exit + end + + // assume that the dictionary file exists in the input directory for the model run + //ok=RunMacro("SDcopyfile",{path_study+"\\data\\turns.DCC",path+"\\turns.DCC"}) + //if !ok then goto exit + + //export turns.csv to turns.dbf + vw = OpenTable("turns", "CSV", {inputDir+"\\turns.csv",}) + ExportView("turns|", "dbase", outputDir+"\\turns.dbf",,) + + // writeline(fpr,mytime+", exporting turns.csv to turns.dbf") + + // import e00 file + e00file="hwycov.e00" + + //check e00 file exists + di = GetDirectoryInfo(inputDir +"\\"+e00file, "File") + if di.length = 0 then do + ok=0 + RunMacro("TCB Error",e00file+" does not exist!") + goto exit + end + + ImportE00(inputDir +"\\"+e00file, outputDir + "\\hwytmp.dbd","line",outputDir + "\\hwytmp.bin",{ + {"Label","street line file"}, + {"Layer Name","hwyline"}, + {"optimize","True"}, + {"Median Split", "True"}, + {"Node Layer Name", "hwynode"}, + {"Node Table", outputDir + "\\hwytmp_.bin"}, + {"Projection","NAD83:406",{"_cdist=1000","_limit=1000","units=us-ft"}}, + }) + + //writeline(fpr,mytime+", importing e00 file") + + //export geo file by specify the line id field and the node id field + db_file=outputDir + "\\hwytmp.dbd" + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file,,) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto exit + + allflds=Getfields(link_lyr,"All") + fullflds=allflds[2] + allnodeflds = GetFields(node_lyr, "All") + + // need to specify full field specifications + lineidfield = link_lyr+".hwycov-id" + nodeidfield = "hwynode.hnode"//for centroids purposes + + opts = {{"Layer Name", "hwyline"}, + {"File Type", "FFB"}, + {"ID Field", lineidfield}, + {"Field Spec", fullflds}, + {"Indexed Fields", {fullflds[1]}}, + {"Label", "street line file"}, + {"Node layer name","hwynode"}, + {"Node ID Field", nodeidfield}, + {"Node Field Spec", allnodeflds[2]}} + + if node_idx > 1 then + opts = opts + {{"Node ID Field", node_aflds[2][node_idx - 1]}} + hwy_db=outputDir + "\\hwy.dbd" + + exportgeography(link_lyr,hwy_db,opts) + + // writeline(fpr,mytime+", exporting e00 file") + + RunMacro("close all") //before delete db_file, close it + deleteDatabase(db_file) + + ok=1 + exit: + //if fpr<>null then closefile(fpr) + return(ok) +endMacro + +/* +copies database (hwy.dbd) and turns file (TURNS.DBF) + +this is required after edits made to the transcad highway database for I15 SB managed lane links + +*/ + +macro "copy database" + shared path, inputDir, outputDir + + hwy_db_in = inputDir + "\\hwy.dbd" + hwy_db_out = outputDir + "\\hwy.dbd" + + /// copye highway database + CopyDatabase(hwy_db_in, hwy_db_out) + + // copy turns file + CopyFile(inputDir+"\\TURNS.DBF", outputDir+"\\TURNS.DBF") + + ok=1 + return(ok) + +endMacro + +/********************************************************************************************************** + fill oneway street with dir field, and calculate toll fields and change AOC and add reliability factor + + Inputs + output\hwy.dbd + + Outputs: + output\hwy.dbd (modified) + + Adds fields to link layer (by period: _EA, _AM, _MD, _PM, _EV) + ITOLL - Toll + 10000 *[0,1] if SR125 toll lane + ITOLL2 - Toll + ITOLL3 - Toll + AOC + ITOLL4 - Toll * 1.03 + AOC + ITOLL5 - Toll * 2.33 + AOC + + Note: Link operation type (IHOV) where: + 1 = General purpose + 2 = 2+ HOV (Managed lanes if lanes > 1) + 3 = 3+ HOV (Managed lanes if lanes > 1) + 4 = Toll lanes + + + +**********************************************************************************************************/ +macro "fill oneway streets" + shared path, inputDir, outputDir + ok=0 + + RunMacro("close all") + + properties = "\\conf\\sandag_abm.properties" + aoc_f = RunMacro("read properties",properties,"aoc.fuel", "S") + aoc_m = RunMacro("read properties",properties,"aoc.maintenance", "S") + aoc=S2R(aoc_f)+S2R(aoc_m) + + db_file=outputDir+"\\hwy.dbd" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + db_link_lyr = db_file + "|" + link_lyr + +// writeline(fpr,mytime+", fill one way streets") +// closefile(fpr) + +/* + //oneway streets, dir = 1 + Opts = null + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection", "Select * where iway = 1"} + Opts.Global.Fields = {"Dir"} + Opts.Global.Method = "Value" + Opts.Global.Parameter = {1} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit +*/ + //CHANGE SR125 TOLL SPEED TO 70MPH (ISPD=70) DELETE THIS SECTION AFTER TESTING + Opts = null + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"ISPD"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = "if ihov=4 and IFC=1 then 70 else ISPD" + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + + // Create RELIABILITY OF FACILITY (TOLL) field + vw = GetView() + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + strct = strct + {{"relifac", "Real", 10, 2, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + //change reliability field for SR125 to 0.65, and all other facilities are 0 + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"relifac"} + Opts.Global.Method = "Formula" +// Opts.Global.Parameter = "if ihov=4 & ifc=1 then 0.65 else 1" + //since we now have reliability fields, setting all reliability factors to 1 + Opts.Global.Parameter = "1" + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + //change AOC to appropriate value for year and cents per mile in COST field and add reliability factor to COST calc. + Opts = null + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"COST"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = "Length * "+R2S(aoc)+" * relifac" + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + // Create copy of ITOLL fields to preserved original settings + vw = GetView() + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + + // changed field types to real (for I15 tolls) - by nagendra.dhakar@rsginc.com + strct = strct + {{"ITOLL2_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL2_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL2_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL2_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL2_EV", "Real", 14, 6, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + tollfld={{"ITOLL2_EA"},{"ITOLL2_AM"},{"ITOLL2_MD"},{"ITOLL2_PM"},{"ITOLL2_EV"}} + tollfld_flg={{"ITOLLO"},{"ITOLLA"},{"ITOLLO"},{"ITOLLP"},{"ITOLLO"}} //note - change this once e00 file contains fields for each of 5 periods + + // set SR125 tolls + for i=1 to tollfld.length do + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tollfld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = tollfld_flg[i] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // clear I15 tolls from previous step + // set other link tolls to 0 - creates a problem in skimming if left to null + // added by nagendra.dhakar@rsginc.com + for i=1 to tollfld.length do + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection", "Select *where ihov=2"} + Opts.Global.Fields = tollfld[i] + Opts.Global.Method = "Value" + Opts.Global.Parameter = {0} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + + // set I15 tolls - added by nagendra.dhakar@rsginc.com + RunMacro("set I15 tolls", link_lyr, tollfld) + + // Create ITOLL3 fields with ITOLL2A and COST + vw = GetView() + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + strct = strct + {{"ITOLL3_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL3_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL3_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL3_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL3_EV", "Real", 14, 6, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + tollfld={{"ITOLL3_EA"},{"ITOLL3_AM"},{"ITOLL3_MD"},{"ITOLL3_PM"},{"ITOLL3_EV"}} + tollfld_flg={{"ITOLL2_EA+COST"},{"ITOLL2_AM+COST"},{"ITOLL2_MD+COST"},{"ITOLL2_PM+COST"},{"ITOLL2_EV+COST"}} //note - change this once e00 file contains fields for each of 5 periods + for i=1 to tollfld.length do + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tollfld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = tollfld_flg[i] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // Create ITOLL4 fields with 1.03*(ITOLL2) and COST + // ITOLL4 = is applied to LHD and MHD only + vw = GetView() + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + strct = strct + {{"ITOLL4_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL4_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL4_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL4_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL4_EV", "Real", 14, 6, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + tollfld={{"ITOLL4_EA"},{"ITOLL4_AM"},{"ITOLL4_MD"},{"ITOLL4_PM"},{"ITOLL4_EV"}} + tollfld_flg={{"1.03*ITOLL2_EA+COST"},{"1.03*ITOLL2_AM+COST"},{"1.03*ITOLL2_MD+COST"},{"1.03*ITOLL2_PM+COST"},{"1.03*ITOLL2_EV+COST"}} //note - change this once e00 file contains fields for each of 5 periods + for i=1 to tollfld.length do + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tollfld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = tollfld_flg[i] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // Create ITOLL5 fields with 2.33*(ITOLL2) and COST + // ITOLL5 = is applied to HHD only + vw = GetView() + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + strct = strct + {{"ITOLL5_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL5_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL5_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL5_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL5_EV", "Real", 14, 6, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + tollfld={{"ITOLL5_EA"},{"ITOLL5_AM"},{"ITOLL5_MD"},{"ITOLL5_PM"},{"ITOLL5_EV"}} + tollfld_flg={{"2.33*ITOLL2_EA+COST"},{"2.33*ITOLL2_AM+COST"},{"2.33*ITOLL2_MD+COST"},{"2.33*ITOLL2_PM+COST"},{"2.33*ITOLL2_EV+COST"}} //note - change this once e00 file contains fields for each of 5 periods + for i=1 to tollfld.length do + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tollfld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = tollfld_flg[i] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // Create ITOLL fields + vw = GetView() + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + strct = strct + {{"ITOLL_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ITOLL_EV", "Real", 14, 6, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + //adding $100 to toll fields to flag toll values from manage lane toll values in skim matrix + tollfld={{"ITOLL_EA"},{"ITOLL_AM"},{"ITOLL_MD"},{"ITOLL_PM"},{"ITOLL_EV"}} + tollfld_flg={{"if ihov=4 then ITOLL2_EA+10000 else ITOLL2_EA"}, + {"if ihov=4 then ITOLL2_AM+10000 else ITOLL2_AM"}, + {"if ihov=4 then ITOLL2_MD+10000 else ITOLL2_MD"}, + {"if ihov=4 then ITOLL2_PM+10000 else ITOLL2_PM"}, + {"if ihov=4 then ITOLL2_EV+10000 else ITOLL2_EV"}} //note - change this once e00 file contains fields for each of 5 periods + + // modified by nagendra.dhakar@rsginc.com to calculate every toll field from itoll2, which are set to the tolls fields in tcoved + + for i=1 to tollfld.length do + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tollfld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = tollfld_flg[i] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + RunMacro("close all") + + ok=1 + quit: + return(ok) +EndMacro + +/********************************************************************************************************* +add i-15 tolls by direction and period + + link ids and corresponding tolls are inputs + toll values are coded by link ids + tolls are determined by gate-to-gate toll optimization, solved using excel solver + tolls from two methods are used + -traversed links (NB PM and SB AM) + -entry and exit links (remaining) + +by: nagendra.dhakar@rsginc.com +**********************************************************************************************************/ + +Macro "set I15 tolls" (lyr, toll_fields) + shared path, inputDir, outputDir + + direction = {"NB","SB"} + periods={"EA","AM","MD","PM","EV"} + + toll_links = {} + tolls = {} + + // NB toll links and corresponding tolls + toll_links.NB = {} + + toll_links.NB.traverse = {29716,460,526,23044,459,463,512,464,469,470,510,29368,9808} + toll_links.NB.entryexit = {31143,29472,52505,52507,52508,475,34231,52511,52512,34229,34228,38793,29765,29766,52513,29764,26766} + + tolls.NB = {} + + tolls.NB.traverse = {} + tolls.NB.entryexit = {} + + // tolls are in cents + tolls.NB.entryexit.EA = {35.00,35.00,35.00,35.00,35.00,15.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00} + tolls.NB.entryexit.AM = {45.05,42.43,31.54,30.00,30.00,20.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,17.41,32.59,32.59,32.59} + tolls.NB.entryexit.MD = {69.91,73.91,70.42,66.12,51.61,0.00,26.88,25.00,25.00,25.00,12.07,37.93,47.51,3.35,46.65,60.66,65.74} + tolls.NB.traverse.PM = {21.83,31.11,50.00,55.34,113.23,50.00,50.00,50.00,50.00,50.00,50.00,50.00,0.00} + tolls.NB.entryexit.EV = {41.73,36.26,32.01,30.00,30.00,20.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,17.77,32.23,32.23,32.23} + + // SB toll links and corresponding tolls + toll_links.SB = {} +/* + // old network + toll_links.SB.traverse = {12193,25749,29442,23128,515,31204,520,22275,524,525,553,528,29415} + toll_links.SB.entryexit = {52514,38796,29768,38794,29763,52510,52509,52506,52510,34227,34233,29407,26398,29767,34226,34232,29471,52515} +*/ + // new network + toll_links.SB.traverse = {12193,25749,52567,23128,515,31204,52569,52550,524,525,52555,52559,52561,52565} + toll_links.SB.entryexit = {52568,52570,29768,38794,29763,52560,52562,52566,52556,34227,34233,29407,26398,52571,52572,29767,52575,52576,52574,34226,34232,29471,52573} + + tolls.SB = {} + + tolls.SB.traverse = {} + tolls.SB.entryexit = {} +/* + // old network + tolls.SB.entryexit.EA = {26.69,25.54,26.96,25.54,39.23,25.54,24.46,25.54,25.54,25.54,24.46,24.46,36.30,23.31,24.46,24.46,28.04,0.00} + tolls.SB.traverse.AM = {0.00,50.00,50.00,89.82,50.00,50.00,63.74,0.00,0.11,76.40,38.80,63.58,83.28} + tolls.SB.entryexit.MD = {26.39,25.00,25.00,25.00,35.00,25.47,22.74,27.26,25.47,25.00,24.53,25.00,35.61,23.61,25.00,25.00,32.65,0.00} + tolls.SB.entryexit.PM = {25.00,25.00,25.00,25.00,35.00,25.00,24.34,25.66,25.00,25.00,25.00,25.00,35.00,25.00,25.00,25.00,26.69,0.00} + tolls.SB.entryexit.EV = {25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,25.00,35.00,25.00,25.00,25.00,25.00,0.00} +*/ + // new network + tolls.SB.traverse.AM = {0.00,59.74,50.00,80.42,50.00,50.00,69.24,0.00,3.18,50.00,50.17,19.06,50.00,84.26} + tolls.SB.entryexit.EA = {25.00,25.00,25.00,25.00,35.00,7.29,7.29,7.29,17.30,25.00,17.30,17.30,35.00,15.00,25.00,25.00,32.70,42.71,32.70,25.00,25.00,42.71,25.00} + tolls.SB.entryexit.MD = {32.80,25.00,25.00,25.00,32.80,11.43,11.43,10.65,18.85,25.00,18.85,18.85,32.80,17.20,25.00,17.20,31.15,38.57,31.15,25.00,25.00,39.35,25.00} + tolls.SB.entryexit.PM = {27.78,25.00,25.00,25.00,35.00,12.67,12.67,12.67,19.36,25.00,19.36,19.36,35.00,15.00,25.00,22.22,30.64,37.33,30.64,25.00,25.00,37.33,25.00} + tolls.SB.entryexit.EV = {29.12,25.00,25.00,25.00,35.00,13.14,13.14,13.14,21.56,25.00,21.56,21.56,35.00,15.00,25.00,20.88,28.44,36.86,28.44,25.00,25.00,36.86,25.00} + + for dir=1 to 2 do + for per=1 to periods.length do + // locate record + + if (direction[dir]="NB" and periods[per] = "PM") or (direction[dir]="SB" and periods[per] = "AM") then method = "traverse" + else method = "entryexit" + + links_array = toll_links.(direction[dir]).(method) + tolls_array = tolls.(direction[dir]).(method).(periods[per]) + + // set toll values + for i=1 to links_array.length do + record_handle = LocateRecord (lyr+"|", "ID", {links_array[i]},{{"Exact", "True"}}) + SetRecordValues(lyr, record_handle, {{toll_fields[per][1],tolls_array[i]}}) + end + end + end + +EndMacro + +/********************************************************************************************************** + add link attributes for tod periods + + Inputs + output\hwy.dbd + + Outputs: + output\hwy.dbd (modified) + +**********************************************************************************************************/ +Macro "add TOD attributes" + + shared path, inputDir, outputDir + ok=0 + + db_file=outputDir+"\\hwy.dbd" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + db_link_lyr = db_file + "|" + link_lyr + + vw = SetView(link_lyr) + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + + // AB Link capacity + strct = strct + {{"ABCP_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCP_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCP_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCP_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCP_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Link capacity + strct = strct + {{"BACP_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACP_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACP_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACP_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACP_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Intersection capacity + strct = strct + {{"ABCX_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCX_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCX_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCX_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCX_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Intersection capacity + strct = strct + {{"BACX_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACX_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACX_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACX_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACX_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Link time + strct = strct + {{"ABTM_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTM_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTM_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTM_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTM_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Link time + strct = strct + {{"BATM_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATM_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATM_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATM_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATM_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Intersection time + strct = strct + {{"ABTX_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTX_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTX_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTX_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABTX_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Intersection time + strct = strct + {{"BATX_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATX_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATX_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATX_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BATX_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Lanes + strct = strct + {{"ABLN_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLN_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLN_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLN_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLN_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Lanes + strct = strct + {{"BALN_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALN_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALN_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALN_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALN_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Drive-alone cost + strct = strct + {{"ABSCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Drive-alone cost + strct = strct + {{"BASCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Shared 2 cost + strct = strct + {{"ABH2CST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH2CST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH2CST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH2CST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH2CST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Shared 2 cost + strct = strct + {{"BAH2CST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH2CST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH2CST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH2CST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH2CST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Shared-3 cost + strct = strct + {{"ABH3CST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH3CST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH3CST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH3CST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABH3CST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Shared-3 cost + strct = strct + {{"BAH3CST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH3CST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH3CST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH3CST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAH3CST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Light-Heavy truck cost + strct = strct + {{"ABLHCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLHCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLHCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLHCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLHCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Light-Heavy truck cost + strct = strct + {{"BALHCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALHCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALHCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALHCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALHCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Medium-Heavy truck cost + strct = strct + {{"ABMHCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABMHCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABMHCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABMHCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABMHCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Medium-Heavy truck cost + strct = strct + {{"BAMHCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAMHCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAMHCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAMHCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAMHCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Heavy-Heavy truck cost + strct = strct + {{"ABHHCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHHCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHHCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHHCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHHCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Heavy-Heavy truck cost + strct = strct + {{"BAHHCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHHCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHHCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHHCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHHCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB Commercial vehicle cost + strct = strct + {{"ABCVCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCVCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCVCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCVCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABCVCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Commercial vehicle cost + strct = strct + {{"BACVCST_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACVCST_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACVCST_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACVCST_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BACVCST_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB SOV Time + strct = strct + {{"ABSTM_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTM_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTM_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTM_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTM_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA SOV Time + strct = strct + {{"BASTM_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTM_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTM_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTM_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTM_EV", "Real", 14, 6, "True", , , , , , , null}} + + // AB HOV Time + strct = strct + {{"ABHTM_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHTM_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHTM_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHTM_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABHTM_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA HOV Time + strct = strct + {{"BAHTM_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHTM_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHTM_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHTM_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BAHTM_EV", "Real", 14, 6, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + // initialize time and cost fields to 999999 + tod_fld = {{"ABSCST_EA"},{"ABSCST_AM"},{"ABSCST_MD"},{"ABSCST_PM"},{"ABSCST_EV"}, + {"BASCST_EA"},{"BASCST_AM"},{"BASCST_MD"},{"BASCST_PM"},{"BASCST_EV"}, + {"ABH2CST_EA"},{"ABH2CST_AM"},{"ABH2CST_MD"},{"ABH2CST_PM"},{"ABH2CST_EV"}, + {"BAH2CST_EA"},{"BAH2CST_AM"},{"BAH2CST_MD"},{"BAH2CST_PM"},{"BAH2CST_EV"}, + {"ABH3CST_EA"},{"ABH3CST_AM"},{"ABH3CST_MD"},{"ABH3CST_PM"},{"ABH3CST_EV"}, + {"BAH3CST_EA"},{"BAH3CST_AM"},{"BAH3CST_MD"},{"BAH3CST_PM"},{"BAH3CST_EV"}, + {"ABSTM_EA"},{"ABSTM_AM"},{"ABSTM_MD"},{"ABSTM_PM"},{"ABSTM_EV"}, + {"BASTM_EA"},{"BASTM_AM"},{"BASTM_MD"},{"BASTM_PM"},{"BASTM_EV"}, + {"ABHTM_EA"},{"ABHTM_AM"},{"ABHTM_MD"},{"ABHTM_PM"},{"ABHTM_EV"}, + {"BAHTM_EA"},{"BAHTM_AM"},{"BAHTM_MD"},{"BAHTM_PM"},{"BAHTM_EV"}, + {"ABLHCST_EA"},{"ABLHCST_AM"},{"ABLHCST_MD"},{"ABLHCST_PM"},{"ABLHCST_EV"}, + {"BALHCST_EA"},{"BALHCST_AM"},{"BALHCST_MD"},{"BALHCST_PM"},{"BALHCST_EV"}, + {"ABMHCST_EA"},{"ABMHCST_AM"},{"ABMHCST_MD"},{"ABMHCST_PM"},{"ABMHCST_EV"}, + {"BAMHCST_EA"},{"BAMHCST_AM"},{"BAMHCST_MD"},{"BAMHCST_PM"},{"BAMHCST_EV"}, + {"ABHHCST_EA"},{"ABHHCST_AM"},{"ABHHCST_MD"},{"ABHHCST_PM"},{"ABHHCST_EV"}, + {"BAHHCST_EA"},{"BAHHCST_AM"},{"BAHHCST_MD"},{"BAHHCST_PM"},{"BAHHCST_EV"}, + {"ABCVCST_EA"},{"ABCVCST_AM"},{"ABCVCST_MD"},{"ABCVCST_PM"},{"ABCVCST_EV"}, + {"BACVCST_EA"},{"BACVCST_AM"},{"BACVCST_MD"},{"BACVCST_PM"},{"BACVCST_EV"} + } + + // now calculate fields + for i=1 to tod_fld.length do + + calcString = {"999999"} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tod_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + + // set capacity fields + tod_fld ={{"ABCP_EA"},{"ABCP_AM"},{"ABCP_MD"},{"ABCP_PM"},{"ABCP_EV"}, //BA link capacity + {"BACP_EA"},{"BACP_AM"},{"BACP_MD"},{"BACP_PM"},{"BACP_EV"}, //AB link capacity + {"ABCX_EA"},{"ABCX_AM"},{"ABCX_MD"},{"ABCX_PM"},{"ABCX_EV"}, //BA intersection capacity + {"BACX_EA"},{"BACX_AM"},{"BACX_MD"},{"BACX_PM"},{"BACX_EV"}} //AB intersection capacity + + org_fld ={"ABCPO","ABCPA","ABCPO","ABCPP","ABCPO", + "BACPO","BACPA","BACPO","BACPP","BACPO", + "ABCXO","ABCXA","ABCXO","ABCXP","ABCXO", + "BACXO","BACXA","BACXO","BACXP","BACXO"} + + factor ={"3/12","1","6.5/12","3.5/3","8/12", + "3/12","1","6.5/12","3.5/3","8/12", + "3/12","1","6.5/12","3.5/3","8/12", + "3/12","1","6.5/12","3.5/3","8/12"} + + // now calculate capacity + for i=1 to tod_fld.length do + + calcString = {"if "+org_fld[i]+ " != 999999 then " + factor[i] + " * " + org_fld[i] + " else 999999"} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tod_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + + // set time fields + tod_fld ={{"ABTM_EA"},{"ABTM_AM"},{"ABTM_MD"},{"ABTM_PM"},{"ABTM_EV"}, //BA link time + {"BATM_EA"},{"BATM_AM"},{"BATM_MD"},{"BATM_PM"},{"BATM_EV"}, //AB link time + {"ABTX_EA"},{"ABTX_AM"},{"ABTX_MD"},{"ABTX_PM"},{"ABTX_EV"}, //BA intersection time + {"BATX_EA"},{"BATX_AM"},{"BATX_MD"},{"BATX_PM"},{"BATX_EV"}} //AB intersection time + + org_fld ={"ABTMO","ABTMA","ABTMO","ABTMP","ABTMO", + "BATMO","BATMA","BATMO","BATMP","BATMO", + "ABTXO","ABTXA","ABTXO","ABTXP","ABTXO", + "BATXO","BATXA","BATXO","BATXP","BATXO"} + + factor ={"1","1","1","1","1", + "1","1","1","1","1", + "1","1","1","1","1", + "1","1","1","1","1"} + + // now calculate time + for i=1 to tod_fld.length do + + calcString = { factor[i] + " * " + org_fld[i]} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tod_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // set lane fields + tod_fld ={{"ABLN_EA"},{"ABLN_AM"},{"ABLN_MD"},{"ABLN_PM"},{"ABLN_EV"}, //AB lanes + {"BALN_EA"},{"BALN_AM"},{"BALN_MD"},{"BALN_PM"},{"BALN_EV"}} //BA lanes + + org_fld ={"ABLNO","ABLNA","ABLNO","ABLNP","ABLNO", + "BALNO","BALNA","BALNO","BALNP","BALNO"} + + factor ={"1","1","1","1","1", + "1","1","1","1","1"} + + // now calculate time + for i=1 to tod_fld.length do + + calcString = { factor[i] + " * " + org_fld[i]} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = tod_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + RunMacro("close all") + + ok=1 + quit: + return(ok) +EndMacro + +/********************************************************************************************************** + Add link fields for reliability + + v/c factor fields: + {"ABLOSC_FACT"},{"ABLOSD_FACT"},{"ABLOSE_FACT"},{"ABLOSFL_FACT"},{"ABLOSFH_FACT"}, + {"BALOSC_FACT"},{"BALOSD_FACT"},{"BALOSE_FACT"},{"BALOSFL_FACT"},{"BALOSFH_FACT"}, + + static reliability fields: + {"ABSTATREL_EA"},{"ABSTATREL_AM"},{"ABSTATREL_MD"},{"ABSTATREL_PM"},{"ABSTATREL_EV"}, + {"BASTATREL_EA"},{"BASTATREL_AM"},{"BASTATREL_MD"},{"BASTATREL_PM"},{"BASTATREL_EV"} + + interchange fields - used in static reliability calculations + {"INTDIST_UP"},{"INTDIST_DOWN"} + + Regression equations for static reliability: + + static reliability(freeway) = intercept + coeff1*ISPD70 + coeff2*1/MajorUpstream + coeff3*1/MajorDownstream + static reliability(arterial) = intercept + coeff1*NumLanesOneLane + coeff2*NumLanesCatTwoLane + coeff3*NumLanesCatThreeLane + coeff4*NumLanesCatFourLanes + coeff5*NumLanesFiveMoreLane + + coeff6*ISPD.CatISPD35Less + coeff7*ISPD.CatISPD35 + coeff8*ISPD.CatISPD40 + coeff9*ISPD.CatISPD45 + coeff1*ISPD.CatISPD50 + coeff10*ISPD.CatISPD50More + + coeff11*ICNT.EstSignal + coeff12*ICNT.EstStop + coeff13*ICNT.EstRailRoad + + Where; + ISPD70: 1 if ISPD=70 else 0 (ISPD is posted speed) + MajorUpstream: distance to major interchange upstream (miles) + MajorDownstream: distance to major interchange downstream (miles) + NumLanesOneLane: 1 if lane=1 else 0 + NumLanesCatTwoLane: 1 if lane=2 else 0 + NumLanesCatThreeLane: 1 if lane=3 else 0 + NumLanesCatFourLanes: 1 if lane=4 else 0 + NumLanesFiveMoreLane: 1 if lane>=5 else 0 + ISPD.CatISPD35Less: 1 if ISPD <35 else 0 + ISPD.CatISPD35: 1 if ISPD =35 else 0 + ISPD.CatISPD40: 1 if ISPD =40 else 0 + ISPD.CatISPD45: 1 if ISPD =45 else 0 + ISPD.CatISPD50: 1 if ISPD =50 else 0 + ISPD.CatISPD50More: 1 if ISPD >=50 else 0 + ICNT.EstSignal: 1 if ICNT=1 else 0 (ICNT is intersection control type); signal-controlled + ICNT.EstStop: 1 if ICNT=2 or ICNT=3 else 0; stop-controlled + ICNT.EstRailRoad: 1 if ICNT>3 else 0; other - railroad etc. + + Steps: + 1. add new fields + 2. populate with default values + 3. calculate v/c factor fields by setting them to estimated coefficients by facility type - freeway and arterial. Ramp and other use arterial coefficients. + 4. pupulate interchange fields by joining highway database with major interchange distance file (output from distance to interchange macro). + 5. calculate static reliability fields for freeway + 6. calculate static reliability fields for arterial, ramp, and other + + Inputs + output\hwy.dbd + output\MajorInterchangeDistance.csv + + Outputs: + output\hwy.dbd (modified) + +by: nagendra.dhakar@rsginc.com +**********************************************************************************************************/ +Macro "add reliability fields" + + shared path, inputDir, outputDir + ok=0 + + db_file=outputDir+"\\hwy.dbd" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + db_link_lyr = db_file + "|" + link_lyr + + vw = SetView(link_lyr) + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + + // **** step 1. add new fields + + // AB v/c factors + strct = strct + {{"ABLOSC_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLOSD_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLOSE_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLOSFL_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABLOSFH_FACT", "Real", 14, 6, "True", , , , , , , null}} + + // BA v/c factors + strct = strct + {{"BALOSC_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALOSD_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALOSE_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALOSFL_FACT", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BALOSFH_FACT", "Real", 14, 6, "True", , , , , , , null}} + + // AB Static Reliability + strct = strct + {{"ABSTATREL_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTATREL_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTATREL_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTATREL_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ABSTATREL_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA Static Reliability + strct = strct + {{"BASTATREL_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTATREL_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTATREL_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTATREL_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BASTATREL_EV", "Real", 14, 6, "True", , , , , , , null}} + + // interchange distance + strct = strct + {{"INTDIST_UP", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"INTDIST_DOWN", "Real", 14, 6, "True", , , , , , , null}} + + // AB total reliability + strct = strct + {{"AB_TOTREL_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_TOTREL_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_TOTREL_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_TOTREL_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_TOTREL_EV", "Real", 14, 6, "True", , , , , , , null}} + + // BA total reliability + strct = strct + {{"BA_TOTREL_EA", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_TOTREL_AM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_TOTREL_MD", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_TOTREL_PM", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_TOTREL_EV", "Real", 14, 6, "True", , , , , , , null}} + + // reliability fields + reliability_fld = {{"ABLOSC_FACT"},{"ABLOSD_FACT"},{"ABLOSE_FACT"},{"ABLOSFL_FACT"},{"ABLOSFH_FACT"}, + {"BALOSC_FACT"},{"BALOSD_FACT"},{"BALOSE_FACT"},{"BALOSFL_FACT"},{"BALOSFH_FACT"}, + {"ABSTATREL_EA"},{"ABSTATREL_AM"},{"ABSTATREL_MD"},{"ABSTATREL_PM"},{"ABSTATREL_EV"}, + {"BASTATREL_EA"},{"BASTATREL_AM"},{"BASTATREL_MD"},{"BASTATREL_PM"},{"BASTATREL_EV"}, + {"AB_TOTREL_EA"},{"AB_TOTREL_AM"},{"AB_TOTREL_MD"},{"AB_TOTREL_PM"},{"AB_TOTREL_EV"}, + {"BA_TOTREL_EA"},{"BA_TOTREL_AM"},{"BA_TOTREL_MD"},{"BA_TOTREL_PM"},{"BA_TOTREL_EV"}} + + ModifyTable(view1, strct) + + // for debug + //RunMacro("TCB Init") + + // **** step 2. populate with default value of 0 + for i=1 to reliability_fld.length do + + calcString = {"0"} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = reliability_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // **** step 3. calculate v/c factor fields + + los_fld ={{"ABLOSC_FACT"},{"ABLOSD_FACT"},{"ABLOSE_FACT"},{"ABLOSFL_FACT"},{"ABLOSFH_FACT"}, //BA link time + {"BALOSC_FACT"},{"BALOSD_FACT"},{"BALOSE_FACT"},{"BALOSFL_FACT"},{"BALOSFH_FACT"}} //AB intersection time + + factor_freeway ={"0.2429","0.1705","-0.2278","-0.1983","1.022", + "0.2429","0.1705","-0.2278","-0.1983","1.022"} + + factor_arterial ={"0.1561","0.0","0.0","-0.1449","0", + "0.1561","0.0","0.0","-0.1449","0"} + + facility_type = {"freeway","arterial","ramp","other"} // freeway (IFC=1), arterial (IFC=2,3), ramp (IFC=8,9), other (IFC=4,5,6,7) + + // lower and upper bounds of IFC for respective facility type = {freeway, arterial, ramp, other} + lwr_bound = {"1","2","8","4"} + upr_bound = {"1","3","9","7"} + + // now calculate v/c factor fields + for fac_type=1 to facility_type.length do + + // set factors (coefficients) for facility type + if fac_type=1 then factor=factor_freeway + else factor=factor_arterial + + for i=1 to los_fld.length do + + query = "Select * where IFC >= " + lwr_bound[fac_type] + " and IFC <= "+upr_bound[fac_type] + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = los_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = factor[i] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + end + + // **** step 4. populate interchange fields (upstream/downstream distance to major interchange) + + distance_file = outputDir+"\\MajorInterchangeDistance.csv" + distance_fld = {"updistance","downdistance"} + + // interchange distance fields + interchange_fld = {{"INTDIST_UP"},{"INTDIST_DOWN"}} + + // set initial value to 9999 + for i=1 to interchange_fld.length do + + calcString = {"9999"} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = interchange_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // now set to distances - in miles + for i=1 to interchange_fld.length do + Opts = null + Opts.Input.[Dataview Set] = {{db_link_lyr, distance_file,{"ID"},{"LinkID"}},"JoinedView"} + Opts.Global.Fields = interchange_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = distance_fld[i] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + // **** step 5. calculate static reliability fields for freeway + + // static reliability(freeway) = intercept + coeff1*ISPD70 + coeff2*1/MajorUpstream + coeff3*1/MajorDownstream + + static_fld = {{"ABSTATREL_EA"},{"ABSTATREL_AM"},{"ABSTATREL_MD"},{"ABSTATREL_PM"},{"ABSTATREL_EV"}, + {"BASTATREL_EA"},{"BASTATREL_AM"},{"BASTATREL_MD"},{"BASTATREL_PM"},{"BASTATREL_EV"}} + + // Freeway coefficients + intercept = {"0.1078"} + speed_factor = {"0.01393"} // ISPD70 + interchange_factor = {"0.011","0.0005445"} //MajorUpstream.Inverse, MajorDownstream.Inverse + + fac_type=1 + factor=factor_freeway + + for i=1 to static_fld.length do + query = "Select * where IFC >= " + lwr_bound[fac_type] + " and IFC <= "+upr_bound[fac_type] + + // intercept + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = static_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = intercept[1] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + // ISPD - add to intercept + calcString = {"if ISPD=70 then " + static_fld[i][1] + "+" +speed_factor[1] + " else " + static_fld[i][1]} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = static_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + // Upstream interchange distance - apply inverse and add to intercept and ISPD + for j=1 to interchange_factor.length do + + calcString = {"if " + interchange_fld[j][1] + "<>null then " + static_fld[i][1] + "+" +interchange_factor[j]+"*1/"+interchange_fld[j][1] + " else " + static_fld[i][1]} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = static_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + + end + + // **** step 6. calculate static reliability fields for arterial, ramp, and other + + // Factors (coefficients) + intercept = {"0.0546552"} + lane_factor = {"0.0","0.0103589","0.0361211","0.0446958","0.0"} //{NumLanesOneLane, NumLanesCatTwoLane, NumLanesCatThreeLane, NumLanesCatFourLanes, NumLanesFiveMoreLane} + speed_factor = {"0.0","0.0075674","0.0091012","0.0080996","-0.0022938","-0.0046211"} //{ISPD.CatISPD35Less (base), ISPD.CatISPD35, ISPD.CatISPD40, ISPD.CatISPD45, ISPD.CatISPD50, ISPD.CatISPD50More} + intersection_factor = {"0.0030973","-0.0063281","0.0127692"} //{ICNT.EstSignal, ICNT.EstStop, ICNT.EstRailRoad} + + // lane fields in network + lane_fld ={{"ABLN_EA"},{"ABLN_AM"},{"ABLN_MD"},{"ABLN_PM"},{"ABLN_EV"}, //AB lanes + {"BALN_EA"},{"BALN_AM"},{"BALN_MD"},{"BALN_PM"},{"BALN_EV"}} //BA lanes + + // intersection fields in network + intersection_fld = {{"ABCNT"},{"ABCNT"},{"ABCNT"},{"ABCNT"},{"ABCNT"}, + {"BACNT"},{"BACNT"},{"BACNT"},{"BACNT"},{"BACNT"}} + + // static reliability(arterial) = intercept + coeff1*NumLanesOneLane + coeff2*NumLanesCatTwoLane + coeff3*umLanesCatThreeLane + coeff4*NumLanesCatFourLanes + coeff5*NumLanesFiveMoreLane+ + // coeff6*ISPD.CatISPD35Less + coeff7*ISPD.CatISPD35 + coeff8*ISPD.CatISPD40 + coeff9*ISPD.CatISPD45 + coeff1*ISPD.CatISPD50 + coeff10*ISPD.CatISPD50More+ + // coeff11*ICNT.EstSignal + coeff12*ICNT.EstStop + coeff13*ICNT.EstRailRoad + + for fac_type=2 to facility_type.length do + + // selection query - to identify links with a facility type + query = "Select * where IFC >= " + lwr_bound[fac_type] + " and IFC <= "+upr_bound[fac_type] + + for i=1 to static_fld.length do + + // intercept + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = static_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = intercept[1] + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + // NumLanes Factors + calcString = {"if " + lane_fld[i][1] + "=1 then "+static_fld[i][1] + "+" +lane_factor[1]+ + " else if " + lane_fld[i][1] + "=2 then "+static_fld[i][1] + "+" +lane_factor[2]+ + " else if " + lane_fld[i][1] + "=3 then "+static_fld[i][1] + "+" +lane_factor[3]+ + " else if " + lane_fld[i][1] + "=4 then "+static_fld[i][1] + "+" +lane_factor[4]+ + " else "+static_fld[i][1] + "+" +lane_factor[5]} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = static_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + // Speed Factors - + calcString = {"if ISPD<35 then "+static_fld[i][1] + "+" +speed_factor[1]+ + " else if ISPD=35 then "+static_fld[i][1] + "+" +speed_factor[2]+ + " else if ISPD=40 then "+static_fld[i][1] + "+" +speed_factor[3]+ + " else if ISPD=45 then "+static_fld[i][1] + "+" +speed_factor[4]+ + " else if ISPD=50 then "+static_fld[i][1] + "+" +speed_factor[5]+ + " else "+static_fld[i][1] + "+" +speed_factor[6]} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = static_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + // Intersection Factors + calcString = {"if " + intersection_fld[i][1]+ "=1 then " + static_fld[i][1] + "+" +intersection_factor[1]+ + " else if " + intersection_fld[i][1]+ "=2 or " + intersection_fld[i][1]+ "=3 then " + static_fld[i][1] + "+" + intersection_factor[2]+ + " else if " + intersection_fld[i][1]+ ">3 then " + static_fld[i][1] + "+" + intersection_factor[3] + + " else " + static_fld[i][1]} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection" , query} + Opts.Global.Fields = static_fld[i] + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + end + end + + RunMacro("close all") + + ok=1 + quit: + return(ok) +EndMacro +/************************************************************************************************ +add preload attributes + +Adds fields to highway line layer for storing preload volumes (currently bus volumes) + +************************************************************************************************/ +Macro "add preload attributes" + + shared path, inputDir, outputDir + + db_file=outputDir+"\\hwy.dbd" + + periods={"_EA","_AM","_MD","_PM","_EV"} + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + db_link_lyr = db_file + "|" + link_lyr + + vw = SetView(link_lyr) + strct = GetTableStructure(vw) + + // Copy the current name to the end of strct + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + + // Add fields to the output table + new_struct = strct + { + {"ABPRELOAD_EA", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_EA", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_AM", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_AM", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_MD", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_MD", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_PM", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_PM", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_EV", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_EV", "real", 14, 6, "False",,,,,,, null}} + + // Modify table structure + ModifyTable(vw, new_struct) + + // initialize to 0 + for i = 1 to periods.length do + + ABField = "ABPRELOAD"+periods[i] + BAField = "BAPRELOAD"+periods[i] + + //initialize to 0 + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {ABField} + Opts.Global.Method = "Value" + Opts.Global.Parameter = {0} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {BAField} + Opts.Global.Method = "Value" + Opts.Global.Parameter = {0} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + end + + + RunMacro("close all") + + ok=1 + quit: + return(ok) + +EndMacro +/************************************************************************************************** + +Macro Code VDF fields + +This macro codes fields for the Tucson volume-delay function on the input highway line layer. It +should be run prior to constructing highway networks for skim-building & assignment. Eventually +the logic in this macro will be replaced by GIS code. + +Functional class (IFC) + + 1 = Freeway + 2 = Prime arterial + 3 = Major arterial + 4 = Collector + 5 = Local collector + 6 = Rural collector + 7 = Local (non Circulation Element) road + 8 = Freeway connector ramps + 9 = Local ramps + 10 = Zone connectors + +Cycle length matrix + + Intersecting Link +Approach Link 2 3 4 5 6 7 8 9 +IFC Description Prime Arterial Major Arterial Collector Local Collector Rural Collector Local Road Freeway connector Local Ramp +2 Prime Arterial 2.5 2 2 2 2 2 2 2 +3 Major Arterial 2 2 2 2 2 2 2 2 +4 Collector 2 2 1.5 1.5 1.5 1.5 1.5 1.5 +5 Local Collector 2 2 1.5 1.25 1.25 1.25 1.25 1.25 +6 Rural Collector 2 2 1.5 1.25 1.25 1.25 1.25 1.25 +7 Local Road 2 2 1.5 1.25 1.25 1.25 1.25 1.25 +8 Freeway connector 2 2 1.5 1.25 1.25 1.25 1.25 1.25 +9 Local Ramp 2 2 1.5 1.25 1.25 1.25 1.25 1.25 + +Ramp with meter (abcnt = 4 or 5) + Cycle length = 2.5 + GC ratio 0.42 (adjusted down from 0.5 for yellow) + +Stop controlled intersection + Cycle length =1.25 + GC ratio 0.42 (adjusted down from 0.5 for yellow) + +*************************************************************************************************/ +Macro "Code VDF fields" + shared path, inputDir, outputDir + + db_file=outputDir+"\\hwy.dbd" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + db_link_lyr = db_file + "|" + link_lyr + + + // Add AB_Cycle, AB_PF, BA_Cycle, and BA_PF + vw = SetView(link_lyr) + strct = GetTableStructure(vw) + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + + strct = strct + {{"AB_GCRatio", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_GCRatio", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_Cycle", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_Cycle", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_PF", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_PF", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ALPHA1", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BETA1", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ALPHA2", "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BETA2", "Real", 14, 6, "True", , , , , , , null}} + ModifyTable(view1, strct) + + // Now set the view to the node layer + SetLayer(node_lyr) + + nodes = GetDataVector(node_lyr+"|", "ID",) + + //create from/end node field in the line layer + start_fld = CreateNodeField(link_lyr, "start_node", node_lyr+".ID", "From", ) + end_fld = CreateNodeField(link_lyr, "end_node", node_lyr+".ID", "To", ) + + //get the count of records for both line and node layer + tot_line_count = GetRecordCount(link_lyr, ) //get number of records in linelayer + tot_node_count = GetRecordCount(node_lyr, ) //get number of records in nodelayer + + //initilize several vectors +// linkclass = {Vector(tot_line_count, "Float", {{"Constant", null}}),Vector(tot_line_count, "Float", {{"Constant", null}})} //line link-classes + + //pass the attibutes to the vectors +// linkclass = GetDataVector(link_lyr+"|", "IFC",) + +// lineId = GetDataVector(link_lyr+"|", "ID",) + + + //go node by node + for i = 1 to tot_node_count do + + //find the IDs of the links that connect at the node, put the effective links to vector 'link_list' + link_list = null + rec_handles = null + + all_link_list = GetNodeLinks(nodes[i]) //get all links connecting at this node + link_list = Vector(all_link_list.length, "Short", {{"Constant", 0}}) //to contain non-connector/ramp links coming to the node + + all_rec_handles = Vector(all_link_list.length, "String", {{"Constant", null}}) //to contain the record handle of all links coming to the node + rec_handles = Vector(all_link_list.length, "String", {{"Constant", null}}) //to contain the record handle of the non-connector/ramp links coming to the node + + //count how many links entering the node + link_count = 0 + two_oneway = 0 + signal = 0 + + for j = 1 to all_link_list.length do + record_handle = LocateRecord(link_lyr+"|","ID",{all_link_list[j]}, {{"Exact", "True"}}) + all_rec_handles[j] = record_handle + + ends_at_node_AB_direction = 0 + ends_at_node_BA_direction = 0 + + signal_at_end = 0 + + if(link_lyr.end_node = nodes[i] and (link_lyr.Dir = 1 or link_lyr.Dir = 0)) then ends_at_node_AB_direction = 1 + if(link_lyr.start_node = nodes[i] and link_lyr.Dir = -1) then ends_at_node_AB_direction = 1 + if(link_lyr.start_node = nodes[i] and (link_lyr.Dir = 1 or link_lyr.Dir = 0)) then ends_at_node_BA_direction = 1 + + if ( ends_at_node_AB_direction = 1 and (link_lyr.[ABGC] <> null and link_lyr.[ABGC] > 0)) then signal_at_end = 1 + if ( ends_at_node_BA_direction = 1 and (link_lyr.[BAGC] <> null and link_lyr.[BAGC] > 0)) then signal_at_end = 1 + + + //only count the links that have approach toward the node + if( ends_at_node_AB_direction = 1 and signal_at_end = 1) then do + signal = signal + 1 + end + else if( ends_at_node_BA_direction and signal_at_end = 1) then do + signal = signal + 1 + end + + link_count = link_count + 1 + link_list[link_count] = all_link_list[j] + rec_handles[link_count] = record_handle + if link_lyr.Dir <> 0 then two_oneway = two_oneway+1 + + + end + + // if at least one incoming link has a gc ratio + if (signal>0) then do + min_lc = 999 + max_lc = 0 + //process the links and find the lowest and highest linkclasses + for j = 1 to link_count do + //find the line record that owns the line ID + SetRecord(link_lyr, rec_handles[j]) //set the current record with the record handle stored in vector 'rec_handles' + + if ((link_lyr.end_node = nodes[i] and (link_lyr.Dir = 1 or link_lyr.Dir = 0)) or + (link_lyr.start_node = nodes[i] and link_lyr.Dir = -1))then do + if link_lyr.[IFC] <> null and link_lyr.[IFC] > 1 and link_lyr.[IFC] < 10 then do //don't count freeways or centroid connectors + if link_lyr.[IFC] > max_lc then max_lc = link_lyr.[IFC] + if link_lyr.[IFC] < min_lc then min_lc = link_lyr.[IFC] + end + end + + end + end + + //iterate through all links at this node and set cycle length + for j = 1 to all_link_list.length do + + SetRecord(link_lyr, all_rec_handles[j]) //set the current record with the record handle stored in vector 'all_rec_handles' + + if(link_lyr.end_node = nodes[i] and (link_lyr.Dir = 1 or link_lyr.Dir = 0)) then ends_at_node_AB_direction = 1 + if(link_lyr.start_node = nodes[i] and link_lyr.Dir = -1) then ends_at_node_AB_direction = 1 + if(link_lyr.start_node = nodes[i] and (link_lyr.Dir = 1 or link_lyr.Dir = 0)) then ends_at_node_BA_direction = 1 + + // Set AB fields for links whose end node is this node and are coded in the A->B direction + if (ends_at_node_AB_direction = 1) then do + + //defaults are 1.25 minute cycle length and 1.0 progression factor + c_len = 1.25 + p_factor = 1.0 + + //set up the cycle length for AB direction if there is a gc ratio and more than 2 links + if (link_lyr.[ABGC]<>0 and signal > 0) then do + + if (link_lyr.[IFC] = 2) then do + if (max_lc = 2) then c_len = 2.5 //Prime arterial & Prime arterial + else c_len = 2.0 //Prime arterial & anything lower + end + else if (link_lyr.[IFC] = 3) then do + if (max_lc > 3) then c_len = 2.0 //Major arterial & anything lower than a Major arterial + else c_len = 2.0 //Major arterial & Prime arterial or Major arterial + end + else if (link_lyr.[IFC] = 4) then do + if (min_lc < 4) then c_len = 2.0 //Anything lower than a Major arterial & Prime arterial + else c_len = 1.5 //Anything lower than a Major arterial & anything lower than a Prime arterial + end + else if (link_lyr.[IFC] > 4) then do + if (min_lc < 4) then c_len = 2.0 + if (min_lc = 4) then c_len = 1.5 + if (min_lc > 4) then c_len = 1.25 + end + + //update attributes + if( link_lyr.[ABGC] > 10) then link_lyr.[AB_GCRatio] = link_lyr.[ABGC]/100 + if( link_lyr.[AB_GCRatio] > 1.0) then link_lyr.[AB_GCRatio] = 1.0 + + link_lyr.[AB_Cycle] = c_len + link_lyr.[AB_PF] = p_factor + + end + + end // end for AB links + + // Set BA fields for links whose start node is this node and are coded in the A->B direction + if (ends_at_node_BA_direction = 1 ) then do + + // Only code links with an existing GC ratio (indicating a signalized intersection) + if (link_lyr.[BAGC]<>0 and signal > 0) then do + + //defaults are 0.4 gc ratio, 1.25 minute cycle length and 1.0 progression factor + gc_ratio = 0.4 + c_len = 1.25 + p_factor = 1.0 + + if (link_lyr.[IFC] = 2) then do + if (max_lc = 2) then c_len = 2.5 //Prime arterial & Prime arterial + else c_len = 2.0 //Prime arterial & anything lower + end + else if (link_lyr.[IFC] = 3) then do + if (max_lc > 3) then c_len = 2.0 //Major arterial & anything lower than a Major arterial + else c_len = 2.0 //Major arterial & Prime arterial or Major arterial + end + else if (link_lyr.[IFC] = 4) then do + if (min_lc < 4) then c_len = 2.0 //Anything lower than a Major arterial & Prime arterial + else c_len = 1.5 //Anything lower than a Major arterial & anything lower than a Prime arterial + end + else if (link_lyr.[IFC] > 4) then do + if (min_lc < 4) then c_len = 2.0 + if (min_lc = 4) then c_len = 1.5 + if (min_lc > 4) then c_len = 1.25 + end + + //update attributes + if( link_lyr.[BAGC] > 10) then link_lyr.[BA_GCRatio] = link_lyr.[BAGC]/100 + if( link_lyr.[BA_GCRatio] > 1.0) then link_lyr.[BA_GCRatio] = 1.0 + link_lyr.[BA_Cycle] = c_len + link_lyr.[BA_PF] = p_factor + + end + + end // end for BA links + + //code metered ramps AB Direction + if(ends_at_node_AB_direction = 1 and (link_lyr.[ABCNT]= 4 or link_lyr.[ABCNT] = 5)) then do + link_lyr.[AB_Cycle] = 2.5 + link_lyr.[AB_GCRatio] = 0.42 + link_lyr.[AB_PF] = 1.0 + end + + //code metered ramps BA Direction + if(ends_at_node_BA_direction = 1 and (link_lyr.[BACNT]= 4 or link_lyr.[BACNT] = 5)) then do + link_lyr.[BA_Cycle] = 2.5 + link_lyr.[BA_GCRatio] = 0.42 + link_lyr.[BA_PF] = 1.0 + end + + //code stops AB Direction + if(ends_at_node_AB_direction = 1 and (link_lyr.[ABCNT]= 2 or link_lyr.[ABCNT] = 3)) then do + link_lyr.[AB_Cycle] = 1.25 + link_lyr.[AB_GCRatio] = 0.42 + link_lyr.[AB_PF] = 1.0 + end + + //code stops BA Direction + if(ends_at_node_BA_direction = 1 and (link_lyr.[BACNT]= 2 or link_lyr.[BACNT] = 3)) then do + link_lyr.[BA_Cycle] = 1.25 + link_lyr.[BA_GCRatio] = 0.42 + link_lyr.[BA_PF] = 1.0 + end + + end // end for links + + end // end for nodes + + + // set alpha1 and beta1 fields, which are based upon free-flow speed to match POSTLOAD loaded time factors + lwr_bound = { " 0", "25", "30", "35", "40", "45", "50", "55", "60", "65", "70", "75"} + upr_bound = { "24", "29", "34", "39", "44", "49", "54", "59", "64", "69", "74", "99"} + alpha1 = {"0.8","0.8","0.8","0.8","0.8","0.8","0.8","0.8","0.8","0.8","0.8","0.8"} + beta1 = { "4", "4", "4", "4", "4", "4", "4", "4", "4", "4" , "4", "4"} + + for j = 1 to lwr_bound.length do + + //alpha1 + calcString = { "if ISPD >= " + lwr_bound[j] + " and ISPD <= "+upr_bound[j] + " then "+alpha1[j]+" else ALPHA1"} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"ALPHA1"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + //beta1 + calcString = { "if ISPD >= " + lwr_bound[j] + " and ISPD <= "+upr_bound[j] + " then "+beta1[j]+" else BETA1"} + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"BETA1"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = calcString + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + end + + //set alpha2 and beta2 fields (note that signalized intersections and stop-controlled intersections have same parameters, only meters vary) + alpha2_default = "4.5" + beta2_default = "2.0" + alpha2_meter = "6.0" + beta2_meter = "2.0" + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"ALPHA2","BETA2"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {alpha2_default, beta2_default} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr,"Selection", "Select * where (abcnt=4 or abcnt=5)"} + Opts.Global.Fields = {"ALPHA2","BETA2"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {alpha2_meter,beta2_meter} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + // replicate across all time periods and add fields for vdf parameters + periods = {"_EA", "_AM", "_MD", "_PM", "_EV"} + meters = { 0, 1, 0, 1, 0} + + for i = 1 to periods.length do + + // Add AB_Cycle, AB_PF, BA_Cycle, and BA_PF + vw = SetView(link_lyr) + strct = GetTableStructure(vw) + for j = 1 to strct.length do + strct[j] = strct[j] + {strct[j][1]} + end + + strct = strct + {{"AB_GCRatio"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_GCRatio"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_Cycle"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_Cycle"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"AB_PF"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BA_PF"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ALPHA1"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BETA1"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"ALPHA2"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + strct = strct + {{"BETA2"+periods[i], "Real", 14, 6, "True", , , , , , , null}} + + ModifyTable(view1, strct) + + in_fld ={"AB_GCRatio", "BA_GCRatio", "AB_Cycle","BA_Cycle","AB_PF","BA_PF"} + + out_fld ={"AB_GCRatio"+periods[i],"BA_GCRatio"+periods[i],"AB_Cycle"+periods[i],"BA_Cycle"+periods[i],"AB_PF"+periods[i],"BA_PF"+periods[i]} + + + values = {0.0,0.0,0.0,0.0,1.0,1.0} + // set GCRatio, Cycle length, PF + for j=1 to out_fld.length do + + //initialize to 0 + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {out_fld[j]} + Opts.Global.Method = "Value" + Opts.Global.Parameter = {values[j]} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr, "Selection", "Select * where "+in_fld[j]+"> 0 and "+in_fld[j]+"<>null"} + Opts.Global.Fields = {out_fld[j]} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {in_fld[j]} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + end + + // reset GCRatio, cycle length and PF fields to 0 if metered ramp and off-peak period + if(meters[i] = 0) then do + + for j=1 to out_fld.length do + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr,"Selection", "Select * where (abcnt=4 or abcnt=5)"} + Opts.Global.Fields = {out_fld[j]} + Opts.Global.Method = "Value" + Opts.Global.Parameter = {values[j]} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + end + end + + + //set alpha1 and beta1 fields, which currently do not vary by time period + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"ALPHA1"+periods[i], "BETA1"+periods[i]} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"ALPHA1","BETA1"} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + //set alpha2 and beta2 fields, which currently do not vary by time period + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"ALPHA2"+periods[i],"BETA2"+periods[i]} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"ALPHA2","BETA2"} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + end // end for periods + + quit: + return(ok) +EndMacro +//***************************************************************************************************************************************************************** + +/************************************************************************8 +build highway network in TransCAD format +input file: + hwy.dbd - hwy line geographic file + turns.csv - turn prohibitor csv file, fields: from (link), to (link), penalty (null) + inktypeturns.dbf - dbf file between freeways and ramp added 0.5 min penalty + linktypelog.dbf - link type look up binary file, format for MMA assignment + +output file: hwy.net - hwy network file + link field included in network file: + Length (in miles) + IFC: functional classification, also used as link type look up field + *TM_EA (ABTM_EA/BATM_EA): Early AM period link travel time + *TM_AM (ABTM_AM/BATM_AM): AM Peak period link travel time + *TM_MD (ABTM_MD/BATM_MD): Midday period link travel time + *TM_PM (ABTM_PM/BATM_PM): PM Peak period link travel time + *TM_EV (ABTM_EV/BATM_EV): Evening period link travel time + *CP_EA (ABCP_EA/BACP_EA): Early AM period link capacity + *CP_AM (ABCP_AM/BACP_AM): AM Peak period link capacity + *CP_MD (ABCP_MD/BACP_MD): Midday period link capacity + *CP_PM (ABCP_PM/BACP_PM): PM Peak period link capacity + *CP_EV (ABCP_EV/BACP_EV): Evening period link capacity + *TX_EA (ABTX_EA/BATX_EA): Early AM period intersection travel time + *TX_AM (ABTX_AM/BATX_AM): AM Peak period intersection travel time + *TX_MD (ABTX_MD/BATX_MD): Midday period intersection travel time + *TX_PM (ABTX_PM/BATX_PM): PM Peak period intersection travel time + *TX_EV (ABTX_EV/BATX_EV): Evening period intersection travel time + *CX_EA (ABCX_EA/BACX_EA): Early AM period intersection capacity + *CX_AM (ABCX_AM/BACX_AM): AM Peak period intersection capacity + *CX_MD (ABCX_MD/BACX_MD): Midday period intersection capacity + *CX_PM (ABCX_PM/BACX_PM): PM Peak period intersection capacity + *CX_EV (ABCX_EV/BACX_EV): Evening period intersection capacity + COST: cost of distance (in cents) 19cents/mile + *CST (ABCST/BACST): generalized cost (in cents) of 19cents/mile + 35cents/minute + *SCST + *H2CST + *H3CST + ID: link ID of hwycad-id + + specify zone centroids, and create network + change network settings with linktype lookup table + turn prohibitors and link type turn penalty file + +************************************************************************************/ + +macro "create hwynet" + shared path, mxzone, inputDir, outputDir + ok = 0 + + RunMacro("close all") + + + // fpr=openfile(path+"\\hwycad.log","a") + // mytime=GetDateAndTime() + + //input file + db_file = outputDir + "\\hwy.dbd" + d_tp_tb = inputDir + "\\linktypeturns.dbf" //turn penalty in cents + s_tp_tb = outputDir + "\\turns.dbf" + + //output files + net_file = outputDir+"\\hwy.net" + + di2= GetDirectoryInfo(d_tp_tb, "file") + di3= GetDirectoryInfo(s_tp_tb, "file") + //check for files + if di2.length=0 and di3.length=0 then do + RunMacro("TCB Error",d_tp_tb+" "+s_tp_tb+" does not exist!") + goto quit + end + + // RunMacro("TCB Init") + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file,,) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + + db_link_lyr=db_file+"|"+link_lyr + db_node_lyr=db_file+"|"+node_lyr + + // STEP 1: Build Highway Network + Opts = null + Opts.Input.[Link Set] = {db_link_lyr,link_lyr} + Opts.Global.[Network Options].[Node ID] = node_lyr+ ".ID" + Opts.Global.[Network Options].[Link ID] = link_lyr + ".ID" + Opts.Global.[Network Options].[Turn Penalties] = "Yes" + Opts.Global.[Network Options].[Keep Duplicate Links] = "FALSE" + Opts.Global.[Network Options].[Ignore Link Direction] = "FALSE" + Opts.Global.[Link Options] = {{"Length", link_lyr+".Length", link_lyr+".Length"}, + {"ID", link_lyr+".ID", link_lyr+".ID"}, + {"IFC", link_lyr+".IFC", link_lyr+".IFC"}, + {"IHOV", link_lyr+".IHOV", link_lyr+".IHOV"}, + {"COST", link_lyr+".COST", link_lyr+".COST"}, + {"*LN_EA", link_lyr + ".ABLN_EA", link_lyr + ".BALN_EA"}, + {"*LN_AM", link_lyr + ".ABLN_AM", link_lyr + ".BALN_AM"}, + {"*LN_MD", link_lyr + ".ABLN_MD", link_lyr + ".BALN_MD"}, + {"*LN_PM", link_lyr + ".ABLN_PM", link_lyr + ".BALN_PM"}, + {"*LN_EV", link_lyr + ".ABLN_EV", link_lyr + ".BALN_EV"}, + {"ITOLL_EA", link_lyr + ".ITOLL_EA", link_lyr + ".ITOLL_EA"}, // Oct-08-2010, added to include toll+cost + {"ITOLL_AM", link_lyr + ".ITOLL_AM", link_lyr + ".ITOLL_AM"}, // Oct-08-2010, added to include toll+cost + {"ITOLL_MD", link_lyr + ".ITOLL_MD", link_lyr + ".ITOLL_MD"}, // Oct-08-2010, added to include toll+cost + {"ITOLL_PM", link_lyr + ".ITOLL_PM", link_lyr + ".ITOLL_PM"}, // Oct-08-2010, added to include toll+cost + {"ITOLL_EV", link_lyr + ".ITOLL_EV", link_lyr + ".ITOLL_EV"}, // Oct-08-2010, added to include toll+cost + {"ITOLL2_EA", link_lyr + ".ITOLL2_EA", link_lyr + ".ITOLL2_EA"}, // Oct-08-2010, added to include toll+cost + {"ITOLL2_AM", link_lyr + ".ITOLL2_AM", link_lyr + ".ITOLL2_AM"}, // Oct-08-2010, added to include toll+cost + {"ITOLL2_MD", link_lyr + ".ITOLL2_MD", link_lyr + ".ITOLL2_MD"}, // Oct-08-2010, added to include toll+cost + {"ITOLL2_PM", link_lyr + ".ITOLL2_PM", link_lyr + ".ITOLL2_PM"}, // Oct-08-2010, added to include toll+cost + {"ITOLL2_EV", link_lyr + ".ITOLL2_EV", link_lyr + ".ITOLL2_EV"}, // Oct-08-2010, added to include toll+cost + {"ITOLL3_EA", link_lyr + ".ITOLL3_EA", link_lyr + ".ITOLL3_EA"}, // Oct-08-2010, added to include toll+cost + {"ITOLL3_AM", link_lyr + ".ITOLL3_AM", link_lyr + ".ITOLL3_AM"}, // Oct-08-2010, added to include toll+cost + {"ITOLL3_MD", link_lyr + ".ITOLL3_MD", link_lyr + ".ITOLL3_MD"}, // Oct-08-2010, added to include toll+cost + {"ITOLL3_PM", link_lyr + ".ITOLL3_PM", link_lyr + ".ITOLL3_PM"}, // Oct-08-2010, added to include toll+cost + {"ITOLL3_EV", link_lyr + ".ITOLL3_EV", link_lyr + ".ITOLL3_EV"}, // Oct-08-2010, added to include toll+cost + {"ITOLL4_EA", link_lyr + ".ITOLL4_EA", link_lyr + ".ITOLL4_EA"}, // Nov-3-2010, added lhd & mhd toll=2*toll+cost + {"ITOLL4_AM", link_lyr + ".ITOLL4_AM", link_lyr + ".ITOLL4_AM"}, // Nov-3-2010, added lhd & mhd toll=2*toll+cost + {"ITOLL4_MD", link_lyr + ".ITOLL4_MD", link_lyr + ".ITOLL4_MD"}, // Nov-3-2010, added lhd & mhd toll=2*toll+cost + {"ITOLL4_PM", link_lyr + ".ITOLL4_PM", link_lyr + ".ITOLL4_PM"}, // Nov-3-2010, added lhd & mhd toll=2*toll+cost + {"ITOLL4_EV", link_lyr + ".ITOLL4_EV", link_lyr + ".ITOLL4_EV"}, // Nov-3-2010, added lhd & mhd toll=2*toll+cost + {"ITOLL5_EA", link_lyr + ".ITOLL5_EA", link_lyr + ".ITOLL5_EA"}, // Nov-3-2010, added hhd toll = 3*toll+cost + {"ITOLL5_AM", link_lyr + ".ITOLL5_AM", link_lyr + ".ITOLL5_AM"}, // Nov-3-2010, added hhd toll = 3*toll+cost + {"ITOLL5_MD", link_lyr + ".ITOLL5_MD", link_lyr + ".ITOLL5_MD"}, // Nov-3-2010, added hhd toll = 3*toll+cost + {"ITOLL5_PM", link_lyr + ".ITOLL5_PM", link_lyr + ".ITOLL5_PM"}, // Nov-3-2010, added hhd toll = 3*toll+cost + {"ITOLL5_EV", link_lyr + ".ITOLL5_EV", link_lyr + ".ITOLL5_EV"}, // Nov-3-2010, added hhd toll = 3*toll+cost + {"ITRUCK", link_lyr + ".ITRUCK", link_lyr + ".ITRUCK"}, // Sep-30-2011, added ITRUCK to the network + {"*CP_EA", link_lyr+".ABCP_EA", link_lyr+".BACP_EA"}, + {"*CP_AM", link_lyr+".ABCP_AM", link_lyr+".BACP_AM"}, + {"*CP_MD", link_lyr+".ABCP_MD", link_lyr+".BACP_MD"}, + {"*CP_PM", link_lyr+".ABCP_PM", link_lyr+".BACP_PM"}, + {"*CP_EV", link_lyr+".ABCP_EV", link_lyr+".BACP_EV"}, + {"*CX_EA", link_lyr+".ABCX_EA", link_lyr+".BACX_EA"}, + {"*CX_AM", link_lyr+".ABCX_AM", link_lyr+".BACX_AM"}, + {"*CX_MD", link_lyr+".ABCX_MD", link_lyr+".BACX_MD"}, + {"*CX_PM", link_lyr+".ABCX_PM", link_lyr+".BACX_PM"}, + {"*CX_EV", link_lyr+".ABCX_EV", link_lyr+".BACX_EV"}, + {"*TM_EA", link_lyr+".ABTM_EA", link_lyr+".BATM_EA"}, + {"*TM_AM", link_lyr+".ABTM_AM", link_lyr+".BATM_AM"}, + {"*TM_MD", link_lyr+".ABTM_MD", link_lyr+".BATM_MD"}, + {"*TM_PM", link_lyr+".ABTM_PM", link_lyr+".BATM_PM"}, + {"*TM_EV", link_lyr+".ABTM_EV", link_lyr+".BATM_EV"}, + {"*TX_EA", link_lyr+".ABTX_EA", link_lyr+".BATX_EA"}, + {"*TX_AM", link_lyr+".ABTX_AM", link_lyr+".BATX_AM"}, + {"*TX_MD", link_lyr+".ABTX_MD", link_lyr+".BATX_MD"}, + {"*TX_PM", link_lyr+".ABTX_PM", link_lyr+".BATX_PM"}, + {"*TX_EV", link_lyr+".ABTX_EV", link_lyr+".BATX_EV"}, + {"*CST", link_lyr+".ABCST", link_lyr+".BACST"}, + {"*SCST_EA", link_lyr+".ABSCST_EA", link_lyr+".BASCST_EA"}, + {"*SCST_AM", link_lyr+".ABSCST_AM", link_lyr+".BASCST_AM"}, + {"*SCST_MD", link_lyr+".ABSCST_MD", link_lyr+".BASCST_MD"}, + {"*SCST_PM", link_lyr+".ABSCST_PM", link_lyr+".BASCST_PM"}, + {"*SCST_EV", link_lyr+".ABSCST_EV", link_lyr+".BASCST_EV"}, + {"*H2CST_EA", link_lyr+".ABH2CST_EA", link_lyr+".BAH2CST_EA"}, + {"*H2CST_AM", link_lyr+".ABH2CST_AM", link_lyr+".BAH2CST_AM"}, + {"*H2CST_MD", link_lyr+".ABH2CST_MD", link_lyr+".BAH2CST_MD"}, + {"*H2CST_PM", link_lyr+".ABH2CST_PM", link_lyr+".BAH2CST_PM"}, + {"*H2CST_EV", link_lyr+".ABH2CST_EV", link_lyr+".BAH2CST_EV"}, + {"*H3CST_EA", link_lyr+".ABH3CST_EA", link_lyr+".BAH3CST_EA"}, + {"*H3CST_AM", link_lyr+".ABH3CST_AM", link_lyr+".BAH3CST_AM"}, + {"*H3CST_MD", link_lyr+".ABH3CST_MD", link_lyr+".BAH3CST_MD"}, + {"*H3CST_PM", link_lyr+".ABH3CST_PM", link_lyr+".BAH3CST_PM"}, + {"*H3CST_EV", link_lyr+".ABH3CST_EV", link_lyr+".BAH3CST_EV"}, + {"*LHCST_EA", link_lyr+".ABLHCST_EA", link_lyr+".BALHCST_EA"}, + {"*LHCST_AM", link_lyr+".ABLHCST_AM", link_lyr+".BALHCST_AM"}, + {"*LHCST_MD", link_lyr+".ABLHCST_MD", link_lyr+".BALHCST_MD"}, + {"*LHCST_PM", link_lyr+".ABLHCST_PM", link_lyr+".BALHCST_PM"}, + {"*LHCST_EV", link_lyr+".ABLHCST_EV", link_lyr+".BALHCST_EV"}, + {"*MHCST_EA", link_lyr+".ABMHCST_EA", link_lyr+".BAMHCST_EA"}, + {"*MHCST_AM", link_lyr+".ABMHCST_AM", link_lyr+".BAMHCST_AM"}, + {"*MHCST_MD", link_lyr+".ABMHCST_MD", link_lyr+".BAMHCST_MD"}, + {"*MHCST_PM", link_lyr+".ABMHCST_PM", link_lyr+".BAMHCST_PM"}, + {"*MHCST_EV", link_lyr+".ABMHCST_EV", link_lyr+".BAMHCST_EV"}, + {"*HHCST_EA", link_lyr+".ABHHCST_EA", link_lyr+".BAHHCST_EA"}, + {"*HHCST_AM", link_lyr+".ABHHCST_AM", link_lyr+".BAHHCST_AM"}, + {"*HHCST_MD", link_lyr+".ABHHCST_MD", link_lyr+".BAHHCST_MD"}, + {"*HHCST_PM", link_lyr+".ABHHCST_PM", link_lyr+".BAHHCST_PM"}, + {"*HHCST_EV", link_lyr+".ABHHCST_EV", link_lyr+".BAHHCST_EV"}, + {"*CVCST_EA", link_lyr+".ABCVCST_EA", link_lyr+".BACVCST_EA"}, + {"*CVCST_AM", link_lyr+".ABCVCST_AM", link_lyr+".BACVCST_AM"}, + {"*CVCST_MD", link_lyr+".ABCVCST_MD", link_lyr+".BACVCST_MD"}, + {"*CVCST_PM", link_lyr+".ABCVCST_PM", link_lyr+".BACVCST_PM"}, + {"*CVCST_EV", link_lyr+".ABCVCST_EV", link_lyr+".BACVCST_EV"}, + {"*STM_EA", link_lyr+".ABSTM_EA", link_lyr+".BASTM_EA"}, + {"*STM_AM", link_lyr+".ABSTM_AM", link_lyr+".BASTM_AM"}, + {"*STM_MD", link_lyr+".ABSTM_MD", link_lyr+".BASTM_MD"}, + {"*STM_PM", link_lyr+".ABSTM_PM", link_lyr+".BASTM_PM"}, + {"*STM_EV", link_lyr+".ABSTM_EV", link_lyr+".BASTM_EV"}, + {"*HTM_EA", link_lyr+".ABHTM_EA", link_lyr+".BAHTM_EA"}, + {"*HTM_AM", link_lyr+".ABHTM_AM", link_lyr+".BAHTM_AM"}, + {"*HTM_MD", link_lyr+".ABHTM_MD", link_lyr+".BAHTM_MD"}, + {"*HTM_PM", link_lyr+".ABHTM_PM", link_lyr+".BAHTM_PM"}, + {"*HTM_EV", link_lyr+".ABHTM_EV", link_lyr+".BAHTM_EV"}, + {"*GCRATIO_EA", link_lyr+".AB_GCRatio_EA", link_lyr+".BA_GCRatio_EA"}, + {"*GCRATIO_AM", link_lyr+".AB_GCRatio_AM", link_lyr+".BA_GCRatio_AM"}, + {"*GCRATIO_MD", link_lyr+".AB_GCRatio_MD", link_lyr+".BA_GCRatio_MD"}, + {"*GCRATIO_PM", link_lyr+".AB_GCRatio_PM", link_lyr+".BA_GCRatio_PM"}, + {"*GCRATIO_EV", link_lyr+".AB_GCRatio_EV", link_lyr+".BA_GCRatio_EV"}, + {"*CYCLE_EA", link_lyr+".AB_Cycle_EA", link_lyr+".BA_Cycle_EA"}, + {"*CYCLE_AM", link_lyr+".AB_Cycle_AM", link_lyr+".BA_Cycle_AM"}, + {"*CYCLE_MD", link_lyr+".AB_Cycle_MD", link_lyr+".BA_Cycle_MD"}, + {"*CYCLE_PM", link_lyr+".AB_Cycle_PM", link_lyr+".BA_Cycle_PM"}, + {"*CYCLE_EV", link_lyr+".AB_Cycle_EV", link_lyr+".BA_Cycle_EV"}, + {"*PF_EA", link_lyr+".AB_PF_EA", link_lyr+".BA_PF_EA"}, + {"*PF_AM", link_lyr+".AB_PF_AM", link_lyr+".BA_PF_AM"}, + {"*PF_MD", link_lyr+".AB_PF_MD", link_lyr+".BA_PF_MD"}, + {"*PF_PM", link_lyr+".AB_PF_PM", link_lyr+".BA_PF_PM"}, + {"*PF_EV", link_lyr+".AB_PF_EV", link_lyr+".BA_PF_EV"}, + {"*ALPHA1_EA", link_lyr+".ALPHA1_EA", link_lyr+".ALPHA1_EA"}, + {"*ALPHA1_AM", link_lyr+".ALPHA1_AM", link_lyr+".ALPHA1_AM"}, + {"*ALPHA1_MD", link_lyr+".ALPHA1_MD", link_lyr+".ALPHA1_MD"}, + {"*ALPHA1_PM", link_lyr+".ALPHA1_PM", link_lyr+".ALPHA1_PM"}, + {"*ALPHA1_EV", link_lyr+".ALPHA1_EV", link_lyr+".ALPHA1_EV"}, + {"*BETA1_EA", link_lyr+".BETA1_EA", link_lyr+".BETA1_EA"}, + {"*BETA1_AM", link_lyr+".BETA1_AM", link_lyr+".BETA1_AM"}, + {"*BETA1_MD", link_lyr+".BETA1_MD", link_lyr+".BETA1_MD"}, + {"*BETA1_PM", link_lyr+".BETA1_PM", link_lyr+".BETA1_PM"}, + {"*BETA1_EV", link_lyr+".BETA1_EV", link_lyr+".BETA1_EV"}, + {"*ALPHA2_EA", link_lyr+".ALPHA2_EA", link_lyr+".ALPHA2_EA"}, + {"*ALPHA2_AM", link_lyr+".ALPHA2_AM", link_lyr+".ALPHA2_AM"}, + {"*ALPHA2_MD", link_lyr+".ALPHA2_MD", link_lyr+".ALPHA2_MD"}, + {"*ALPHA2_PM", link_lyr+".ALPHA2_PM", link_lyr+".ALPHA2_PM"}, + {"*ALPHA2_EV", link_lyr+".ALPHA2_EV", link_lyr+".ALPHA2_EV"}, + {"*BETA2_EA", link_lyr+".BETA2_EA", link_lyr+".BETA2_EA"}, + {"*BETA2_AM", link_lyr+".BETA2_AM", link_lyr+".BETA2_AM"}, + {"*BETA2_MD", link_lyr+".BETA2_MD", link_lyr+".BETA2_MD"}, + {"*BETA2_PM", link_lyr+".BETA2_PM", link_lyr+".BETA2_PM"}, + {"*BETA2_EV", link_lyr+".BETA2_EV", link_lyr+".BETA2_EV"}, + {"*PRELOAD_EA", link_lyr+".ABPRELOAD_EA", link_lyr+".BAPRELOAD_EA"}, + {"*PRELOAD_AM", link_lyr+".ABPRELOAD_AM", link_lyr+".BAPRELOAD_AM"}, + {"*PRELOAD_MD", link_lyr+".ABPRELOAD_MD", link_lyr+".BAPRELOAD_MD"}, + {"*PRELOAD_PM", link_lyr+".ABPRELOAD_PM", link_lyr+".BAPRELOAD_PM"}, + {"*PRELOAD_EV", link_lyr+".ABPRELOAD_EV", link_lyr+".BAPRELOAD_EV"}, + {"*LOSC_FACT", link_lyr+".ABLOSC_FACT", link_lyr+".BALOSC_FACT"}, // added for reliability - 02/02/2016 + {"*LOSD_FACT", link_lyr+".ABLOSD_FACT", link_lyr+".BALOSD_FACT"}, // added for reliability - 02/02/2016 + {"*LOSE_FACT", link_lyr+".ABLOSE_FACT", link_lyr+".BALOSE_FACT"}, // added for reliability - 02/02/2016 + {"*LOSFL_FACT", link_lyr+".ABLOSFL_FACT", link_lyr+".BALOSFL_FACT"}, // added for reliability - 02/02/2016 + {"*LOSFH_FACT", link_lyr+".ABLOSFH_FACT", link_lyr+".BALOSFH_FACT"}, // added for reliability - 02/02/2016 + {"*STATREL_EA", link_lyr+".ABSTATREL_EA", link_lyr+".BASTATREL_EA"}, // added for reliability - 02/02/2016 + {"*STATREL_AM", link_lyr+".ABSTATREL_AM", link_lyr+".BASTATREL_AM"}, // added for reliability - 02/02/2016 + {"*STATREL_MD", link_lyr+".ABSTATREL_MD", link_lyr+".BASTATREL_MD"}, // added for reliability - 02/02/2016 + {"*STATREL_PM", link_lyr+".ABSTATREL_PM", link_lyr+".BASTATREL_PM"}, // added for reliability - 02/02/2016 + {"*STATREL_EV", link_lyr+".ABSTATREL_EV", link_lyr+".BASTATREL_EV"}, + {"*_TOTREL_EA", link_lyr+".AB_TOTREL_EA", link_lyr+".BA_TOTREL_EA"}, + {"*_TOTREL_AM", link_lyr+".AB_TOTREL_AM", link_lyr+".BA_TOTREL_AM"}, + {"*_TOTREL_MD", link_lyr+".AB_TOTREL_MD", link_lyr+".BA_TOTREL_MD"}, + {"*_TOTREL_PM", link_lyr+".AB_TOTREL_PM", link_lyr+".BA_TOTREL_PM"}, + {"*_TOTREL_EV", link_lyr+".AB_TOTREL_EV", link_lyr+".BA_TOTREL_EV"}} // added for reliability - 02/02/2016 + + // add two node fields into the network for turning movement purposes, by JXu + Opts.Global.[Node Options].ID = node_lyr + ".ID" + Opts.Global.[Node Options].DATA = node_lyr + ".temp" + Opts.Output.[Network File] = net_file + RunMacro("HwycadLog",{"createhwynet_turn.rsc: create hwynet1","Build Highway Network"}) + ok = RunMacro("TCB Run Operation", 1, "Build Highway Network", Opts) + if !ok then goto quit + + // STEP 2: Highway Network Setting + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Centroids Set] = {db_node_lyr, node_lyr, "Selection", "select * where ID <="+i2s(mxzone)} + Opts.Global.[Spc Turn Pen Method] = 3 + Opts.Input.[Def Turn Pen Table] = {d_tp_tb} + Opts.Input.[Spc Turn Pen Table] = {s_tp_tb} + Opts.Field.[Link type] = "IFC" + Opts.Global.[Global Turn Penalties] = {0, 0, 0, 0} + Opts.Flag.[Use Link Types] = "True" + RunMacro("HwycadLog",{"createhwynet_turn.rsc: create hwynet1","Highway Network Setting"}) + ok = RunMacro("TCB Run Operation", 2, "Highway Network Setting", Opts) + if !ok then goto quit + + mytime=GetDateAndTime() + + RunMacro("close all") //before delete db_file, close it + + + //writeline(fpr,mytime+", network setting") + ok=1 + quit: + //if fpr<>null then closefile(fpr) + return(ok) +endMacro +/************************************************************************************* +Calculate upstream and downsstream distances to major interchanges for freeway segments + +steps: +1. identify major interchange nodes +2. for each freeway segment, calculate upstream and downstream segment + +input: + output\\hwy.dbd + +output: + output\\MajorInterchangeDistance.csv + +by: nagendra.dhakar@rsginc.com +*************************************************************************************/ +Macro "DistanceToInterchange" + shared path, inputDir, outputDir + shared interchanges, freeways, linklayer, nodelayer + + ok=0 + + // input highway database + db_file=outputDir+"\\hwy.dbd" + hwy_dbd=db_file + + // output settings + out_file = outputDir+"\\MajorInterchangeDistance.csv" + + // add layers + layers = GetDBLayers(hwy_dbd) + linklayer=layers[2] + nodelayer=layers[1] + + db_linklayer=hwy_dbd+"|"+linklayer + db_nodelayer=hwy_dbd+"|"+nodelayer + + info = GetDBInfo(hwy_dbd) + temp_map = CreateMap("temp",{{"scope",info[1]}}) + + temp_layer = AddLayer(temp_map,linklayer,hwy_dbd,linklayer) + temp_layer = AddLayer(temp_map,nodelayer,hwy_dbd,nodelayer) + + // Identify Interchanges + SetLayer(linklayer) + + // Major interchange + query_ramps = 'Select * where (IFC=8) AND position(NM,"HOV")=0' // Major interchange - HOV access connectors are removed + MaxLinks = 50 + + on Error do ShowMessage("The SQL query: (" + query_ramps + ") is not correct.") end + VerifyQuery(query_ramps) + + nramps = SelectByQuery("Ramp Set", "Several", query_ramps,) + + query_freeways = "Select * where IFC=1" + on Error do ShowMessage("The SQL query: (" + query_freeways + ") is not correct.") end + VerifyQuery(query_freeways) + + nfreeways = SelectByQuery("Freeway Set", "Several",query_freeways,) + + // get freeway segments ids, IHOV, ANode BNode + freeways = GetDataVectors("Freeway Set", {"ID","IHOV"},) + + // intersect with nodes to select connected nodes + SetLayer(nodelayer) + nnodes = SelectByLinks("Interchange Set", "Several", "Ramp Set") + ninterchanges = SelectByLinks("Interchange Set", "Subset", "Freeway Set") + + // get interchange ids + interchanges = GetDataVector("Interchange Set","ID",) + + outfile = OpenFile(out_file, "w") + WriteLine(outfile, JoinStrings({"LinkID","Length","updistance","downdistance","ihov","UpLinks","DownLinks"},",")) + + on Error goto quit + + // loop through the freeway segments + dim upstreamlinkset[freeways[1].Length,MaxLinks-1], downstreamlinkset[freeways[1].Length,MaxLinks-1] + + CreateProgressBar("Calculating Interchange Distances", "True") + + for i=1 to freeways[1].Length do + perc=RealToInt(100*i/freeways[1].Length) + + UpdateProgressBar("Calculating Interchange Distances for LinkID: " +string(freeways[1][i]), perc) + + SetLayer(linklayer) + linkid = freeways[1][i] + ihov = freeways[2][i] + + query = "Select * where ID="+String(linkid) + count = SelectByQuery("Selection", "Several", query,) + linklength = GetDataVector("Selection", "Length",) + + nodes = GetEndPoints(linkid) + FromNode=nodes[1] + ToNode=nodes[2] + + // upstream - from node + isInterchange = RunMacro("NodeIsInterchange", FromNode) + + BaseLink = linkid + j=1 + + query1="n/a" + query2="n/a" + upstreamdistance=linklength[1]*0.5 + downstreamdistance=linklength[1]*0.5 + numupstreamlinks=0 + numdownstreamlinks=0 + + if (ihov<>2) then do + while (isInterchange=0) do + SetLayer(nodelayer) + links = GetNodeLinks(FromNode) // links set that meet at the node + + coordinates_base=GetCoordsFromLinks(linklayer, , {{BaseLink,1}}) + + // find the freeway link that is not the current link + upstreamlink = RunMacro("FindNextLink",links,BaseLink) + + if (upstreamlink <> null) then do + + coordinates_upstream=GetCoordsFromLinks(linklayer, , {{upstreamlink,1}}) + opposite = RunMacro("IsOppositeDirection",coordinates_base[1],coordinates_upstream[1]) // 1- true, 0- false + + if (opposite=0 and j1 and upstreamlink= linkid) then isInterchange=1 + else do + upstreamlinkset[i][j] = upstreamlink + j=j+1 + end + end + else do + isInterchange=1 + if (j=MaxLinks) then upstreamdistance=99 + end + end + else do + isInterchange=1 + if (j=MaxLinks) then upstreamdistance=99 + end + + end + + numupstreamlinks =j-1 + + // calculate upstream distance + SetLayer(linklayer) + + if j>=2 then do + query1 = "Select * where ID="+String(upstreamlinkset[i][1]) + + if j>2 then do + for iter=2 to numupstreamlinks do + query1 = JoinStrings({query1," or ID=",r2s(upstreamlinkset[i][iter])},"") + end + end + + count = SelectByQuery("Selection", "Several", query1,) + lengths = GetDataVector("Selection", "Length",) + upstreamdistance=VectorStatistic(lengths,"Sum",) + + // add half of the current link length to make the distance from midpoint + upstreamdistance = upstreamdistance + (linklength[1]*0.5) + end + + + // downstream - to node + isInterchange = RunMacro("NodeIsInterchange", ToNode) + + BaseLink = linkid + j=1 + while (isInterchange=0) do + SetLayer(nodelayer) + links = GetNodeLinks(ToNode) + + coordinates_base=GetCoordsFromLinks(linklayer, , {{BaseLink,-1}}) + + // find the freeway link that is not the current link + downstreamlink = RunMacro("FindNextLink",links,BaseLink) + + if (downstreamlink <> null) then do + coordinates_downstream=GetCoordsFromLinks(linklayer, , {{downstreamlink,-1}}) + opposite = RunMacro("IsOppositeDirection",coordinates_base[1],coordinates_downstream[1]) // 1- true, 0- false + + if (opposite=0 and j1 and downstreamlink=linkid) then isInterchange=1 + else do + downstreamlinkset[i][j] = downstreamlink + j=j+1 + end + + end + else do + isInterchange=1 + if (j=MaxLinks) then downstreamdistance=99 + end + end + else do + isInterchange=1 + if (j=MaxLinks) then downstreamdistance=99 + end + + end + numdownstreamlinks =j-1 + + // calculate downstream distance + SetLayer(linklayer) + + if j>=2 then do + query2 = "Select * where ID="+String(downstreamlinkset[i][1]) + + if j>2 then do + for iter=2 to numdownstreamlinks do + query2 = JoinStrings({query2," or ID=",r2s(downstreamlinkset[i][iter])},"") + end + end + + count = SelectByQuery("Selection", "Several", query2,) + lengths = GetDataVector("Selection", "Length",) + downstreamdistance=VectorStatistic(lengths,"Sum",) + + // add half of the current link length to make the distance from midpoint + downstreamdistance = downstreamdistance + (linklength[1]*0.5) + + end + + end + + else do + // HOV segments - set default value of 9999 miles. Distances are not calculated as HOV segments are pretty reliable. + upstreamdistance = 9999 + downstreamdistance = 9999 + numupstreamlinks = 9999 + numdownstreamlinks = 9999 + + end + + WriteLine(outfile, JoinStrings({i2s(linkid),r2s(linklength[1]),r2s(upstreamdistance),r2s(downstreamdistance),i2s(ihov),i2s(numupstreamlinks),i2s(numdownstreamlinks)},",")) + + end + + CloseFile(outfile) + + DestroyProgressBar() + ok=1 + return(ok) + + quit: + showmessage("Error, i: " + string(i) + ", j: " + string(j) + ", linkid: " + string(linkid)) + +EndMacro +/************************************************************************************* +Check if the nodes is an interchange: 0-No, 1- Yes +**************************************************************************************/ +Macro "NodeIsInterchange" (nodeid) + shared interchanges + + isInter = 0 + + for i=1 to interchanges.Length do + if nodeid=interchanges[i] then isInter = 1 + end + + return (isInter) + +EndMacro +/************************************************************************************* +Identify forward links: + Identify links that are not the previous link (linkid) + Selects the link that is also a freeway and assign that as the next link + Assumption: there is only one next freeway link +**************************************************************************************/ +Macro "FindNextLink" (linkset,linkid) + shared linklayer + + nextlink = null + + for i=1 to linkset.Length do + if linkid <> linkset[i] then do + IsFreeway = RunMacro("LinkIsFreeway",linkset[i]) + if (IsFreeway=1) then do + IsWrongDirection = RunMacro("WrongDirection",linkset[i],linkid) + IsHov = RunMacro("LinkIsHov",linkset[i]) + if (IsHov=0 & IsWrongDirection=0) then nextlink = linkset[i] + end + end + end + + return (nextlink) + +EndMacro +/************************************************************************************* +Check if the link is in the wrong direction +**************************************************************************************/ +Macro "WrongDirection" (link,linkid) + shared linklayer + + SetLayer(linklayer) + nodes1 = GetEndPoints(linkid) + nodes2 = GetEndPoints(link) + + tonode1 = nodes1[2] // base link + tonode2 = nodes2[2] // next link + + // compare ToNode - if they are same then wrong direction + if tonode1 = tonode2 then return(1) + else return(0) + +EndMacro + +/************************************************************************************* +Check if the links is a freeway link: 0-No, 1- Yes +**************************************************************************************/ +Macro "LinkIsFreeway" (link) + shared freeways + + freeway=0 + for j=1 to freeways[1].Length do + if link = freeways[1][j] then freeway=1 + end + + return (freeway) + +EndMacro +/************************************************************************************* +Check if link is a HOV segment +**************************************************************************************/ +Macro "LinkIsHov" (link) + shared freeways + + hov=0 + for j=1 to freeways[1].Length do + if link = freeways[1][j] then do + if freeways[2][j]=2 then hov=1 + end + end + + return(hov) + +EndMacro +/************************************************************************************* +Find link direction (coordinates as input) +**************************************************************************************/ +Macro "GetLinkDirection" (coordinates) + + maxnum = coordinates.length + + nodeA = coordinates[1] + nodeB = coordinates[maxnum] + + deltaX = nodeB.lon-nodeA.lon + deltaY = nodeB.lat-nodeA.lat + + if deltaY>0 then slope1 = deltaX/deltaY + else slope1 = deltaX + + if deltaX>0 then slope2 = deltaY/deltaX + else slope2 = deltaY + + direction = "" + if abs(slope1) > abs(slope2) then do + //pre_dir = "EW" + if deltaX<0 then direction = "WB" + else direction = "EB" + end + else do + //pre_dir = "NS" + if deltaY<0 then direction = "SB" + else direction = "NB" + end + + return(direction) + +EndMacro +/************************************************************************************* +Check if the two segments (coordinates as input) have opposite direction +**************************************************************************************/ +Macro "IsOppositeDirection" (coordinates1, coordinates2) + + direction1 = RunMacro("GetLinkDirection",coordinates1) + direction2 = RunMacro("GetLinkDirection",coordinates2) + + if direction1="NB" and direction2="SB" then return(1) + else if direction2="NB" and direction1="SB" then return(1) + else if direction1="EB" and direction2="WB" then return(1) + else if direction2="EB" and direction1="WB" then return(1) + else return(0) + +EndMacro diff --git a/sandag_abm/src/main/gisdk/createtodtables.rsc b/sandag_abm/src/main/gisdk/createtodtables.rsc new file mode 100644 index 0000000..677d87d --- /dev/null +++ b/sandag_abm/src/main/gisdk/createtodtables.rsc @@ -0,0 +1,916 @@ +/************************************************************** + CreateAutoTables //modified "externalExternalTripsByYear.csv" input file and code, on 09/16/16, YMA + + Inputs + input\airportAutoTrips_XX.mtx + input\autoTrips_XX.mtx + input\extTrip_XX.mtx + + where XX is period = {_EA,_AM,_MD,_PM,_EV} + + input\commVehTODTrips.mtx + input\dailyDistributionMatricesTruckam.mtx + input\dailyDistributionMatricesTruckpm.mtx + input\dailyDistributionMatricesTruckop.mtx + + Outputs + output\Trip_XX.mtx + +*******************************************************************/ +Macro "Create Auto Tables" + + shared path, inputDir, outputDir + + periods={"_EA","_AM","_MD","_PM","_EV"} + + // read properties from sandag_abm.properties in /conf folder + properties = "\\conf\\sandag_abm.properties" + skipSpecialEventModel = RunMacro("read properties",properties,"RunModel.skipSpecialEventModel", "S") + //VOT bins for non resident models, 1->3 + votBinEE = 3 + votBinExternalInternal = 3 + votBinCommercialVehicles=3 + + /* + truckTables = { + inputDir+"\\dailyDistributionMatricesTruckam.mtx", + inputDir+"\\dailyDistributionMatricesTruckop.mtx", + inputDir+"\\dailyDistributionMatricesTruckpm.mtx" } + + truckPeriods = {2, 1, 2, 3, 2} + truckFactors = {0.1, 1.0, 0.65, 1.0, 0.25} + truckMatrices ={"lhdn","lhdt","mhdn","mhdt","hhdn","hhdt"} + */ + + truckTables = { + outputDir+"\\dailyDistributionMatricesTruckEA.mtx", + outputDir+"\\dailyDistributionMatricesTruckAM.mtx", + outputDir+"\\dailyDistributionMatricesTruckMD.mtx", + outputDir+"\\dailyDistributionMatricesTruckPM.mtx", + outputDir+"\\dailyDistributionMatricesTruckEV.mtx" } + + dim truckMatrices[truckTables.length] + dim truckCurrencies[truckTables.length] + + for i = 1 to truckTables.length do + // create truck matrix currencies + truckMatrices[i] = OpenMatrix(truckTables[i], ) + truckCurrencies[i] = CreateMatrixCurrencies(truckMatrices[i], , , ) + end + + externalInternalTables = { + outputDir+"\\usSdWrk", + outputDir+"\\usSdNon" + } + + //create external-external matrix from csv input file + ok = RunMacro("TCB Run Macro", 1,"Create External-External Trip Matrix",{}) + if !ok then goto quit + + //create external-external currencies + externalExternalMatrixName = outputDir + "\\externalExternalTrips.mtx" + externalExternalMatrix = OpenMatrix(externalExternalMatrixName, ) + + externalExternalCurrency = CreateMatrixCurrency(externalExternalMatrix,'Trips',,,) + externalExternalDiurnalFactors = { 0.074, 0.137, 0.472, 0.183, 0.133} + externalExternalOccupancyFactors = {0.43, 0.42, 0.15 } + + + internalExternalTables = { + { + outputDir+"\\autoInternalExternalTrips_EA_low.mtx", + outputDir+"\\autoInternalExternalTrips_AM_low.mtx", + outputDir+"\\autoInternalExternalTrips_MD_low.mtx", + outputDir+"\\autoInternalExternalTrips_PM_low.mtx", + outputDir+"\\autoInternalExternalTrips_EV_low.mtx"}, + { + outputDir+"\\autoInternalExternalTrips_EA_med.mtx", + outputDir+"\\autoInternalExternalTrips_AM_med.mtx", + outputDir+"\\autoInternalExternalTrips_MD_med.mtx", + outputDir+"\\autoInternalExternalTrips_PM_med.mtx", + outputDir+"\\autoInternalExternalTrips_EV_med.mtx" + }, + { + outputDir+"\\autoInternalExternalTrips_EA_high.mtx", + outputDir+"\\autoInternalExternalTrips_AM_high.mtx", + outputDir+"\\autoInternalExternalTrips_MD_high.mtx", + outputDir+"\\autoInternalExternalTrips_PM_high.mtx", + outputDir+"\\autoInternalExternalTrips_EV_high.mtx" + } + } + visitorTables = { + { + outputDir+"\\autoVisitorTrips_EA_low.mtx", + outputDir+"\\autoVisitorTrips_AM_low.mtx", + outputDir+"\\autoVisitorTrips_MD_low.mtx", + outputDir+"\\autoVisitorTrips_PM_low.mtx", + outputDir+"\\autoVisitorTrips_EV_low.mtx"}, + { + outputDir+"\\autoVisitorTrips_EA_med.mtx", + outputDir+"\\autoVisitorTrips_AM_med.mtx", + outputDir+"\\autoVisitorTrips_MD_med.mtx", + outputDir+"\\autoVisitorTrips_PM_med.mtx", + outputDir+"\\autoVisitorTrips_EV_med.mtx"}, + { + outputDir+"\\autoVisitorTrips_EA_high.mtx", + outputDir+"\\autoVisitorTrips_AM_high.mtx", + outputDir+"\\autoVisitorTrips_MD_high.mtx", + outputDir+"\\autoVisitorTrips_PM_high.mtx", + outputDir+"\\autoVisitorTrips_EV_high.mtx"} + } + crossBorderTables = { + { + outputDir+"\\autoCrossBorderTrips_EA_low.mtx", + outputDir+"\\autoCrossBorderTrips_AM_low.mtx", + outputDir+"\\autoCrossBorderTrips_MD_low.mtx", + outputDir+"\\autoCrossBorderTrips_PM_low.mtx", + outputDir+"\\autoCrossBorderTrips_EV_low.mtx"}, + { + outputDir+"\\autoCrossBorderTrips_EA_med.mtx", + outputDir+"\\autoCrossBorderTrips_AM_med.mtx", + outputDir+"\\autoCrossBorderTrips_MD_med.mtx", + outputDir+"\\autoCrossBorderTrips_PM_med.mtx", + outputDir+"\\autoCrossBorderTrips_EV_med.mtx"}, + { + outputDir+"\\autoCrossBorderTrips_EA_high.mtx", + outputDir+"\\autoCrossBorderTrips_AM_high.mtx", + outputDir+"\\autoCrossBorderTrips_MD_high.mtx", + outputDir+"\\autoCrossBorderTrips_PM_high.mtx", + outputDir+"\\autoCrossBorderTrips_EV_high.mtx"} + } + + airportTables = { + { + outputDir+"\\autoAirportTrips_EA_low.mtx", + outputDir+"\\autoAirportTrips_AM_low.mtx", + outputDir+"\\autoAirportTrips_MD_low.mtx", + outputDir+"\\autoAirportTrips_PM_low.mtx", + outputDir+"\\autoAirportTrips_EV_low.mtx"}, + { + outputDir+"\\autoAirportTrips_EA_med.mtx", + outputDir+"\\autoAirportTrips_AM_med.mtx", + outputDir+"\\autoAirportTrips_MD_med.mtx", + outputDir+"\\autoAirportTrips_PM_med.mtx", + outputDir+"\\autoAirportTrips_EV_med.mtx"}, + { + outputDir+"\\autoAirportTrips_EA_high.mtx", + outputDir+"\\autoAirportTrips_AM_high.mtx", + outputDir+"\\autoAirportTrips_MD_high.mtx", + outputDir+"\\autoAirportTrips_PM_high.mtx", + outputDir+"\\autoAirportTrips_EV_high.mtx"} + } + personTables = { + { + outputDir+"\\autoTrips_EA_low.mtx", + outputDir+"\\autoTrips_AM_low.mtx", + outputDir+"\\autoTrips_MD_low.mtx", + outputDir+"\\autoTrips_PM_low.mtx", + outputDir+"\\autoTrips_EV_low.mtx"}, + { + outputDir+"\\autoTrips_EA_med.mtx", + outputDir+"\\autoTrips_AM_med.mtx", + outputDir+"\\autoTrips_MD_med.mtx", + outputDir+"\\autoTrips_PM_med.mtx", + outputDir+"\\autoTrips_EV_med.mtx"}, + { + outputDir+"\\autoTrips_EA_high.mtx", + outputDir+"\\autoTrips_AM_high.mtx", + outputDir+"\\autoTrips_MD_high.mtx", + outputDir+"\\autoTrips_PM_high.mtx", + outputDir+"\\autoTrips_EV_high.mtx"} + } + //the following table names have the period appended + CTRampMatrices = {"SOV_GP","SOV_PAY","SR2_GP","SR2_HOV","SR2_PAY","SR3_GP","SR3_HOV","SR3_PAY"} + + //output files + outMatrixNames = {"Trip"+periods[1]+"_VOT.mtx", "Trip"+periods[2]+"_VOT.mtx", "Trip"+periods[3]+"_VOT.mtx", "Trip"+periods[4]+"_VOT.mtx", "Trip"+periods[5]+"_VOT.mtx"} + outTableNames = {"SOV_GP_LOW", "SOV_PAY_LOW", "SR2_GP_LOW","SR2_HOV_LOW", "SR2_PAY_LOW", "SR3_GP_LOW","SR3_HOV_LOW","SR3_PAY_LOW", + "SOV_GP_MED", "SOV_PAY_MED", "SR2_GP_MED","SR2_HOV_MED", "SR2_PAY_MED", "SR3_GP_MED","SR3_HOV_MED","SR3_PAY_MED", + "SOV_GP_HIGH", "SOV_PAY_HIGH", "SR2_GP_HIGH","SR2_HOV_HIGH", "SR2_PAY_HIGH", "SR3_GP_HIGH","SR3_HOV_HIGH","SR3_PAY_HIGH", + "lhdn","mhdn","hhdn","lhdt","mhdt","hhdt"} + + commVehTable = outputDir+"\\commVehTODTrips.mtx" + commVehMatrices = {"EA NonToll","AM NonToll","MD NonToll","PM NonToll","EV NonToll","EA Toll","AM Toll","MD Toll","PM Toll","EV Toll"} + + // create comm vehicle matrix currencies + commVehMatrix = OpenMatrix(commVehTable, ) + commVehCurrencies = CreateMatrixCurrencies(commVehMatrix, , , ) + + + for i = 1 to periods.length do + + //open person trip matrix currencies + personMatrixLow = OpenMatrix(personTables[1][i], ) + personCurrenciesLow = CreateMatrixCurrencies(personMatrixLow, , , ) + + personMatrixMed = OpenMatrix(personTables[2][i], ) + personCurrenciesMed = CreateMatrixCurrencies(personMatrixMed, , , ) + + personMatrixHigh = OpenMatrix(personTables[3][i], ) + personCurrenciesHigh = CreateMatrixCurrencies(personMatrixHigh, , , ) + + totalOutMatrices = CTRampMatrices.length * 3 + + counter = 0 + dim curr_array[totalOutMatrices] + for j = 1 to totalOutMatrices do + counter = counter + 1 + curr_array[j] = CreateMatrixCurrency(personMatrixLow, CTRampMatrices[counter]+periods[i], ,, ) + if counter = CTRampMatrices.length then counter=0 + + end + + //open internal-external matrix currencies + internalExternalMatrixLow = OpenMatrix(internalExternalTables[1][i], ) + internalExternalCurrenciesLow = CreateMatrixCurrencies(internalExternalMatrixLow, , , ) + + internalExternalMatrixMed = OpenMatrix(internalExternalTables[2][i], ) + internalExternalCurrenciesMed = CreateMatrixCurrencies(internalExternalMatrixMed, , , ) + + internalExternalMatrixHigh = OpenMatrix(internalExternalTables[3][i], ) + internalExternalCurrenciesHigh = CreateMatrixCurrencies(internalExternalMatrixHigh, , , ) + + //open airport matrix currencies + airportMatrixLow = OpenMatrix(airportTables[1][i], ) + airportCurrenciesLow = CreateMatrixCurrencies(airportMatrixLow, , , ) + + airportMatrixMed = OpenMatrix(airportTables[2][i], ) + airportCurrenciesMed = CreateMatrixCurrencies(airportMatrixMed, , , ) + + airportMatrixHigh = OpenMatrix(airportTables[3][i], ) + airportCurrenciesHigh = CreateMatrixCurrencies(airportMatrixHigh, , , ) + + //open visitor matrix currencies + visitorMatrixLow = OpenMatrix(visitorTables[1][i], ) + visitorCurrenciesLow = CreateMatrixCurrencies(visitorMatrixLow, , , ) + + visitorMatrixMed = OpenMatrix(visitorTables[2][i], ) + visitorCurrenciesMed = CreateMatrixCurrencies(visitorMatrixMed, , , ) + + visitorMatrixHigh = OpenMatrix(visitorTables[3][i], ) + visitorCurrenciesHigh = CreateMatrixCurrencies(visitorMatrixHigh, , , ) + + //open cross border matrix currencies + crossBorderMatrixLow = OpenMatrix(crossBorderTables[1][i], ) + crossBorderCurrenciesLow = CreateMatrixCurrencies(crossBorderMatrixLow, , , ) + + crossBorderMatrixMed = OpenMatrix(crossBorderTables[2][i], ) + crossBorderCurrenciesMed = CreateMatrixCurrencies(crossBorderMatrixMed, , , ) + + crossBorderMatrixHigh = OpenMatrix(crossBorderTables[3][i], ) + crossBorderCurrenciesHigh = CreateMatrixCurrencies(crossBorderMatrixHigh, , , ) + + + //open external-internal work matrix currencies + externalInternalWrkMatrix = OpenMatrix(externalInternalTables[1]+periods[i]+".mtx", ) + externalInternalWrkCurrencies = CreateMatrixCurrencies(externalInternalWrkMatrix, , , ) + + //open external-internal non-work matrix currencies + externalInternalNonMatrix = OpenMatrix(externalInternalTables[2]+periods[i]+".mtx", ) + externalInternalNonCurrencies = CreateMatrixCurrencies(externalInternalNonMatrix, , , ) + + //open special event matrix currencies; Wu added 5/16/2017 + specialEventMatrix = OpenMatrix(specialEventables[i], ) + specialEventCurrencies = CreateMatrixCurrencies(specialEventMatrix, , , ) + + + //create output trip table and matrix currencies for this time period + outMatrix = CopyMatrixStructure(curr_array, {{"File Name", outputDir+"\\"+outMatrixNames[i]}, + {"Label", outMatrixNames[i]}, + {"Tables",outTableNames}, + {"File Based", "Yes"}}) + SetMatrixCoreNames(outMatrix, outTableNames) + + outCurrencies= CreateMatrixCurrencies(outMatrix, , , ) + +//LOW VOT + // calculate output matrices + outCurrencies.SOV_GP_LOW :=Nz(outCurrencies.SOV_GP_LOW) + outCurrencies.SOV_GP_LOW := Nz(personCurrenciesLow.("SOV_GP"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SOV_GP"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SOV_GP"+periods[i])) + + Nz(airportCurrenciesLow.("SOV_GP"+periods[i])) + + Nz(visitorCurrenciesLow.("SOV_GP"+periods[i])) + + if votBinExternalInternal=1 then outCurrencies.SOV_GP_LOW := outCurrencies.SOV_GP_LOW + Nz(externalInternalWrkCurrencies.("DAN")) + Nz(externalInternalNonCurrencies.("DAN")) + if votBinExternalExternal=1 then outCurrencies.SOV_GP_LOW := outCurrencies.SOV_GP_LOW + (Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[1]) + if votBinCommercialVehicles=1 then outCurrencies.SOV_GP_LOW := outCurrencies.SOV_GP_LOW + Nz(commVehCurrencies.(commVehMatrices[i])) + + outCurrencies.SOV_PAY_LOW :=Nz(outCurrencies.SOV_PAY_LOW) + outCurrencies.SOV_PAY_LOW := Nz(personCurrenciesLow.("SOV_PAY"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SOV_PAY"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SOV_PAY"+periods[i])) + + Nz(airportCurrenciesLow.("SOV_PAY"+periods[i])) + + Nz(visitorCurrenciesLow.("SOV_PAY"+periods[i])) + + if votBinExternalInternal=1 then outCurrencies.SOV_PAY_LOW := outCurrencies.SOV_PAY_LOW + Nz(externalInternalWrkCurrencies.("DAT")) + Nz(externalInternalNonCurrencies.("DAT")) + if votBinCommercialVehicles=1 then outCurrencies.SOV_PAY_LOW := outCurrencies.SOV_PAY_LOW + Nz(commVehCurrencies.(commVehMatrices[i+5])) + + outCurrencies.SR2_GP_LOW :=Nz(outCurrencies.SR2_GP_LOW) + outCurrencies.SR2_GP_LOW := Nz(personCurrenciesLow.("SR2_GP"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SR2_GP"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SR2_GP"+periods[i])) + + Nz(airportCurrenciesLow.("SR2_GP"+periods[i])) + + Nz(visitorCurrenciesLow.("SR2_GP"+periods[i])) + + outCurrencies.SR2_HOV_LOW :=Nz(outCurrencies.SR2_HOV_LOW) + outCurrencies.SR2_HOV_LOW := Nz(personCurrenciesLow.("SR2_HOV"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SR2_HOV"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SR2_HOV"+periods[i])) + + Nz(airportCurrenciesLow.("SR2_HOV"+periods[i])) + + Nz(visitorCurrenciesLow.("SR2_HOV"+periods[i])) + + if votBinExternalInternal=1 then outCurrencies.SR2_HOV_LOW := outCurrencies.SR2_HOV_LOW + Nz(externalInternalWrkCurrencies.("S2N")) + Nz(externalInternalNonCurrencies.("S2N")) + if votBinExternalExternal=1 then outCurrencies.SR2_HOV_LOW := outCurrencies.SR2_HOV_LOW + Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[2] + + outCurrencies.SR2_PAY_LOW :=Nz(outCurrencies.SR2_PAY_LOW) + outCurrencies.SR2_PAY_LOW := Nz(personCurrenciesLow.("SR2_PAY"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SR2_PAY"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SR2_PAY"+periods[i])) + + Nz(airportCurrenciesLow.("SR2_PAY"+periods[i])) + + Nz(visitorCurrenciesLow.("SR2_PAY"+periods[i])) + + if votBinExternalInternal=1 then outCurrencies.SR2_PAY_LOW := outCurrencies.SR2_PAY_LOW + Nz(externalInternalWrkCurrencies.("S2T")) + Nz(externalInternalNonCurrencies.("S2T")) + + outCurrencies.SR3_GP_LOW :=Nz(outCurrencies.SR3_GP_LOW) + outCurrencies.SR3_GP_LOW := Nz(personCurrenciesLow.("SR3_GP"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SR3_GP"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SR3_GP"+periods[i])) + + Nz(airportCurrenciesLow.("SR3_GP"+periods[i])) + + Nz(visitorCurrenciesLow.("SR3_GP"+periods[i])) + + outCurrencies.SR3_HOV_LOW :=Nz(outCurrencies.SR3_HOV_LOW) + outCurrencies.SR3_HOV_LOW := Nz(personCurrenciesLow.("SR3_HOV"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SR3_HOV"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SR3_HOV"+periods[i])) + + Nz(airportCurrenciesLow.("SR3_HOV"+periods[i])) + + Nz(visitorCurrenciesLow.("SR3_HOV"+periods[i])) + + if votBinExternalInternal=1 then outCurrencies.SR3_HOV_LOW := outCurrencies.SR3_HOV_LOW + Nz(externalInternalWrkCurrencies.("S3N")) + Nz(externalInternalNonCurrencies.("S3N")) + if votBinExternalExternal=1 then outCurrencies.SR3_HOV_LOW := outCurrencies.SR3_HOV_LOW + Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[3] + + outCurrencies.SR3_PAY_LOW :=Nz(outCurrencies.SR3_PAY_LOW) + outCurrencies.SR3_PAY_LOW := Nz(personCurrenciesLow.("SR3_PAY"+periods[i])) + + Nz(internalExternalCurrenciesLow.("SR3_PAY"+periods[i])) + + Nz(crossBorderCurrenciesLow.("SR3_PAY"+periods[i])) + + Nz(airportCurrenciesLow.("SR3_PAY"+periods[i])) + + Nz(visitorCurrenciesLow.("SR3_PAY"+periods[i])) + + if votBinExternalInternal=1 then outCurrencies.SR3_PAY_LOW := outCurrencies.SR3_PAY_LOW + Nz(externalInternalWrkCurrencies.("S3T")) + Nz(externalInternalNonCurrencies.("S3T")) + +//MED VOT + // calculate output matrices + outCurrencies.SOV_GP_MED :=Nz(outCurrencies.SOV_GP_MED) + outCurrencies.SOV_GP_MED := Nz(personCurrenciesMed.("SOV_GP"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SOV_GP"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SOV_GP"+periods[i])) + + Nz(airportCurrenciesMed.("SOV_GP"+periods[i])) + + Nz(visitorCurrenciesMed.("SOV_GP"+periods[i])) + + if votBinExternalInternal=2 then outCurrencies.SOV_GP_MED := outCurrencies.SOV_GP_MED + Nz(externalInternalWrkCurrencies.("DAN")) + Nz(externalInternalNonCurrencies.("DAN")) + if votBinExternalExternal=2 then outCurrencies.SOV_GP_MED := outCurrencies.SOV_GP_MED + (Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[1]) + if votBinCommercialVehicles=2 then outCurrencies.SOV_GP_MED := outCurrencies.SOV_GP_MED + Nz(commVehCurrencies.(commVehMatrices[i])) + + outCurrencies.SOV_PAY_MED :=Nz(outCurrencies.SOV_PAY_MED) + outCurrencies.SOV_PAY_MED := Nz(personCurrenciesMed.("SOV_PAY"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SOV_PAY"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SOV_PAY"+periods[i])) + + Nz(airportCurrenciesMed.("SOV_PAY"+periods[i])) + + Nz(visitorCurrenciesMed.("SOV_PAY"+periods[i])) + + if votBinExternalInternal=2 then outCurrencies.SOV_PAY_MED := outCurrencies.SOV_PAY_MED + Nz(externalInternalWrkCurrencies.("DAT")) + Nz(externalInternalNonCurrencies.("DAT")) + if votBinCommercialVehicles=2 then outCurrencies.SOV_PAY_MED := outCurrencies.SOV_PAY_MED + Nz(commVehCurrencies.(commVehMatrices[i+5])) + + outCurrencies.SR2_GP_MED :=Nz(outCurrencies.SR2_GP_MED) + outCurrencies.SR2_GP_MED := Nz(personCurrenciesMed.("SR2_GP"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SR2_GP"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SR2_GP"+periods[i])) + + Nz(airportCurrenciesMed.("SR2_GP"+periods[i])) + + Nz(visitorCurrenciesMed.("SR2_GP"+periods[i])) + + outCurrencies.SR2_HOV_MED :=Nz(outCurrencies.SR2_HOV_MED) + outCurrencies.SR2_HOV_MED := Nz(personCurrenciesMed.("SR2_HOV"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SR2_HOV"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SR2_HOV"+periods[i])) + + Nz(airportCurrenciesMed.("SR2_HOV"+periods[i])) + + Nz(visitorCurrenciesMed.("SR2_HOV"+periods[i])) + + if votBinExternalInternal=2 then outCurrencies.SR2_HOV_MED := outCurrencies.SR2_HOV_MED + Nz(externalInternalWrkCurrencies.("S2N")) + Nz(externalInternalNonCurrencies.("S2N")) + if votBinExternalExternal=2 then outCurrencies.SR2_HOV_MED := outCurrencies.SR2_HOV_MED + Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[2] + + outCurrencies.SR2_PAY_MED :=Nz(outCurrencies.SR2_PAY_MED) + outCurrencies.SR2_PAY_MED := Nz(personCurrenciesMed.("SR2_PAY"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SR2_PAY"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SR2_PAY"+periods[i])) + + Nz(airportCurrenciesMed.("SR2_PAY"+periods[i])) + + Nz(visitorCurrenciesMed.("SR2_PAY"+periods[i])) + + if votBinExternalInternal=2 then outCurrencies.SR2_PAY_MED := outCurrencies.SR2_PAY_MED + Nz(externalInternalWrkCurrencies.("S2T")) + Nz(externalInternalNonCurrencies.("S2T")) + + outCurrencies.SR3_GP_MED :=Nz(outCurrencies.SR3_GP_MED) + outCurrencies.SR3_GP_MED := Nz(personCurrenciesMed.("SR3_GP"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SR3_GP"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SR3_GP"+periods[i])) + + Nz(airportCurrenciesMed.("SR3_GP"+periods[i])) + + Nz(visitorCurrenciesMed.("SR3_GP"+periods[i])) + + outCurrencies.SR3_HOV_MED :=Nz(outCurrencies.SR3_HOV_MED) + outCurrencies.SR3_HOV_MED := Nz(personCurrenciesMed.("SR3_HOV"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SR3_HOV"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SR3_HOV"+periods[i])) + + Nz(airportCurrenciesMed.("SR3_HOV"+periods[i])) + + Nz(visitorCurrenciesMed.("SR3_HOV"+periods[i])) + + if votBinExternalInternal=2 then outCurrencies.SR3_HOV_MED := outCurrencies.SR3_HOV_MED + Nz(externalInternalWrkCurrencies.("S3N")) + Nz(externalInternalNonCurrencies.("S3N")) + if votBinExternalExternal=2 then outCurrencies.SR3_HOV_MED := outCurrencies.SR3_HOV_MED + Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[3] + + outCurrencies.SR3_PAY_MED :=Nz(outCurrencies.SR3_PAY_MED) + outCurrencies.SR3_PAY_MED := Nz(personCurrenciesMed.("SR3_PAY"+periods[i])) + + Nz(internalExternalCurrenciesMed.("SR3_PAY"+periods[i])) + + Nz(crossBorderCurrenciesMed.("SR3_PAY"+periods[i])) + + Nz(airportCurrenciesMed.("SR3_PAY"+periods[i])) + + Nz(visitorCurrenciesMed.("SR3_PAY"+periods[i])) + + if votBinExternalInternal=2 then outCurrencies.SR3_PAY_MED := outCurrencies.SR3_PAY_MED + Nz(externalInternalWrkCurrencies.("S3T")) + Nz(externalInternalNonCurrencies.("S3T")) + +//HIGH VOT + // calculate output matrices + outCurrencies.SOV_GP_HIGH :=Nz(outCurrencies.SOV_GP_HIGH) + outCurrencies.SOV_GP_HIGH := Nz(personCurrenciesHigh.("SOV_GP"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SOV_GP"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SOV_GP"+periods[i])) + + Nz(airportCurrenciesHigh.("SOV_GP"+periods[i])) + + Nz(visitorCurrenciesHigh.("SOV_GP"+periods[i])) + + if votBinExternalInternal=3 then outCurrencies.SOV_GP_HIGH := outCurrencies.SOV_GP_HIGH + Nz(externalInternalWrkCurrencies.("DAN")) + Nz(externalInternalNonCurrencies.("DAN")) + if votBinExternalExternal=3 then outCurrencies.SOV_GP_HIGH := outCurrencies.SOV_GP_HIGH + (Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[1]) + if votBinCommercialVehicles=3 then outCurrencies.SOV_GP_HIGH := outCurrencies.SOV_GP_HIGH + Nz(commVehCurrencies.(commVehMatrices[i])) + + outCurrencies.SOV_PAY_HIGH :=Nz(outCurrencies.SOV_PAY_HIGH) + outCurrencies.SOV_PAY_HIGH := Nz(personCurrenciesHigh.("SOV_PAY"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SOV_PAY"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SOV_PAY"+periods[i])) + + Nz(airportCurrenciesHigh.("SOV_PAY"+periods[i])) + + Nz(visitorCurrenciesHigh.("SOV_PAY"+periods[i])) + + if votBinExternalInternal=3 then outCurrencies.SOV_PAY_HIGH := outCurrencies.SOV_PAY_HIGH + Nz(externalInternalWrkCurrencies.("DAT")) + Nz(externalInternalNonCurrencies.("DAT")) + if votBinCommercialVehicles=3 then outCurrencies.SOV_PAY_HIGH := outCurrencies.SOV_PAY_HIGH + Nz(commVehCurrencies.(commVehMatrices[i+5])) + + outCurrencies.SR2_GP_HIGH :=Nz(outCurrencies.SR2_GP_HIGH) + outCurrencies.SR2_GP_HIGH := Nz(personCurrenciesHigh.("SR2_GP"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SR2_GP"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SR2_GP"+periods[i])) + + Nz(airportCurrenciesHigh.("SR2_GP"+periods[i])) + + Nz(visitorCurrenciesHigh.("SR2_GP"+periods[i])) + + outCurrencies.SR2_HOV_HIGH :=Nz(outCurrencies.SR2_HOV_HIGH) + outCurrencies.SR2_HOV_HIGH := Nz(personCurrenciesHigh.("SR2_HOV"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SR2_HOV"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SR2_HOV"+periods[i])) + + Nz(airportCurrenciesHigh.("SR2_HOV"+periods[i])) + + Nz(visitorCurrenciesHigh.("SR2_HOV"+periods[i])) + + if votBinExternalInternal=3 then outCurrencies.SR2_HOV_HIGH := outCurrencies.SR2_HOV_HIGH + Nz(externalInternalWrkCurrencies.("S2N")) + Nz(externalInternalNonCurrencies.("S2N")) + if votBinExternalExternal=3 then outCurrencies.SR2_HOV_HIGH := outCurrencies.SR2_HOV_HIGH + Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[2] + + outCurrencies.SR2_PAY_HIGH :=Nz(outCurrencies.SR2_PAY_HIGH) + outCurrencies.SR2_PAY_HIGH := Nz(personCurrenciesHigh.("SR2_PAY"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SR2_PAY"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SR2_PAY"+periods[i])) + + Nz(airportCurrenciesHigh.("SR2_PAY"+periods[i])) + + Nz(visitorCurrenciesHigh.("SR2_PAY"+periods[i])) + + if votBinExternalInternal=3 then outCurrencies.SR2_PAY_HIGH := outCurrencies.SR2_PAY_HIGH + Nz(externalInternalWrkCurrencies.("S2T")) + Nz(externalInternalNonCurrencies.("S2T")) + + outCurrencies.SR3_GP_HIGH :=Nz(outCurrencies.SR3_GP_HIGH) + outCurrencies.SR3_GP_HIGH := Nz(personCurrenciesHigh.("SR3_GP"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SR3_GP"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SR3_GP"+periods[i])) + + Nz(airportCurrencies.("SR3_GP"+periods[i])) + + Nz(visitorCurrencies.("SR3_GP"+periods[i])) + + outCurrencies.SR3_HOV_HIGH :=Nz(outCurrencies.SR3_HOV_HIGH) + outCurrencies.SR3_HOV_HIGH := Nz(personCurrenciesHigh.("SR3_HOV"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SR3_HOV"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SR3_HOV"+periods[i])) + + Nz(airportCurrenciesHigh.("SR3_HOV"+periods[i])) + + Nz(visitorCurrenciesHigh.("SR3_HOV"+periods[i])) + + + if votBinExternalInternal=3 then outCurrencies.SR3_HOV_HIGH := outCurrencies.SR3_HOV_HIGH + Nz(externalInternalWrkCurrencies.("S3N")) + Nz(externalInternalNonCurrencies.("S3N")) + if votBinExternalExternal=3 then outCurrencies.SR3_HOV_HIGH := outCurrencies.SR3_HOV_HIGH + Nz(externalExternalCurrency) * externalExternalDiurnalFactors[i] * externalExternalOccupancyFactors[3] + + outCurrencies.SR3_PAY_HIGH :=Nz(outCurrencies.SR3_PAY_HIGH) + outCurrencies.SR3_PAY_HIGH := Nz(personCurrenciesHigh.("SR3_PAY"+periods[i])) + + Nz(internalExternalCurrenciesHigh.("SR3_PAY"+periods[i])) + + Nz(crossBorderCurrenciesHigh.("SR3_PAY"+periods[i])) + + Nz(airportCurrenciesHigh.("SR3_PAY"+periods[i])) + + Nz(visitorCurrenciesHigh.("SR3_PAY"+periods[i])) + + if votBinExternalInternal=3 then outCurrencies.SR3_PAY_HIGH := outCurrencies.SR3_PAY_HIGH + Nz(externalInternalWrkCurrencies.("S3T")) + Nz(externalInternalNonCurrencies.("S3T")) + + outCurrencies.lhdn := truckCurrencies[i].lhdn + outCurrencies.mhdn := truckCurrencies[i].mhdn + outCurrencies.hhdn := truckCurrencies[i].hhdn + outCurrencies.lhdt := truckCurrencies[i].lhdt + outCurrencies.mhdt := truckCurrencies[i].mhdt + outCurrencies.hhdt := truckCurrencies[i].hhdt + end + RunMacro("close all" ) + quit: + Return(1 ) + +EndMacro + + +/************************************************************** + CreateTransitTables + + Inputs + input\tranTrips_XX.mtx + input\tranAirportTrips_XX.mtx + + where XX is period = {_EA,_AM,_MD,_PM,_EV} + + + Outputs + output\tranTotalTrips_XX.mtx + + TODO: Add Mexican resident and visitor trips + +*******************************************************************/ +Macro "Create Transit Tables" + + shared path, inputDir, outputDir + + periods={"_EA","_AM","_MD","_PM","_EV"} + + dim personFiles[periods.length] + dim airportFiles[periods.length] + dim crossBorderFiles[periods.length] + dim visitorFiles[periods.length] + dim internalExternalFiles[periods.length] + dim outFiles[periods.length] + + + for i = 1 to periods.length do + personFiles[i] = outputDir+"\\tranTrips"+periods[i]+".mtx" + airportFiles[i] = outputDir+"\\tranAirportTrips"+periods[i]+".mtx" + crossBorderFiles[i] = outputDir+"\\tranCrossBorderTrips"+periods[i]+".mtx" + visitorFiles[i] = outputDir+"\\tranVisitorTrips"+periods[i]+".mtx" + internalExternalFiles[i] = outputDir+"\\tranInternalExternalTrips"+periods[i]+".mtx" + outFiles[i] = outputDir+"\\tranTotalTrips"+periods[i]+".mtx" + end + + + //the following table names have the period appended + tableNames = {"WLK_LOC","WLK_EXP","WLK_BRT","WLK_LRT","WLK_CMR","PNR_LOC","PNR_EXP","PNR_BRT","PNR_LRT","PNR_CMR","KNR_LOC","KNR_EXP","KNR_BRT","KNR_LRT","KNR_CMR"} + + + segments = {"CTRAMP","Airport","Visitor","CrossBorder","Int-Ext","Total"} + numberSegments = segments.length + dim statistics[numberSegments] + dim totalTrips[numberSegments,tableNames.length] + + for i = 1 to periods.length do + + //open person trip matrix currencies + personMatrix = OpenMatrix(personFiles[i], ) + personCurrencies = CreateMatrixCurrencies(personMatrix, , , ) + + //open airport matrix currencies + airportMatrix = OpenMatrix(airportFiles[i], ) + airportCurrencies = CreateMatrixCurrencies(airportMatrix, , , ) + + //open visitor matrix currencies + visitorMatrix = OpenMatrix(visitorFiles[i], ) + visitorCurrencies = CreateMatrixCurrencies(visitorMatrix, , , ) + + //open crossBorder matrix currencies + crossBorderMatrix = OpenMatrix(crossBorderFiles[i], ) + crossBorderCurrencies = CreateMatrixCurrencies(crossBorderMatrix, , , ) + + //open internalExternal matrix currencies + internalExternalMatrix = OpenMatrix(internalExternalFiles[i], ) + internalExternalCurrencies = CreateMatrixCurrencies(internalExternalMatrix, , , ) + + + dim curr_array[tableNames.length] + for j = 1 to curr_array.length do + curr_array[j] = CreateMatrixCurrency(personMatrix, tableNames[j]+periods[i], ,, ) + end + + //create output trip table and matrix currencies for this time period + outMatrix = CopyMatrixStructure(curr_array, {{"File Name", outFiles[i]}, + {"Label", outFiles[i]}, + {"Tables",tableNames}, + {"Compression",0}, + {"File Based", "Yes"}}) + SetMatrixCoreNames(outMatrix, tableNames) + + outCurrencies= CreateMatrixCurrencies(outMatrix, , , ) + + + // calculate output matrices + for j = 1 to tableNames.length do + + outCurrencies.(tableNames[j]) := personCurrencies.(tableNames[j]+periods[i]) + + airportCurrencies.(tableNames[j]+periods[i]) + + visitorCurrencies.(tableNames[j]+periods[i]) + + crossBorderCurrencies.(tableNames[j]+periods[i]) + + internalExternalCurrencies.(tableNames[j]+periods[i]) + + end + + //for reporting + statistics[1] = MatrixStatistics(personMatrix,) + statistics[2] = MatrixStatistics(airportMatrix,) + statistics[3] = MatrixStatistics(visitorMatrix,) + statistics[4] = MatrixStatistics(crossBorderMatrix,) + statistics[5] = MatrixStatistics(internalExternalMatrix,) + statistics[6] = MatrixStatistics(outMatrix,) + + // calculate totals and save in arrays + for j = 1 to tableNames.length do + + for k = 1 to numberSegments do + + // Sum the tables in the person trip file + + if k<6 then totalTrips[k][j] = statistics[k].(tableNames[j]+periods[i]).Sum else totalTrips[k][j] = statistics[k].(tableNames[j]).Sum + end + end + + //write the table for inputs to the report file + AppendToReportFile(0, "Transit Factoring for Period "+periods[i], {{"Section", "True"}}) + fileColumn = { {"Name", "File"}, {"Percentage Width", 20}, {"Alignment", "Left"}} + modeColumns = null + for j = 1 to tableNames.length do + modeColumns = modeColumns + { { {"Name", tableNames[j]}, {"Percentage Width", (100-20)/tableNames.length}, {"Alignment", "Left"}, {"Decimals", 0} } } + end + columns = {fileColumn} + modeColumns + AppendTableToReportFile( columns, {{"Title", "Transit Factor Input File Totals"}}) + + for j = 1 to numberSegments do + outRow = null + for k = 1 to tableNames.length do + outRow = outRow + {totalTrips[j][k] } + end + outRow = { segments[j] } + outRow + AppendRowToReportFile(outRow,) + end + + CloseReportFileSection() + + + + end + RunMacro("close all" ) + quit: + Return(1 ) + +EndMacro +/************************************************************** +Create TOD Tables From 4Step Model + + TransCAD Macro used to create trip tables from 4-step model + for assignment to 5 tod networks for first iteration of AB + model. Only needs to be run once for any given scenario year. + + Inputs + input\trptollam2.mtx + input\trptollop2.mtx + input\trptollpm2.mtx + + Outputs + output\Trip_EA.mtx + output\Trip_AM.mtx + output\Trip_MD.mtx + output\Trip_PM.mtx + output\Trip_EV.mtx + +Each matrix has the following cores: + SOV_GP SOV General purpose lanes + SOV_PAY SOV Toll eligible + SR2_GP SR2 General purpose lanes + SR2_HOV SR2 HOV lanes + SR2_PAY SR2 Toll eligible + SR3_GP SR3 General purpose lanes + SR3_HOV SR3 HOV lanes + SR3_PAY SR3 Toll eligible + lhdn Light heavy duty general purpose lanes + mhdn Medium heavy duty general purpose lanes + hhdn Heavy heavy duty general purpose lanes + lhdt Light heavy duty toll eligibl + mhdt Medium heavy duty general purpose lanes + hhdt Heavy heavy duty general purpose lanes + +**************************************************************/ +Macro "Create TOD Tables From 4Step Model" + + shared path, inputDir, outputDir + + /* + inputDir = "c:\\projects\\sandag\\series12\\base2008\\input" + outputDir = "c:\\projects\\sandag\\series12\\base2008\\output" + */ + + //inputs + amMatrixName = "trptollam2.mtx" + opMatrixName = "trptollop2.mtx" + pmMatrixName = "trptollpm2.mtx" + + inTableNames = {"dan", "dat", "s2nn", "s2nh", "s2th", "M1", "M2", "M3", "lhdn","mhdn","hhdn", "lhdt","mhdt","hhdt"} + + + //output files + outMatrixNames = {"Trip_EA.mtx", "Trip_AM.mtx", "Trip_MD.mtx", "Trip_PM.mtx", "Trip_EV.mtx"} + outTableNames = {"SOV_GP", "SOV_PAY", "SR2_GP","SR2_HOV", "SR2_PAY", "SR3_GP","SR3_HOV","SR3_PAY","lhdn","mhdn","hhdn","lhdt","mhdt","hhdt"} + + // open input matrices + amMatrix = OpenMatrix(inputDir+"\\"+amMatrixName, ) + opMatrix = OpenMatrix(inputDir+"\\"+opMatrixName, ) + pmMatrix = OpenMatrix(inputDir+"\\"+pmMatrixName, ) + + // create input matrix currencies + dim inCurrencies[outMatrixNames.length,inTableNames.length] + for i = 1 to inTableNames.length do + inCurrencies[1][i] = CreateMatrixCurrency(opMatrix, inTableNames[i], ,, ) + inCurrencies[2][i] = CreateMatrixCurrency(amMatrix, inTableNames[i], ,, ) + inCurrencies[3][i] = CreateMatrixCurrency(opMatrix, inTableNames[i], ,, ) + inCurrencies[4][i] = CreateMatrixCurrency(pmMatrix, inTableNames[i], ,, ) + inCurrencies[5][i] = CreateMatrixCurrency(opMatrix, inTableNames[i], ,, ) + end + + + // create the output matrices, copying the matrix structure of the input matrices. Then rename the matrices. + dim outMatrices[outMatrixNames.length] + dim outCurrencies[outMatrixNames.length,outTableNames.length] + for i = 1 to outMatrixNames.length do + + outMatrices[i] = CopyMatrixStructure(inCurrencies[i], {{"File Name", outputDir+"\\"+outMatrixNames[i]}, + {"Label", outMatrixNames[i]}, + {"Tables",outTableNames}, + {"File Based", "Yes"}}) + SetMatrixCoreNames(outMatrices[i], outTableNames) + + for j = 1 to outTableNames.length do + outCurrencies[i][j] = CreateMatrixCurrency(outMatrices[i], outTableNames[j], ,, ) + end + end + + // factor the off-peak input table to 3 time periods (1=EA,3=MD,5=PM, and the factors are generic across input tables) + for i = 1 to outTableNames.length do + outCurrencies[1][i] := inCurrencies[1][i] * 0.10 + outCurrencies[2][i] := inCurrencies[2][i] + outCurrencies[3][i] := inCurrencies[3][i] * 0.65 + outCurrencies[4][i] := inCurrencies[4][i] + outCurrencies[5][i] := inCurrencies[5][i] * 0.25 + end + + Return(1) + + + +EndMacro + + +/*************************************************************************************************************************** + + + +****************************************************************************************************************************/ +Macro "Create EE & EI Trips" + + + shared path, inputDir, outputDir, inputTruckDir, mxzone, mxtap, mxext,mxlink,mxrte + + //inputs + amMatrixName = "trptollam2.mtx" + opMatrixName = "trptollop2.mtx" + pmMatrixName = "trptollpm2.mtx" + + inTableNames = {"dan", "dat", "s2nn", "s2nh", "s2th", "M1", "M2", "M3", "lhdn","mhdn","hhdn", "lhdt","mhdt","hhdt"} + + //output files + outMatrixNames = {"ExtTrip_EA.mtx", "ExtTrip_AM.mtx", "ExtTrip_MD.mtx", "ExtTrip_PM.mtx", "ExtTrip_EV.mtx"} + outTableNames = {"SOV_GP", "SOV_PAY", "SR2_GP","SR2_HOV", "SR2_PAY", "SR3_GP","SR3_HOV","SR3_PAY","lhdn","mhdn","hhdn","lhdt","mhdt","hhdt"} + + // open input matrices + amMatrix = OpenMatrix(inputDir+"\\"+amMatrixName, ) + opMatrix = OpenMatrix(inputDir+"\\"+opMatrixName, ) + pmMatrix = OpenMatrix(inputDir+"\\"+pmMatrixName, ) + + // create input matrix currencies + dim inCurrencies[outMatrixNames.length,inTableNames.length] + for i = 1 to inTableNames.length do + inCurrencies[1][i] = CreateMatrixCurrency(opMatrix, inTableNames[i], ,, ) + inCurrencies[2][i] = CreateMatrixCurrency(amMatrix, inTableNames[i], ,, ) + inCurrencies[3][i] = CreateMatrixCurrency(opMatrix, inTableNames[i], ,, ) + inCurrencies[4][i] = CreateMatrixCurrency(pmMatrix, inTableNames[i], ,, ) + inCurrencies[5][i] = CreateMatrixCurrency(opMatrix, inTableNames[i], ,, ) + end + + //create an array of internal zone ids + dim zones[mxzone] + for i = 1 to zones.length do + zones[i]=i2s(i+mxext) + end + // create the output matrices, copying the matrix structure of the input matrices. Then rename the matrices. + dim outMatrices[outMatrixNames.length] + dim outCurrencies[outMatrixNames.length,outTableNames.length] + for i = 1 to outMatrixNames.length do + + outMatrices[i] = CopyMatrixStructure(inCurrencies[i], {{"File Name", outputDir+"\\"+outMatrixNames[i]}, + {"Label", outMatrixNames[i]}, + {"Tables",outTableNames}, + {"File Based", "Yes"}}) + SetMatrixCoreNames(outMatrices[i], outTableNames) + + for j = 1 to outTableNames.length do + outCurrencies[i][j] = CreateMatrixCurrency(outMatrices[i], outTableNames[j], ,, ) + + // set the output matrix to the input matrix + outCurrencies[i][j] := inCurrencies[i][j] + + //set the internal-internal values to 0 + FillMatrix(outCurrencies[i][j], zones, zones, {"Copy", 0.0},) + + end + end + + // factor the off-peak input table to 3 time periods (1=EA,3=MD,5=PM, and the factors are generic across input tables) + for i = 1 to outTableNames.length do + outCurrencies[1][i] := outCurrencies[1][i] * 0.10 + outCurrencies[2][i] := outCurrencies[2][i] + outCurrencies[3][i] := outCurrencies[3][i] * 0.65 + outCurrencies[4][i] := outCurrencies[4][i] + outCurrencies[5][i] := outCurrencies[5][i] * 0.25 + end + RunMacro("close all" ) + quit: + Return(1 ) + + +EndMacro +/*************************************************************************************************************************** + +Create external-external trip table -- modified 09/16/16 YMA + +****************************************************************************************************************************/ + +Macro "Create External-External Trip Matrix" // modified "externalExternalTripsByYear.csv" input and code, 09/14/16 YMA + + shared path, inputDir, outputDir, mxzone, mxext, scenarioYear + + //TODO: open external-external matrix here + //externalExternalFileName = inputDir+"\\externalExternalTrips.csv" // old input file + externalExternalFileName = inputDir+"\\externalExternalTripsByYear.csv" + externalExternalMatrixName = outputDir + "\\externalExternalTrips.mtx" + + extExtView = OpenTable("extExt", "CSV", {externalExternalFileName}, {{"Shared", "True"}}) + + opts = {} + opts.Label = "Trips" + opts.Type = "Float" + opts.Tables = {"2012","2014","2016","2017","2020","2025","2030","2035","2040","2045","2050"} + opts.[File Name] = externalExternalMatrixName + + extMatrix = CreateMatrixFromScratch(externalExternalMatrixName,mxzone,mxzone,opts) + coreNames = GetMatrixCoreNames(extMatrix ) + + for c = 1 to coreNames.length do + + if s2i(coreNames[c]) = s2i(scenarioYear) then do + + extCurren = CreateMatrixCurrency(extMatrix, coreNames[c], , , ) + extCurren := 0 + + rec = LocateRecord(extExtView+"|","year", {scenarioYear},{{"Exact", "True"}}) + + while rec <> null do + rec_vals = GetRecordValues(extExtView, rec, {"year","originTaz","destinationTaz","Trips"}) + year = rec_vals[1][2] + if year = s2i(scenarioYear) then do + originTaz = rec_vals[2][2] + destinationTaz = rec_vals[3][2] + Trips = rec_vals[4][2] + SetMatrixValue(extCurren, i2s(originTaz), i2s(destinationTaz), Trips) + rec= GetNextrecord(extExtView+"|",rec ,{{"year", "Ascending"},{"originTaz", "Ascending"}}) + end + else do + rec=null + end + end + SetMatrixCoreName(extMatrix, coreNames[c], "Trips") + end + else DropMatrixCore(extMatrix,coreNames[c]) + end + + + RunMacro("close all" ) + quit: + Return(1 ) +EndMacro + + diff --git a/sandag_abm/src/main/gisdk/createtrnroutes.rsc b/sandag_abm/src/main/gisdk/createtrnroutes.rsc new file mode 100644 index 0000000..ae1f5e9 --- /dev/null +++ b/sandag_abm/src/main/gisdk/createtrnroutes.rsc @@ -0,0 +1,655 @@ +/****************************************************************************** + +Create all transit + +update travel time with congested time from adjuststr.bin - Macro "update travel time" +then create transit network from selection set of routes - Macro"create transit networks" +(input: mode.dbf include fields: mode_id, mode_name, fare, fare_type, fare_field ) + +c********************************************************************************/ + +Macro "Create all transit" + shared path, inputDir, outputDir, mxtap + + ok=RunMacro("Import transit layer",{}) + if !ok then goto quit + + ok=RunMacro("Add transit time fields") + if !ok then goto quit + + ok=RunMacro("Update stop xy") + if !ok then goto quit + + ok=RunMacro("Create transit routes") + if !ok then goto quit + + ok=RunMacro("calc preload") + if !ok then goto quit + + ok=RunMacro("update preload fields") + if !ok then goto quit + + ok = RunMacro("TCB Run Macro", 1, "update headways",{}) + if !ok then goto quit + + RunMacro("close all") + + ok=1 + quit: + return(ok) + +EndMacro + +/************************************************************************************ + +Import transit layer + +import e00 and export to geo file + +Inputs + input\trcov.e00 + +Outputs + output\transit.dbd + + +************************************************************************************/ + +Macro "Import transit layer" + shared path, inputDir, outputDir, mxtap + + //check e00 file exists + di = GetDirectoryInfo(inputDir+"\\trcov.e00", "File") + if di.length = 0 then do + RunMacro("TCB Error", "trcov.e00 doesn't exist") + return(0) + end + + + ImportE00(inputDir + "\\trcov.e00", outputDir + "\\trtmp.dbd","line",outputDir+ "\\trtmp.bin",{ + {"Label","transit line file"}, + {"Layer Name","transit"}, + {"optimize","True"}, + {"Median Split", "True"}, + {"Node Layer Name", "Endpoints"}, + {"Node Table", outputDir + "\\trtmp_.bin"}, + {"Projection","NAD83:406",{"_cdist=1000","_limit=1000","units=us-ft"}}, + }) + + //open the intermediate transit line layer geo file + map = RunMacro("G30 new map", outputDir + "\\trtmp.dbd","False") + SetLayer("transit") + allflds=GetFields("transit","All") + fullflds=allflds[2] + allnodeflds = GetFields("endpoints", "All") + + // need to specify full field specifications + lineidfield = "transit.trcov-id"//arcinfo id field + nodeidfield = "endpoints.tnode"//for centroids purposes + + opts = {{"Layer Name", "transit"}, + {"File Type", "FFB"}, + {"ID Field", lineidfield}, + {"Field Spec", fullflds}, + {"Indexed Fields", {fullflds[1]}}, + {"Label", "transit line file"}, + {"Node layer name","trnode"}, + {"Node ID Field", nodeidfield}, + {"Node Field Spec", allnodeflds[2]}} + + if node_idx > 1 then + opts = opts + {{"Node ID Field", node_aflds[2][node_idx - 1]}} + + ExportGeography("transit",outputDir + "\\transit.dbd",opts) + + RunMacro("close all") + DeleteDatabase(outputDir+"\\trtmp.dbd") + + return(1) + + quit: + return(0) +EndMacro + +/******************************************************************************************* + +Add transit time fields + +Adds fields to the transit line layer. Local and premium time fields are added for +each period and direction. The field names are + +xxField_yy where + +Field is LOCTIME (local transit time) or PRETIME (premium transit time) +Field is TM + +xx is AB or BA +yy is period + EA: Early AM + AM: AM peak + MD: Midday + PM: PM peak + EV: Evening + +Note: this should be replaced by a revised transit network + +*******************************************************************************************/ +Macro "Add transit time fields" + + shared path, inputDir, outputDir + db_file = outputDir+"\\transit.dbd" + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + db_link_lyr = db_file + "|" + link_lyr + SetLayer(link_lyr) + vw = GetView() + strct = GetTableStructure(vw) + + // Copy the current name to the end of strct + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + + // Add fields to the output table + new_struct = strct + { + {"ABTM_EA", "real", 14, 6, "False",,,,,,, null}, + {"BATM_EA", "real", 14, 6, "False",,,,,,, null}, + {"ABTM_AM", "real", 14, 6, "False",,,,,,, null}, + {"BATM_AM", "real", 14, 6, "False",,,,,,, null}, + {"ABTM_MD", "real", 14, 6, "False",,,,,,, null}, + {"BATM_MD", "real", 14, 6, "False",,,,,,, null}, + {"ABTM_PM", "real", 14, 6, "False",,,,,,, null}, + {"BATM_PM", "real", 14, 6, "False",,,,,,, null}, + {"ABTM_EV", "real", 14, 6, "False",,,,,,, null}, + {"BATM_EV", "real", 14, 6, "False",,,,,,, null}} + + // Modify table structure + ModifyTable(vw, new_struct) + vw = GetView() + + // Set time fields to their respective input fields (especially needed for transit-only links) + periods = {"_EA","_AM","_MD","_PM","_EV"} + orig_periods = {"O", "A", "O", "P", "O"} + for i = 1 to periods.length do + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"ABTM"+periods[i]} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"ABTM"+orig_periods[i]} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + Opts = null + Opts.Input.[View Set] = {db_link_lyr, link_lyr} + Opts.Input.[Dataview Set] = {db_link_lyr, link_lyr} + Opts.Global.Fields = {"BATM"+periods[i]} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = {"BATM"+orig_periods[i]} + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + if !ok then goto quit + + + end + + + RunMacro("close all") + + ok=1 + quit: + return(ok) + +EndMacro + +/*************************************************************************************************************************** +Update stop xy + +Update transit node file with longitude and latitude of nearest node(?) + +Input files: + input\trstop.bin + +Output files: + output\transit.dbd + +***************************************************************************************************************************/ +Macro "Update stop xy" + shared path, inputDir, outputDir + + Opts = null + Opts.Input.[Dataview Set] = {{inputDir+"\\trstop.bin", outputDir+"\\transit.dbd|trnode", "NearNode", "ID"}, "trstop+trnode"} + Opts.Global.Fields = {"trstop.Longitude"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = "trnode.Longitude" + + ok = RunMacro("TCB Run Operation", 1, "Fill Dataview", Opts) + + if !ok then goto quit + + // STEP 2: Fill Dataview + Opts = null + Opts.Input.[Dataview Set] = {{inputDir+"\\trstop.bin", outputDir+"\\transit.dbd|trnode", "NearNode", "ID"}, "trstop+trnode"} + Opts.Global.Fields = {"trstop.Latitude"} + Opts.Global.Method = "Formula" + Opts.Global.Parameter = "trnode.Latitude" + + ok = RunMacro("TCB Run Operation", 2, "Fill Dataview", Opts) + if !ok then goto quit + ok=1 + quit: + Return(ok) + +EndMacro + +/************************************************************************** +Create transit routes + +Create transit routes from table, and add the following fields to route table + +mode +headway +real route +fare +configdir + + +input files: + input\trlink.bin binary file for routes with link-id numbers + rte_number: sequential route number + link_id: node id + direction: +/- + input\trstop.bin stop table + input\trrt.bin route table + output\transit.dbd transit line layer with the updated congested travel time + +output files: + output\transitrt.rts transit route file + +***************************************************************************/ +Macro "Create transit routes" + shared path, inputDir, outputDir + + //check input bin files exist + lk_tb=inputDir+"\\trlink.bin" + stp_tb=inputDir+"\\trstop.bin" + rte_tb=inputDir+"\\trrt.bin" + + fnm=lk_tb + di = GetDirectoryInfo(fnm, "File") + if di.length = 0 then do + ok=0 + RunMacro("TCB Error",fnm +"does not exist!") + goto quit + end + + fnm=stp_tb + di = GetDirectoryInfo(fnm, "File") + if di.length = 0 then do + ok=0 + RunMacro("TCB Error",fnm +"does not exist!") + goto quit + end + + fnm=rte_tb + di = GetDirectoryInfo(fnm, "File") + if di.length = 0 then do + ok=0 + RunMacro("TCB Error",fnm +"does not exist!") + goto quit + end + + // delete any old index file left from last time + fnm=outputDir+"\\trlink.bx" + ok=RunMacro("SDdeletefile",{fnm}) if !ok then goto quit + + fnm=outputDir+"\\trstop.bx" + ok=RunMacro("SDdeletefile",{fnm}) if !ok then goto quit + + fnm=outputDir+"\\trrt.bx" + ok=RunMacro("SDdeletefile",{fnm}) if !ok then goto quit + + Opts = null + Opts = {{"Routes Table" , rte_tb}, + {"Stops Table", stp_tb}, + {"Stops", "Route Stops",}} + Opts.Label = "Transit Routes" + Opts.Name = "Transit Routes" + geo_path = outputDir+"\\transit.dbd" + geo_layer = "transit" + rte_file=outputDir+"\\transitrt.rts" + info = CreateRouteSystemFromTables(lk_tb, geo_path, geo_layer,rte_file , Opts) + map = RunMacro("G30 new rt map", rte_file, "False", "False",) + + RunMacro("close all") + + ok=1 + quit: + return(ok) +EndMacro +/******************************************************************** + +Create pre-load volumes on highway network from bus routes in +transit line layer. + + + +input files: hwycov.e00 - hwy line layer ESRI exchange file +output files: hwy.dbd - hwy line geographic file + hwycad.log- a log file + hwycad.err - error file with error info + +v0.1 5/28/2012 jef + +********************************************************************/ + +macro "calc preload" + shared path,inputDir,outputDir,mxzone + + db_file=outputDir+"\\transit.dbd" + rte_file=outputDir+"\\transitrt.rts" + + + periods = {"_EA","_AM","_MD","_PM","_EV"} + hours = { 3, 3, 6.5, 3.5, 5} + headway_flds = {"OP_Headway","AM_Headway","OP_Headway","PM_Headway","OP_Headway"} + + bus_pce = 3.0 + + //load transit line layer and route file + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file,,) // line database + LinkIDField = link_lyr+".ID" + {rs_lyr, stop_lyr, ph_lyr} = RunMacro("TCB Add RS Layers", rte_file, "ALL",) // route system + if rs_lyr = null then goto quit + + //add fields for transit pce + SetLayer(link_lyr) + vw = GetView() + strct = GetTableStructure(vw) + + // Copy the current name to the end of strct + for i = 1 to strct.length do + strct[i] = strct[i] + {strct[i][1]} + end + + // Add fields to the output table + new_struct = strct + { + {"ABPRELOAD_EA", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_EA", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_AM", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_AM", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_MD", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_MD", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_PM", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_PM", "real", 14, 6, "False",,,,,,, null}, + {"ABPRELOAD_EV", "real", 14, 6, "False",,,,,,, null}, + {"BAPRELOAD_EV", "real", 14, 6, "False",,,,,,, null}} + + // Modify table structure + ModifyTable(vw, new_struct) + + // query to determine valid routes + SetLayer(rs_lyr) + qry = "Select * where Mode > 0" + sel="All" + + n = SelectByQuery(sel, "Several", qry,) + CreateProgressBar("Loading...", "True") + RT_ViewSet = rs_lyr+"|" + + rh = GetFirstRecord(RT_ViewSet, null) + nRecords = GetRecordCount(rs_lyr, sel ) + count = 1 + + // loop through each route + while rh <> null do + + + // loop through periods + for i = 1 to periods.length do // for time period + + + hdwyvals = GetRecordValues(rs_lyr, rh, {"Route_ID", headway_flds[i]}) // get route headway + rtnm = GetRouteNam(rs_lyr, hdwyvals[1][2]) + + // get the links for each route + rt_links = GetRouteLinks(rs_lyr, rtnm) + msg = "Loading Route " + rtnm + " ..." + if UpdateProgressBar(msg, r2i(count/nRecords*100)) = "True" then do + ShowMessage("Execution stopped by user.") + DestroyProgressBar() + Return() + end + + // calculate bus frequency based on headway + veh_per_hour=0.0 + if (hdwyvals[2][2] <> null and hdwyvals[2][2]>0) then veh_per_hour = 60.0 / hdwyvals[2][2] // 60 / HDWY + + if veh_per_hour > 0 then do + View_Set = link_lyr + "|" + + // loop for every link along the route + for link = 1 to rt_links.length do + + // set record for the link + rh2 = LocateRecord(View_Set, LinkIDField, {rt_links[link][1], rt_links[link][2]},) + if rh2 <> null then do + + + ABFillField = "ABPRELOAD"+periods[i] + BAFillField = "BAPRELOAD"+periods[i] + + // get bus flow + fldvals = GetRecordValues(link_lyr, rh2, {ABFillField, BAFillField}) + ab_val = fldvals[1][2] + ba_val = fldvals[2][2] + + transit_pce = veh_per_hour * hours[i] * bus_pce + + if rt_links[link][2] = 1 then do // FORWARD + + if fldvals[1][2] = null then do + ab_val = transit_pce + end + else do + ab_val = fldvals[1][2] + transit_pce + end + end + else do // REVERSE + if fldvals[2][2] = null then do + ba_val = transit_pce + end + else do + ba_val = fldvals[2][2] + transit_pce + end + end + + // set the proper link id with the preload value + SetRecordValues(link_lyr, rh2, {{ABFillField, ab_val}, {BAFillField, ba_val}}) + + end + + end + end + end + + count = count + 1 + next_rcd: + rh = GetNextRecord(RT_ViewSet, null, null) + end + DestroyProgressBar() + + RunMacro("close all") + + ok=1 + quit: + return(ok) +EndMacro +/********************************************************************************************************** +Update preload fields + +Updates preload fields on the highway line layer from the transit line layer +**********************************************************************************************************/ +Macro "update preload fields" + + shared path, inputDir, outputDir + + periods = {"_EA","_AM","_MD","_PM","_EV"} + db_file=outputDir+"\\hwy.dbd" + net_file = outputDir + "\\hwy.net" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + + vw = SetView(link_lyr) + + for i = 1 to periods.length do + + transitTable = outputDir+"\\transit.bin" + ABField = "ABPRELOAD"+periods[i] + BAField = "BAPRELOAD"+periods[i] + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, transitTable, {"ID"}, {"[TRCOV-ID]"}}, ABField } + Opts.Global.Fields = {"hwyline."+ABField} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"if transit."+ABField+" <>null then transit."+ABField+" else 0.0" } + ok = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ok then goto quit + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, transitTable, {"ID"}, {"[TRCOV-ID]"}}, BAField} + Opts.Global.Fields = {"hwyline."+BAField} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"if transit."+BAField+" <>null then transit."+BAField+" else 0.0" } + ok = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ok then goto quit + + end + + + //update the highway network with the new fields + for i = 1 to periods.length do + + field = "*PRELOAD"+periods[i] + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*PRELOAD"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABPRELOAD"+periods[i],link_lyr+".BAPRELOAD"+periods[i] } } + Opts.Global.Options.Constants = {1} + ok = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ok then goto quit + end + + RunMacro("close all") + + ok=1 + quit: + return(ok) + +EndMacro + +/********************************************************************************************************** +Update headway fields based upon Vovsha headway function + +**********************************************************************************************************/ +Macro "update headways" + + shared path, inputDir, outputDir + + db_file=outputDir+"\\transit.dbd" + rte_file=outputDir+"\\transitrt.rts" + + headway_flds = {"AM_Headway","OP_Headway","PM_Headway"} + + dim rev_headway[headway_flds.length] + + //load transit line layer and route file + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file,,) // line database + LinkIDField = link_lyr+".ID" + {rs_lyr, stop_lyr, ph_lyr} = RunMacro("TCB Add RS Layers", rte_file, "ALL",) // route system + if rs_lyr = null then goto quit + + SetLayer(rs_lyr) + vw = GetView() + + RT_ViewSet = rs_lyr+"|" + + rh = GetFirstRecord(RT_ViewSet, null) + + // loop through each route + while rh <> null do + + hdwyvals = GetRecordValues(rs_lyr, rh, headway_flds) // get route headway + + //for each headway + for i = 1 to hdwyvals.length do + + //calculate revised headway + rev_headway[i] = RunMacro("calculate revised headway",hdwyvals[i][2]) + + // set the headways back in the route record + SetRecordValues(rs_lyr, rh, {{headway_flds[i], rev_headway[i]}}) + end + + rh = GetNextRecord(RT_ViewSet, null, null) + end + + + RunMacro("close all") + + ok=1 + quit: + Return(ok) +EndMacro + + +/***************************************************************************** + + Revised headways + +*****************************************************************************/ +Macro "calculate revised headway" (headway) + + // CALCULATE REVISED HEADWAY + + slope_1=1.0 //slope for 1st segment (high frequency) transit + slope_2=0.8 //slope for 2nd segemnt (med frequency) transit + slope_3=0.7 //slope for 3rd segment (low frequency) transit + slope_4=0.2 //slope for 4th segment (very low freq) transit + + break_1=10 //breakpoint of 1st segment, min + break_2=20 //breakpoint of 2nd segment, min + break_3=30 //breakpoint of 3rd segment, min + + + if headway < break_1 then do + rev_headway = headway * slope_1 + end + else if headway < break_2 then do + part_1_headway = break_1 * slope_1 + part_2_headway = (headway - break_1) * slope_2 + rev_headway = part_1_headway + part_2_headway + end + else if headway < break_3 then do + part_1_headway = break_1 * slope_1 + part_2_headway = (break_2 - break_1) * slope_2 + part_3_headway = (headway - break_2) * slope_3 + rev_headway = part_1_headway + part_2_headway + part_3_headway + end + else do + part_1_headway = break_1 * slope_1 + part_2_headway = (break_2 - break_1) * slope_2 + part_3_headway = (break_3 - break_2) * slope_3 + part_4_headway = (headway - break_3) * slope_4 + rev_headway = part_1_headway + part_2_headway + part_3_headway + part_4_headway + end + + Return(rev_headway) + +EndMacro + + \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/dbox.rsc b/sandag_abm/src/main/gisdk/dbox.rsc new file mode 100644 index 0000000..c111630 --- /dev/null +++ b/sandag_abm/src/main/gisdk/dbox.rsc @@ -0,0 +1,256 @@ + +dBox "Run ABM" title: "SANDAG ABM" + init do + shared path, path_study + shared scr + + path_study="${workpath}" + scen_namefile = "\\scen_name.txt" + scen_info = GetFileInfo(path_study + scen_namefile) + if scen_info<>null then do + fptr_from = OpenFile(path_study + scen_namefile, "r") + scr=readarray(fptr_from) + end + else do + scr=null + while scr=Null do + RunMacro("getpathdirectory") + end + fptr_from = OpenFile(path_study + scen_namefile, "w") + WriteArray(fptr_from,scr) + closefile(fptr_from) + end +//end of editing + scen_num={1} + + path=scr[scen_num[1]] + +enditem + +text "Study Area:" 1,0,12 +text 12,0,34,1 Framed variable: path_study + +Button "Browse..." 48.5, 3, 16 do + opts={{"Initial Directory", path_study}} + path_study = ChooseDirectory("Choose a Study Area Directory",opts) + path_fortran=path_study+"\\fortran" + path_vb=path_study+"\\vb" + scen_info = GetFileInfo(path_study + scen_namefile) + if scen_info<>null then do + fptr_from = OpenFile(path_study + scen_namefile, "r") + scr=readarray(fptr_from) + end + else do + scr=null + while scr=Null do + RunMacro("getpathdirectory") + end + fptr_from = OpenFile(path_study + scen_namefile, "w") + WriteArray(fptr_from,scr) + closefile(fptr_from) + end + scen_num={1} + path=scr[scen_num[1]] + +enditem +//end of editing + +text "Add Scenario pathes in sequence order" 1,1.5, 38 + scroll list "scens" 1, 2.5, 46, 9 list:scr variable: scen_num multiple + help: "Select one or more scenarios to run" do + if scr = null then do // if any scenario chosen + while scr=null do + RunMacro("getpathdirectory") + end + fptr_from = OpenFile(path_study + scen_namefile, "w") + WriteArray(fptr_from,scr) + closefile(fptr_from) + scen_num ={1} // first scenario chosen + if tab_indx=1 then RunMacro("enable all1") else RunMacro("enable allfdlp") //enable all the "run" buttons + end + path=scr[scen_num[1]] + +enditem + +button "Quit" 48.5, 0, 16 do + batch_run_mode= false +//added by JXu on Nov 1, 2006 + maps = GetMaps() + if maps <> null then do + for i = 1 to maps[1].length do + SetMapSaveFlag(maps[1][i],"False") + end + end + RunMacro("G30 File Close All") + mtxs = GetMatrices() + if mtxs <> null then do + handles = mtxs[1] + for i = 1 to handles.length do + handles[i] = null + end + end +//end of editing + Return() +enditem + +button "Add" same , 1.5, 7 do + RunMacro("getpathdirectory") +//added by JXu + fptr_from = OpenFile(path_study + scen_namefile, "w") + WriteArray(fptr_from,scr) + closefile(fptr_from) +//end of editing + scen_num={1} + path=scr[scen_num[1]] + enableitem("Delete") +enditem + +// delete a scenario +button "Delete" 57.5,1.5,7 do + scr = ExcludeArrayElements(scr,scen_num[1],scen_num.length) + while scr= null do + RunMacro("getpathdirectory") + end + + fptr_from = OpenFile(path_study + scen_namefile, "w") + WriteArray(fptr_from,scr) + closefile(fptr_from) + scen_num={1} + path=scr[scen_num[1]] + +enditem + + +button "Change Study" 48.5, 4.5, 16 do + scr = null + RunMacro("getstudydirectory") + scen_info = GetFileInfo(path_study + scen_namefile) + if scen_info<>null then do + fptr_from = OpenFile(path_study + scen_namefile, "r") + scr=readarray(fptr_from) + tmp_flag=0 + for i=1 to scr.length do + if scr[i]=path then do + i=scr.length+1 + tmp_flag=1 + end + else i=i+1 + end + if tmp_flag=0 then do + scr=scr+{path} + fptr_from = OpenFile(path_study + scen_namefile, "w") + WriteArray(fptr_from,scr) + closefile(fptr_from) + end + end + else do + scr={path} + fptr_from = OpenFile(path_study + scen_namefile, "w") + WriteArray(fptr_from,scr) + closefile(fptr_from) + end + + scen_num={1} + + path=scr[scen_num[1]] +enditem + + + button "Run ABM" same, 6, 16 do + hideDbox() + RunMacro("TCB Init") + for sc = 1 to scen_num.length do + path = scr[ scen_num[sc] ] + ok = RunMacro("Run SANDAG ABM") + if !ok then goto exit + end + exit: + showdbox() + RunMacro("TCB Closing", run_ok, "False") + enditem + + + button "Export Data" same, 7.5, 16 do + hideDbox() + RunMacro("TCB Init") + for sc = 1 to scen_num.length do + path = scr[ scen_num[sc] ] + ok = RunMacro("ExportSandagData") + if !ok then goto exit + end + exit: + showdbox() + RunMacro("TCB Closing", run_ok, "False") + enditem + + button "Sum Transit Sellink" same, 9, 16 do + hideDbox() + RunMacro("TCB Init") + for sc = 1 to scen_num.length do + path = scr[ scen_num[sc] ] + ok = RunMacro("Sum Up Select Link Transit Trips") + if !ok then goto exit + end + exit: + showdbox() + RunMacro("TCB Closing", run_ok, "False") + enditem + + button "Sum Hwy Sellink" same, 10.5, 16 do + hideDbox() + RunMacro("TCB Init") + for sc = 1 to scen_num.length do + path = scr[ scen_num[sc] ] + ok = RunMacro("Sum Up Select Link Highway Trips") + if !ok then goto exit + end + exit: + showdbox() + RunMacro("TCB Closing", run_ok, "False") + enditem + + +EndDbox + +// Macro "getpathdirectory" doesn't allow the selected path with different path_study. +Macro "getpathdirectory" + shared path,path_study,scr + opts={{"Initial Directory", path_study}} + tmp_path=choosedirectory("Choose an alternative directory in the same study area", opts) + strlen=len(tmp_path) + for i = 1 to strlen do + tmp=right(tmp_path,i) + tmpx=left(tmp,1) + if tmpx="\\" then goto endfor + end + endfor: + strlenx=strlen-i + tmppath_study=left(tmp_path,strlenx) + if path_study=tmppath_study then do + path=tmp_path + tmp_flag=0 + for i=1 to scr.length do + if scr[i]=path then do + tmp_flag=1 + i=scr.length+1 + end + else i=i+1 + end + if tmp_flag=0 then do + tmp = CopyArray(scr) + tmp = tmp + {tmp_path} + scr = CopyArray(tmp) + end + //showmessage("write description of the alternative in the head file") + //x=RunProgram("notepad "+path+"\\head",) + mytime=GetDateAndTime() + + end + else do + path=null + msg1="The alternative directory selected is invalid because it has different study area! " + msg2="Please select again within the same study area " + msg3=" or use the Browse button to select a different study area." + showMessage(msg1+msg2+path_study+msg3) + end +EndMacro \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/exportTCData.rsc b/sandag_abm/src/main/gisdk/exportTCData.rsc new file mode 100644 index 0000000..2b1ce4b --- /dev/null +++ b/sandag_abm/src/main/gisdk/exportTCData.rsc @@ -0,0 +1,40 @@ +Macro "ExportSandagData" + + shared path_study, path, inputDir, outputDir + + RunMacro("close all") + RunMacro("TCB Init") + + + inputDir = path+"\\input" + outputDir = path+"\\output" + reportDir = path+"\\report" + + network_file = outputDir+"\\hwy.dbd" + + output_network_file = reportDir + "\\hwy_tcad" + output_transit_onoff_file = reportDir + "\\transit_onoff" + output_transit_flow_file = reportDir + "\\transit_flow" + output_transit_aggflow_file = reportDir + "\\transit_aggflow" + input_route_file = inputDir + "\\trrt" + output_route_file = reportDir + "\\trrt" + input_stop_file = inputDir + "\\trstop" + output_stop_file = reportDir + "\\trstop" + + input_hwyload_file = RunMacro("FormPath",{outputDir,"hwyload_"}) + output_hwyload_file = RunMacro("FormPath",{reportDir,"hwyload_"}) + + external_zones = {"1","2","3","4","5","6","7","8","9","10","11","12"} + + RunMacro("ExportNetworkToCsv",network_file,output_network_file) + RunMacro("ExportHwyloadtoCSV",input_hwyload_file,output_hwyload_file) + RunMacro("ExportBintoCSV",input_route_file, output_route_file) + RunMacro("ExportBintoCSV",input_stop_file, output_stop_file) + RunMacro("ExportTransitTablesToCsv",outputDir,RunMacro("BuildOnOffOptions"),output_transit_onoff_file) + RunMacro("ExportTransitTablesToCsv",outputDir,RunMacro("BuildTransitFlowOptions"),output_transit_flow_file) + RunMacro("ExportTransitTablesToCsv",outputDir,RunMacro("BuildAggFlowOptions"),output_transit_aggflow_file) + + RunMacro("G30 File Close All") + return(1) + +EndMacro diff --git a/sandag_abm/src/main/gisdk/externalInternal.rsc b/sandag_abm/src/main/gisdk/externalInternal.rsc new file mode 100644 index 0000000..d59e81d --- /dev/null +++ b/sandag_abm/src/main/gisdk/externalInternal.rsc @@ -0,0 +1,356 @@ +Macro "US to SD External Trip Model" + + shared path, inputDir, outputDir, mxext, scenarioYear + + controlTotals = "externalInternalControlTotals.csv" + + controlTotalsView = OpenTable("Control Totals", "CSV", {inputDir+"\\"+controlTotals}, {{"Shared", "True"}}) + mgraView = OpenTable("MGRA View", "CSV",{inputDir+"\\mgra13_based_input"+scenarioYear+".csv"}, {{"Shared", "True"}}) + + eaDanMatrix = OpenMatrix(outputDir+"\\"+"impdan_EA_high.mtx", ) + eaDanMC = CreateMatrixCurrencies(eaDanMatrix,,,) + eaDatMatrix = OpenMatrix(outputDir+"\\"+"impdat_EA_high.mtx", ) + eaDatMC = CreateMatrixCurrencies(eaDatMatrix,,,) + eaS2nhMatrix = OpenMatrix(outputDir+"\\"+"imps2nh_EA_high.mtx", ) + eaS2nhMC = CreateMatrixCurrencies(eaS2nhMatrix,,,) + eaS2thMatrix = OpenMatrix(outputDir+"\\"+"imps2th_EA_high.mtx", ) + eaS2thMC = CreateMatrixCurrencies(eaS2thMatrix,,,) + eaS3nhMatrix = OpenMatrix(outputDir+"\\"+"imps3nh_EA_high.mtx", ) + eaS3nhMC = CreateMatrixCurrencies(eaS3nhMatrix,,,) + eaS3thMatrix = OpenMatrix(outputDir+"\\"+"imps3th_EA_high.mtx", ) + eaS3thMC = CreateMatrixCurrencies(eaS3thMatrix,,,) + + amDanMatrix = OpenMatrix(outputDir+"\\"+"impdan_AM_high.mtx", ) + amDanMC = CreateMatrixCurrencies(amDanMatrix,,,) + amDatMatrix = OpenMatrix(outputDir+"\\"+"impdat_AM_high.mtx", ) + amDatMC = CreateMatrixCurrencies(amDatMatrix,,,) + amS2nhMatrix = OpenMatrix(outputDir+"\\"+"imps2nh_AM_high.mtx", ) + amS2nhMC = CreateMatrixCurrencies(amS2nhMatrix,,,) + amS2thMatrix = OpenMatrix(outputDir+"\\"+"imps2th_AM_high.mtx", ) + amS2thMC = CreateMatrixCurrencies(amS2thMatrix,,,) + amS3nhMatrix = OpenMatrix(outputDir+"\\"+"imps3nh_AM_high.mtx", ) + amS3nhMC = CreateMatrixCurrencies(amS3nhMatrix,,,) + amS3thMatrix = OpenMatrix(outputDir+"\\"+"imps3th_AM_high.mtx", ) + amS3thMC = CreateMatrixCurrencies(amS3thMatrix,,,) + + mdDanMatrix = OpenMatrix(outputDir+"\\"+"impdan_MD_high.mtx", ) + mdDanMC = CreateMatrixCurrencies(mdDanMatrix,,,) + mdDatMatrix = OpenMatrix(outputDir+"\\"+"impdat_MD_high.mtx", ) + mdDatMC = CreateMatrixCurrencies(mdDatMatrix,,,) + mdS2nhMatrix = OpenMatrix(outputDir+"\\"+"imps2nh_MD_high.mtx", ) + mdS2nhMC = CreateMatrixCurrencies(mdS2nhMatrix,,,) + mdS2thMatrix = OpenMatrix(outputDir+"\\"+"imps2th_MD_high.mtx", ) + mdS2thMC = CreateMatrixCurrencies(mdS2thMatrix,,,) + mdS3nhMatrix = OpenMatrix(outputDir+"\\"+"imps3nh_MD_high.mtx", ) + mdS3nhMC = CreateMatrixCurrencies(mdS3nhMatrix,,,) + mdS3thMatrix = OpenMatrix(outputDir+"\\"+"imps3th_MD_high.mtx", ) + mdS3thMC = CreateMatrixCurrencies(mdS3thMatrix,,,) + + pmDanMatrix = OpenMatrix(outputDir+"\\"+"impdan_PM_high.mtx", ) + pmDanMC = CreateMatrixCurrencies(pmDanMatrix,,,) + pmDatMatrix = OpenMatrix(outputDir+"\\"+"impdat_PM_high.mtx", ) + pmDatMC = CreateMatrixCurrencies(pmDatMatrix,,,) + pmS2nhMatrix = OpenMatrix(outputDir+"\\"+"imps2nh_PM_high.mtx", ) + pmS2nhMC = CreateMatrixCurrencies(pmS2nhMatrix,,,) + pmS2thMatrix = OpenMatrix(outputDir+"\\"+"imps2th_PM_high.mtx", ) + pmS2thMC = CreateMatrixCurrencies(pmS2thMatrix,,,) + pmS3nhMatrix = OpenMatrix(outputDir+"\\"+"imps3nh_PM_high.mtx", ) + pmS3nhMC = CreateMatrixCurrencies(pmS3nhMatrix,,,) + pmS3thMatrix = OpenMatrix(outputDir+"\\"+"imps3th_PM_high.mtx", ) + pmS3thMC = CreateMatrixCurrencies(pmS3thMatrix,,,) + + evDanMatrix = OpenMatrix(outputDir+"\\"+"impdan_EV_high.mtx", ) + evDanMC = CreateMatrixCurrencies(evDanMatrix,,,) + evDatMatrix = OpenMatrix(outputDir+"\\"+"impdat_EV_high.mtx", ) + evDatMC = CreateMatrixCurrencies(evDatMatrix,,,) + evS2nhMatrix = OpenMatrix(outputDir+"\\"+"imps2nh_EV_high.mtx", ) + evS2nhMC = CreateMatrixCurrencies(evS2nhMatrix,,,) + evS2thMatrix = OpenMatrix(outputDir+"\\"+"imps2th_EV_high.mtx", ) + evS2thMC = CreateMatrixCurrencies(evS2thMatrix,,,) + evS3nhMatrix = OpenMatrix(outputDir+"\\"+"imps3nh_EV_high.mtx", ) + evS3nhMC = CreateMatrixCurrencies(evS3nhMatrix,,,) + evS3thMatrix = OpenMatrix(outputDir+"\\"+"imps3th_EV_high.mtx", ) + evS3thMC = CreateMatrixCurrencies(evS3thMatrix,,,) + + freeTimeCurrencies = {eaDanMC.("*STM_EA (Skim)"),eaS2nhMC.("*HTM_EA (Skim)"),eaS3nhMC.("*HTM_EA (Skim)"), + amDanMC.("*STM_AM (Skim)"),amS2nhMC.("*HTM_AM (Skim)"),amS3nhMC.("*HTM_AM (Skim)"), + mdDanMC.("*STM_MD (Skim)"),mdS2nhMC.("*HTM_MD (Skim)"),mdS3nhMC.("*HTM_MD (Skim)"), + pmDanMC.("*STM_PM (Skim)"),pmS2nhMC.("*HTM_PM (Skim)"),pmS3nhMC.("*HTM_PM (Skim)"), + evDanMC.("*STM_EV (Skim)"),evS2nhMC.("*HTM_EV (Skim)"),evS3nhMC.("*HTM_EV (Skim)")} + + tollTimeCurrencies = {eaDatMC.("*STM_EA (Skim)"),eaS2thMC.("*HTM_EA (Skim)"),eaS3thMC.("*HTM_EA (Skim)"), + amDatMC.("*STM_AM (Skim)"),amS2thMC.("*HTM_AM (Skim)"),amS3thMC.("*HTM_AM (Skim)"), + mdDatMC.("*STM_MD (Skim)"),mdS2thMC.("*HTM_MD (Skim)"),mdS3thMC.("*HTM_MD (Skim)"), + pmDatMC.("*STM_PM (Skim)"),pmS2thMC.("*HTM_PM (Skim)"),pmS3thMC.("*HTM_PM (Skim)"), + evDatMC.("*STM_EV (Skim)"),evS2thMC.("*HTM_EV (Skim)"),evS3thMC.("*HTM_EV (Skim)")} + + //mod(eaS3thMC.("s3th_EA - itoll_EA"),10000), + + tollCostCurrencies = {eaDatMC.("dat_EA - itoll_EA"),eaS2thMC.("s2t_EA - itoll_EA"),eaS3thMC.("s3t_EA - itoll_EA"), + amDatMC.("dat_AM - itoll_AM"),amS2thMC.("s2t_AM - itoll_AM"),amS3thMC.("s3t_AM - itoll_AM"), + mdDatMC.("dat_MD - itoll_MD"),mdS2thMC.("s2t_MD - itoll_MD"),mdS3thMC.("s3t_MD - itoll_MD"), + pmDatMC.("dat_PM - itoll_PM"),pmS2thMC.("s2t_PM - itoll_PM"),pmS3thMC.("s3t_PM - itoll_PM"), + evDatMC.("dat_EV - itoll_EV"),evS2thMC.("s2t_EV - itoll_EV"),evS3thMC.("s3t_EV - itoll_EV")} + + controlTaz = GetDataVector(controlTotalsView+"|", "taz", {{"Sort Order", {{"taz", "Ascending"}}}} ) + controlWrk = GetDataVector(controlTotalsView+"|", "work", {{"Sort Order", {{"taz", "Ascending"}}}} ) + controlNon = GetDataVector(controlTotalsView+"|", "nonwork", {{"Sort Order", {{"taz", "Ascending"}}}} ) + + // create mgra size vectrors + + mgraView = OpenTable("MGRA View", "CSV", {inputDir+"\\mgra13_based_input"+scenarioYear+".csv"}, {{"Shared", "True"}}) + + mgra = GetDataVector(mgraView+"|", "mgra", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + taz = GetDataVector(mgraView+"|", "TAZ", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + hh = GetDataVector(mgraView+"|", "hh", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_ag = GetDataVector(mgraView+"|", "emp_ag", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_non_bldg_prod = GetDataVector(mgraView+"|", "emp_const_non_bldg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_non_bldg_office = GetDataVector(mgraView+"|", "emp_const_non_bldg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_utilities_prod = GetDataVector(mgraView+"|", "emp_utilities_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_utilities_office = GetDataVector(mgraView+"|", "emp_utilities_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_bldg_prod = GetDataVector(mgraView+"|", "emp_const_bldg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_const_bldg_office = GetDataVector(mgraView+"|", "emp_const_bldg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_mfg_prod = GetDataVector(mgraView+"|", "emp_mfg_prod", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_mfg_office = GetDataVector(mgraView+"|", "emp_mfg_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_whsle_whs = GetDataVector(mgraView+"|", "emp_whsle_whs", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_trans = GetDataVector(mgraView+"|", "emp_trans", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_retail = GetDataVector(mgraView+"|", "emp_retail", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_prof_bus_svcs = GetDataVector(mgraView+"|", "emp_prof_bus_svcs", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_prof_bus_svcs_bldg_maint = GetDataVector(mgraView+"|", "emp_prof_bus_svcs_bldg_maint", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_ed_k12 = GetDataVector(mgraView+"|", "emp_pvt_ed_k12", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_ed_post_k12_oth = GetDataVector(mgraView+"|", "emp_pvt_ed_post_k12_oth", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_health = GetDataVector(mgraView+"|", "emp_health", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_personal_svcs_office = GetDataVector(mgraView+"|", "emp_personal_svcs_office", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_amusement = GetDataVector(mgraView+"|", "emp_amusement", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_hotel = GetDataVector(mgraView+"|", "emp_hotel", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_restaurant_bar = GetDataVector(mgraView+"|", "emp_restaurant_bar", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_personal_svcs_retail = GetDataVector(mgraView+"|", "emp_personal_svcs_retail", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_religious = GetDataVector(mgraView+"|", "emp_religious", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_pvt_hh = GetDataVector(mgraView+"|", "emp_pvt_hh", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_ent = GetDataVector(mgraView+"|", "emp_state_local_gov_ent", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_fed_non_mil = GetDataVector(mgraView+"|", "emp_fed_non_mil", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_fed_mil = GetDataVector(mgraView+"|", "emp_fed_mil", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_blue = GetDataVector(mgraView+"|", "emp_state_local_gov_blue", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_state_local_gov_white = GetDataVector(mgraView+"|", "emp_state_local_gov_white", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + emp_public_ed = GetDataVector(mgraView+"|", "emp_public_ed", {{"Sort Order", {{"mgra", "Ascending"}}}} ) + + emp_blu = emp_const_non_bldg_prod + emp_const_non_bldg_office + emp_utilities_prod + emp_utilities_office + emp_const_bldg_prod + emp_const_bldg_office + emp_mfg_prod + emp_mfg_office + emp_whsle_whs + emp_trans + emp_svc = emp_prof_bus_svcs + emp_prof_bus_svcs_bldg_maint + emp_personal_svcs_office + emp_personal_svcs_retail + emp_edu = emp_pvt_ed_k12 + emp_pvt_ed_post_k12_oth + emp_public_ed + emp_gov = emp_state_local_gov_ent + emp_fed_non_mil + emp_fed_non_mil + emp_state_local_gov_blue + emp_state_local_gov_white + emp_ent = emp_amusement + emp_hotel + emp_restaurant_bar + emp_oth = emp_religious + emp_pvt_hh + emp_fed_mil + + wrk_size_mgra = ( emp_blu + + 1.364 * emp_retail + + 4.264 * emp_ent + + 0.781 * emp_svc + + 1.403 * emp_edu + + 1.779 * emp_health + + 0.819 * emp_gov + + 0.708 * emp_oth ) + + non_size_mgra = ( hh + + 1.069 * emp_blu + + 4.001 * emp_retail + + 6.274 * emp_ent + + 0.901 * emp_svc + + 1.129 * emp_edu + + 2.754 * emp_health + + 1.407 * emp_gov + + 0.304 * emp_oth ) + + // aggregate to TAZ + + rowLabels = GetMatrixRowLabels(mdDatMC.("Length (Skim)")) + numZones = rowLabels.length + dim wrkSizeTaz[numZones] + dim nonSizeTaz[numZones] + + for i=1 to numZones do + wrkSizeTaz[i] = 0 + nonSizeTaz[i] = 0 + end + + for i=1 to mgra.length do + tazNumber = taz[i] + wrkSizeTaz[tazNumber] = wrkSizeTaz[tazNumber] + wrk_size_mgra[i] + nonSizeTaz[tazNumber] = nonSizeTaz[tazNumber] + non_size_mgra[i] + end + + wrkSizeVector = ArrayToVector(wrkSizeTaz,{{"Row Based","False"},{"Type","Float"}} ) + nonSizeVector = ArrayToVector(nonSizeTaz,{{"Row Based","False"},{"Type","Float"}}) + + + // Initialize matrices + + opts = {} + opts.Label = "Trips" + opts.Type = "Double" + opts.Tables = {'Trips'} + + opts.[File Name] = outputDir+"\\"+"usSdWrkPA.mtx" + wrkMatrixPA = CreateMatrixFromScratch("wrkMatrixPA",numZones,numZones,opts) + wrkCurrenPA = CreateMatrixCurrency(wrkMatrixPA,'Trips',,,) + + opts.[File Name] = outputDir+"\\"+"usSdNonPA.mtx" + nonMatrixPA = CreateMatrixFromScratch("nonMatrixPA",numZones,numZones,opts) + nonCurrenPA = CreateMatrixCurrency(nonMatrixPA,'Trips',,,) + + //create exponentiated distance impedance matrices + opts.Label = "Prob" + opts.Type = "Double" + opts.Tables = {'Prob'} + + opts.[File Name] = outputDir+"\\"+"wrkProb.mtx" + wrkProbMatrix = CreateMatrixFromScratch("wrkProb",numZones,numZones,opts) + wrkProb = CreateMatrixCurrency(wrkProbMatrix,'Prob',,,) + + opts.[File Name] = outputDir+"\\"+"nonProb.mtx" + nonProbMatrix = CreateMatrixFromScratch("nonProb",numZones,numZones,opts) + nonProb = CreateMatrixCurrency(nonProbMatrix,'Prob',,,) + + wrkDistCoef = -0.029 + nonDistCoef = -0.006 + + wrkProb := wrkSizeVector * exp( wrkDistCoef * mdDatMC.("Length (Skim)")) + nonProb := nonSizeVector * exp( nonDistCoef * mdDatMC.("Length (Skim)")) + + wrkSumVector = GetMatrixVector(wrkProb, {{"Marginal", "Row Sum"}}) + wrkProb := wrkProb/wrkSumVector + + nonSumVector = GetMatrixVector(nonProb, {{"Marginal", "Row Sum"}}) + nonProb := nonProb/nonSumVector + + wrkCurrenPA := 0 + nonCurrenPA := 0 + + // Loop over external zones and set values in output matrix + for i=1 to controlTaz.length do + + wrkTotal = controlWrk[i] + nonTotal = controlNon[i] + + wrkTripVector = wrkTotal * GetMatrixVector(wrkProb,{{"Row", controlTaz[i]}}) + nonTripVector = nonTotal * GetMatrixVector(wrkProb,{{"Row", controlTaz[i]}}) + + SetMatrixVector(wrkCurrenPA, wrkTripVector, {{"Row",controlTaz[i]}}) + SetMatrixVector(nonCurrenPA, nonTripVector, {{"Row",controlTaz[i]}}) + + end + + // Convert PA to OD and Apply Diurnal Factors + opts.Label = "Trips" + opts.Type = "Float" + opts.Tables = {'Trips'} + + opts.[File Name] = outputDir+"\\"+"usSdWrkDaily.mtx" + wrkMatrixAP = TransposeMatrix(wrkMatrixPA,opts) + wrkCurrenAP = CreateMatrixCurrency(wrkMatrixAP,'Trips',,,) + + opts.[File Name] = outputDir+"\\"+"usSdNonDaily.mtx" + nonMatrixAP = TransposeMatrix(nonMatrixPA,opts) + nonCurrenAP = CreateMatrixCurrency(nonMatrixAP,'Trips',,,) + + wrkCurrenPA := 0.5 * wrkCurrenPA + nonCurrenPA := 0.5 * nonCurrenPA + wrkCurrenAP := 0.5 * wrkCurrenAP + nonCurrenAP := 0.5 * nonCurrenAP + + // Apply Occupancy and Diurnal Factors + + opts.Tables = {"DAN","S2N","S3N","DAT","S2T","S3T"} + + opts.[File Name] = outputDir+"\\"+"usSdWrk_EA.mtx" + wrkMatrixEA = CreateMatrixFromScratch("wrkMatrixEA",numZones,numZones,opts) + wrkCurrenEA = CreateMatrixCurrencies(wrkMatrixEA,,,) + opts.[File Name] = outputDir+"\\"+"usSdWrk_AM.mtx" + wrkMatrixAM = CreateMatrixFromScratch("wrkMatrixAM",numZones,numZones,opts) + wrkCurrenAM = CreateMatrixCurrencies(wrkMatrixAM,,,) + opts.[File Name] = outputDir+"\\"+"usSdWrk_MD.mtx" + wrkMatrixMD = CreateMatrixFromScratch("wrkMatrixMD",numZones,numZones,opts) + wrkCurrenMD = CreateMatrixCurrencies(wrkMatrixMD,,,) + opts.[File Name] = outputDir+"\\"+"usSdWrk_PM.mtx" + wrkMatrixPM = CreateMatrixFromScratch("wrkMatrixPM",numZones,numZones,opts) + wrkCurrenPM = CreateMatrixCurrencies(wrkMatrixPM,,,) + opts.[File Name] = outputDir+"\\"+"usSdWrk_EV.mtx" + wrkMatrixEV = CreateMatrixFromScratch("wrkMatrixEV",numZones,numZones,opts) + wrkCurrenEV = CreateMatrixCurrencies(wrkMatrixEV,,,) + + opts.[File Name] = outputDir+"\\"+"usSdNon_EA.mtx" + nonMatrixEA = CreateMatrixFromScratch("nonMatrixEA",numZones,numZones,opts) + nonCurrenEA = CreateMatrixCurrencies(nonMatrixEA,,,) + opts.[File Name] = outputDir+"\\"+"usSdNon_AM.mtx" + nonMatrixAM = CreateMatrixFromScratch("nonMatrixAM",numZones,numZones,opts) + nonCurrenAM = CreateMatrixCurrencies(nonMatrixAM,,,) + opts.[File Name] = outputDir+"\\"+"usSdNon_MD.mtx" + nonMatrixMD = CreateMatrixFromScratch("nonMatrixMD",numZones,numZones,opts) + nonCurrenMD = CreateMatrixCurrencies(nonMatrixMD,,,) + opts.[File Name] = outputDir+"\\"+"usSdNon_PM.mtx" + nonMatrixPM = CreateMatrixFromScratch("nonMatrixPM",numZones,numZones,opts) + nonCurrenPM = CreateMatrixCurrencies(nonMatrixPM,,,) + opts.[File Name] = outputDir+"\\"+"usSdNon_EV.mtx" + nonMatrixEV = CreateMatrixFromScratch("nonMatrixEV",numZones,numZones,opts) + nonCurrenEV = CreateMatrixCurrencies(nonMatrixEV,,,) + + wrkCurrenAll = {wrkCurrenEA,wrkCurrenAM,wrkCurrenMD,wrkCurrenPM,wrkCurrenEV} + nonCurrenAll = {nonCurrenEA,nonCurrenAM,nonCurrenMD,nonCurrenPM,nonCurrenEV} + + wrkDiurnalPA = {0.26,0.26,0.41,0.06,0.02} + wrkDiurnalAP = {0.08,0.07,0.41,0.42,0.02} + + nonDiurnalPA = {0.25,0.39,0.30,0.04,0.02} + nonDiurnalAP = {0.12,0.11,0.37,0.38,0.02} + + wrkOccupancy = {0.58,0.31,0.11} + nonOccupancy = {0.55,0.29,0.15} + + matrixNames = {"DAN","S2N","S3N","DAT","S2T","S3T"} + + for periodIdx=1 to 5 do + for occupIdx = 1 to 3 do + + wrkCurrenAll[periodIdx].(matrixNames[occupIdx]) := wrkOccupancy[occupIdx] * ( wrkDiurnalPA[periodIdx] * wrkCurrenPA + wrkDiurnalAP[periodIdx] * wrkCurrenAP ) + nonCurrenAll[periodIdx].(matrixNames[occupIdx]) := nonOccupancy[occupIdx] * ( nonDiurnalPA[periodIdx] * nonCurrenPA + nonDiurnalAP[periodIdx] * nonCurrenAP ) + + end + end + + // Toll choice split + + // values of time is cents per minute (toll cost is in cents) + votWork = 15.00 // $9.00/hr + votNonwork = 22.86 // $13.70/hr + ivtCoef = -0.03 + + for periodIdx=1 to 5 do + for occupIdx = 1 to 3 do + + currIndex = (periodIdx - 1) * 3 + occupIdx + + //wrkProb is work toll probability + wrkProb := if tollCostCurrencies[currIndex]>1000 then exp(ivtCoef * ( tollTimeCurrencies[ currIndex] - freeTimeCurrencies[ currIndex ] + mod(tollCostCurrencies[ currIndex ],10000) / votWork ) - 3.39) else + exp(ivtCoef * ( tollTimeCurrencies[ currIndex] - freeTimeCurrencies[ currIndex ] + tollCostCurrencies[ currIndex ] / votWork ) - 3.39) + + wrkProb := if tollCostCurrencies[ currIndex ] > 0 then wrkProb else 0 + wrkProb := wrkProb / ( 1 + wrkProb ) + + + wrkCurrenAll[periodIdx].(matrixNames[occupIdx+3]) := wrkCurrenAll[periodIdx].(matrixNames[occupIdx]) * wrkProb + wrkCurrenAll[periodIdx].(matrixNames[occupIdx]) := wrkCurrenAll[periodIdx].(matrixNames[occupIdx]) * (1.0 - wrkProb) + + //nonProb is non-work toll probability + nonProb := exp(ivtCoef * ( tollTimeCurrencies[ currIndex ] - freeTimeCurrencies[ currIndex] + mod(tollCostCurrencies[ currIndex],10000) / votNonwork )- 3.39) + nonProb := if tollCostCurrencies[ currIndex ] > 0 then nonProb else 0 + nonProb := nonProb / ( 1 + nonProb ) + nonCurrenAll[periodIdx].(matrixNames[occupIdx+3]) := nonCurrenAll[periodIdx].(matrixNames[occupIdx]) * nonProb + nonCurrenAll[periodIdx].(matrixNames[occupIdx]) := nonCurrenAll[periodIdx].(matrixNames[occupIdx]) * (1.0 - nonProb) + + end + end + + RunMacro("close all") + Return(1) + quit: + Return(0) +EndMacro \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/gui_generic.rsc b/sandag_abm/src/main/gisdk/gui_generic.rsc new file mode 100644 index 0000000..5692403 --- /dev/null +++ b/sandag_abm/src/main/gisdk/gui_generic.rsc @@ -0,0 +1,45 @@ + +dBox "Setup Scenario" title: "SANDAG ABM" + init do + shared path, path_study + path = "${workpath}" +enditem + +// set model run parameters +button "Set Model Parameters" 0,0,30, 2 do + RunMacro("TCB Init") + runString = "T:\\ABM\\release\\ABM\\${version}\\dist\\parameterEditor.exe "+path + RunMacro("HwycadLog",{"gui.rsc:","Create a scenario"+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Create a scenario", runString) +enditem + +// run model +button "Run Model" 0, 3, 30, 2 do + //hideDbox() + RunMacro("TCB Init") + RunMacro("getpathdirectory") + pFile_info = GetFileInfo(path+'\\conf\\sandag_abm.properties') + if pFile_info=null then do + CopyFile(path+"\\conf\\sandag_abm_standard.properties", path+"\\conf\\sandag_abm.properties") + end + ok = RunMacro("Run SANDAG ABM") + if !ok then goto exit + exit: + showdbox() + RunMacro("TCB Closing", run_ok, "False") +enditem + +//exit +button "Quit" 0, 6, 30, 2 do + RunMacro("G30 File Close All") + Return() +enditem + +EndDbox + +// Macro "getpathdirectory" doesn't allow the selected path with different path_study. +Macro "getpathdirectory" + shared path,path_study,scr + opts={{"Initial Directory", path}} + path=choosedirectory("Choose a scenario folder", opts) +EndMacro \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/hwyassign.rsc b/sandag_abm/src/main/gisdk/hwyassign.rsc new file mode 100644 index 0000000..d6809c5 --- /dev/null +++ b/sandag_abm/src/main/gisdk/hwyassign.rsc @@ -0,0 +1,896 @@ +/********************************************************************************* +Multi-model Multi-class Assignement +macro "hwy assignment" + +input files: hwy.dbd + hwy.net + Trip_EA.mtx: Early AM auto trip matrix file + Trip_AM.mtx: AM Peak auto trip matrix file + Trip_MD.mtx: Midday auto trip matrix file + Trip_PM.mtx: PM Peak auto trip matrix file + Trip_EV.mtx: Evening auto trip matrix file + +each file has 14 cores: + + Name Description + ------- --------------------------------------- + SOV_GP Drive Alone Non-Toll + SOV_PAY Drive Alone Toll + SR2_GP Shared-ride 2 Person Non-HOV Non-Toll + SR2_HOV Shared-ride 2 Person HOV Non-Toll + SR2_PAY Shared-ride 2 Person HOV Toll Eligible + SR3_GP Shared-ride 3+ Person Non-HOV Non-Toll + SR2_HOV Shared-ride 3+ Person HOV Non-Toll + SR2_PAY Shared-ride 3+ Person HOV Toll Eligible + lhdn Light heavy-duty Truck Non-Toll + mhdn Medium heavy-duty Truck Non-Toll + hhdnv Heavy heavy-duty Truck Non-Toll + lhdt Light heavy-duty Truck Toll + mhdt Medium heavy-duty Truck Toll + hhdt Heavy heavy-duty Truck Toll + + Functions are added by J Xu between Dec 2006 and March 2007 + (1) Select Link Analysis and split the resulting flow table by each select link inquiries; + (2) Enhanced highway assignment for four different cases, involving toll. + (3) Turning movement + +output files: + + hwyload_EA.bin: Early AM loaded network binary file + hwyload_AM.bin: Am Peak loaded network binary file + hwyload_MD.bin: Midday loaded network binary file + hwyload_PM.bin: PM Peak loaded network binary file + hwyload_EV.bin: Evening loaded network binary file + +Optionally (for select link and turning movements): + + turns_EA.bin: Early AM turning movement file + turns_AM.bin: Am Peak turning movement file + turns_MD.bin: Midday turning movement file + turns_PM.bin: PM Peak turning movement file + turns_EV.bin: Evening turning movement file + + select_EA.mtx: Early AM select link trip matrix file + select_AM.mtx: Am Peak select link trip matrix file + select_MD.mtx: Midday select link trip matrix file + select_PM.mtx: PM Peak select link trip matrix file + select_EV.mtx: Evening select link trip matrix file + + +SANDAG ABM Version 1.0 + JEF 2012-03-20 + changed linktypeturnscst.dbf to linktypeturns.dbf as Joel suggested. +*************************************************************************************/ + +Macro "hwy assignment" (args) + + Shared path, inputDir, outputDir, mxzone + + properties = "\\conf\\sandag_abm.properties" + convergence = RunMacro("read properties",properties,"convergence", "S") + assign_reliability="true" + + turn_file="\\nodes.txt" + turn_flag=0 + NumofCPU = 8 + iteration = args[1] + assignByVOT= args[2] + + // for debug + + periods = {"_EA","_AM","_MD","_PM","_EV"} + + RunMacro("close all") + dim excl_qry[periods.length],excl_toll[periods.length],excl_dat[periods.length],excl_s2nh[periods.length],excl_s2th[periods.length],excl_s3nh[periods.length] + dim excl_s3th[periods.length],excl_lhdn[periods.length],excl_mhdn[periods.length],excl_hhdn[periods.length],excl_lhdt[periods.length],excl_mhdt[periods.length] + dim excl_hhdt[periods.length],toll_fld[periods.length],toll_fld2[periods.length] + + linkt= {"*TM_EA","*TM_AM","*TM_MD","*TM_PM","*TM_EV"} + linkcap={"*CP_EA","*CP_AM","*CP_MD","*CP_PM","*CP_EV"} +// xt= {"*TX_EA","*TX_AM","*TX_MD","*TX_PM","*TX_EV"} + xcap= {"*CX_EA","*CX_AM","*CX_MD","*CX_PM","*CX_EV"} + + cycle={"*CYCLE_EA","*CYCLE_AM","*CYCLE_MD","*CYCLE_PM","*CYCLE_EV"} + pfact={"*PF_EA","*PF_AM","*PF_MD","*PF_PM","*PF_EV"} + gcrat={"*GCRATIO_EA","*GCRATIO_AM","*GCRATIO_MD","*GCRATIO_PM","*GCRATIO_EV"} + alpha1={"*ALPHA1_EA","*ALPHA1_AM","*ALPHA1_MD","*ALPHA1_PM","*ALPHA1_EV"} + beta1={"*BETA1_EA","*BETA1_AM","*BETA1_MD","*BETA1_PM","*BETA1_EV"} + alpha2={"*ALPHA2_EA","*ALPHA2_AM","*ALPHA2_MD","*ALPHA2_PM","*ALPHA2_EV"} + beta2={"*BETA2_EA","*BETA2_AM","*BETA2_MD","*BETA2_PM","*BETA2_EV"} + preload={"*PRELOAD_EA","*PRELOAD_AM","*PRELOAD_MD","*PRELOAD_PM","*PRELOAD_EV"} + statrel={"*STATREL_EA","*STATREL_AM","*STATREL_MD","*STATREL_PM","*STATREL_EV"} + + db_file = outputDir + "\\hwy.dbd" + net_file= outputDir+"\\hwy.net" + + turn={"turns_EA.bin","turns_AM.bin","turns_MD.bin","turns_PM.bin","turns_EV.bin"} + selectlink_mtx={"select_EA.mtx","select_AM.mtx","select_MD.mtx","select_PM.mtx","select_EV.mtx"} //added for select link analysis by JXu + selinkqry_file="selectlink_query.txt" + if GetFileInfo(inputDir + "\\"+ selinkqry_file) <> null then do //select link analysis is only available in stage II + selink_flag =1 + fptr_from = OpenFile(inputDir + "\\"+selinkqry_file, "r") + tmp_qry=readarray(fptr_from) + index =1 + selinkqry_name=null + selink_qry=null + subs=null + while index <=ArrayLength(tmp_qry) do + if left(trim(tmp_qry[index]),1)!="*" then do + subs=ParseString(trim(tmp_qry[index]),",") + if subs!=null then do + query=subs[3] + if ArrayLength(subs)>3 then do + for i=4 to ArrayLength(subs) do + query=query+" "+subs[2]+" "+subs[i] + end + end + selinkqry_name=selinkqry_name+{subs[1]} + selink_qry=selink_qry+{query} + end + end + index = index + 1 + end + end + + asign = {"hwyload_EA.bin","hwyload_AM.bin","hwyload_MD.bin","hwyload_PM.bin","hwyload_EV.bin"} + oue_path = {"oue_path_EA.obt", "oue_path_AM.obt","oue_path_MD.obt","oue_path_PM.obt","oue_path_EV.obt"} + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + db_link_lyr=db_file+"|"+link_lyr + db_node_lyr=db_file+"|"+node_lyr + + // drive-alone non-toll exclusion set + excl_dan={db_link_lyr, link_lyr, "dan", "Select * where !((ihov=1|ifc>7)&ITRUCK<5)"} + + // shared-2 non-toll non-HOV exclusion set + excl_s2nn=excl_dan + + // shared 3+ non-toll non-HOV exclusion set + excl_s3nn=excl_dan + + + for i = 1 to periods.length do + // drive-alone toll exclusion set + //excl_dat[i]={db_link_lyr, link_lyr, "dat", "Select * where !(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)&ITRUCK<5)"} + excl_dat[i]={db_link_lyr, link_lyr, "dat", "Select * where !((ihov=1|ihov=4|((ihov=2|ihov=3)&abln"+periods[i]+"<9)|ifc>7)& ITRUCK<5)"} + + // shared-2 non-toll HOV exclusion set + excl_s2nh[i]={db_link_lyr, link_lyr, "s2nh", "Select * where !((ihov=1|(ihov=2&abln"+periods[i]+" <9)|ifc>7)&ITRUCK<5)"} + + // shared-2 toll HOV exclusion set + excl_s2th[i]={db_link_lyr, link_lyr, "s2th", "Select * where !(((ihov=1|(ihov=2&abln"+periods[i]+"<9)|ihov=4|(ihov=3&itoll"+periods[i]+">0&abln"+periods[i]+"<9))|ifc>7)&ITRUCK<5)"} + + // shared=3+ non-toll non-HOV exclusion set + excl_s3nh[i]={db_link_lyr, link_lyr, "s3nh", "Select * where !((ihov=1|((ihov=2|ihov=3)&abln"+periods[i]+"<9)|ifc>7)&ITRUCK<5)"} + + // shared=3+ toll HOV exclusion set + excl_s3th[i]={db_link_lyr, link_lyr, "s3th", "Select * where abln"+periods[i]+"=9|ITRUCK>4"} + + // light-heavy truck non-toll exclusion set + excl_lhdn[i]={db_link_lyr, link_lyr, "lhdn", "Select * where !((ihov=1|ifc>7)&(ITRUCK<4|ITRUCK=7))"} + + // medium-heavy truck non-toll exclusion set + excl_mhdn[i]={db_link_lyr, link_lyr, "mhdn", "Select * where !((ihov=1|ifc>7)&(ITRUCK<3|ITRUCK>5))"} + + // heavy-heavy truck non-toll exclusion set + excl_hhdn[i]={db_link_lyr, link_lyr, "hhdn", "Select * where !((ihov=1|ifc>7)&(ITRUCK=1|ITRUCK>4))"} + + // light-heavy truck toll exclusion set + //excl_lhdt[i]={db_link_lyr, link_lyr, "lhd", "Select * where !(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7) & (ITRUCK<4|ITRUCK=7))"} + excl_lhdt[i]={db_link_lyr, link_lyr, "lhd", "Select * where !(((ihov=1|ihov=4|((ihov=2|ihov=3)&(abln"+periods[i]+"<9)))|ifc>7) & (ITRUCK<4|ITRUCK=7))"} + + // medium-heavy truck toll exclusion set + //excl_mhdt[i]={db_link_lyr, link_lyr, "mhd", "Select * where !(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)&(ITRUCK<3|ITRUCK>5))"} + excl_mhdt[i]={db_link_lyr, link_lyr, "mhd", "Select * where !(((ihov=1|ihov=4|((ihov=2|ihov=3)&(abln"+periods[i]+"<9)))|ifc>7)&(ITRUCK<3|ITRUCK>5))"} + + // heavy-heavy truck toll exclusion set + //excl_hhdt[i]={db_link_lyr, link_lyr, "hhd", "Select * where !(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)&(ITRUCK=1|ITRUCK>4))"} + excl_hhdt[i]={db_link_lyr, link_lyr, "hhd", "Select * where !(((ihov=1|ihov=4|((ihov=2|ihov=3)&(abln"+periods[i]+"<9)))|ifc>7)&(ITRUCK=1|ITRUCK>4))"} + + end + + //reset exclusion array value based on the selection set results + + set = "dat" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + for i = 1 to periods.length do + //n = SelectByQuery(set, "Several","Select * where !((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)",) + n = SelectByQuery(set, "Several","Select * where !((ihov=1|ihov=4|((ihov=2|ihov=3)&abln"+periods[i]+"<9)|ifc>7)& ITRUCK<5)",) + if n = 0 then excl_dat[i]=null + end + + set = "s2nh" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + for i = 1 to periods.length do + n = SelectByQuery(set, "Several","Select * where !((ihov=1|(ihov=2&abln"+periods[i]+"<9)|ifc>7)&ITRUCK<5)",) + if n = 0 then excl_s2nh[i]=null + end + + set = "s2th" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + for i = 1 to periods.length do + n = SelectByQuery(set, "Several", "Select * where !(((ihov=1|(ihov=2&abln"+periods[i]+"<9)|ihov=4|(ihov=3&itoll"+periods[i]+">0&abln"+periods[i]+"<9))|ifc>7)&ITRUCK<5)",) + if n = 0 then excl_s2th[i]=null + end + + set = "s3nh" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + for i = 1 to periods.length do + n = SelectByQuery(set, "Several","Select * where !((ihov=1|((ihov=2|ihov=3)&abln"+periods[i]+"<9)|ifc>7)&ITRUCK<5)",) + if n = 0 then excl_s3nh[i]=null + end + + set = "s3th" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + for i = 1 to periods.length do + n = SelectByQuery(set, "Several", "Select * where abln"+periods[i]+"=9|ITRUCK>4",) + if n = 0 then excl_s3th[i]=null + end + + if assignByVOT = "false" then do + trip={"Trip_EA.mtx","Trip_AM.mtx","Trip_MD.mtx","Trip_PM.mtx","Trip_EV.mtx"} + num_class=14 + vehclass={1,2,3,4,5,6,7,8,9,10,11,12,13,14} + class_PCE={1,1,1,1,1,1,1,1,1.3,1.5,2.5,1.3,1.5,2.5} + VOT={67,67,67,67,67,67,67,67,67,68,89,67,68,89} // vot is in cents per minute: 67 cents/min = $40.20/hour + + for i = 1 to periods.length do + excl_qry[i]={excl_dan,excl_dat[i],excl_s2nn,excl_s2nh[i],excl_s2th[i],excl_s3nn,excl_s3nh[i],excl_s3th[i],excl_lhdn[i],excl_mhdn[i],excl_hhdn[i],excl_lhdt[i],excl_mhdt[i],excl_hhdt[i]} + toll_fld2[i]= {"COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i],"COST","COST","COST","ITOLL3"+periods[i],"ITOLL4"+periods[i],"ITOLL5"+periods[i]} + end + end + else do + + // for VOT assignment, explode the passenger modes 1 through 8 to 1 through 24. First 8 low vot, next 8 med vot, final 8 high vot. Then 6 truck classes for total 30 classes. + trip={"Trip"+periods[1]+"_VOT.mtx", "Trip"+periods[2]+"_VOT.mtx", "Trip"+periods[3]+"_VOT.mtx", "Trip"+periods[4]+"_VOT.mtx", "Trip"+periods[5]+"_VOT.mtx"} + num_class=30 + vehclass={1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28,29,30} + class_PCE={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1.3,1.5,2.5,1.3,1.5,2.5} + VOT={16.6,16.6,16.6,16.6,16.6,16.6,16.6,16.6,33.3,33.3,33.3,33.3,33.3,33.3,33.3,33.3,100,100,100,100,100,100,100,100,67,68,89,67,68,89} //assuming $10/hr, $20/hr, and $60/hr as max of each range + + for i = 1 to periods.length do + excl_qry[i]={ + excl_dan,excl_dat[i],excl_s2nn,excl_s2nh[i],excl_s2th[i],excl_s3nn,excl_s3nh[i],excl_s3th[i], + excl_dan,excl_dat[i],excl_s2nn,excl_s2nh[i],excl_s2th[i],excl_s3nn,excl_s3nh[i],excl_s3th[i], + excl_dan,excl_dat[i],excl_s2nn,excl_s2nh[i],excl_s2th[i],excl_s3nn,excl_s3nh[i],excl_s3th[i], + excl_lhdn[i],excl_mhdn[i],excl_hhdn[i],excl_lhdt[i],excl_mhdt[i],excl_hhdt[i]} + toll_fld2[i]= { + "COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i], + "COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i], + "COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i],"COST","COST","ITOLL3"+periods[i], + "COST","COST","COST","ITOLL3"+periods[i],"ITOLL4"+periods[i],"ITOLL5"+periods[i]} + end + end + + + + //Prepare selection set for turning movement report, by JXu + if (turn_flag=1 & iteration=4) then do + if GetFileInfo(inputDir+turn_file)!=null then do + fptr_turn = OpenFile(inputDir + turn_file,"r") + tmp_qry=readarray(fptr_turn) + turn_qry=null + index=1 + while index <=ArrayLength(tmp_qry) do + if index=1 then + turn_qry = "select * where " + "ID=" + tmp_qry[1] + else + turn_qry = turn_qry + " OR " + "ID=" + tmp_qry[index] + if tmp_qry[index]="all" or tmp_qry[index]="All" or tmp_qry[index]="ALL" then do + turn_qry = "select * where ID>"+i2s(mxzone) //select all nodes except centroids + index=ArrayLength(tmp_qry) + end + index=index+1 + end + closefile(fptr_turn) + end + else turn_qry = "select * where temp=1" + if GetFileInfo(path+"\\turn.err")!=null then do + ok=RunMacro("SDdeletefile",{path+"\\turn.err"}) + if !ok then goto quit + end + + tmpset = "turn" + vw_set = node_lyr + "|" + tmpset + SetLayer(node_lyr) + n = SelectByQuery(tmpset , "Several", turn_qry,) + if n = 0 then do + showmessage("Warning!!! No intersections selected for turning movement.") + fp_tmp = OpenFile(path + "\\turn.err","w") + WriteArray(fp_tmp,{"No intersections have been selected for turning movement."}) + closefile(fp_tmp) + return(1) + end + end + + + //set hwy.net with turn penalty of time in minutes + d_tp_tb = inputDir + "\\linktypeturns.dbf" + s_tp_tb = outputDir + "\\turns.dbf" + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Toll Set] = {db_link_lyr, link_lyr} + Opts.Input.[Centroids Set] = {db_node_lyr, node_lyr, "Selection", "select * where ID <="+i2s(mxzone)} + Opts.Global.[Spc Turn Pen Method] = 3 + Opts.Input.[Def Turn Pen Table] = {d_tp_tb} + Opts.Input.[Spc Turn Pen Table] = {s_tp_tb} + Opts.Field.[Link type] = "IFC" + Opts.Global.[Global Turn Penalties] = {0, 0, 0, 0} + Opts.Flag.[Use Link Types] = "True" + RunMacro("HwycadLog",{"hwyassign.rsc: hwy assignment","Highway Network Setting"}) + ok = RunMacro("TCB Run Operation", 1, "Highway Network Setting", Opts) + if !ok then goto quit + + // STEP 1: MMA + for i = 1 to periods.length do + + //set the vdf DLL and vdf field names based on whether reliability is being used or not +// if assign_reliability="true" then do + vdf_fields = {linkt[i], linkcap[i], xcap[i], cycle[i],pfact[i], gcrat[i], alpha1[i], beta1[i], alpha2[i], beta2[i], + "*LOSC_FACT","*LOSD_FACT","*LOSE_FACT", "*LOSFL_FACT", "*LOSFH_FACT", statrel[i], "Length", preload[i]} + vdf_file = "shrp.vdf" + vdf_defaults={ , , ,1.5 ,1 , 0.4 , 0.15, 4, 0.15, 4, 0, 0, 0, 0, 0, 0, 0, 0 } +// end +/* else do + vdf_fields = {linkt[i], linkcap[i], xcap[i], cycle[i],pfact[i], gcrat[i], alpha1[i], beta1[i], alpha2[i], beta2[i], preload[i]} + vdf_file = "tucson_vdf_rev.vdf" + vdf_defaults={ , , ,1.5 ,1 , 0.4 , 0.15, 4, 0.15, 4, 0 } + end + */ + net = ReadNetwork(net_file) + NetOpts = null + NetOpts.[Link ID] = link_lyr+".ID" + NetOpts.[Type] = "Enable" + NetOpts.[Write to file] = "Yes" + ChangeLinkStatus(net,, NetOpts) + + // Open the trip table to assign, and get the first table name + ODMatrix = outputDir + "\\"+trip[i] + m = OpenMatrix(ODMatrix,) + matrixCores = GetMatrixCoreNames(GetMatrix()) + coreName = matrixCores[1] + + + //settings for highway assignment + Opts = null + Opts.Global.[Force Threads] = 2 + Opts.Input.Database = db_file + Opts.Input.Network = net_file + + Opts.Input.[OD Matrix Currency] = {ODMatrix, coreName, , } + Opts.Input.[Exclusion Link Sets] = excl_qry[i] + Opts.Field.[Vehicle Classes] = vehclass + Opts.Field.[Fixed Toll Fields] = toll_fld2[i] + Opts.Field.[VDF Fld Names] = vdf_fields + Opts.Global.[Number of Classes] = num_class + Opts.Global.[Class PCEs] = class_PCE + Opts.Global.[Class VOIs] = VOT + Opts.Global.[Load Method] = "NCFW" + Opts.Global.[N Conjugate] = 2 + Opts.Global.[Loading Multiplier] = 1 + Opts.Global.Convergence = 0.0005 + Opts.Global.[Cost Function File] = vdf_file + Opts.Global.[VDF Defaults] = vdf_defaults + Opts.Global.[Iterations]=1000 + Opts.Flag.[Do Share Report] = 1 + Opts.Output.[Flow Table] = outputDir+"\\"+asign[i] + if (turn_flag=1 & iteration=4) then Opts.Input.[Turning Movement Node Set] = {db_node_lyr, node_lyr, "Selection", turn_qry} + if (turn_flag=1 & iteration=4) then Opts.Flag.[Do Turn Movement] = 1 + if (turn_flag=1 & iteration=4) then Opts.Output.[Movement Table] = outputDir+"\\"+turn[i] + Opts.Field.[MSA Flow] = "_MSAFlow" + periods[i] + Opts.Field.[MSA Cost] = "_MSACost" + periods[i] + Opts.Field.[MSA Time] = "_MSATime" + periods[i] + Opts.Global.[MSA Iteration] = iteration + if (selink_flag = 1 & iteration = 4) then do + Opts.Global.[Critical Queries] = selink_qry + Opts.Global.[Critical Set names] = selinkqry_name + Opts.Output.[Critical Matrix].Label = "Select Link Matrix" + Opts.Output.[Critical Matrix].Compression = 1 + Opts.Output.[Critical Matrix].[File Name] = outputDir +"\\"+selectlink_mtx[i] + end + RunMacro("HwycadLog",{"hwyassign.rsc: hwy assignment","MMA: "+asign[i]}) + ok = RunMacro("TCB Run Procedure", i, "MMA", Opts) + if !ok then goto quit + end + if!ok then goto quit + + ok=1 + quit: + RunMacro("close all") + return(ok) +EndMacro + +//added by JXu to split the flow table by queries. + +Macro "Selink Flow Split" (arr_selink) + shared path, inputDir, outputDir + asign=arr_selink[1] + selinkqry_name=arr_selink[2] + m=ArrayLength(selinkqry_name)+1 + dim new_flowtb[ArrayLength(asign),ArrayLength(selinkqry_name)+1] //All new flow table names after splitting for OP, AM and PM period assignments (3x5=15 names) + for i=1 to ArrayLength(asign) do + for j=1 to ArrayLength(selinkqry_name) do + new_flowtb[i][j] = outputDir+"\\"+left(asign[i],len(asign[i])-4)+"sl"+ i2s(j) +".bin" + end + new_flowtb[i][ArrayLength(selinkqry_name)+1]=outputDir+"\\"+asign[i] + end +//rename the original flow table file name to avoid the file name conflit with the splitted flow table. + for i=1 to ArrayLength(asign) do + new_file=left(asign[i],len(asign[i])-4)+"_orig.bin" + dict_nm = left(asign[i],len(asign[i])-4)+".dcb" + newdict_nm = left(asign[i],len(asign[i])-4)+"_orig.dcb" + ok=RunMacro("SDrenamefile",{outputDir+"\\"+asign[i],outputDir+"\\"+new_file}) if!ok then goto quit + ok=RunMacro("SDrenamefile",{outputDir+"\\"+dict_nm,outputDir+"\\"+newdict_nm}) if!ok then goto quit + asign[i]=new_file + end + +// This loop closes all views: + tmp = GetViews() + if tmp<>null then + for i = 1 to ArrayLength(tmp[1]) do + CloseView(tmp[1][i]) + end + + flowtb_vw = OpenTable("Flow Table", "FFB", {outputDir+"\\"+asign[1],}) + flowtb_fldinfo = GetViewStructure(flowtb_vw) //Get all the fields info from the flow table + dim flds_flag[ArrayLength(flowtb_fldinfo),ArrayLength(selinkqry_name)+1] +//flds_flag[i][j]=1 if flowtb_fldinfo[i][1] will be exported to .bin file for query j; +//if j is more than number of queries, then flds_flag[i][j] decides if flowtb_fldinfo[i][1] will be exported to .bin flow table without query info. + for i=1 to ArrayLength(flowtb_fldinfo) do + flag_tot = 0 + for j=1 to ArrayLength(selinkqry_name) do + if Position(flowtb_fldinfo[i][1],selinkqry_name[j])=0 then do + flds_flag[i][j]=0 + flag_tot=flag_tot+1 + end + else flds_flag[i][j]=1 + end + if flag_tot = ArrayLength(selinkqry_name) then do + for j=1 to ArrayLength(selinkqry_name) do + flds_flag[i][j]=1 + end + flds_flag[i][ArrayLength(selinkqry_name)+1]=1 //This will be exported to the flow table of original format without any query info + end + else flds_flag[i][ArrayLength(selinkqry_name)+1]=0 + end + + dim newflds[ArrayLength(selinkqry_name)+1] + for j=1 to ArrayLength(selinkqry_name)+1 do + for i=1 to ArrayLength(flowtb_fldinfo) do + if flds_flag[i][j]=1 then + newflds[j]=newflds[j]+{flowtb_fldinfo[i][1]} + end + end + + for i=1 to arraylength(asign) do + flow_vw = OpenTable("All Flow", "FFB", {outputDir+"\\"+asign[i],}) + for j=1 to arraylength(selinkqry_name) do + ExportView(flow_vw+"|", "FFB", new_flowtb[i][j],newflds[j], + {{"Additional Fields",{{"AB_Flow_"+selinkqry_name[j],"Real",15,4,"No"}, + {"BA_Flow_"+selinkqry_name[j],"Real",15,4,"No"}, + {"Tot_Flow_"+selinkqry_name[j],"Real",15,4,"No"}}} + }) + end + ExportView(flow_vw+"|", "FFB", new_flowtb[i][m],newflds[m],) + end + + //Fill in the newly added fields in the splitted flow table for each query + for i=1 to arraylength(asign) do + newflow_vw=null + newflow_fldinfo=null + For j=1 to arraylength(selinkqry_name) do + newflow_vw = OpenTable("Splitted Flow", "FFB", {new_flowtb[i][j],}) + newflow_fldinfo = GetViewStructure(newflow_vw) + AB_qry_flds=null + BA_qry_flds=null + for k=1 to ArrayLength(newflow_fldinfo) do + if Position(newflow_fldinfo[k][1],selinkqry_name[j])<>0 then do + if Position(newflow_fldinfo[k][1],"AB")<>0 then + AB_qry_flds=AB_qry_flds+{newflow_fldinfo[k][1]} + if Position(newflow_fldinfo[k][1],"BA")<>0 then + BA_qry_flds=BA_qry_flds+{newflow_fldinfo[k][1]} + end + end + order = {{"ID1", "Ascending"}} + rh = GetFirstRecord(newflow_vw+ "|", order) + while rh <> null do + AB_vals=0 + BA_vals=0 + for k=1 to ArrayLength(AB_qry_flds) do + vals=GetRecordValues(newflow_vw, rh, {AB_qry_flds[k],BA_qry_flds[k]}) + AB_vals=AB_vals+NZ(vals[1][2]) + BA_vals=BA_vals+NZ(vals[2][2]) + Tot_vals=AB_vals+BA_vals + end + SetRecordValues(newflow_vw, rh, {{"AB_Flow_"+selinkqry_name[j], AB_vals}, + {"BA_Flow_"+selinkqry_name[j], BA_vals}, + {"Tot_Flow_"+selinkqry_name[j],Tot_vals}}) + setRecord(newflow_vw, rh) + rh = GetNextRecord(newflow_vw + "|", rh, order) + end + end + end + + ok=1 + quit: + RunMacro("close all") + return(ok) + +endMacro + + +/********************************************************************************************************** + + combine truck tt_nt assign + + +**********************************************************************************************************/ +Macro "combine truck tt_nt assign"(arr) + shared path, inputDir, outputDir + stage = arr[1] + + asignbin={"lodtollop2.bin","lodtollam2.bin","lodtollpm2.bin"} + asigndcb={"lodtollop2.DCB","lodtollam2.DCB","lodtollpm2.DCB"} + copybin={"lodtollclassop2.bin","lodtollclassam2.bin","lodtollclasspm2.bin"} + copydcb={"lodtollclassop2.DCB","lodtollclassam2.DCB","lodtollclasspm2.DCB"} + viewNames ={"lodtollop2","lodtollam2","lodtollpm2"} + + // Copy files + for k=1 to 3 do + // check if copy files already exist, if exist delete + file=outputDir+"\\"+copybin[k] + dif2=GetDirectoryInfo(file,"file") + if dif2.length>0 then deletefile(file) + ok=1 + + CopyTableFiles(null,"FFB", outputDir+"\\"+asignbin[k], outputDir+"\\"+asigndcb[k],outputDir+"\\"+copybin[k], outputDir+"\\"+copydcb[k]) + + // delete the original highway files once copied + // check if copy files already exist, if exist delete + file=outputDir+"\\"+asignbin[k] + dif2=GetDirectoryInfo(file,"file") + if dif2.length>0 then deletefile(file) + ok=1 + + // Get copied files + view = OpenTable("assignment", "FFB", {outputDir+"\\"+copybin[k],} ) + ok1 = (view1 != null) + + // number of records + records = GetRecordCount(view, null) + + hov3_info = GetFileInfo(inputDir+"\\hov3") + hov3out_info = GetFileInfo(inputDir+"\\hov3out") + if (hov3_info=null & hov3out_info=null) then do + //get fields + fvector = GetDataVectors(view+"|",{"ID1", "AB_Flow_PCE", "BA_Flow_PCE", "Tot_Flow_PCE", "AB_Time", + "BA_Time", "Max_Time","AB_VOC","BA_VOC","Max_VOC","AB_V_Dist_T", + "BA_V_Dist_T","Tot_V_Dist_T","AB_VHT","BA_VHT","Tot_VHT", + "AB_Speed","BA_Speed","AB_VDF","BA_VDF","Max_VDF", + "AB_Flow_dan","BA_Flow_dan","AB_Flow_dat","BA_Flow_dat", + "AB_Flow_s2nn","BA_Flow_s2nn","AB_Flow_s2nh","BA_Flow_s2nh","AB_Flow_s2th","BA_Flow_s2th", + "AB_Flow_M1","BA_Flow_M1","AB_Flow_M2","BA_Flow_M2","AB_Flow_M3","BA_Flow_M3", + "AB_Flow_lhdn","BA_Flow_lhdn","AB_Flow_lhdt","BA_Flow_lhdt", + "AB_Flow_mhdn","BA_Flow_mhdn","AB_Flow_mhdt","BA_Flow_mhdt", + "AB_Flow_hhdn","BA_Flow_hhdn","AB_Flow_hhdt","BA_Flow_hhdt", + "AB_Flow","BA_Flow","Tot_Flow"},) + //create output file + view = CreateTable(viewNames[k], outputDir+"\\"+asignbin[k], "FFB", { + {"ID1" , "Integer (4 bytes)" , 10, null,"No", }, + {"AB_Flow_PCE" , "Real (8 bytes)" , 15, 4 ,"No","Link AB Flow "}, + {"BA_Flow_PCE" , "Real (8 bytes)" , 15, 4 ,"No","Link BA Flow "}, + {"Tot_Flow_PCE" , "Real (8 bytes)" , 15, 4 ,"No","Link Total Flow "}, + {"AB_Time" , "Real (8 bytes)" , 15, 4 ,"No","AB Loaded Travel Time "}, + {"BA_Time" , "Real (8 bytes)" , 15, 4 ,"No","BA Loaded Travel Time "}, + {"Max_Time" , "Real (8 bytes)" , 15, 4 ,"No","Maximum Loaded Time "}, + {"AB_VOC" , "Real (8 bytes)" , 15, 4 ,"No","AB Volume to Capacity Ratio "}, + {"BA_VOC" , "Real (8 bytes)" , 15, 4 ,"No","BA Volume to Capacity Ratio "}, + {"Max_VOC" , "Real (8 bytes)" , 15, 4 ,"No","Maximum Volume to Capacity Ratio "}, + {"AB_V_Dist_T" , "Real (8 bytes)" , 15, 4 ,"No","AB vehicle miles or km of travel "}, + {"BA_V_Dist_T" , "Real (8 bytes)" , 15, 4 ,"No","BA vehicle miles or km of travel "}, + {"Tot_V_Dist_T" , "Real (8 bytes)" , 15, 4 ,"No","Total vehicle miles or km of travel "}, + {"AB_VHT" , "Real (8 bytes)" , 15, 4 ,"No","AB vehicle hours of travel "}, + {"BA_VHT" , "Real (8 bytes)" , 15, 4 ,"No","BA vehicle hours of travel "}, + {"Tot_VHT" , "Real (8 bytes)" , 15, 4 ,"No","Total vehicle hours of travel "}, + {"AB_Speed" , "Real (8 bytes)" , 15, 4 ,"No","AB Loaded Speed "}, + {"BA_Speed" , "Real (8 bytes)" , 15, 4 ,"No","BA Loaded Speed "}, + {"AB_VDF" , "Real (8 bytes)" , 15, 4 ,"No","Link AB Volume Delay Function "}, + {"BA_VDF" , "Real (8 bytes)" , 15, 4 ,"No","Link BA Volume Delay Function "}, + {"Max_VDF" , "Real (8 bytes)" , 15, 4 ,"No","Maximum Link Volume Delay Function Value "}, + {"AB_Flow_dan" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for dan "}, + {"BA_Flow_dan" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for dan "}, + {"AB_Flow_dat" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for dat "}, + {"BA_Flow_dat" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for dat "}, + {"AB_Flow_s2nn" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s2nn "}, + {"BA_Flow_s2nn" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s2nn "}, + {"AB_Flow_s2nh" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s2nh "}, + {"BA_Flow_s2nh" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s2nh "}, + {"AB_Flow_s2th" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s2th "}, + {"BA_Flow_s2th" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s2th "}, + {"AB_Flow_M1" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for M1 "}, + {"BA_Flow_M1" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for M1 "}, + {"AB_Flow_M2" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for M2 "}, + {"BA_Flow_M2" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for M2 "}, + {"AB_Flow_M3" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for M3 "}, + {"BA_Flow_M3" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for M3 "}, + {"AB_Flow_lhd" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for lhd "}, + {"BA_Flow_lhd" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for lhd "}, + {"AB_Flow_mhd" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for mhd "}, + {"BA_Flow_mhd" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for mhd "}, + {"AB_Flow_hhd" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for hhd "}, + {"BA_Flow_hhd" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for hhd "}, + {"AB_Flow" , "Real (8 bytes)" , 15, 4 ,"No","Link AB Veh Flow "}, + {"BA_Flow" , "Real (8 bytes)" , 15, 4 ,"No","Link BA Veh Flow "}, + {"Tot_Flow" , "Real (8 bytes)" , 15, 4 ,"No","Link Total Veh Flow "} + }) + SetView(view) + + //calculate and set values + for i = 1 to records do + rh = AddRecord(view, { + {"ID1" , fvector[1 ][i]}, + {"AB_Flow_PCE" , fvector[2 ][i]}, + {"BA_Flow_PCE" , fvector[3 ][i]}, + {"Tot_Flow_PCE" , fvector[4 ][i]}, + {"AB_Time" , fvector[5 ][i]}, + {"BA_Time" , fvector[6 ][i]}, + {"Max_Time" , fvector[7 ][i]}, + {"AB_VOC" , fvector[8 ][i]}, + {"BA_VOC" , fvector[9 ][i]}, + {"Max_VOC" , fvector[10][i]}, + {"AB_V_Dist_T" , fvector[11][i]}, + {"BA_V_Dist_T" , fvector[12][i]}, + {"Tot_V_Dist_T" , fvector[13][i]}, + {"AB_VHT" , fvector[14][i]}, + {"BA_VHT" , fvector[15][i]}, + {"Tot_VHT" , fvector[16][i]}, + {"AB_Speed" , fvector[17][i]}, + {"BA_Speed" , fvector[18][i]}, + {"AB_VDF" , fvector[19][i]}, + {"BA_VDF" , fvector[20][i]}, + {"Max_VDF" , fvector[21][i]}, + {"AB_Flow_dan" , fvector[22][i]}, + {"BA_Flow_dan" , fvector[23][i]}, + {"AB_Flow_dat" , fvector[24][i]}, + {"BA_Flow_dat" , fvector[25][i]}, + {"AB_Flow_s2nn" , fvector[26][i]}, + {"BA_Flow_s2nn" , fvector[27][i]}, + {"AB_Flow_s2nh" , fvector[28][i]}, + {"BA_Flow_s2nh" , fvector[29][i]}, + {"AB_Flow_s2th" , fvector[30][i]}, + {"BA_Flow_s2th" , fvector[31][i]}, + {"AB_Flow_M1" , fvector[32][i]}, + {"BA_Flow_M1" , fvector[33][i]}, + {"AB_Flow_M2" , fvector[34][i]}, + {"BA_Flow_M2" , fvector[35][i]}, + {"AB_Flow_M3" , fvector[36][i]}, + {"BA_Flow_M3" , fvector[37][i]}, + {"AB_Flow_lhd" , fvector[38][i] + fvector[40][i]}, + {"BA_Flow_lhd" , fvector[39][i] + fvector[41][i]}, + {"AB_Flow_mhd" , fvector[42][i] + fvector[44][i]}, + {"BA_Flow_mhd" , fvector[43][i] + fvector[45][i]}, + {"AB_Flow_hhd" , fvector[46][i] + fvector[48][i]}, + {"BA_Flow_hhd" , fvector[47][i] + fvector[49][i]}, + {"AB_Flow" , fvector[50][i]}, + {"BA_Flow" , fvector[51][i]}, + {"Tot_Flow" , fvector[52][i]} + }) + end + end + else do + fvector = GetDataVectors(view+"|",{"ID1", "AB_Flow_PCE", "BA_Flow_PCE", "Tot_Flow_PCE", "AB_Time", + "BA_Time", "Max_Time","AB_VOC","BA_VOC","Max_VOC","AB_V_Dist_T", + "BA_V_Dist_T","Tot_V_Dist_T","AB_VHT","BA_VHT","Tot_VHT", + "AB_Speed","BA_Speed","AB_VDF","BA_VDF","Max_VDF", + "AB_Flow_dan","BA_Flow_dan","AB_Flow_dat","BA_Flow_dat", + "AB_Flow_s2nn","BA_Flow_s2nn","AB_Flow_s2nh","BA_Flow_s2nh","AB_Flow_s2th","BA_Flow_s2th", + "AB_Flow_s3nn","BA_Flow_s3nn","AB_Flow_s3nh","BA_Flow_s3nh","AB_Flow_s3th","BA_Flow_s3th", + "AB_Flow_lhdn","BA_Flow_lhdn","AB_Flow_lhdt","BA_Flow_lhdt", + "AB_Flow_mhdn","BA_Flow_mhdn","AB_Flow_mhdt","BA_Flow_mhdt", + "AB_Flow_hhdn","BA_Flow_hhdn","AB_Flow_hhdt","BA_Flow_hhdt", + "AB_Flow","BA_Flow","Tot_Flow"},) + //create output file + view = CreateTable(viewNames[k], path+"\\"+asignbin[k], "FFB", { + {"ID1" , "Integer (4 bytes)" , 10, null,"No", }, + {"AB_Flow_PCE" , "Real (8 bytes)" , 15, 4 ,"No","Link AB Flow "}, + {"BA_Flow_PCE" , "Real (8 bytes)" , 15, 4 ,"No","Link BA Flow "}, + {"Tot_Flow_PCE" , "Real (8 bytes)" , 15, 4 ,"No","Link Total Flow "}, + {"AB_Time" , "Real (8 bytes)" , 15, 4 ,"No","AB Loaded Travel Time "}, + {"BA_Time" , "Real (8 bytes)" , 15, 4 ,"No","BA Loaded Travel Time "}, + {"Max_Time" , "Real (8 bytes)" , 15, 4 ,"No","Maximum Loaded Time "}, + {"AB_VOC" , "Real (8 bytes)" , 15, 4 ,"No","AB Volume to Capacity Ratio "}, + {"BA_VOC" , "Real (8 bytes)" , 15, 4 ,"No","BA Volume to Capacity Ratio "}, + {"Max_VOC" , "Real (8 bytes)" , 15, 4 ,"No","Maximum Volume to Capacity Ratio "}, + {"AB_V_Dist_T" , "Real (8 bytes)" , 15, 4 ,"No","AB vehicle miles or km of travel "}, + {"BA_V_Dist_T" , "Real (8 bytes)" , 15, 4 ,"No","BA vehicle miles or km of travel "}, + {"Tot_V_Dist_T" , "Real (8 bytes)" , 15, 4 ,"No","Total vehicle miles or km of travel "}, + {"AB_VHT" , "Real (8 bytes)" , 15, 4 ,"No","AB vehicle hours of travel "}, + {"BA_VHT" , "Real (8 bytes)" , 15, 4 ,"No","BA vehicle hours of travel "}, + {"Tot_VHT" , "Real (8 bytes)" , 15, 4 ,"No","Total vehicle hours of travel "}, + {"AB_Speed" , "Real (8 bytes)" , 15, 4 ,"No","AB Loaded Speed "}, + {"BA_Speed" , "Real (8 bytes)" , 15, 4 ,"No","BA Loaded Speed "}, + {"AB_VDF" , "Real (8 bytes)" , 15, 4 ,"No","Link AB Volume Delay Function "}, + {"BA_VDF" , "Real (8 bytes)" , 15, 4 ,"No","Link BA Volume Delay Function "}, + {"Max_VDF" , "Real (8 bytes)" , 15, 4 ,"No","Maximum Link Volume Delay Function Value "}, + {"AB_Flow_dan" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for dan "}, + {"BA_Flow_dan" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for dan "}, + {"AB_Flow_dat" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for dat "}, + {"BA_Flow_dat" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for dat "}, + {"AB_Flow_s2nn" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s2nn "}, + {"BA_Flow_s2nn" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s2nn "}, + {"AB_Flow_s2nh" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s2nh "}, + {"BA_Flow_s2nh" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s2nh "}, + {"AB_Flow_s2th" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s2th "}, + {"BA_Flow_s2th" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s2th "}, + {"AB_Flow_s3nn" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s3nn "}, + {"BA_Flow_s3nn" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s3nn "}, + {"AB_Flow_s3nh" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s3nh "}, + {"BA_Flow_s3nh" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s3nh "}, + {"AB_Flow_s3th" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for s3th "}, + {"BA_Flow_s3th" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for s3th "}, + {"AB_Flow_lhd" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for lhd "}, + {"BA_Flow_lhd" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for lhd "}, + {"AB_Flow_mhd" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for mhd "}, + {"BA_Flow_mhd" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for mhd "}, + {"AB_Flow_hhd" , "Real (8 bytes)" , 15, 4 ,"No","AB Flow for hhd "}, + {"BA_Flow_hhd" , "Real (8 bytes)" , 15, 4 ,"No","BA Flow for hhd "}, + {"AB_Flow" , "Real (8 bytes)" , 15, 4 ,"No","Link AB Veh Flow "}, + {"BA_Flow" , "Real (8 bytes)" , 15, 4 ,"No","Link BA Veh Flow "}, + {"Tot_Flow" , "Real (8 bytes)" , 15, 4 ,"No","Link Total Veh Flow "} + }) + SetView(view) + + //calculate and set values + for i = 1 to records do + rh = AddRecord(view, { + {"ID1" , fvector[1 ][i]}, + {"AB_Flow_PCE" , fvector[2 ][i]}, + {"BA_Flow_PCE" , fvector[3 ][i]}, + {"Tot_Flow_PCE" , fvector[4 ][i]}, + {"AB_Time" , fvector[5 ][i]}, + {"BA_Time" , fvector[6 ][i]}, + {"Max_Time" , fvector[7 ][i]}, + {"AB_VOC" , fvector[8 ][i]}, + {"BA_VOC" , fvector[9 ][i]}, + {"Max_VOC" , fvector[10][i]}, + {"AB_V_Dist_T" , fvector[11][i]}, + {"BA_V_Dist_T" , fvector[12][i]}, + {"Tot_V_Dist_T" , fvector[13][i]}, + {"AB_VHT" , fvector[14][i]}, + {"BA_VHT" , fvector[15][i]}, + {"Tot_VHT" , fvector[16][i]}, + {"AB_Speed" , fvector[17][i]}, + {"BA_Speed" , fvector[18][i]}, + {"AB_VDF" , fvector[19][i]}, + {"BA_VDF" , fvector[20][i]}, + {"Max_VDF" , fvector[21][i]}, + {"AB_Flow_dan" , fvector[22][i]}, + {"BA_Flow_dan" , fvector[23][i]}, + {"AB_Flow_dat" , fvector[24][i]}, + {"BA_Flow_dat" , fvector[25][i]}, + {"AB_Flow_s2nn" , fvector[26][i]}, + {"BA_Flow_s2nn" , fvector[27][i]}, + {"AB_Flow_s2nh" , fvector[28][i]}, + {"BA_Flow_s2nh" , fvector[29][i]}, + {"AB_Flow_s2th" , fvector[30][i]}, + {"BA_Flow_s2th" , fvector[31][i]}, + {"AB_Flow_s3nn" , fvector[32][i]}, + {"BA_Flow_s3nn" , fvector[33][i]}, + {"AB_Flow_s3nh" , fvector[34][i]}, + {"BA_Flow_s3nh" , fvector[35][i]}, + {"AB_Flow_s3th" , fvector[36][i]}, + {"BA_Flow_s3th" , fvector[37][i]}, + {"AB_Flow_lhd" , fvector[38][i] + fvector[40][i]}, + {"BA_Flow_lhd" , fvector[39][i] + fvector[41][i]}, + {"AB_Flow_mhd" , fvector[42][i] + fvector[44][i]}, + {"BA_Flow_mhd" , fvector[43][i] + fvector[45][i]}, + {"AB_Flow_hhd" , fvector[46][i] + fvector[48][i]}, + {"BA_Flow_hhd" , fvector[47][i] + fvector[49][i]}, + {"AB_Flow" , fvector[50][i]}, + {"BA_Flow" , fvector[51][i]}, + {"Tot_Flow" , fvector[52][i]} + }) + end + end + end // end for loop + + vws = GetViewNames() + for p = 1 to vws.length do + CloseView(vws[p]) + end + return(1) + + quit: + return(0) +EndMacro + + + + +Macro "create trip tables by VOT"(args) + + shared path, inputDir, outputDir + + inFiles={"Trip_EA.mtx","Trip_AM.mtx","Trip_MD.mtx","Trip_PM.mtx","Trip_EV.mtx"} + outFiles={"Trip_EA_VOT.mtx","Trip_AM_VOT.mtx","Trip_MD_VOT.mtx","Trip_PM_VOT.mtx","Trip_EV_VOT.mtx"} + inTableNames = {"SOV_GP", "SOV_PAY", "SR2_GP","SR2_HOV", "SR2_PAY", "SR3_GP","SR3_HOV","SR3_PAY","lhdn","mhdn","hhdn","lhdt","mhdt","hhdt"} + outTableNames = { + "SOV_GP_LOW", "SOV_PAY_LOW", "SR2_GP_LOW","SR2_HOV_LOW", "SR2_PAY_LOW", "SR3_GP_LOW","SR3_HOV_LOW","SR3_PAY_LOW", + "SOV_GP_MED", "SOV_PAY_MED", "SR2_GP_MED","SR2_HOV_MED", "SR2_PAY_MED", "SR3_GP_MED","SR3_HOV_MED","SR3_PAY_MED", + "SOV_GP_HI", "SOV_PAY_HI", "SR2_GP_HI","SR2_HOV_HI", "SR2_PAY_HI", "SR3_GP_HI","SR3_HOV_HI","SR3_PAY_HI", + "lhdn","mhdn","hhdn","lhdt","mhdt","hhdt"} + + for i = 1 to inFiles.length do + + //open person trip matrix currencies + inMatrix = OpenMatrix(outputDir+"\\"+inFiles[i], ) + inCurrencies = CreateMatrixCurrencies(inMatrix, , , ) + + dim curr_array[inTableNames.length] + for j = 1 to inTableNames.length do + curr_array[j] = CreateMatrixCurrency(inMatrix, inTableNames[j], ,, ) + end + + //create output trip table and matrix currencies for this time period + outMatrix = CopyMatrixStructure(curr_array, {{"File Name", outputDir+"\\"+outFiles[i]}, + {"Label", outFiles[i]}, + {"Tables",outTableNames}, + {"File Based", "Yes"}}) + SetMatrixCoreNames(outMatrix, outTableNames) + + outCurrencies= CreateMatrixCurrencies(outMatrix, , , ) + + // calculate output matrices + outCurrencies.SOV_GP_LOW := inCurrencies.SOV_GP * 0.3333333 + outCurrencies.SOV_GP_MED := inCurrencies.SOV_GP * 0.3333333 + outCurrencies.SOV_GP_HI := inCurrencies.SOV_GP * 0.3333333 + + outCurrencies.SOV_PAY_LOW := inCurrencies.PAY_GP * 0.3333333 + outCurrencies.SOV_PAY_MED := inCurrencies.PAY_GP * 0.3333333 + outCurrencies.SOV_PAY_HI := inCurrencies.PAY_GP * 0.3333333 + + outCurrencies.SR2_GP_LOW := inCurrencies.SR2_GP * 0.3333333 + outCurrencies.SR2_GP_MED := inCurrencies.SR2_GP * 0.3333333 + outCurrencies.SR2_GP_HI := inCurrencies.SR2_GP * 0.3333333 + + outCurrencies.SR2_HOV_LOW := inCurrencies.SR2_HOV * 0.3333333 + outCurrencies.SR2_HOV_MED := inCurrencies.SR2_HOV * 0.3333333 + outCurrencies.SR2_HOV_HI := inCurrencies.SR2_HOV * 0.3333333 + + outCurrencies.SR2_PAY_LOW := inCurrencies.SR2_PAY * 0.3333333 + outCurrencies.SR2_PAY_MED := inCurrencies.SR2_PAY * 0.3333333 + outCurrencies.SR2_PAY_HI := inCurrencies.SR2_PAY * 0.3333333 + + outCurrencies.SR3_GP_LOW := inCurrencies.SR3_GP * 0.3333333 + outCurrencies.SR3_GP_MED := inCurrencies.SR3_GP * 0.3333333 + outCurrencies.SR3_GP_HI := inCurrencies.SR3_GP * 0.3333333 + + outCurrencies.SR3_HOV_LOW := inCurrencies.SR3_HOV * 0.3333333 + outCurrencies.SR3_HOV_MED := inCurrencies.SR3_HOV * 0.3333333 + outCurrencies.SR3_HOV_HI := inCurrencies.SR3_HOV * 0.3333333 + + outCurrencies.SR3_PAY_LOW := inCurrencies.SR3_PAY * 0.3333333 + outCurrencies.SR3_PAY_MED := inCurrencies.SR3_PAY * 0.3333333 + outCurrencies.SR3_PAY_HI := inCurrencies.SR3_PAY * 0.3333333 + + outCurrencies.lhdn := inCurrencies.lhdn + outCurrencies.mhdn := inCurrencies.mhdn + outCurrencies.hhdn := inCurrencies.hhdn + outCurrencies.lhdt := inCurrencies.lhdt + outCurrencies.mhdt := inCurrencies.mhdt + outCurrencies.hhdt := inCurrencies.hhdt + + end + RunMacro("close all" ) + + Return(1) + quit: + Return(0) +EndMacro diff --git a/sandag_abm/src/main/gisdk/hwyskim.rsc b/sandag_abm/src/main/gisdk/hwyskim.rsc new file mode 100644 index 0000000..01576e0 --- /dev/null +++ b/sandag_abm/src/main/gisdk/hwyskim.rsc @@ -0,0 +1,1257 @@ +/*********************************************** +Hwy skim all + +This macro calls macro "Update highway network", which updates highway network with times +from last highway assignment, and then skims highway network by calling macro "hwy skim" for +the following modes: + +dant Drive-alone non-toll +dat Drive-alone toll +s2nh Shared-2 non-toll HOV +s2th Shared-2 toll HOV +s3nh Shared-3 non-toll HOV +s3th Shared-3 toll HOV +truck Truck + +***********************************************/ +Macro "Hwy skim all" (args) + + skimByVOT= args[1] + + if skimByVOT="false" then do + + da_vot=67.00 // $0.67 cents per minute VOT ($40.2 per hour) + s2_vot=67.00 + s3_vot=67.00 + lh_vot=67.00 + mh_vot=68.00 + hh_vot=89.00 + cv_vot=67.00 + + vot_array = {da_vot, s2_vot, s3_vot, lh_vot, mh_vot, hh_vot, cv_vot} + + ok=RunMacro("Update highway network", vot_array) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"dant",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"dat",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s2nh",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s2th",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s3nh",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s3th",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"cvn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"cvt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"lhdn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"lhdt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"mhdn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"mhdt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"hhdn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"hhdt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"truck",}) + if !ok then goto quit + + end + else do + + vot_bins = {"low", "med", "high"} + // da, s2, s3, lh, mh, hh, cv} + vot_by_bin = {{16.6, 16.6, 16.6, 67.0, 68.0, 89.0, 67.0}, + {33.3, 33.3, 33.3, 67.0, 68.0, 89.0, 67.0}, + { 100, 100, 100, 67.0, 68.0, 89.0, 67.0} + } + + for i = 1 to vot_bins.length do + + ok=RunMacro("Update highway network", vot_by_bin[i]) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"dant",vot_bins[i]}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"dat",vot_bins[i]}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s2nh",vot_bins[i]}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s2th",vot_bins[i]}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s3nh",vot_bins[i]}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"s3th",vot_bins[i]}) + if !ok then goto quit + +/* + // reliability for time periods (15-mins) + for tod=1 to 96 do + + if (tod=25 or tod=26 or tod=35 or tod=36) then do //AM Period - 30 min shoulders + ok=RunMacro("hwy skim time bins",{"dant",vot_bins[i],tod}) + if !ok then goto quit + + ok=RunMacro("hwy skim time bins",{"dat",vot_bins[i],tod}) + if !ok then goto quit + + ok=RunMacro("hwy skim time bins",{"s2nh",vot_bins[i],tod}) + if !ok then goto quit + + ok=RunMacro("hwy skim time bins",{"s2th",vot_bins[i],tod}) + if !ok then goto quit + + ok=RunMacro("hwy skim time bins",{"s3nh",vot_bins[i],tod}) + if !ok then goto quit + + ok=RunMacro("hwy skim time bins",{"s3th",vot_bins[i],tod}) + if !ok then goto quit + end + + end + */ + end + + // don't skim commercial vehicles or trucks by vot + ok=RunMacro("hwy skim",{"cvn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"cvt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"lhdn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"lhdt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"mhdn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"mhdt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"hhdn",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"hhdt",}) + if !ok then goto quit + + ok=RunMacro("hwy skim",{"truck",}) + if !ok then goto quit + + end + + return(1) + + quit: + return(0) + +EndMacro + +/******************************************************************************** + +Update highway network + +Updates highway line layer and network with fields from latest assignment flow tables. + + Arguments + 1 drive-alone value-of-time (cents/min) + 2 shared 2 value-of-time (cents/min) + 3 shared 3+ value-of-time (cents/min) + 4 light-heavy truck value-of-time (cents/min) + 5 medium-heavy truck value-of-time (cents/min) + 6 heavy-heavy truck value-of-time (cents/min) + 7 commercial vehicle value-of-time (cents/min) + + +The following fields are updated on the line layer: + +Field Description +------- --------------- +STM SOV time +HTM HOV time +SCST SOV generalized cost +H2CST Shared-2 generalized cost +H3CST Shared-3 generalized cost +LHCST Light-heavy truck generalized cost +MHCST Medium-heavy truck generalized cost +HHCST Heavy-heavy truck generalized cost +CVCST Heavy-heavy truck generalized cost + + +Each field is xxField_yy where: + + xx is AB or BA indicating direction + yy is period, as follows: + EA: Early AM + AM: AM peak + MD: Midday + PM: PM peak + EV: Evening + +Inputs: + input\hwy.dbd Highway line layer + input\hwy.net Highway network + output\hwyload_yy.bin Loaded flow table from assignment, one per period (yy) + +Outputs: + output\hwy.dbd Updated highway line layer + output\hwy.net Updated highway network + +********************************************************************************/ +Macro "Update highway network" (args) + + shared path, inputDir, outputDir + + da_vot= args[1] + s2_vot= args[2] + s3_vot= args[3] + lh_vot= args[4] + mh_vot= args[5] + hh_vot= args[6] + cv_vot= args[7] + + // input files + db_file = outputDir + "\\hwy.dbd" + net_file = outputDir + "\\hwy.net" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + db_node_lyr = db_file + "|" + node_lyr + + periods = {"_EA", "_AM", "_MD", "_PM", "_EV"} + + da_vot=da_vot*60/100 //Convert to dollars per hour VOT so don't have to change gen cost function below + s2_vot=s2_vot*60/100 + s3_vot=s3_vot*60/100 + lh_vot=lh_vot*60/100 + mh_vot=mh_vot*60/100 + hh_vot=hh_vot*60/100 + cv_vot=cv_vot*60/100 + + //Recompute generalized cost using MSA cost in flow table, + for i = 1 to periods.length do + + flowTable = outputDir+"\\hwyload"+periods[i]+".bin" + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"sovtime"+periods[i] } + Opts.Global.Fields = {"ABSTM"+periods[i],"BASTM"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"AB_MSA_Cost" , + "BA_MSA_Cost" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"hovtime"+periods[i] } + Opts.Global.Fields = {"ABHTM"+periods[i],"BAHTM"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"AB_MSA_Cost" , + "BA_MSA_Cost" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"dajoin"+periods[i] } + Opts.Global.Fields = {"ABSCST"+periods[i],"BASCST"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"AB_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(da_vot)+"*60)" , + "BA_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(da_vot)+"*60)" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // Light-Heavy truck cost + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"dajoin"+periods[i] } + Opts.Global.Fields = {"ABLHCST"+periods[i],"BALHCST"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"AB_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(lh_vot)+"*60)" , + "BA_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(lh_vot)+"*60)" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // Medium-Heavy truck cost + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"dajoin"+periods[i] } + Opts.Global.Fields = {"ABMHCST"+periods[i],"BAMHCST"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"AB_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(mh_vot)+"*60)" , + "BA_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(mh_vot)+"*60)" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // Heavy-Heavy truck cost + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"dajoin"+periods[i] } + Opts.Global.Fields = {"ABHHCST"+periods[i],"BAHHCST"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"AB_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(hh_vot)+"*60)" , + "BA_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(hh_vot)+"*60)" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // Commercial vehicle cost + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"dajoin"+periods[i] } + Opts.Global.Fields = {"ABCVCST"+periods[i],"BACVCST"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"AB_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(cv_vot)+"*60)" , + "BA_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(cv_vot)+"*60)" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"s2join"+periods[i] } + Opts.Global.Fields = {"ABH2CST"+periods[i],"BAH2CST"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"if (IHOV=3 or IHOV=4) then (AB_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(s2_vot)+"*60)) else AB_MSA_Cost + (COST/100)/"+String(s2_vot)+"*60" , + "if (IHOV=3 or IHOV=4) then (BA_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(s2_vot)+"*60)) else BA_MSA_Cost + (COST/100)/"+String(s2_vot)+"*60" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"s3join"+periods[i] } + Opts.Global.Fields = {"ABH3CST"+periods[i],"BAH3CST"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"if IHOV=4 then (AB_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(s3_vot)+"*60)) else AB_MSA_Cost + (COST/100)/"+String(s2_vot)+"*60" , + "if IHOV=4 then (BA_MSA_Cost + ((ITOLL3"+periods[i]+"/100)/"+String(s3_vot)+"*60)) else BA_MSA_Cost + (COST/100)/"+String(s2_vot)+"*60" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + // Total Reliability - The Dataview Set is a joined view of the link layer and the flow table, based on link ID + // calculate as square of link reliability - after skimming take square root of the total reliability + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"reliabilityjoin"+periods[i] } + Opts.Global.Fields = {"AB_TOTREL"+periods[i],"BA_TOTREL"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"pow(AB_MSA_Cost - AB_MSA_Time,2)", + "pow(BA_MSA_Cost - BA_MSA_Time,2)" } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + + //Now update the network with the calculated cost fields + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*STM"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABSTM"+periods[i],link_lyr+".BASTM"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*HTM"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABHTM"+periods[i],link_lyr+".BAHTM"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*SCST"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABSCST"+periods[i],link_lyr+".BASCST"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*H2CST"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABH2CST"+periods[i],link_lyr+".BAH2CST"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*H3CST"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABH3CST"+periods[i],link_lyr+".BAH3CST"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*LHCST"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABLHCST"+periods[i],link_lyr+".BALHCST"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*MHCST"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABMHCST"+periods[i],link_lyr+".BAMHCST"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*HHCST"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABHHCST"+periods[i],link_lyr+".BAHHCST"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*CVCST"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".ABCVCST"+periods[i],link_lyr+".BACVCST"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + // update total reliability fields + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*_TOTREL"+periods[i] + Opts.Global.Options.[Link Fields] = { {link_lyr+".AB_TOTREL"+periods[i],link_lyr+".BA_TOTREL"+periods[i] } } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + end + + + ok=1 + runmacro("close all") + quit: + + return(ok) + +EndMacro + +/******************************************************************************************** + +hwy skim + +Skim highway network for the following modes (passed as argument) + + +Mode Description Cost attribute +---- --------------------- -------------- +truck Truck SCST +lhdn Light-heavy-duty non-toll LHCST +mhdn Medium-heavy-duty non-toll MHCST +hhdn Heavy-heavy-duty non-toll HHCST +lhdt Light-heavy-duty toll LHCST +mhdt Medium-heavy-duty toll MHCST +hhdt Heavy-heavy-duty toll HHCST +cvn Commercial vehicle non-toll CVCST +cvt Commercial vehicle toll CVCST +dant Drive-alone non-toll SCST +dat Drive-alone toll SCST +s2nh Shared-2 non-toll HOV H2CST +s2th Shared-2 toll non-HOV H2CST +s3nh Shared-3 non-toll HOV H3CST +s3th Shared-3 toll HOV H3CST + +Note: dant skims also apply to shared-2 non-toll, non-HOV and shared 3+ non-toll, non-HOV + +v1.0 jef 3/30/2012 +v2.0 jef 5/10/2015 added value-of-time bins and commercial vehicle modes + +*/ +Macro "hwy skim" (args) + + shared path, inputDir, outputDir, mxzone + + mode=args[1] + + //vot_bin is the value-of-time bin that will be appended to each skim name; prepend "_" + if args[2]=null then vot_bin="" else vot_bin="_"+args[2] + + dim skimbyset1[3],skimbyset2[3] + + + // input files + db_file = outputDir + "\\hwy.dbd" + net_file = outputDir + "\\hwy.net" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + db_node_lyr = db_file + "|" + node_lyr + net = ReadNetwork(net_file) + + periods = {"_EA", "_AM", "_MD", "_PM", "_EV"} + + for i = 1 to periods.length do + + skimbyset1 = null // second skim varaible (in addition to LENGTH) + skimbyset2 = null // third skim variable + skimbyset3 = null // fourth skim variable + + // The truck skim is used for heavy trip distribution + if mode = "truck" then do + + CostFld = "*SCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!((ihov=1|ihov=4|ifc>7)&(ITRUCK=1|ITRUCK>4))" // query for exclusion link set + + set = "TrkToll"+periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where (ihov=4 and (ITRUCK=1|ITRUCK>4))",) + if n > 0 then skimbyset1={vw_set, {"itoll"+periods[i]}} + + // skimbyset2 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset2={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imptrk"+periods[i]+vot_bin+".mtx" // output skim matrices + + end + + // The skims by weight class are used for truck toll diversion + else if mode = "lhdn" then do // light duty truck non-toll + + CostFld = "*LHCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!((ihov=1|ifc>7)&(ITRUCK<4|ITRUCK=7))" // query for lhd non-toll exclusion link set + + // skimbyset1 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imp"+mode+periods[i]+vot_bin+".mtx" // output skim matrices + end + else if mode = "mhdn" then do // medium duty truck non-toll + + CostFld = "*MHCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!((ihov=1|ifc>7)&(ITRUCK<3|ITRUCK>5))" // query for mhd non-toll exclusion link set + + // skimbyset1 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imp"+mode+periods[i]+vot_bin+".mtx" // output skim matrices + end + else if mode = "hhdn" then do // heavy duty truck non-toll + + CostFld = "*HHCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!((ihov=1|ifc>7)&(ITRUCK=1|ITRUCK>4))" // query for hhd non-toll exclusion link set + + // skimbyset1 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imp"+mode+periods[i]+vot_bin+".mtx" // output skim matrices + end + + else if mode = "lhdt" then do + CostFld = "*SCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7) & (ITRUCK<4|ITRUCK=7))" // query for lhd toll exclusion link set + + tollfield = "ITOLL2" // toll value + + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where " + excl_qry,) + if n = 0 then excl_qry=null // reset value if no selection records + + // skimbyset1 = toll + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {tollfield + periods[i] }} + + // skimbyset2 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset2={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imp"+mode+periods[i]+vot_bin+".mtx" // output skim matrices + end + else if mode = "mhdt" then do + CostFld = "*SCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)&(ITRUCK<3|ITRUCK>5))" // query for mhd toll exclusion link set + + tollfield = "ITOLL2" // toll value + + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where " + excl_qry,) + if n = 0 then excl_qry=null // reset value if no selection records + + // skimbyset1 = toll + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {tollfield + periods[i] }} + + // skimbyset2 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset2={vw_set, {"*_TOTREL" + periods[i]}} + + + skimmat = "imp"+mode+periods[i]+vot_bin+".mtx" // output skim matrices + end + else if mode = "hhdt" then do + CostFld = "*SCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)&(ITRUCK=1|ITRUCK>4))" // query for hhd toll exclusion link set + + tollfield = "ITOLL2" // toll value + + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where " + excl_qry,) + if n = 0 then excl_qry=null // reset value if no selection records + + // skimbyset1 = toll + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {tollfield + periods[i] }} + + // skimbyset2 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset2={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imp"+mode+periods[i]+vot_bin+".mtx" // output skim matrices + end + + else if mode = "cvn" then do // commercial vehicles non-toll + CostFld = "*CVCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM" +periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!((ihov=1|ifc>7)&(ITRUCK=1|ITRUCK>4))" // query for hhd non-toll exclusion link set + + // skimbyset1 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "impcvn"+periods[i]+vot_bin+".mtx" // output skim matrices + end + + else if mode = "cvt" then do // commercial vehicle toll skims; uses same selection set as drive-alone toll + CostFld = "*CVCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM"+periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)&ITRUCK<5)" + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several","Select * where "+excl_qry,) + if n = 0 then excl_qry=null //reset value if no selection records + + tollfield = "ITOLL2" // toll value + + // skimbyset1 = toll + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {tollfield + periods[i] }} + + // skimbyset2 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset2={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "impcvt"+periods[i]+vot_bin+".mtx" + end + else if mode = "dant" then do + + CostFld = "*SCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM"+periods[i] // first skim varaible (in addition to LENGTH) + + excl_qry = "!(ihov=1&ITRUCK<5)" // query for exclusion link set + + // skimbyset1 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset1={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "impdan"+periods[i]+vot_bin+".mtx" // output skim matrices + end + else if mode = "dat" then do + + CostFld = "*SCST"+periods[i] // minimizing cost field + SkimVar1 = "*STM"+periods[i] // first skim varaible (in addition to LENGTH) + + //excl_qry = "!(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))|ifc>7)&ITRUCK<5)" + excl_qry = "!(((ihov=1|ihov=4|((ihov=2|ihov=3)&(abln"+periods[i]+"<9)))|ifc>7)&ITRUCK<5)" + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several","Select * where "+excl_qry,) + if n = 0 then excl_qry=null //reset value if no selection records + + // skimbyset1 = length on toll lanes + set = "datdst"+periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + //n = SelectByQuery(set, "Several", "Select * where ((ihov=4|((ihov=2|ihov=3)&(itoll"+periods[i]+">0&abln"+periods[i]+"<9)))&ITRUCK<5)",) + n = SelectByQuery(set, "Several", "Select * where ((ihov=4|((ihov=2|ihov=3)&(abln"+periods[i]+"<9)))&ITRUCK<5)",) + if n > 0 then skimbyset1={vw_set, {"Length"}} + + // skimbyset2 = cost + set = mode + periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset2={vw_set, {"itoll"+periods[i]}} + + // skimbyset3 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset3={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "impdat"+periods[i]+vot_bin+".mtx" + end + else if mode = "s2nh" then do + + CostFld = "*H2CST"+periods[i] // minimizing cost field + SkimVar1 = "*HTM"+periods[i] + + excl_qry ="!((ihov=1|(ihov=2&abln"+periods[i]+" <9)|ifc>7)&ITRUCK<5)"//initialize the value + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several","Select * where "+excl_qry,) + if n = 0 then excl_qry=null //reset value if no selection records + + set = "s2hdst" + periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where (abln"+periods[i]+"<9 and ihov=2 and ITRUCK<5)",) + if n > 0 then skimbyset2={vw_set, {"Length"}} + + // skimbyset3 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset3={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imps2nh"+periods[i]+vot_bin+".mtx" + end + else if mode = "s2th" then do + + CostFld = "*H2CST"+periods[i] // minimizing cost field + SkimVar1 ="*HTM"+periods[i] + + excl_qry = "!(((ihov=1|(ihov=2&abln"+periods[i]+"<9)|ihov=4|(ihov=3&itoll"+periods[i]+">0&abln"+periods[i]+"<9))|ifc>7)&ITRUCK<5)" + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several","Select * where " + excl_qry,) + if n = 0 then excl_qry=null //reset value if no selection records + + set = "s2tdst"+periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where (((abln"+periods[i]+"<9 & ihov=2) | (ihov=4 | (ihov=3 & itoll"+periods[i]+" >0 & abln"+periods[i]+"< 9)))& ITRUCK<5)",) + if n > 0 then skimbyset1={vw_set, {"Length"}} + + set = "s2t"+periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where ((ihov=4|(ihov=3 & itoll"+periods[i]+" >0 & abln"+periods[i]+" < 9)) & ITRUCK<5)",) + if n > 0 then skimbyset2={vw_set, {"itoll"+periods[i]}} + + // skimbyset3 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset3={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imps2th"+periods[i]+vot_bin+".mtx" + + end + else if mode = "s3nh" then do + + CostFld = "*H3CST"+periods[i] // minimizing cost field + SkimVar1 = "*HTM" +periods[i] + + excl_qry = "!((ihov=1|((ihov=2|ihov=3)&abln"+periods[i]+"<9)|ifc>7)& ITRUCK<5)" + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where " + excl_qry,) + if n = 0 then excl_qry=null + + set = "s3hdst"+periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where (abln"+periods[i]+"<9 & (ihov=2 | ihov=3) & ITRUCK<5)",) + if n > 0 then skimbyset2={vw_set, {"Length"}} + + // skimbyset3 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset3={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imps3nh"+periods[i]+vot_bin+".mtx" + + end + else if mode = "s3th" then do + + CostFld = "*H3CST" + periods[i] // minimizing cost field + SkimVar1 = "*HTM" + periods[i] + + excl_qry = "(abln"+periods[i]+"=9 | ITRUCK >4)" + set = mode + periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where " + excl_qry,) + if n = 0 then excl_qry=null + + set = "s3tdst" + periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where (((abln"+periods[i]+"<9 and (ihov=2 or ihov=3)) or ihov=4)and ITRUCK <5)",) + if n > 0 then skimbyset1={vw_set, {"Length"}} + + set = "s3t" + periods[i] + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where (ihov=4 and ITRUCK <5)",) + if n > 0 then skimbyset2={vw_set, {"itoll"+periods[i]}} + + // skimbyset3 = reliability + set = mode + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where 1=1",) // for all links + if n > 0 then skimbyset3={vw_set, {"*_TOTREL" + periods[i]}} + + skimmat = "imps3th"+periods[i]+vot_bin+".mtx" + end + + + //delete existing skim file + ok=RunMacro("SDdeletefile",{outputDir+"\\"+skimmat}) + if !ok then goto quit + + //skim network + set = "AllLinks" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectAll(set) + NetOpts = null + NetOpts.[Link ID] = link_lyr+".ID" + NetOpts.[Type] = "Enable" + ChangeLinkStatus(net,vw_set, NetOpts) // first enable all links + + if excl_qry<>null then do + set = "toll" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where "+excl_qry,) + NetOpts = null + NetOpts.[Link ID] = link_lyr+".ID" + NetOpts.[Type] = "Disable" + ChangeLinkStatus(net,vw_set, NetOpts) // disable exclusion query + end + + Opts = null + Opts.Input.Network = net_file + Opts.Input.[Origin Set] = {db_node_lyr, node_lyr, "Centroids", "select * where ID <= " + i2s(mxzone)} + Opts.Input.[Destination Set] = {db_node_lyr, node_lyr, "Centroids"} + Opts.Input.[Via Set] = {db_node_lyr, node_lyr} + Opts.Field.Minimize = CostFld + Opts.Field.Nodes = node_lyr + ".ID" + Opts.Field.[Skim Fields]={{"Length","All"},{SkimVar1,"All"}} + + // provide skimset + if skimbyset1 <> null then do + if skimbyset2 <> null then do + if skimbyset3 <> null then + Opts.Field.[Skim by Set]={skimbyset1,skimbyset2,skimbyset3} + else + Opts.Field.[Skim by Set]={skimbyset1,skimbyset2} + end + else if skimbyset3 <> null then + Opts.Field.[Skim by Set]={skimbyset1,skimbyset3} + else + Opts.Field.[Skim by Set]={skimbyset1} + end + else if skimbyset2 <> null then do + if skimbyset3 <> null then + Opts.Field.[Skim by Set]={skimbyset2,skimbyset3} + else + Opts.Field.[Skim by Set]={skimbyset2} + end + else if skimbyset3 <> null then + Opts.Field.[Skim by Set]={skimbyset3} + + //end of previous if string + if (mode = "lhdn" | mode = "mhdn" | mode = "hhdn" | mode = "lhdt" | mode = "mhdt" | mode = "hhdt") then + if (mode = "lhdn" | mode = "mhdn" | mode = "hhdn") then + Opts.Output.[Output Matrix].Label = "impedance truck" + else if (mode = "lhdt" | mode = "mhdt" | mode = "hhdt") then + Opts.Output.[Output Matrix].Label = "impedance truck toll" + else + Opts.Output.[Output Matrix].Label = "congested " + mode + " impedance" + Opts.Output.[Output Matrix].Compression = 0 //uncompressed, for version 4.8 plus + Opts.Output.[Output Matrix].[File Name] = outputDir + "\\"+skimmat + + RunMacro("HwycadLog",{"hwyskim.rsc: hwy skim","TCSPMAT: "+skimmat+"; "+CostFld}) + ok = RunMacro("TCB Run Procedure", 1, "TCSPMAT", Opts) + if !ok then goto quit + + // STEP 2: Intrazonal added by Ziying Ouyang, June 3, 2009 + // mtxcore={"Length (Skim)"}+{SkimVar1[i]+" (Skim)"}+{SkimVar2[i]+" (Skim)"}+{SkimVar3[i]+" (Skim)"} + mtxcore={"Length (Skim)"}+{SkimVar1+" (Skim)"} + for j = 1 to mtxcore.length do + Opts = null + Opts.Global.Factor = 0.5 + Opts.Global.Neighbors = 3 + Opts.Global.Operation = 1 + Opts.Global.[Treat Missing] = 2 + Opts.Input.[Matrix Currency] = {outputDir + "\\"+skimmat,mtxcore[j], , } + RunMacro("HwycadLog",{"hwyskim.rsc: hwy skim","Intrazonal: "+skimmat+"; "+mtxcore[j]}) + ok = RunMacro("TCB Run Procedure", j, "Intrazonal", Opts) + if !ok then goto quit + end + + // take square root of the reliability which is sum of square of link reliability - write code after generating skims - todo + mtxcore = mode+" - *_TOTREL"+periods[i] + m=OpenMatrix(outputDir + "\\"+skimmat,) + mc=CreateMatrixCurrency(m,mtxcore,,,) + mc:=Nz(mc) // zero out intra-zonal values + mc:=sqrt(mc) // take square root + + end + + ok=1 + runmacro("close all") + quit: + + return(ok) + +EndMacro + +/* + +hwy skim 15 mins time slices + +Skim reliability with following shift variables: + +Variable Time Bin Estimate-Freeway Estimate-Arterial +-------- -------- ---------------- ----------------- +BeforeAM.Step1 32 -0.0183 -0.0054 +BeforeAM.Step2 29 0.0092 -0.0032 +BeforeAM.Step3 26 0.0107 0.0030 +BeforeAM.Step4 20 -0.0019 0.0055 +AfterAM.Step1 32 -0.0082 -0.0009 +AfterAM.Step2 36 0.0000 0.0000 +AfterAM.Step3 39 0.0000 0.0000 +BeforePM.Step1 70 -0.0067 0.0011 +BeforePM.Step2 66 -0.0028 0.0000 +BeforePM.Step3 62 0.0094 -0.0018 +BeforePM.Step4 58 0.0000 0.0000 +AfterPM.Step1 70 -0.0077 -0.0079 +AfterPM.Step2 71 0.0000 0.0025 +AfterPM.Step3 79 0.0075 0.0037 + +{"EA","AM","MD","PM","EV1","EV2"} = {{15,24},{25,36},{37,62},{63,76},{77,96},{0,14}} + +*/ + +macro "hwy skim time bins" (args) + + shared path, inputDir, outputDir, mxzone + + mode = args[1] + + //vot_bin is the value-of-time bin that will be appended to each skim name; prepend "_" + if args[2]=null then vot_bin="" else vot_bin="_"+args[2] + timebin=args[3] + + // period thresholds + Peak_AM = 32 + Low_MD = 41 + Peak_PM = 70 + + // shift variable settings + // {beforeAM_step1, beforeAM_step2,beforeAM_step3,beforeAM_step4,afterAM_step1,afterAM_step2,afterAM_step3,beforePM_step1,beforePM_step2,beforePM_step3,beforePM_step4,afterPM_step1,afterPM_step2,afterPM_step3} + time_bins = {Peak_AM,29,26,20,Peak_AM,36,39,Peak_PM,66,62,58,Peak_PM,71,79} + factor_freeway = {-0.0183,0.0092,0.0107,-0.0019,-0.0082,0.0000,0.0000,-0.0067,-0.0028,0.0094,0.0000,-0.0077,0.0000,0.0075} + factor_arterial = {-0.0054,-0.0032,0.0030,0.0055,-0.0009,0.0000,0.0000,0.0011,0.0000,-0.0018,0.0000,-0.0079,0.0025,0.0037} + + facility_type = {"freeway","arterial","ramp","other"} // freeway (IFC=1), arterial (IFC=2,3), ramp (IFC=8,9), other (IFC=4,5,6,7) + periods = {"_EA", "_AM", "_MD", "_PM", "_EV"} + + // lower and upper bounds of IFC for respective facility type = {freeway, arterial, ramp, other} + lwr_bound = {"1","2","8","4"} + upr_bound = {"1","3","9","7"} + + // input files + db_file = outputDir + "\\hwy.dbd" + net_file = outputDir + "\\hwy.net" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + db_node_lyr = db_file + "|" + node_lyr + net = ReadNetwork(net_file) + + //Recompute total reliability for 15 mins time slices + for fac_type=1 to facility_type.length do + + if fac_type=1 then factor=factor_freeway + else factor=factor_arterial + + // corresponding model time period + if timebin>=15 and timebin<=24 then period = periods[1] // EA + if timebin>=25 and timebin<=36 then period = periods[2] // AM + if timebin>=37 and timebin<=62 then period = periods[3] // MD + if timebin>=63 and timebin<=76 then period = periods[4] // PM + if (timebin>=1 and timebin<=14) or (timebin>=77 and timebin<=96) then period = periods[5] // EV + + // initialize shift variables + beforeAM_step1=0 + beforeAM_step2=0 + beforeAM_step3=0 + beforeAM_step4=0 + afterAM_step1=0 + afterAM_step2=0 + afterAM_step3=0 + beforePM_step1=0 + beforePM_step2=0 + beforePM_step3=0 + beforePM_step4=0 + afterPM_step1=0 + afterPM_step2=0 + afterPM_step3=0 + + // calculate shift reliability + + // before AM + if timebintime_bins[5] and timebintime_bins[6] and timebintime_bins[7] and timebin=Low_MD and timebin=Low_MD and timebin=Low_MD and timebin=Low_MD and timebintime_bins[12] then afterPM_step1=factor[12]*(timebin-time_bins[12]) + if timebin>time_bins[13] then afterPM_step2=factor[13]*(timebin-time_bins[13]) + if timebin>time_bins[14] then afterPM_step3=factor[14]*(timebin-time_bins[14]) + + // calculate total shift reliability factors + shift_factor = beforeAM_step1 + beforeAM_step2 + beforeAM_step3 + beforeAM_step4 + + afterAM_step1 + afterAM_step2 + afterAM_step3 + + beforePM_step1 + beforePM_step2 + beforePM_step3 + beforePM_step4 + + afterPM_step1 + afterPM_step2 + afterPM_step3 + + // expressions to calculate AB/BA shift reliability - squareof link reliability + expression_AB = "AB_TOTREL" + period + "+ pow(" + String(shift_factor) + "*Length*AB_Time,2)" + expression_BA = "BA_TOTREL" + period + "+ pow(" + String(shift_factor) + "*Length*BA_Time,2)" + + flowTable = outputDir+"\\hwyload"+period+".bin" + + query = "Select * where IFC >= " + lwr_bound[fac_type] + " and IFC <= "+upr_bound[fac_type] + + // Total Reliability - The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"reliabilityjoin"+period, "selection", query} + Opts.Global.Fields = {"AB_TOTREL"+period,"BA_TOTREL"+period} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {expression_AB, + expression_BA } + ret_value = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ret_value then goto quit + end + + // update total reliability fields + Opts = null + Opts.Input.Database = db_file + Opts.Input.Network = net_file + Opts.Input.[Link Set] = {db_file+"|"+link_lyr, link_lyr} + Opts.Global.[Fields Indices] = "*_TOTREL"+period + Opts.Global.Options.[Link Fields] = { {link_lyr+".AB_TOTREL"+period,link_lyr+".BA_TOTREL"+period} } + Opts.Global.Options.Constants = {1} + ret_value = RunMacro("TCB Run Operation", "Update Network Field", Opts) + if !ret_value then goto quit + + // settings for skim + if mode = "dant" then do + CostFld = "*SCST"+period // minimizing cost field + excl_qry = "!(ihov=1&ITRUCK<5)" // query for exclusion link set + skimmat = "impdan_"+String(timebin)+vot_bin+".mtx" // output skim matrices + end + else if mode = "dat" then do + CostFld = "*SCST"+period // minimizing cost field + excl_qry = "!(((ihov=1|ihov=4|((ihov=2|ihov=3)&(itoll"+period+">0&abln"+period+"<9)))|ifc>7)&ITRUCK<5)" + skimmat = "impdat_"+String(timebin)+vot_bin+".mtx" + end + else if mode = "s2nh" then do + CostFld = "*H2CST"+period // minimizing cost field + excl_qry ="!((ihov=1|(ihov=2&abln"+period+" <9)|ifc>7)&ITRUCK<5)"//initialize the value + skimmat = "imps2nh"+String(timebin)+vot_bin+".mtx" + end + else if mode = "s2th" then do + CostFld = "*H2CST"+period // minimizing cost field + excl_qry = "!(((ihov=1|(ihov=2&abln"+period+"<9)|ihov=4|(ihov=3&itoll"+period+">0&abln"+period+"<9))|ifc>7)&ITRUCK<5)" + skimmat = "imps2th"+String(timebin)+vot_bin+".mtx" + end + else if mode = "s3nh" then do + CostFld = "*H3CST"+period // minimizing cost field + excl_qry = "!((ihov=1|((ihov=2|ihov=3)&abln"+period+"<9)|ifc>7)& ITRUCK<5)" + skimmat = "imps3nh"+String(timebin)+vot_bin+".mtx" + end + else if mode = "s3th" then do + CostFld = "*H3CST"+period // minimizing cost field + excl_qry = "(abln"+period+"=9 | ITRUCK >4)" + skimmat = "imps3th"+String(timebin)+vot_bin+".mtx" + end + + //skim network + set = "AllLinks" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectAll(set) + NetOpts = null + NetOpts.[Link ID] = link_lyr+".ID" + NetOpts.[Type] = "Enable" + ChangeLinkStatus(net,vw_set, NetOpts) // first enable all links + + if excl_qry<>null then do + set = "toll" + vw_set = link_lyr + "|" + set + SetLayer(link_lyr) + n = SelectByQuery(set, "Several", "Select * where "+excl_qry,) + NetOpts = null + NetOpts.[Link ID] = link_lyr+".ID" + NetOpts.[Type] = "Disable" + ChangeLinkStatus(net,vw_set, NetOpts) // disable exclusion query + end + + Opts = null + Opts.Input.Network = net_file + Opts.Input.[Origin Set] = {db_node_lyr, node_lyr, "Centroids", "select * where ID <= " + i2s(mxzone)} + Opts.Input.[Destination Set] = {db_node_lyr, node_lyr, "Centroids"} + Opts.Input.[Via Set] = {db_node_lyr, node_lyr} + Opts.Field.Minimize = CostFld + Opts.Field.Nodes = node_lyr + ".ID" + //Opts.Field.[Skim Fields].["*_TOTREL"+period]="All" + Opts.Field.[Skim Fields]={{"*_TOTREL"+period,"All"}} + Opts.Output.[Output Matrix].Label = "reliability " + mode + + Opts.Output.[Output Matrix].Compression = 0 //uncompressed, for version 4.8 plus + Opts.Output.[Output Matrix].[File Name] = outputDir + "\\"+skimmat + + RunMacro("HwycadLog",{"hwyskim.rsc: hwy skim time bins","TCSPMAT: "+skimmat+"; "+CostFld}) + ok = RunMacro("TCB Run Procedure", 1, "TCSPMAT", Opts, &Ret) + if !ok then goto quit + + // update skims by taking square root of reliability + mtxcore = "*_TOTREL"+period + " (Skim)" + m=OpenMatrix(outputDir + "\\"+skimmat,) + mc=CreateMatrixCurrency(m,mtxcore,,,) + mc:=Nz(mc) // zero out intra-zonal values + mc:=sqrt(mc) // take square root + + ok=1 + runmacro("close all") + quit: + + return(ok) + +EndMacro + diff --git a/sandag_abm/src/main/gisdk/matrixPrecisionReduction.rsc b/sandag_abm/src/main/gisdk/matrixPrecisionReduction.rsc new file mode 100644 index 0000000..e605f73 --- /dev/null +++ b/sandag_abm/src/main/gisdk/matrixPrecisionReduction.rsc @@ -0,0 +1,51 @@ +/********************************************************************************************************** +Reduce matrix precision +About: + Script to reduce matrix precision. Precision defined in property file. + Author: Wu Sun, SANDAG + Developed: May 2015 + +Note: +Aggregate models such as truck, commercial vehicle, and EI models tend to have fake precisions. +The fake precisions make these matrices very large. +When matrixes are loaded into ABM database, it takes a large amount of DB space. +This scripts is to reduce fake precisions to make space managable. +**********************************************************************************************************/ +Macro "reduce matrix precision"(dir, mat, precision) + + //get matrix info + m = OpenMatrix(dir+"//"+mat, ) + coreNames = GetMatrixCoreNames(m) + numCores=coreNames.length + + //initialize arrays + dim sum[numCores] + dim rsum[numCores] + + //get matrix currency + currency=RunMacro("set input matrix currencies",dir, mat) + + for i = 1 to numCores do + //zero out null cells + currency[i]:=Nz(currency[i]) + + //sums of matrix by core + marginal_sums = GetMatrixMarginals(currency[i], "Sum", "row" ) + sum[i]=Sum(marginal_sums) + RunMacro("HwycadLog",{"matrixPrecisionReduction.rsc:","sum of "+coreNames[i]+" before reduction:"+r2s(sum[i])}) + + //reduce matrix precision using matrix expression. + expr="if(["+coreNames[i]+"]<"+precision+") then 0.0 else ["+coreNames[i]+"]" + EvaluateMatrixExpression(currency[i], expr,,, ) + rmarginal_sums = GetMatrixMarginals(currency[i], "Sum", "row" ) + rsum[i]=Sum(rmarginal_sums) + RunMacro("HwycadLog",{"matrixPrecisionReduction.rsc:","sum of "+coreNames[i]+" after reduction:"+r2s(rsum[i])}) + end + + //scale up reduced matrix to orirginal sum + for i = 1 to numCores do + currency[i]:=currency[i]*sum[i]/rsum[i] + end + +EndMacro + diff --git a/sandag_abm/src/main/gisdk/parameter.rsc b/sandag_abm/src/main/gisdk/parameter.rsc new file mode 100644 index 0000000..d569002 --- /dev/null +++ b/sandag_abm/src/main/gisdk/parameter.rsc @@ -0,0 +1,8 @@ +macro "parameters" +shared mxzone,mxtap,mxext,mxlink,mxrte +mxzone=4996 +mxtap=2500 +mxext=12 +mxrte=380 +mxlink=41000 +endmacro \ No newline at end of file diff --git a/sandag_abm/src/main/gisdk/sandag_abm.lst b/sandag_abm/src/main/gisdk/sandag_abm.lst new file mode 100644 index 0000000..07cd1e8 --- /dev/null +++ b/sandag_abm/src/main/gisdk/sandag_abm.lst @@ -0,0 +1,22 @@ +${workpath}\\${year}\\gisdk\\dbox.rsc +${workpath}\\${year}\\gisdk\\sandag_abm_master.rsc +${workpath}\\${year}\\gisdk\\parameter.rsc +${workpath}\\${year}\\gisdk\\SandagCommon.rsc +${workpath}\\${year}\\gisdk\\createhwynet.rsc +${workpath}\\${year}\\gisdk\\hwyassign.rsc +${workpath}\\${year}\\gisdk\\hwyskim.rsc +${workpath}\\${year}\\gisdk\\createtrnroutes.rsc +${workpath}\\${year}\\gisdk\\trnskim.rsc +${workpath}\\${year}\\gisdk\\trnassign.rsc +${workpath}\\${year}\\gisdk\\commVehGen.rsc +${workpath}\\${year}\\gisdk\\commVehDist.rsc +${workpath}\\${year}\\gisdk\\commVehTOD.rsc +${workpath}\\${year}\\gisdk\\commVehDiversion.rsc +${workpath}\\${year}\\gisdk\\createtodtables.rsc +${workpath}\\${year}\\gisdk\\externalInternal.rsc +${workpath}\\${year}\\gisdk\\TruckModel.rsc +${workpath}\\${year}\\gisdk\\create_LUZ_Skims.rsc +${workpath}\\${year}\\gisdk\\sandag_abm_outputs.rsc +${workpath}\\${year}\\gisdk\\exportTCData.rsc +${workpath}\\${year}\\gisdk\\Utilities.rsc +${workpath}\\${year}\\gisdk\\matrixPrecisionReduction.rsc diff --git a/sandag_abm/src/main/gisdk/sandag_abm_generic.lst b/sandag_abm/src/main/gisdk/sandag_abm_generic.lst new file mode 100644 index 0000000..2f8b0f4 --- /dev/null +++ b/sandag_abm/src/main/gisdk/sandag_abm_generic.lst @@ -0,0 +1,23 @@ +${workpath}\\gisdk\\dbox.rsc +${workpath}\\gisdk\\gui.rsc +${workpath}\\gisdk\\sandag_abm_master.rsc +${workpath}\\gisdk\\parameter.rsc +${workpath}\\gisdk\\SandagCommon.rsc +${workpath}\\gisdk\\createhwynet.rsc +${workpath}\\gisdk\\hwyassign.rsc +${workpath}\\gisdk\\hwyskim.rsc +${workpath}\\gisdk\\createtrnroutes.rsc +${workpath}\\gisdk\\trnskim.rsc +${workpath}\\gisdk\\trnassign.rsc +${workpath}\\gisdk\\commVehGen.rsc +${workpath}\\gisdk\\commVehDist.rsc +${workpath}\\gisdk\\commVehTOD.rsc +${workpath}\\gisdk\\commVehDiversion.rsc +${workpath}\\gisdk\\createtodtables.rsc +${workpath}\\gisdk\\externalInternal.rsc +${workpath}\\gisdk\\TruckModel.rsc +${workpath}\\gisdk\\create_LUZ_Skims.rsc +${workpath}\\gisdk\\sandag_abm_outputs.rsc +${workpath}\\gisdk\\exportTCData.rsc +${workpath}\\gisdk\\Utilities.rsc +${workpath}\\gisdk\\matrixPrecisionReduction.rsc diff --git a/sandag_abm/src/main/gisdk/sandag_abm_master.rsc b/sandag_abm/src/main/gisdk/sandag_abm_master.rsc new file mode 100644 index 0000000..ccd497b --- /dev/null +++ b/sandag_abm/src/main/gisdk/sandag_abm_master.rsc @@ -0,0 +1,411 @@ +Macro "Run SANDAG ABM" + + RunMacro("TCB Init") + + shared path, inputDir, outputDir, inputTruckDir, mxzone, mxtap, mxext,mxlink,mxrte,scenarioYear,version + + + sample_rate = { 0.2, 0.5, 1.0 } + max_iterations=sample_rate.length //number of feedback loops + skimByVOT = "true" + assignByVOT = "true" + + path = "${workpath}" + + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","*********Model Run Starting************"}) + + path_parts = SplitPath(path) + path_no_drive = path_parts[2]+path_parts[3] + drive=path_parts[1] + path_forward_slash = Substitute(path_no_drive, "\\", "/", ) + + inputDir = path+"\\input" + outputDir = path+"\\output" + inputTruckDir = path+"\\input_truck" + + SetLogFileName(path+"\\logFiles\\tclog.xml") + SetReportFileName(path+"\\logFiles\\tcreport.xml") + + RunMacro("parameters") + + // read properties from sandag_abm.properties in /conf folder + properties = "\\conf\\sandag_abm.properties" + sample_rate = RunMacro("read properties array",properties,"sample_rates", "S") + max_iterations=sample_rate.length //number of feedback loops + scenarioYear = RunMacro("read properties",properties,"scenarioYear", "S") + skipCopyWarmupTripTables = RunMacro("read properties",properties,"RunModel.skipCopyWarmupTripTables", "S") + skipCopyBikeLogsum = RunMacro("read properties",properties,"RunModel.skipCopyBikeLogsum", "S") + skipCopyWalkImpedance= RunMacro("read properties",properties,"RunModel.skipCopyWalkImpedance", "S") + skipWalkLogsums= RunMacro("read properties",properties,"RunModel.skipWalkLogsums", "S") + skipBikeLogsums= RunMacro("read properties",properties,"RunModel.skipBikeLogsums", "S") + skipBuildHwyNetwork = RunMacro("read properties",properties,"RunModel.skipBuildHwyNetwork", "S") + skipBuildTransitNetwork= RunMacro("read properties",properties,"RunModel.skipBuildTransitNetwork", "S") + startFromIteration = s2i(RunMacro("read properties",properties,"RunModel.startFromIteration", "S")) + skipHighwayAssignment = RunMacro("read properties array",properties,"RunModel.skipHighwayAssignment", "S") + skipHighwaySkimming = RunMacro("read properties array",properties,"RunModel.skipHighwaySkimming", "S") + skipTransitSkimming = RunMacro("read properties array",properties,"RunModel.skipTransitSkimming", "S") + skipCoreABM = RunMacro("read properties array",properties,"RunModel.skipCoreABM", "S") + skipOtherSimulateModel = RunMacro("read properties array",properties,"RunModel.skipOtherSimulateModel", "S") + skipSpecialEventModel = RunMacro("read properties array",properties,"RunModel.skipSpecialEventModel", "S") + skipCTM = RunMacro("read properties array",properties,"RunModel.skipCTM", "S") + skipEI = RunMacro("read properties array",properties,"RunModel.skipEI", "S") + skipTruck = RunMacro("read properties array",properties,"RunModel.skipTruck", "S") + skipTripTableCreation = RunMacro("read properties array",properties,"RunModel.skipTripTableCreation", "S") + skipFinalHighwayAssignment = RunMacro("read properties",properties,"RunModel.skipFinalHighwayAssignment", "S") + skipFinalTransitAssignment = RunMacro("read properties",properties,"RunModel.skipFinalTransitAssignment", "S") + skipFinalHighwaySkimming = RunMacro("read properties",properties,"RunModel.skipFinalHighwaySkimming", "S") + skipFinalTransitSkimming = RunMacro("read properties",properties,"RunModel.skipFinalTransitSkimming", "S") + skipLUZSkimCreation = RunMacro("read properties",properties,"RunModel.skipLUZSkimCreation", "S") + skipDataExport = RunMacro("read properties",properties,"RunModel.skipDataExport", "S") + skipDataLoadRequest = RunMacro("read properties",properties,"RunModel.skipDataLoadRequest", "S") + skipDeleteIntermediateFiles = RunMacro("read properties",properties,"RunModel.skipDeleteIntermediateFiles", "S") + precision = RunMacro("read properties",properties,"RunModel.MatrixPrecision", "S") + minSpaceOnC=RunMacro("read properties",properties,"RunModel.minSpaceOnC", "S") + + // Swap Server Configurations + runString = path+"\\bin\\serverswap.bat "+drive+" "+path_no_drive+" "+path_forward_slash + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Server Config Swap: "+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Run ServerSwap", runString) + if !ok then goto quit + ok=RunMacro("find String","\\logFiles\\serverswap.log","FATAL") + if !ok then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","ServerSwap failed! Open logFiles/serverswap.log for details."}) + goto quit + end + + //Update year specific properties + runString = path+"\\bin\\updateYearSpecificProps.bat "+drive+" "+path_no_drive+" "+path_forward_slash + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Update year specific properties: "+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Update Year Specific Properties", runString) + if !ok then goto quit + + + //check free space on C drive + runString = path+"\\bin\\checkFreeSpaceOnC.bat "+minSpaceOnC + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Checking if there is enough space on C drive: "+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Check space on C drive", runString) + + //check AT and Transit networks consistency + runString = path+"\\bin\\checkAtTransitNetworkConsistency.cmd "+drive+" "+path_forward_slash + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Checking if AT and Transit Networks are consistent: "+" "+runString}) + RunProgram(runString, ) + ok=RunMacro("find String","\\logFiles\\AtTransitCheck_event.log","FATAL") + if !ok then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","AT and Transit network consistency chekcing failed! Open AtTransitCheck_event.log for details."}) + goto quit + end + + // copy bike logsums from input to output folder + if skipCopyBikeLogsum = "false" then do + CopyFile(inputDir+"\\bikeMgraLogsum.csv", outputDir+"\\bikeMgraLogsum.csv") + CopyFile(inputDir+"\\bikeTazLogsum.csv", outputDir+"\\bikeTazLogsum.csv") + end + if skipBikeLogsums = "false" then do + runString = path+"\\bin\\runSandagBikeLogsums.cmd "+drive+" "+path_forward_slash + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Java-Run create AT logsums and walk impedances"+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Run AT-Logsums", runString) + if !ok then goto quit + end + + // copy walk impedance from input to output folder + if skipCopyWalkImpedance = "false" then do + CopyFile(inputDir+"\\walkMgraEquivMinutes.csv", outputDir+"\\walkMgraEquivMinutes.csv") + CopyFile(inputDir+"\\walkMgraTapEquivMinutes.csv", outputDir+"\\walkMgraTapEquivMinutes.csv") + end + if skipWalkLogsums = "false" then do + runString = path+"\\bin\\runSandagWalkLogsums.cmd "+drive+" "+path_forward_slash + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Java-Run create AT logsums and walk impedances"+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Run AT-Logsums", runString) + if !ok then goto quit + end + + // copy initial trip tables from input to output folder + if skipCopyWarmupTripTables = "false" then do + CopyFile(inputDir+"\\Trip_EA_VOT.mtx", outputDir+"\\Trip_EA_VOT.mtx") + CopyFile(inputDir+"\\Trip_AM_VOT.mtx", outputDir+"\\Trip_AM_VOT.mtx") + CopyFile(inputDir+"\\Trip_MD_VOT.mtx", outputDir+"\\Trip_MD_VOT.mtx") + CopyFile(inputDir+"\\Trip_PM_VOT.mtx", outputDir+"\\Trip_PM_VOT.mtx") + CopyFile(inputDir+"\\Trip_EV_VOT.mtx", outputDir+"\\Trip_EV_VOT.mtx") + end + + // Build highway network + if skipBuildHwyNetwork = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - run create hwy"}) + ok = RunMacro("TCB Run Macro", 1, "run create hwy",{}) + if !ok then goto quit + end + + // Create transit routes + if skipBuildTransitNetwork = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - run create all transit"}) + ok = RunMacro("TCB Run Macro", 1, "Create all transit",{}) + if !ok then goto quit + end + + //Looping + for iteration = startFromIteration to max_iterations do + + if skipCoreABM[iteration] = "false" or skipOtherSimulateModel[iteration] = "false" or skipSpecialEventModel[iteration] = "false" then do //Wu modified to add special event model 5/19/2017 + // Start matrix manager locally + runString = path+"\\bin\\runMtxMgr.cmd "+drive+" "+path_no_drive + ok = RunMacro("TCB Run Command", 1, "Start matrix manager", runString) + if !ok then goto quit + + // Start JPPF driver + runString = path+"\\bin\\runDriver.cmd "+drive+" "+path_no_drive + ok = RunMacro("TCB Run Command", 1, "Start JPPF Driver", runString) + if !ok then goto quit + + // Start HH Manager, and worker nodes + runString = path+"\\bin\\StartHHAndNodes.cmd "+drive+" "+path_no_drive + ok = RunMacro("TCB Run Command", 1, "Start HH Manager, JPPF Driver, and nodes", runString) + if !ok then goto quit + end + + // Run highway assignment + if skipHighwayAssignment[iteration] = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - hwy assignment"}) + ok = RunMacro("TCB Run Macro", 1, "hwy assignment",{iteration, assignByVOT}) + if !ok then goto quit + end + + // Skim highway network + if skipHighwaySkimming[iteration] = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Hwy skim all"}) + ok = RunMacro("TCB Run Macro", 1, "Hwy skim all",{skimByVOT}) + if !ok then goto quit + + // Create drive to transit access file + runString = path+"\\bin\\CreateD2TAccessFile.bat "+drive+" "+path_forward_slash + + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Java - Creating drive to transit access file"}) + ok = RunMacro("TCB Run Command", 1, "Creating drive to transit access file", runString) + if !ok then goto quit + end + + // Skim transit network + if skipTransitSkimming[iteration] = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Build transit skims"}) + ok = RunMacro("TCB Run Macro", 1, "Build transit skims",{}) + if !ok then goto quit + end + + // First move some trip matrices so model will crash if ctramp model doesn't produced csv/mtx files for assignment + if (iteration > startFromIteration) then do + fromDir = outputDir + toDir = outputDir+"\\iter"+String(iteration-1) + //check for directory of output + if GetDirectoryInfo(toDir, "Directory")=null then do + CreateDirectory( toDir) + end + status = RunProgram("cmd.exe /c copy "+fromDir+"\\auto*.mtx "+toDir+"\\auto*.mtx",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\tran*.mtx "+toDir+"\\tran*.mtx",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\nmot*.mtx "+toDir+"\\nmot*.mtx",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\othr*.mtx "+toDir+"\\othr*.mtx",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\trip*.mtx "+toDir+"\\trip*.mtx",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\internalExternalTrips.csv "+toDir+"\\internalExternalTrips.csv",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\airport_out.csv "+toDir+"\\airport_out.csv",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\crossBorderTrips.csv "+toDir+"\\crossBorderTrips.csv",) + status = RunProgram("cmd.exe /c copy "+fromDir+"\\visitorTrips.csv "+toDir+"\\visitorTrips.csv",) + +// status = RunProgram("cmd.exe /c copy "+fromDir+"\\daily*.mtx "+toDir+"\\daily*.mtx",) +// status = RunProgram("cmd.exe /c copy "+fromDir+"\\comm*.mtx "+toDir+"\\comm*.mtx",) + + status = RunProgram("cmd.exe /c del "+fromDir+"\\auto*.mtx",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\tran*.mtx",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\nmot*.mtx",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\othr*.mtx",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\trip*.mtx",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\internalExternalTrips.csv",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\airport_out.csv",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\crossBorderTrips.csv",) + status = RunProgram("cmd.exe /c del "+fromDir+"\\visitorTrips.csv",) + +// status = RunProgram("cmd.exe /c del "+fromDir+"\\daily*.mtx",) +// status = RunProgram("cmd.exe /c del "+fromDir+"\\comm*.mtx",) + + end + + + // Run CT-RAMP model + if skipCoreABM[iteration] = "false" then do + runString = path+"\\bin\\runSandagAbm_SDRM.cmd "+drive+" "+path_forward_slash +" "+sample_rate[iteration]+" "+i2s(iteration) + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Java-Run CT-RAMP"+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Run CT-RAMP", runString) + if !ok then goto quit + end + + + // Run airport model, visitor model, cross-border model, internal-external model + if skipOtherSimulateModel[iteration] = "false" then do + runString = path+"\\bin\\runSandagAbm_SMM.cmd "+drive+" "+path_forward_slash +" "+sample_rate[iteration]+" "+i2s(iteration) + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Java-Run airport model, visitor model, cross-border model"+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Run CT-RAMP", runString) + if !ok then goto quit + end + + // Run special event model + if skipSpecialEventModel[iteration] = "false" then do + runString = path+"\\bin\\runSandagAbm_SEM.cmd "+drive+" "+path_forward_slash +" "+sample_rate[iteration]+" "+i2s(iteration) + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Java-Run special event model"+" "+runString}) + ok = RunMacro("TCB Run Command", 1, "Run CT-RAMP", runString) + if !ok then goto quit + end + + + if skipCTM[iteration] = "false" then do + //Commercial vehicle trip generation + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - run commercial vehicle generation"}) + ok = RunMacro("TCB Run Macro", 1, "Commercial Vehicle Generation",{}) + if !ok then goto quit + + //Commercial vehicle trip distribution + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - run commercial vehicle distribution"}) + ok = RunMacro("TCB Run Macro", 1, "Commercial Vehicle Distribution",{}) + if !ok then goto quit + + //Commercial vehicle time-of-day + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - run commercial vehicle Time Of Day"}) + ok = RunMacro("TCB Run Macro", 1, "Commercial Vehicle Time Of Day",{}) + if !ok then goto quit + + //Commercial vehicle toll diversion model + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - run commercial vehicle Toll Diversion"}) + ok = RunMacro("TCB Run Macro", 1, "cv toll diversion model",{}) + if !ok then goto quit + + // reduce commerical travel matrix precisions + RunMacro("HwycadLog",{"sandag_abm_master.rsc","reduce matrix precision for commVehTODTrips.mtx"}) + RunMacro("reduce matrix precision",outputDir,"commVehTODTrips.mtx", precision) + end + + /* + @WSU 2-23-2017 + Run EI and truck models only in the starting iteration (not necessarily the 1st iteration) + Purpose: + Reduce number of iterations to cut model run time by 2-2.5 hrs + Notes: + 1) Combined EI and truck trips are less than 2.5% of total trips; + 2) Trip generations are not sensitive to skims, total EI and truck demands are not affected; + 3) Skims only affect EI and truck destination choices + */ + if iteration = startFromIteration then do + //Run External(U.S.)-Internal Model + if skipEI[iteration] = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - US to SD External Trip Model"}) + ok = RunMacro("TCB Run Macro", 1, "US to SD External Trip Model",{}) + if !ok then goto quit + + // reduce EI matrix precisions + + m={"usSdWrk_EA.mtx","usSdWrk_AM.mtx","usSdWrk_MD.mtx","usSdWrk_PM.mtx","usSdWrk_EV.mtx","usSdNon_EA.mtx","usSdNon_AM.mtx","usSdNon_MD.mtx","usSdNon_PM.mtx","usSdNon_EV.mtx"} + for i = 1 to m.length do + RunMacro("HwycadLog",{"sandag_abm_master.rsc","reduce precision for:"+m[i]}) + RunMacro("reduce matrix precision",outputDir,m[i], precision) + end + end + + //Run Truck Model + if skipTruck[iteration] = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - truck model"}) + ok = RunMacro("truck model",properties, iteration) + if !ok then goto quit + + // reduce truck matrix precisions + m={"dailyDistributionMatricesTruckEA.mtx","dailyDistributionMatricesTruckAM.mtx","dailyDistributionMatricesTruckMD.mtx","dailyDistributionMatricesTruckPM.mtx","dailyDistributionMatricesTruckEV.mtx"} + for i = 1 to m.length do + RunMacro("HwycadLog",{"sandag_abm_master.rsc","reduce precision for:"+m[i]}) + RunMacro("reduce matrix precision",outputDir,m[i], precision) + end + end + end + + //Construct trip tables + if skipTripTableCreation[iteration] = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Create Auto Tables"}) + ok = RunMacro("TCB Run Macro", 1, "Create Auto Tables",{}) + if !ok then goto quit + + // reduce EE matrix precisions + RunMacro("HwycadLog",{"sandag_abm_master.rsc","reduce matrix precision for externalExternalTrips.mtx"}) + RunMacro("reduce matrix precision",outputDir,"externalExternalTrips.mtx", precision) + end + + end + + // Run final highway assignment + if skipFinalHighwayAssignment = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - hwy assignment"}) + ok = RunMacro("TCB Run Macro", 1, "hwy assignment",{4,assignByVOT}) + if !ok then goto quit + end + + if skipFinalTransitAssignment = "false" then do + //Construct transit trip tables + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Create Transit Tables"}) + ok = RunMacro("TCB Run Macro", 1, "Create Transit Tables",{}) + if !ok then goto quit + + //Run final and only transit assignment + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Assign Transit"}) + ok = RunMacro("TCB Run Macro", 1, "Assign Transit",{4}) + if !ok then goto quit + end + + // Skim highway network based on final highway assignment + if skipFinalHighwaySkimming = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Hwy skim all"}) + ok = RunMacro("TCB Run Macro", 1, "Hwy skim all",{}) + if !ok then goto quit + end + + // Skim transit network based on final transit assignemnt + if skipFinalTransitSkimming = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Build transit skims"}) + ok = RunMacro("TCB Run Macro", 1, "Build transit skims",{}) + if !ok then goto quit + end + + //Create LUZ skims + if skipLUZSkimCreation = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Create LUZ Skims"}) + ok = RunMacro("TCB Run Macro", 1, "Create LUZ Skims",{}) + if !ok then goto quit + end + + //export TransCAD data (networks and trip tables) + if skipDataExport = "false" then do + RunMacro("HwycadLog",{"sandag_abm_master.rsc:","Macro - Export TransCAD Data"}) + ok = RunMacro("TCB Run Macro", 1, "ExportSandagData",{}) + if !ok then goto quit + + // export core ABM data + runString = path+"\\bin\\DataExporter.bat "+drive+" "+path_no_drive + ok = RunMacro("TCB Run Command", 1, "Export core ABM data", runString) + if !ok then goto quit + end + + //request data load after model run finish successfully + if skipDataLoadRequest = "false" then do + runString = path+"\\bin\\DataLoadRequest.bat "+drive+path_no_drive+" "+String(max_iterations)+" "+scenarioYear+" "+sample_rate[max_iterations] + ok = RunMacro("TCB Run Command", 1, "Data load request", runString) + if !ok then goto quit + end + + // delete trip table files in iteration sub folder if model finishes without crashing + if skipDeleteIntermediateFiles = "false" then do + for iteration = startFromIteration to max_iterations-1 do + toDir = outputDir+"\\iter"+String(iteration-1) + status = RunProgram("cmd.exe /c del "+toDir+"\\auto*.mtx",) + status = RunProgram("cmd.exe /c del "+toDir+"\\tran*.mtx",) + status = RunProgram("cmd.exe /c del "+toDir+"\\nmot*.mtx",) + status = RunProgram("cmd.exe /c del "+toDir+"\\othr*.mtx",) + status = RunProgram("cmd.exe /c del "+toDir+"\\trip*.mtx",) + end + end + + RunMacro("TCB Closing", ok, "False") + return(1) + quit: + return(0) +EndMacro diff --git a/sandag_abm/src/main/gisdk/sandag_abm_outputs.rsc b/sandag_abm/src/main/gisdk/sandag_abm_outputs.rsc new file mode 100644 index 0000000..5213abf --- /dev/null +++ b/sandag_abm/src/main/gisdk/sandag_abm_outputs.rsc @@ -0,0 +1,293 @@ +Macro "_OpenTable" (file,view_name) + ext = Lower(Right(file,3)) + if ext = "csv" then do + type = "CSV" + end + else if ext = "bin" then do + type = "FFB" + end + else do + ShowMessage("Cannot open table of type " + ext) + ShowMessage(2) + end + return(OpenTable(view_name,type,{file,})) +EndMacro + +Macro "GetTodToken" + return("%%TOD%%") +EndMacro + +Macro "GetSkimToken" + return("%%SKIM%%") +EndMacro + +Macro "GetTodPeriods" + return({"EA","AM","MD","PM","EV"}) +EndMacro + +Macro "GetSkimPeriods" + return({"AM","PM","OP"}) +EndMacro + +Macro "GetTodSkimMapping" + mapping = null + mapping.EA = "OP" + mapping.AM = "AM" + mapping.MD = "OP" + mapping.PM = "PM" + mapping.EV = "OP" + return(mapping) +EndMacro + +Macro "GetHighwayModes" + return({"SOV_GP","SOV_PAY","SR2_GP","SR2_HOV","SR2_PAY","SR3_GP","SR3_HOV","SR3_PAY","lhdn","mhdn","hhdn","lhdt","mhdt","hhdt"}) +EndMacro + +Macro "GetTransitModes" + return({"LOC","LRT","EXP","CMR","BRT"}) +EndMacro + +Macro "GetTransitAccessModes" + return({"WLK","PNR","KNR"}) +EndMacro + +Macro "ExportNetworkToCsv" (network_file,output_file_base) + {node_layer,line_layer} = GetDBLayers(network_file) + network_layer = AddLayerToWorkspace("network_line_layer",network_file,line_layer) + SetLayer(network_layer) + view = GetView() + ExportView(view+"|","CSV",output_file_base+".csv",,{{"CSV Header", "True"},{"Force Numeric Type", "double"}}) + CloseView(view) + +EndMacro + + +Macro "ExportHwyloadtoCSV"(input_file_base, output_file_base) + + tod_periods = RunMacro("GetTodPeriods") + + for t = 1 to tod_periods.length do + tod = tod_periods[t] + input_file= input_file_base+tod+".bin" + view = OpenTable("Binary Table","FFB",{input_file,}, {{"Shared", "True"}}) + SetView(view) + ExportView(view+"|", "CSV", output_file_base+tod+".csv", + {"ID1", + "AB_Flow_PCE", + "BA_Flow_PCE", + "AB_Time", + "BA_Time", + "AB_VOC", + "BA_VOC", + "AB_V_Dist_T", + "BA_V_Dist_T", + "AB_VHT", + "BA_VHT", + "AB_Speed", + "BA_Speed", + "AB_VDF", + "BA_VDF", + "AB_MSA_Flow", + "BA_MSA_Flow", + "AB_MSA_Time", + "BA_MSA_Time", + "AB_Flow_SOV_GP_LOW", + "BA_Flow_SOV_GP_LOW", + "AB_Flow_SOV_PAY_LOW", + "BA_Flow_SOV_PAY_LOW", + "AB_Flow_SR2_GP_LOW", + "BA_Flow_SR2_GP_LOW", + "AB_Flow_SR2_HOV_LOW", + "BA_Flow_SR2_HOV_LOW", + "AB_Flow_SR2_PAY_LOW", + "BA_Flow_SR2_PAY_LOW", + "AB_Flow_SR3_GP_LOW", + "BA_Flow_SR3_GP_LOW", + "AB_Flow_SR3_HOV_LOW", + "BA_Flow_SR3_HOV_LOW", + "AB_Flow_SR3_PAY_LOW", + "BA_Flow_SR3_PAY_LOW", + "AB_Flow_SOV_GP_MED", + "BA_Flow_SOV_GP_MED", + "AB_Flow_SOV_PAY_MED", + "BA_Flow_SOV_PAY_MED", + "AB_Flow_SR2_GP_MED", + "BA_Flow_SR2_GP_MED", + "AB_Flow_SR2_HOV_MED", + "BA_Flow_SR2_HOV_MED", + "AB_Flow_SR2_PAY_MED", + "BA_Flow_SR2_PAY_MED", + "AB_Flow_SR3_GP_MED", + "BA_Flow_SR3_GP_MED", + "AB_Flow_SR3_HOV_MED", + "BA_Flow_SR3_HOV_MED", + "AB_Flow_SR3_PAY_MED", + "BA_Flow_SR3_PAY_MED", + "AB_Flow_SOV_GP_HIGH", + "BA_Flow_SOV_GP_HIGH", + "AB_Flow_SOV_PAY_HIGH", + "BA_Flow_SOV_PAY_HIGH", + "AB_Flow_SR2_GP_HIGH", + "BA_Flow_SR2_GP_HIGH", + "AB_Flow_SR2_HOV_HIGH", + "BA_Flow_SR2_HOV_HIGH", + "AB_Flow_SR2_PAY_HIGH", + "BA_Flow_SR2_PAY_HIGH", + "AB_Flow_SR3_GP_HIGH", + "BA_Flow_SR3_GP_HIGH", + "AB_Flow_SR3_HOV_HIGH", + "BA_Flow_SR3_HOV_HIGH", + "AB_Flow_SR3_PAY_HIGH", + "BA_Flow_SR3_PAY_HIGH", + "AB_Flow_lhdn", + "BA_Flow_lhdn", + "AB_Flow_mhdn", + "BA_Flow_mhdn", + "AB_Flow_hhdn", + "BA_Flow_hhdn", + "AB_Flow_lhdt", + "BA_Flow_lhdt", + "AB_Flow_mhdt", + "BA_Flow_mhdt", + "AB_Flow_hhdt", + "BA_Flow_hhdt", + "AB_Flow", + "BA_Flow"}, + {{"CSV Header", "True"},{"Force Numeric Type", "double"}}) + CloseView(view) + end + ok=1 + quit: + return(ok) +EndMacro + + + + + +Macro "BuildTransitFlowOptions" + //name,source_name,primary key column + skim_token = RunMacro("GetSkimToken") + topts = {{"ROUTE", "Route" ,True }, + {"FROM_STOP", "From_Stop" ,True }, + {"TO_STOP", "To_Stop" ,True }, + {"CENTROID", "Centroid" ,False }, + {"FROMMP", "From_MP" ,False }, + {"TOMP", "To_MP" ,False }, + {"TRANSITFLOW", "TransitFlow" ,False }, + {"BASEIVTT", "BaseIVTT" ,False }, + {"COST", "Cost" ,False }, + {"VOC", "VOC" ,False }} + fopts = {"flow",""} + return({topts,fopts}) +EndMacro + +Macro "BuildOnOffOptions" + //name,source_name,primary key column + skim_token = RunMacro("GetSkimToken") + topts = {{"ROUTE", "ROUTE" ,True }, + {"STOP", "STOP" ,True }, + {"BOARDINGS", "On" ,False}, + {"ALIGHTINGS", "Off" ,False}, + {"WALKACCESSON", "WalkAccessOn" ,False}, + {"DIRECTTRANSFERON", "DirectTransferOn" ,False}, + {"WALKTRANSFERON", "WalkTransferOn" ,False}, + {"DIRECTTRANSFEROFF", "DirectTransferOff" ,False}, + {"WALKTRANSFEROFF", "WalkTransferOff" ,False}, + {"EGRESSOFF", "EgressOff" ,False}} + fopts = {"ono",""} + return({topts,fopts}) +EndMacro + + +Macro "BuildAggFlowOptions" + //name,source_name,primary key column + skim_token = RunMacro("GetSkimToken") + topts = {{"LINK_ID", "ID1" ,True }, + {"AB_TransitFlow", "AB_TransitFlow" ,false}, + {"BA_TransitFlow", "BA_TransitFlow" ,False}, + {"AB_NonTransit", "AB_NonTransit" ,False}, + {"BA_NonTransit", "BA_NonTransit" ,False}, + {"AB_TotalFlow", "AB_TotalFlow" ,False}, + {"BA_TotalFlow", "BA_TotalFlow" ,False}, + {"AB_Access_Walk_Flow", "AB_Access_Walk_Flow" ,False}, + {"BA_Access_Walk_Flow", "BA_Access_Walk_Flow" ,False}, + {"AB_Xfer_Walk_Flow", "AB_Xfer_Walk_Flow" ,False}, + {"BA_Xfer_Walk_Flow", "BA_Xfer_Walk_Flow" ,False}, + {"AB_Egress_Walk_Flow", "AB_Egress_Walk_Flow" ,False}, + {"BA_Egress_Walk_Flow", "BA_Egress_Walk_Flow" ,False}} + fopts = {"agg",""} + return({topts,fopts}) +EndMacro + + + +Macro "ExportTransitTablesToCsv" (results_dir,transit_options,output_file_base) + fopts = transit_options[2] + transit_options = transit_options[1] + header = "MODE,ACCESSMODE,TOD" + for i = 1 to transit_options.length do + header = header + "," + transit_options[i][1] + end + + f = OpenFile(output_file_base + ".csv","w") + WriteLine(f,header) + + table_name = Upper(Right(output_file_base,Len(output_file_base) - PositionTo(,output_file_base,"\\"))) + + transit_modes = RunMacro("GetTransitModes") + transit_access_modes = RunMacro("GetTransitAccessModes") + tod_periods = RunMacro("GetTodPeriods") + tod_skim_mapping = RunMacro("GetTodSkimMapping") + skim_token = RunMacro("GetSkimToken") + + for i = 1 to tod_periods.length do + tod = tod_periods[i] + for t = 1 to transit_modes.length do + transit_mode = transit_modes[t] + for ta = 1 to transit_access_modes.length do + transit_access_mode = transit_access_modes[ta] + tf = RunMacro("FormPath",{results_dir,fopts[1] + transit_access_modes[ta] + "_" + transit_mode + "_" + tod + fopts[2] + ".bin"}) + if GetFileInfo(tf) <> null then do + view = RunMacro("_OpenTable",tf,"tview") + + rh = GetFirstRecord(view + "|",) + while rh <> null do + line = transit_mode + "," + transit_access_mode + "," + tod + for to = 1 to transit_options.length do + line = line + "," + RunMacro("ToString",view.(Substitute(transit_options[to][2],skim_token,tod_skim_mapping.(tod),))) + end + WriteLine(f,line) + structure = GetViewStructure(view) + for to = 1 to transit_options.length do + field_id = -1 + field = Substitute(transit_options[to][2],skim_token,tod_skim_mapping.(tod),) + for s = 1 to structure.length do + if structure[s][1] = field then do + field_id = s + end + end + if field_id < 1 then do + ShowMessage("couldn't find field: " + field) + ShowMessage(2) + end + + end + rh = GetNextRecord(view + "|",rh,) + end + CloseView(view) + end + end + end + end + + CloseFile(f) + +EndMacro + +Macro "SaveMatrix" (matrix_in,file_out) + m = OpenMatrix(matrix_in,) + CreateTableFromMatrix(m,file_out,"CSV",{{"Complete","Yes"}}) +EndMacro + + diff --git a/sandag_abm/src/main/gisdk/sellinkMtxAgg.rsc b/sandag_abm/src/main/gisdk/sellinkMtxAgg.rsc new file mode 100644 index 0000000..d0be578 --- /dev/null +++ b/sandag_abm/src/main/gisdk/sellinkMtxAgg.rsc @@ -0,0 +1,223 @@ +//Aggregate transit select link trip matrix +//Input: trn_sellinkxxxxx_xx.mtx select link trip table by access mode, line haul mode, and time of day +// a text file with a list of TAPs to sum up trips +//Ouput: trn_sellink_total.csv +//Author: Ziying Ouyang +// @ziying.ouyang@sandag.org +//Date: Feb 5, 2014 + + +Macro "Sum Up Select Link Transit Trips" + shared path_study, path, outputDir + RunMacro("TCB Init") + + sum_all = 0 + sum_sg = 0 + pct_sg = 0 + + outputDir = path+"\\output" + sellink_file = outputDir+"\\trn_sellinkWLK_LRT_EA.mtx" + if GetFileInfo(sellink_file) <> null then do + periodName = {"_EA", "_AM", "_MD", "_PM", "_EV"} + + matrixCore = { + "WLK_LOC", + "WLK_EXP", + "WLK_BRT", + "WLK_LRT", + "WLK_CMR", + "PNR_LOC", + "PNR_EXP", + "PNR_BRT", + "PNR_LRT", + "PNR_CMR", + "KNR_LOC", + "KNR_EXP", + "KNR_BRT", + "KNR_LRT", + "KNR_CMR" } + + //open smart growth tap CSV file + in_file = path_study + "\\sg_tap.csv" + if GetFileInfo(in_file) <> null then do + + view = OpenTable("SmartGrowthTap","CSV",{in_file,}, {{"Shared", "True"}}) + SetView(view) + vw_TAP = GetView() + view_set = vw_TAP +"|" + + for per = 1 to periodName.length do + for mat = 1 to matrixCore.length do + + + sellkmtx = outputDir+"\\trn_sellink"+matrixCore[mat]+periodName[per]+".mtx" + m = OpenMatrix(sellkmtx,) + + sg_orig_index = CreateMatrixIndex("Smart Growth Orig", m, "Row",view_set, "sg_tap", "sg_tap" ) + sg_dest_index = CreateMatrixIndex("Smart Growth Dest", m, "Column",view_set, "sg_tap", "sg_tap" ) + + mc = CreateMatrixCurrency(m, , , , ) + mc_sg_orig = CreateMatrixCurrency(m, ,"Smart Growth Orig","Columns", ) + mc_sg_dest = CreateMatrixCurrency(m, ,"Rows","Smart Growth Dest", ) + mc_sg_to_sg = CreateMatrixCurrency(m, ,"Smart Growth Orig","Smart Growth Dest", ) + + sum_row = GetMatrixMarginals(mc, "Sum", "row" ) + + sum_row_sg_orig = GetMatrixMarginals(mc_sg_orig, "Sum", "row" ) + sum_row_sg_dest = GetMatrixMarginals(mc_sg_dest, "Sum", "row" ) + sum_row_sg_to_sg = GetMatrixMarginals(mc_sg_to_sg, "Sum", "row" ) + + sum_all = sum_all + Sum(sum_row) + sum_sg = sum_sg + Sum(sum_row_sg_orig) + Sum(sum_row_sg_dest) - Sum(sum_row_sg_to_sg) + + DeleteMatrixIndex(m, "Smart Growth Orig") + DeleteMatrixIndex(m, "Smart Growth Dest") + + //close matrix + mc = null + m = null + + end + end + + if sum_all > 0 then pct_sg = sum_sg /sum_all + + out_file = path_study + "\\trn_sellink_sg.csv" + + dif2 = GetDirectoryInfo(out_file,"file") + if dif2.length <= 0 then do + fpr = OpenFile(out_file,"w") + WriteLine(fpr, "Scenario, Total select link trips, smart growth select link trips, % of sg trips") + end + else do + fpr = OpenFile(out_file,"a") + end + + WriteLine(fpr,path + "," + r2s(sum_all) + "," + r2s(sum_sg) + "," + r2s(pct_sg)) + CloseFile(fpr) + end + else ShowMessage("Missing smart growth tap file in " + path_study) + End + RunMacro("close all") + RunMacro("TCB Closing", ok, "False") + return(1) +EndMacro + +Macro "Sum Up Select Link Highway Trips" + + shared path_study, path, outputDir + RunMacro("TCB Init") + + outputDir = path+"\\output" + sellink_file = outputDir+"\\select_EA.mtx" + if GetFileInfo(sellink_file) <> null then do + + m = OpenMatrix(sellink_file,) + coreNames = GetMatrixCoreNames(m) + m=null + + //hard coded the occupancy rate, could be improved based on coreNames + occupancy = {1, 1, 2, 2, 2, 3.34, 3.34, 3.34, 1, 1, 1, 1, 1, 1} + + sum_all = 0 + sum_sg = 0 + pct_sg = 0 + sum_ind = 0 + pct_ind = 0 + + periodName = {"_EA","_AM","_MD","_PM","_EV"} + + //open smart growth TAZ CSV file + in_file = path_study + "\\sg_taz.csv" + in_file_indian = path_study + "\\indian_reservation_taz.csv" + + if GetFileInfo(in_file) <> null then do + view = OpenTable("SmartGrowthTAZ","CSV",{in_file,}, {{"Shared", "True"}}) + SetView(view) + vw_TAZ = GetView() + view_set = vw_TAZ +"|" + + view_ind = OpenTable("IndianReservationTAZ","CSV",{in_file_indian,}, {{"Shared", "True"}}) + SetView(view_ind) + vw_TAZ_ind = GetView() + view_set_ind = vw_TAZ_ind +"|" + + for per = 1 to periodName.length do + + sellkmtx = outputDir + "\\select" + periodName[per] +".mtx" + m = OpenMatrix(sellkmtx,) + + sg_index_orig = CreateMatrixIndex("SG Index Orig", m, "Row",view_set,"SG_TAZ" , "SG_TAZ" ) + sg_index_dest = CreateMatrixIndex("SG Index Dest", m, "Column",view_set,"SG_TAZ" , "SG_TAZ" ) + + ind_index_orig = CreateMatrixIndex("Indian Index Orig", m, "Row",view_set_ind,"Indian_TAZ" , "Indian_TAZ" ) + ind_index_dest = CreateMatrixIndex("Indian Index Dest", m, "Column",view_set_ind,"Indian_TAZ" , "Indian_TAZ" ) + + mc = CreateMatrixCurrencies(m, "Rows", "Columns", ) + mc_sg_orig = CreateMatrixCurrencies(m, "SG Index Orig","Columns",) + mc_sg_dest = CreateMatrixCurrencies(m, "Rows","SG Index Dest",) + mc_sg_to_sg = CreateMatrixCurrencies(m, "SG Index Orig","SG Index Dest",) + + mc_ind_orig = CreateMatrixCurrencies(m, "Indian Index Orig","Columns",) + mc_ind_dest = CreateMatrixCurrencies(m, "Rows","Indian Index Dest",) + mc_ind_to_ind = CreateMatrixCurrencies(m, "Indian Index Orig","Indian Index Dest",) + + // select link assignment trip matrix includes the total trips as the last core + for core = 1 to coreNames.length - 1 do + sum_row = GetMatrixMarginals(mc.(coreNames[core]), "Sum", "row" ) + + sum_row_sg_orig = GetMatrixMarginals(mc_sg_orig.(coreNames[core]), "Sum", "row" ) + sum_row_sg_dest = GetMatrixMarginals(mc_sg_dest.(coreNames[core]), "Sum", "row" ) + sum_row_sg_to_sg = GetMatrixMarginals(mc_sg_to_sg.(coreNames[core]), "Sum", "row" ) + + + sum_row_ind_orig = GetMatrixMarginals(mc_ind_orig.(coreNames[core]), "Sum", "row" ) + sum_row_ind_dest = GetMatrixMarginals(mc_ind_dest.(coreNames[core]), "Sum", "row" ) + sum_row_ind_to_ind = GetMatrixMarginals(mc_ind_to_ind.(coreNames[core]), "Sum", "row" ) + + sum_all = sum_all + Sum(sum_row) * occupancy[core] + sum_sg = sum_sg + (Sum(sum_row_sg_orig) + Sum(sum_row_sg_dest)) * occupancy[core] - Sum(sum_row_sg_to_sg) * occupancy[core] + sum_ind = sum_ind + (Sum(sum_row_ind_orig) + Sum(sum_row_ind_dest)) * occupancy[core] - Sum(sum_row_ind_to_ind) * occupancy[core] + + end + + //close matrix + DeleteMatrixIndex(m, "SG Index Orig") + DeleteMatrixIndex(m, "SG Index Dest") + DeleteMatrixIndex(m, "Indian Index Orig") + DeleteMatrixIndex(m, "Indian Index Dest") + mc = null + mc_sg = null + mc_ind = null + m = null + end + + if sum_all > 0 then do + pct_sg = sum_sg /sum_all + pct_ind = sum_ind/sum_all + end + + out_file = path_study + "\\hwy_sellink.csv" + + dif2 = GetDirectoryInfo(out_file,"file") + if dif2.length <= 0 then do + fpr = OpenFile(out_file,"w") + WriteLine(fpr, "Scenario, Total select link trips, smart growth select link trips, % of sg trips, indian reservation trips, % of indian reservation trips") + end + else do + fpr = OpenFile(out_file,"a") + end + + WriteLine(fpr,path + "," + r2s(sum_all) + "," + r2s(sum_sg) + "," + r2s(pct_sg) + "," + r2s(sum_ind) + "," + r2s(pct_ind)) + CloseFile(fpr) + + end + else ShowMessage("Missing smart growth TAZ file in " + path_study) + + end + RunMacro("close all") + RunMacro("TCB Closing", ok, "False") + return(1) + +EndMacro + diff --git a/sandag_abm/src/main/gisdk/sellink_volume.rsc b/sandag_abm/src/main/gisdk/sellink_volume.rsc new file mode 100644 index 0000000..dd462c3 --- /dev/null +++ b/sandag_abm/src/main/gisdk/sellink_volume.rsc @@ -0,0 +1,85 @@ +/* + Export daily select link volumes by direction + Need to figure out vary by # of query + author: Ziying Ouyang zou@sandag.org + date: 12/16/2015 +*/ +Macro "ExportHwyloadtoCSV Select Link" + + shared path, input_path, output_path + path="T:\\projects\\sr13\\version13_3_0\\abm_runs\\2012" + input_path = path+"\\input" + output_path = path+"\\output" + + query_list = RunMacro("Get SL Query # from QRY",input_path) + if query_list.length > 0 then do + + Dim v_ab_flow_slk[query_list.length], v_ba_flow_slk[query_list.length] + Dim v_ab_flow_slk_pk[2,query_list.length], v_ba_flow_slk_pk[2,query_list.length] + input_file = {"hwyload_EA.bin","hwyload_AM.bin","hwyload_MD.bin","hwyload_PM.bin","hwyload_EV.bin"} + + fields = {"ID1"} + for j = 1 to query_list.length do + fields = fields + {"AB_Flow_" + query_list[j]} + fields = fields + {"BA_Flow_" + query_list[j]} + end + + for i = 1 to input_file.length do + view = OpenTable("Binary Table","FFB",{output_path+"\\"+input_file[i],}, {{"Shared", "True"}}) + SetView(view) + v_lodselk = GetDataVectors(view+"|", fields, ) + for j = 1 to query_list.length do + v_ab_flow_slk[j] = Nz(v_ab_flow_slk[j]) + v_lodselk[2*(j-1)+2] + v_ba_flow_slk[j] = Nz(v_ba_flow_slk[j]) + v_lodselk[2*(j-1)+3] + end + if i = 2 or i = 4 then do //save AM/PM select link ab/ba volumes (AM 1, PM 2) + for j = 1 to query_list.length do + v_ab_flow_slk_pk[i/2][j] = v_lodselk[2*(j-1)+2] + v_ba_flow_slk_pk[i/2][j] = v_lodselk[2*(j-1)+3] + end + end + + end + + header = "ID1" + for j = 1 to query_list.length do + header = header + "," + "AB_Flow_" + query_list[j] + "," + "BA_Flow_" + query_list[j] + "," + "Tot_Flow_" + query_list[j] + end + + f = OpenFile(output_path+ "\\"+"loadselk.csv","w") + WriteLine(f,header) + + for i = 1 to v_lodselk[1].length do + line = i2s(v_lodselk[1][i]) + for j = 1 to query_list.length do + line = line + "," + r2s(v_ab_flow_slk[j][i]) + "," + r2s(Nz(v_ba_flow_slk[j][i])) + "," + r2s(v_ab_flow_slk[j][i]+Nz(v_ba_flow_slk[j][i])) + end + WriteLine(f,line) + end + + closeFile(f) + //Peak Period Select Link Volumes + header = "ID1" + for j = 1 to query_list.length do + header = header + "," + "AB_Flow_AM_" + query_list[j] + "," + "BA_Flow_AM_" + query_list[j] + "," + "Tot_Flow_AM_" + query_list[j] + "," + "AB_Flow_PM_" + query_list[j] + "," + "BA_Flow_PM_" + query_list[j] + "," + "Tot_Flow_PM_" + query_list[j] + end + + f = OpenFile(output_path+ "\\"+"loadselkpk.csv","w") + WriteLine(f,header) + + for i = 1 to v_lodselk[1].length do + line = i2s(v_lodselk[1][i]) + for j = 1 to query_list.length do + line = line + "," + r2s(v_ab_flow_slk_pk[1][j][i]) + "," + r2s(Nz(v_ba_flow_slk_pk[1][j][i])) + "," + r2s(v_ab_flow_slk_pk[1][j][i]+Nz(v_ba_flow_slk_pk[1][j][i])) + line = line + "," + r2s(v_ab_flow_slk_pk[2][j][i]) + "," + r2s(Nz(v_ba_flow_slk_pk[2][j][i])) + "," + r2s(v_ab_flow_slk_pk[2][j][i]+Nz(v_ba_flow_slk_pk[2][j][i])) + end + WriteLine(f,line) + end + + CloseFile(f) + end + + else ShowMessage("Number of select links is 0") + RunMacro("close all") + +EndMacro diff --git a/sandag_abm/src/main/gisdk/trnassign.rsc b/sandag_abm/src/main/gisdk/trnassign.rsc new file mode 100644 index 0000000..e61c1e7 --- /dev/null +++ b/sandag_abm/src/main/gisdk/trnassign.rsc @@ -0,0 +1,177 @@ +/********************************************************************************* +Transit Assignment + + input files: transitrt.rts + CT-RAMP trip tables ("tranTrips_period.mtx", where period = EA, AM, MD, PM, and NT) + each file has 15 cores, named as follows: ACC_LHM_PER + where: + ACC = access mode - WLK,PNR,KNR + LHM = line-haul mode - LOC,EXP,BRT,LRT,CMR + PER = period - EA, AM, MD, PM, NT + Transit networks (localpk.tnw,localop,tnw,prempk.tnw,premop.tnw) + Transit route file (transitrt.rts) + output files: + 75 flow bin file (3 access modes * 5 line-haul modes * 5 time periods) + 75 walk bin file + 75 onoff bin file + 75 collapsed onoff files in both binary and csv format + +*********************************************************************************/ + +Macro "Assign Transit" (args) + + + shared path,inputDir, outputDir, mxtap + +iteration = args[1] +rt_file=outputDir + "\\transitrt.rts" + +periodName = {"_EA", "_AM", "_MD", "_PM", "_EV"} + +matrixCore = { + "WLK_LOC", + "WLK_EXP", + "WLK_BRT", + "WLK_LRT", + "WLK_CMR", + "PNR_LOC", + "PNR_EXP", + "PNR_BRT", + "PNR_LRT", + "PNR_CMR", + "KNR_LOC", + "KNR_EXP", + "KNR_BRT", + "KNR_LRT", + "KNR_CMR" } + + network={"locl","prem","prem","prem","prem","locl","prem","prem","prem","prem","locl","prem","prem","prem","prem"} + dim onOffTables[matrixCore.length * periodName.length] + + selinkqry = inputDir + "\\"+"sellink_transit.qry" + if GetFileInfo(selinkqry) <> null then sellink_flag = 1 //select link analysis is only for last iteration (4) + + i = 0 + k = 1 + for per = 1 to periodName.length do + for mat = 1 to matrixCore.length do + + i = i + 1 + + networkFile = outputDir+"\\"+network[mat]+periodName[per]+".tnw" + matrixFile = outputDir+"\\tranTotalTrips"+periodName[per]+".mtx" + matrixName = matrixCore[mat] + flowFile = outputDir+"\\flow"+matrixCore[mat]+periodName[per]+".bin" + walkFile = outputDir+"\\ntl"+matrixCore[mat]+periodName[per]+".bin" + onOffFile = outputDir+"\\ono"+matrixCore[mat]+periodName[per]+".bin" + aggFile = outputDir+"\\agg"+matrixCore[mat]+periodName[per]+".bin" + + onOffTables[k] = onOffFile + k = k +1 + + if sellink_flag = 1 & iteration = 4 then sellkmtx = outputDir+"\\trn_sellink"+matrixCore[mat]+periodName[per]+".mtx" + + + // STEP 1: Transit Assignment + Opts = null + Opts.Input.[Transit RS] = rt_file + Opts.Input.Network = networkFile + Opts.Input.[OD Matrix Currency] = {matrixFile,matrixName,,} + + Opts.Output.[Flow Table] = flowFile + Opts.Output.[Walk Flow Table] = walkFile + Opts.Output.[OnOff Table] = onOffFile + Opts.Output.[Aggre Table] = aggFile + Opts.Flag.[Do Maximum Fare] = 1 //added for 4.8 build 401 + if sellink_flag = 1 & iteration = 4 then do + Opts.Flag.critFlag = 1 + Opts.Global.[Critical Query File] = selinkqry + Opts.Output.[Critical Matrix].Label = "Critical Matrix" + Opts.Output.[Critical Matrix].[File Name] = sellkmtx + end + RunMacro("HwycadLog",{"trassigns.rsc: transit assigns","Transit Assignment PF: "+matrixCore[mat]+periodName[per]}) + ok = RunMacro("TCB Run Procedure", (per*100+mat), "Transit Assignment PF", Opts) + + if !ok then goto quit + + end + end + + properties = "\\conf\\sandag_abm.properties" + collapseOnOffByRoute = RunMacro("read properties",properties,"RunModel.collapseOnOffByRoute", "S") + if collapseOnOffByRoute = "true" then do + ok = RunMacro("Collapse OnOffs By Route", onOffTables, rt_file) + if !ok then goto quit + end + + quit: + RunMacro("close all") + Return( ok ) + +EndMacro +/************************************************************* +* +* A macro that will collapse transit on-offs by route and append +* route name. +* +* Arguments +* onOffTables An array of on-off tables +* rtsfile A transit route file +* +*************************************************************/ +Macro "Collapse OnOffs By Route" (onOffTables,rtsfile) + + {rte_lyr,stp_lyr,} = RunMacro("TCB Add RS Layers", rtsfile, "ALL", ) + + fields = { + {"On","Sum",}, + {"Off","Sum",}, + {"DriveAccessOn","Sum",}, + {"WalkAccessOn","Sum",}, + {"DirectTransferOn","Sum",}, + {"WalkTransferOn","Sum",}, + {"DirectTransferOff","Sum",}, + {"WalkTransferOff","Sum",}, + {"EgressOff","Sum",} + } + + // for all on off tables + for i = 1 to onOffTables.length do + + onOffView = OpenTable("OnOffTable", "FFB", {onOffTables[i], null}) + path = SplitPath(onOffTables[i]) + outFile = path[1]+path[2]+path[3]+"_COLL.bin" + + fields = GetFields(onOffView, "All") + + //include all fields in each table except for STOP and ROUTE + collFields = null + for j = 1 to fields[1].length do + + if(fields[1][j] !="STOP" and fields[1][j]!= "ROUTE") then do + + collFields = collFields + {{fields[1][j],"Sum",}} + + end + end + + // Collapse stops out of the table by collapsing on ROUTE + rslt = AggregateTable("CollapsedView", onOffView+"|", "FFB", outFile, "ROUTE", collFields, ) + + CloseView(onOffView) + + // Join the route layer for route name and other potentially useful data + onOffCollView = OpenTable("OnOffTableColl", "FFB", {outFile}) + joinedView = JoinViews("OnOffJoin", onOffCollView+".Route", rte_lyr+".Route_ID",) + + // Write the joined data to a binary file + outJoinFile = path[1]+path[2]+path[3]+"_COLL_JOIN.bin" + ExportView(joinedView+"|","FFB", outJoinFile , , ) + outJoinFile = path[1]+path[2]+path[3]+"_COLL_JOIN.csv" + ExportView(joinedView+"|","CSV", outJoinFile , , ) + end + + Return(1) + quit: + Return( RunMacro("TCB Closing", ret_value, True ) ) +EndMacro diff --git a/sandag_abm/src/main/gisdk/trnskim.rsc b/sandag_abm/src/main/gisdk/trnskim.rsc new file mode 100644 index 0000000..4313570 --- /dev/null +++ b/sandag_abm/src/main/gisdk/trnskim.rsc @@ -0,0 +1,1038 @@ +/******************************************************************************** +transit skim matrix to create skim matrix files + skim values includes fare, in vehicle time, initial wait time, + transfer wait time, tranfer walk time, access time, egress time + dwell time, transfer penalty, # of transfers + *TMO, or *TMP (depends on which time period) +for premium service skim *TMO, or *TMP by mode, additional cores were created +input files: transit.dbd - transit line layer + transitrt.rts - transit route layer + localop.tnw - local bus off peak transit network + localpk.tnw - local bus peak transit network + premop.tnw - premium bus service off peak transit network + prempk.tnw - premium bus service peak transit network + modenu.dbf - dbf file for mode table + fare.mtx - fare matrix for zonal fares for lightrail and coaster + +output files: + implbopx2.mtx - skim matrix file for local bus off peak service + implbpkx2.mtx - skim matrix file for local bus peak service + imppropx2.mtx - skim matrix file for premium bus off peak service + impprpkx2.mtx - skim matrix file for premium bus peak service + implr.mtx - skim ltrzone + impcr.mtx - skim crzone +history + 10/8/03 zou to change the fare system to flat fare and skim + rail link fields separately. + 9/3/04 retain the commuter rail from the light rail category + 1/25/05 rewrite the script using moduels + 4/14/09 ZOU changed it to 3tod +********************************************************************************/ +Macro "Create transit network" + + shared path,inputDir, outputDir, mxtap + ok=RunMacro("Create transit networks") + if !ok then goto quit + Return(1) + + quit: + Return(0) +EndMacro + +/*********************************************************************************** +*******************************************************************/ + +Macro "Build transit skims" + + shared path,inputDir, outputDir, mxtap + + ok = RunMacro("Update transit time fields") + if !ok then goto quit + + /* + ok=RunMacro("Create rail net") + if !ok then goto quit + */ + ok=RunMacro("Create transit networks") + if !ok then goto quit + + ok = RunMacro("Skim transit networks") + if !ok then goto quit + + /* + ok= RunMacro("zero null ivt time") + if !ok then goto quit +*/ + ok= RunMacro("Process transit skims") + if !ok then goto quit + + Return(1) + + quit: + Return(0) +EndMacro +/*********************************************************************************** + + +Inputs: + input\mode5tod.dbf Mode table + output\transit.dbd Transit line layer + output\xxxx_yy.tnw Transit networks + + where xxxxx is transit mode (locl or prem) and yy is period (EA, AM, MD, PM, EV) + +Outputs: + impxxxx_yy.mtx Transit skims + + where xxxxx is transit mode (locl or prem) and yy is period (EA, AM, MD, PM, EV) + +***********************************************************************************/ +Macro "Skim transit networks" + + shared path,inputDir, outputDir, mxtap + NumofCPU=2 + + mode_tb = inputDir+"\\mode5tod.dbf" + // xfer_tb = path+"\\modexfer.dbf" + db_file = outputDir + "\\transit.dbd" + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + + db_node_lyr = db_file + "|" + node_lyr + + periods = {"_EA","_AM","_MD","_PM","_EV"} + modes = {"prem","locl"} + + //varies by modes + skmodes={{4,5,6,7,8,9,10},} + skvar={{"Fare", "Initial Wait Time", "Transfer Wait Time", "Transfer Walk Time", "Access Walk Time","Egress Walk Time","Dwelling Time", "Number of Transfers"}, + {"Fare", "In-Vehicle Time", "Initial Wait Time", "Transfer Wait Time", "Transfer Walk Time","Access Walk Time","Egress Walk Time", "Dwelling Time", "Number of Transfers"}} + + // not sure what the PRE and LOC time are yet + skvars={skvar[1]+{"Length","*TM"},skvar[2]} + + + for i = 1 to periods.length do + for j = 1 to modes.length do + Opts = null + // Opts.Global.[Force Threads] = NumofCPU + Opts.Input.Database = db_file + Opts.Input.Network = outputDir+"\\"+modes[j]+periods[i]+".tnw" + Opts.Input.[Origin Set] = {db_node_lyr, node_lyr, "Selection", "Select * where id <"+i2s(mxtap)} + Opts.Input.[Destination Set] = {db_node_lyr, node_lyr, "Selection"} + Opts.Input.[Mode Table] = {mode_tb} + // Opts.Input.[Mode Xfer Table] = {xfer_tb} + Opts.Global.[Skim Var] = skvars[j] + Opts.Global.[OD Layer Type] = 2 + if skmodes<> null then Opts.Global.[Skim Modes] = skmodes[j] + Opts.Flag.[Do Skimming] = 1 + Opts.Flag.[Do Maximum Fare] = 1 //added for 4.8 build 401 + Opts.Output.[Skim Matrix].Label = "Skim Matrix ("+modes[j]+periods[i]+")" + Opts.Output.[Skim Matrix].Compression = 0 //uncompressed + Opts.Output.[Skim Matrix].[File Name] = outputDir+"\\imp"+modes[j]+periods[i]+".mtx" + // Opts.Output.[TPS Table] = outputDir+"\\"+modes[j]+periods[i]+".tps" + ok = RunMacro("TCB Run Procedure", i, "Transit Skim PF", Opts) + + if !ok then goto quit + end + end + + ok=1 + quit: + RunMacro("close all") + Return(ok) +EndMacro +/*********************************************************************************** + + +Inputs: + input\mode5tod.dbf + output\transit.dbd + +***********************************************************************************/ +Macro "Special transit skims" (arr) + + shared path,inputDir, outputDir, mxtap + + skimvar=arr[1] + + mode_tb = inputDir+"\\mode5tod.dbf" + // xfer_tb = path+"\\modexfer.dbf" + db_file = outputDir + "\\transit.dbd" + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + + db_node_lyr = db_file + "|" + node_lyr + + fpr=openfile(path+"\\hwycad.log","a") + mytime=GetDateAndTime() + writeline(fpr,mytime+", skim trnets") + + if skimvar="rail" then do //skim lrtzone and crzone to get the trolley and coaster fares + skvars={{"lrtzone"},{"Crzone"}} + trskimmtxs={"implr.mtx","impcr.mtx"} + trnets={"lr.tnw","cr.tnw"} + mtxdes={"Skim Matrix (light Rail)","Skim Matrix (coaster)"} + end + else if skimvar="fwylen" then do //skim length and fwylen + skvars={{"length","fwylen"},{"length","fwylen"}} + trskimmtxs={"imppropdst2.mtx","impprpkdst2.mtx"} + trnets={"prem_MD.tnw","prem_AM.tnw"} + mtxdes={"Length (Shortest OP Premium Path)","Length (Shortest PK Premium Path)"} + end + + for i = 1 to trnets.length do + Opts = null + Opts.Global.[Force Threads] = NumofCPU + Opts.Input.Database = db_file + Opts.Input.Network = path+"\\"+trnets[i] + Opts.Input.[Origin Set] = {db_node_lyr, node_lyr, "Selection", "Select * where id <"+i2s(mxtap)} + Opts.Input.[Destination Set] = {db_node_lyr, node_lyr, "Selection"} + Opts.Input.[Mode Table] = {mode_tb} + // Opts.Input.[Mode Xfer Table] = {xfer_tb} + Opts.Global.[Skim Var] = skvars[i] + Opts.Global.[OD Layer Type] = 2 + if skmodes<> null then Opts.Global.[Skim Modes] = skmodes[i] + Opts.Flag.[Do Skimming] = 1 + Opts.Flag.[Do Maximum Fare] = 1 //added for 4.8 build 401 + Opts.Output.[Skim Matrix].Label = mtxdes[i] + Opts.Output.[Skim Matrix].Compression = 0 //uncompressed + Opts.Output.[Skim Matrix].[File Name] = path+"\\"+trskimmtxs[i] + ok = RunMacro("TCB Run Procedure", i, "Transit Skim PF", Opts) + // ok = RunMacro("TCB Run Procedure", i, "Transit Skim Max Fare", Opts)//using maximized fare + + if !ok then goto quit + end + + ok=1 + quit: + RunMacro("close all") + Return(ok) +EndMacro + +/*************************************************************************************************************************** +This macro puts zeros in the null cells for unprocessed transit skims: premium and local modes +3/19/2015 Wu modified to zero out all ivts +****************************************************************************************************************************/ +Macro "zero null ivt time" + + shared path, outputDir + periods = {"_EA","_AM","_MD","_PM","_EV"} + + for i=1 to periods.length do + + //open matrix + fileNameSkimP = outputDir + "\\impprem"+periods[i]+".mtx" + mp = OpenMatrix(fileNameSkimP,) + currsp= CreateMatrixCurrencies(mp, , , ) + currsp.("*TM (Local)"):=Nz(currsp.("*TM (Local)")) + currsp.("*TM (Commuter Rail)"):=Nz(currsp.("*TM (Commuter Rail)")) + currsp.("*TM (Light Rail)"):=Nz(currsp.("*TM (Light Rail)")) + currsp.("*TM (Regional BRT (Yello)"):=Nz(currsp.("*TM (Regional BRT (Yello)")) + currsp.("*TM (Regional BRT (Red))"):=Nz(currsp.("*TM (Regional BRT (Red))")) + currsp.("*TM (Limited Express)"):=Nz(currsp.("*TM (Limited Express)")) + currsp.("*TM (Express)"):=Nz(currsp.("*TM (Express)")) + + fileNameSkimL = outputDir + "\\implocl"+periods[i]+".mtx" + ml = OpenMatrix(fileNameSkimL,) + currsl= CreateMatrixCurrencies(ml, , , ) + currsl.("In-Vehicle Time"):=Nz(currsl.("In-Vehicle Time")) + end + quit: + Return(1) +EndMacro + +/*********************************************************************************************************************************** + Extract Main Mode from Transit Skims + + This macro: +------------ + 1- extracts the main mode from transit skims + 2- writes main mode as a core to output transit matrix + + Inputs: +---------- + + output\impxxxx_yy.mtx + + where: + xxxx is mode (locl or prem) + yy is time period (EA, AM, MD, PM, NT) + + + Outputs: + + + output\impxxxx_yyo.mtx + + where: + xxxx is mode (locl or prem) + yy is time period (EA, AM, MD, PM, NT) + + + Input transit modes: +---------------------- + CR, LR, BRT Yellow, BRT Red, Limited EXP, EXP, LB + + Output transit modes: +----------------------- + 1-CR Mode choice code 4 + 2-LR Mode choice code 5 + 3-BRT (BRT Yellow+BRT Red) Mode choice code 6 + 4-EXP (EXP+Limited EXP) Mode choice code 7 + 5-LB Mode choice code 8 + + Input-output Matrix cores correspondence table: +------------------------------------------------- + 1) Premium input-output + Input Output + Fare(1) Fare(1) + Initial Wait Time(2) Initial Wait Time(2) + Transfer Wait Time(3) Transfer Wait Time(3) + Transfer Walk Time(4)+Access Walk Time(5)+Egress Walk Time(6) Walk Time(4) + Dwelling time(7) ------ + Number of Transfers(8) Number of Transfers(5) + Length:CR(9) Length:CR(6) + Length:LR(10) Length:LR(7) + Length:BRT Yellow(11)+BRT Red(12) Length:BRT(8) + Length:Limited EXP(13)+EXP(14) Length:EXP(9) + Length:LB(15) Length:LB(10) + IVT:CR(16) IVT:CR(11) + IVT:LR(17) IVT:LR(12) + IVT:BRT Yellow(18)+BRT Red(19) IVT:BRT(13) + IVT:Limited EXP(20)+EXP(21) IVT:EXP(14) + IVT:LB(22) IVT:LB(15) + --- IVT:Sum(16) + --- IVT:Main Mode(17) + + 2) Local input-output + Input Output + Fare(1) Fare(1) + In-Vehicle Time(2)+Dwelling Time(8) Total IV Time(2) + Initial Wait Time(3) Initial Wait Time(3) + Transfer Wait Time(4) Transfer Wait Time(4) + Transfer Walk Time(5)+Access Walk Time(6)+Egress Walk Time(7) Walk Time(5) + Number of Transfers(9) Number of Transfers(6) + + Author: Wu Sun + wsu@sandag.org, SANDAG + 05/25/09 ver2, + modified 4/16/2012 jef - for AB model + + +***********************************************************************************************************************************/ +Macro "Process transit skims" + shared path,inputDir, outputDir + + periods = {"_EA","_AM","_MD","_PM","_EV"} + modes = {"prem","locl"} + + //output core names, by mode + outMatrixCores={{"Fare","Initial Wait Time","Transfer Wait Time","Walk Time", "Number of Transfers", "Length:CR", + "Length:LR","Length:BRT","Length:EXP","Length:LB","IVT:CR","IVT:LR","IVT:BRT","IVT:EXP","IVT:LB","IVT:Sum","Main Mode"}, + {"Fare","Total IV Time","Initial Wait Time","Transfer Wait Time","Walk Time", "Number of Transfers"}} + + //input output matrix core lookup table, by mode + //Note: if index is set to -1, it represents an aggregation + inOutCoreLookUp={{1,2,3,-1,8,9,10,-1,-1,15,16,17,-1,-1,22}, + {1,-1,3,4,-1,9}} + + //skim aggretation lookup table, by mode + //Note: items match up with those in inOutCoreLookUp array where index is set to -1 + aggLookUp={ {{4,5,6},{11,12},{13,14},{18,19},{20,21}}, + {{2,8},{5,6,7}}} + + //dwelling time core index, by mode + // Note: set to -1 if no dwelling time allocation + dwlTimeIndex={7, -1} + + //dwelling time allocation line-haul modes (line-haul modes that ivt times need to be adjusted using dwelling time), by mode + // Note 1: rail modes are not included because they already include station dwell time. + // Note 2: Set to -1 if no dwelling time allocation + dwlAlloModes={{13,14,15}, -1} + + //ivt core start index, by mode + ivtStartIndex={11,2} + + //number of line-haul modes in output matrices, by mode + numOutModes={5,1} + + //calculate indices, including ivt sum index, main mode index, and ivt end idnex + dim ivtSumIndex[modes.length] + dim ivtEndIndex[modes.length] + for i=1 to modes.length do + ivtSumIndex[i]=outMatrixCores[i].length-1 + ivtEndIndex[i]=ivtStartIndex[i]+numOutModes[i]-1 + end + + //evaluation expression for coding main mode, by mode + //Note: if no main mode coding is necessary, leave null + expr={{"if(([IVT:LB]/ [IVT:Sum]) >0.5) then 8 else if [IVT:Sum]=null then 0 else if ([IVT:EXP]> [IVT:CR] & [IVT:EXP]> [IVT:LR] & [IVT:EXP]> [IVT:BRT] & [IVT:EXP]> [IVT:LB]) then 7 else if ([IVT:BRT]> [IVT:CR] & [IVT:BRT]> [IVT:LR] ) then 6", + "if ([Main Mode]=null & [IVT:LR]> [IVT:CR]) then 5 else if([Main Mode]=null) then 4 else [Main Mode]"},} + + + //-------------------------------------------------- + //This section aggregates matrices, allocates dwell time, and extracts main mode + //-------------------------------------------------- + + for i=1 to modes.length do + for j=1 to periods.length do + + //set input matrix currencies + inputFile = "imp"+modes[i]+periods[j]+".mtx" + inMatrixCurrency=RunMacro("set input matrix currencies",outputDir,inputFile) + + //set up output matrix currencies, empty at this point + outputFile = "imp"+modes[i]+periods[j]+"o.mtx" + matrixLabel = modes[i]+" "+periods[j] + outMatrixCurrency=RunMacro("set output matrix currencies",outputDir,inMatrixCurrency[1],outputFile,outMatrixCores[i],matrixLabel) + + //populate output matrix currencies except 'ivt sum' and 'main mode' cores + outMatrixCurrency=RunMacro("transit aggregate skims",inMatrixCurrency,outMatrixCurrency,inOutCoreLookUp[i],aggLookUp[i]) + + //populate 'main mode' core in output matrix + if expr[i]<>null then do + outMatrixCurrency=RunMacro("set main mode",inMatrixCurrency,outMatrixCurrency,dwlTimeIndex[i],ivtStartIndex[i],ivtEndIndex[i],ivtSumIndex[i],dwlAlloModes[i],expr[i]) + end + + end + end + + Return(1) +EndMacro + +/******************************************************************************************************************************** +set input matrix currencies + +Create and return an array of matrix currencies for the specified file in the specified directory + +*********************************************************************************************************************************/ +Macro "set input matrix currencies" (dir, trnInSkim) + //inputs, keyed to scenarioDirectory + inskim=dir+"\\"+trnInSkim + + //open input transit matrices + inMatrix = OpenMatrix(inskim, "True") + inMatrixCores = GetMatrixCoreNames(inMatrix) + numCoresIn=inMatrixCores.length + matrixInfo=GetMatrixInfo(inMatrix) + + //create inMatrix currencies + dim inMatrixCurrency[numCoresIn] + for i = 1 to numCoresIn do + inMatrixCurrency[i] = CreateMatrixCurrency(inMatrix, inMatrixCores[i], null, null, ) + end + + Return(inMatrixCurrency) +EndMacro + +/******************************************************************************************************************************** +set output matrix currencies + +Create a matrix file and return an array of matrix currencies for the file + +*********************************************************************************************************************************/ + +Macro "set output matrix currencies" (dir, inMatrixCurrency, trnOutSkim, outMatrixCores, label) + //outputs, keyed to scenarioDirectory + outskim=dir+"\\"+trnOutSkim + + //outMatrix core length + numCoresOut=outMatrixCores.length + + //outMatirx structure + dim outMatrixStructure[numCoresOut] + for i=1 to numCoresOut do + outMatrixStructure[i]=inMatrixCurrency + end + + //Create the output transit matrix (with main mode core) + Opts = null + Opts.[Compression] = 1 + Opts.[Tables] = outMatrixCores + Opts.[Type] = "Float" + Opts.[File Name] =outskim + Opts.[Label] = label + outMatrix = CopyMatrixStructure(outMatrixStructure,Opts) + + //create outMatrix currencies + dim outMatrixCurrency[numCoresOut] + for i=1 to numCoresOut do + outMatrixCurrency[i] = CreateMatrixCurrency(outMatrix, outMatrixCores[i], null, null, ) + outMatrixCurrency[i]:=0.0 + end + + //return outMatrixCurrency + return(outMatrixCurrency) +EndMacro + +/******************************************************************************************************************************** +transit aggregate skims + +Aggregate matrix currrencies in the input file and store the results in the output file + +*********************************************************************************************************************************/ + +Macro "transit aggregate skims"(inMatrixCurrency,outMatrixCurrency,inOutCoreLookUp,aggLookUp) + //populate all outMatrix cores except the last 2, using input-output core lookup table and aggregation lookup table + aggCounter=0 + for i = 1 to inOutCoreLookUp.length do + outMatrixCurrency[i]:=0.0 + lookupIndex=inOutCoreLookUp[i] + if lookupIndex=-1 then do + aggCounter=aggCounter+1 + aggIndices=aggLookUp[aggCounter] + for j=1 to aggIndices.length do + //name = inMatrixCurrency[aggIndices[j]].Core + //expr = "if ["+ name + "] = null then 0.0 else [" + name +"]" + //EvaluateMatrixExpression(inMatrixCurrency[aggIndices[j]], expr, , , ) + outMatrixCurrency[i]:=outMatrixCurrency[i]+Nz(inMatrixCurrency[aggIndices[j]]) + end + end + else do + outMatrixCurrency[i]:=Nz(inMatrixCurrency[lookupIndex]) + end + end + + return(outMatrixCurrency) +EndMacro + +/******************************************************************************************************************************** +set main mode + +Set the main mode in the file based upon the expression + +*********************************************************************************************************************************/ + +Macro "set main mode"(inMatrixCurrency,outMatrixCurrency,dwlTimeIndex,ivtStartIndex,ivtEndIndex,ivtSumIndex,dam,expr) + + //initialize outMatrixCurrency[ivtSumIndex], use as a temporary currency for storing sum values + outMatrixCurrency[ivtSumIndex]:=0.0 + + //sum ivt of dwelling allocation modes + for i=1 to dam.length do + outMatrixCurrency[ivtSumIndex]:=outMatrixCurrency[ivtSumIndex]+outMatrixCurrency[dam[i]] + end + + //allocate dwelling time + for i=1 to dam.length do + outMatrixCurrency[dam[i]]:=outMatrixCurrency[dam[i]]*(1.0+inMatrixCurrency[dwlTimeIndex]/outMatrixCurrency[ivtSumIndex]) + end + + //zero out outMatrixCurrency[ivtSumIndex] + outMatrixCurrency[ivtSumIndex]:=0.0 + + //set total ivt time to outMatrix + for i=ivtStartIndex to ivtEndIndex do + outMatrixCurrency[ivtSumIndex]:=outMatrixCurrency[ivtSumIndex]+Nz(outMatrixCurrency[i]) + end + + //set main mode to outMatrix using an expression + for i=1 to expr.length do + EvaluateMatrixExpression(outMatrixCurrency[outMatrixCurrency.length], expr[i],,, ) + end + + return(outMatrixCurrency) +EndMacro +/********************************************************************************* + +Update transit time fields + +This macro updates transit time fields with MSA times from flow tables + +The following fields are updated: + +xxField_yy where + +Field is TM + +xx is AB or BA +yy is period + EA: Early AM + AM: AM peak + MD: Midday + PM: PM peak + EV: Evening + + TODO: Update times for transit based on postload code pasted below + +*********************************************************************************/ +Macro "Update transit time fields" + + shared path, inputDir, outputDir + + periods = {"_EA","_AM","_MD","_PM","_EV"} + + // input files + db_file = outputDir + "\\transit.dbd" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file) + SetLayer(link_lyr) + vw = GetView() + + /* + if(shoulder) then !adjust times for freeway shoulder operation + xxspd=xlen*60.0/xtime + if(xxspd.lt.35.0) xtime=xlen*(60.0/35.0) + endif + tranlt(ipk,idir)=xtime + brtlt(ipk,idir)=xtime + + adjust time for priority treatment + if(aatfc(1).gt.1.and.aatfc(1).lt.8.and.artxlkid(aatid).and. + * myear.eq.2030) then !adjust times for priority treatment + xtime=xtime*0.90 + + if(aatcnt(idir,1).eq.5) then + hovlt(ipk,idir)=hovlt(ipk,idir)*hovfac(ipk) !hovfac = 0.33 for peak, 1 for off-peak + tranlt(ipk,idir)=tranlt(ipk,idir)*hovfac(ipk) + brtlt(ipk,idir)=brtlt(ipk,idir)*hovfac(ipk) + + */ + + //Recompute generalized cost using MSA cost in flow table, for links with MSA cost (so that transit only links aren't overwritten with null) + for i = 1 to periods.length do + flowTable = outputDir+"\\hwyload"+periods[i]+".bin" + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"AB time"+periods[i] } + Opts.Global.Fields = {"ABTM"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"if AB_MSA_Cost<>null then AB_MSA_Cost else ABTM"+periods[i] } + ok = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ok then goto quit + + // The Dataview Set is a joined view of the link layer and the flow table, based on link ID + Opts.Input.[Dataview Set] = {{db_file+"|"+link_lyr, flowTable, {"ID"}, {"ID1"}},"BA time"+periods[i]} + Opts.Global.Fields = {"BATM"+periods[i]} // the field to fill + Opts.Global.Method = "Formula" // the fill method + Opts.Global.Parameter = {"if BA_MSA_Cost<>null then BA_MSA_Cost else BATM"+periods[i] } + ok = RunMacro("TCB Run Operation", "Fill Dataview", Opts, &Ret) + if !ok then goto quit + + end + + ok=1 + quit: + RunMacro("close all") + return(ok) + +EndMacro + +/*************************************************************************************** +Create rail net + +This script creates two rail networks; one for commuter rail and one for light-rail. The +networks are used to create light rail zonal fare matrix by skimming light rail stops for LR network. + +to create lrzone skim matrix replaced the value of lrzone by light rail fares + +Inputs: + input\modenu061.dbf Mode table + output\transit.dbd Transit line layer + output\transitrt.rts Transit route system + +Outputs: + output\cr.tnw Commuter rail transit network + output\lr.tnw Light rail transit network + +3/16/05 zou c +***************************************************************************************/ +Macro "Create rail net" + + shared path,mxtap, inputDir, outputDir + + db_file=outputDir+"\\transit.dbd" + rte_file=outputDir+"\\transitrt.rts" + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file,,) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + + db_link_lyr=db_file+"|"+link_lyr + db_node_lyr=db_file+"|"+node_lyr + rte_lyr = RunMacro("TCB Add RS Layers", rte_file, , ) + + stp_lyr = GetStopsLayerFromRS(rte_lyr) + db_rte_lyr = rte_file + "|" + rte_lyr + db_stp_lyr = rte_file + "|" + stp_lyr + + //route selection set names + sets = {"crpk","lrpk"} + + //selection query strings + //rcu - changed query to drop routes 399 and 599 12/27/06 + // todo: fix this + query_strs={"select * where am_headway >0 and route_name <> '399103' and route_name <> '399203' and route_name <> '599101' and route_name <> '599201'", + "select * where am_headway >0 and route_name <> '399103' and route_name <> '399203' and route_name <> '599101' and route_name <> '599201'"} + trnets = {"cr.tnw","lr.tnw"} + + // Build 4(2?) Transit Networks + for i = 1 to trnets.length do + Opts = null + Opts.Input.[Transit RS] = rte_file + Opts.Input.[RS Set] = {db_rte_lyr, rte_lyr,sets[i],query_strs[i]} + Opts.Input.[Walk Link Set] = {db_link_lyr, link_lyr, "walklink", "Select * where MINMODE<4"} + Opts.Input.[Stop Set] = {db_stp_lyr, stp_lyr} + Opts.Global.[Network Options].[Route Attributes].mode = {rte_lyr+".mode"} + Opts.Global.[Network Options].[Route Attributes].AM_HEADWAY = {rte_lyr+".AM_HEADWAY"} + Opts.Global.[Network Options].[Route Attributes].OP_HEADWAY = {rte_lyr+".OP_HEADWAY"} + Opts.Global.[Network Options].[Route Attributes].FARE = {rte_lyr+".FARE"} + Opts.Global.[Network Options].[Street Attributes].Length = {link_lyr+".Length",link_lyr+".Length"} + Opts.Global.[Network Options].[Street Attributes].[*TM_MD] = {link_lyr+".ABTM_MD", link_lyr+".BATM_MD"} + Opts.Global.[Network Options].[Street Attributes].[*TM_AM] = {link_lyr+".ABTM_AM", link_lyr+".BATM_AM"} + Opts.Global.[Network Options].[Street Attributes].LRTZONE = {link_lyr+".LRTZONE", link_lyr+".LRTZONE"} + Opts.Global.[Network Options].[Street Attributes].CRZONE = {link_lyr+".CRZONE", link_lyr+".CRZONE"} + Opts.Global.[Network Options].Walk = "Yes" + Opts.Global.[Network Options].Overide = {stp_lyr+".ID", stp_lyr+".nearnode"} + Opts.Global.[Network Options].[Link Attributes] = + {{"Length", {link_lyr+".Length",link_lyr+".Length"}, "SUMFRAC"}, + {"*TM_MD", {link_lyr+".ABTM_MD", link_lyr+".BATM_MD"}, "SUMFRAC"}, + {"*TM_AM", {link_lyr+".ABTM_AM", link_lyr+".BATM_AM"}, "SUMFRAC"}, + {"lrtzone",{link_lyr+".lrtzone", link_lyr+".lrtzone"}, "SUMFRAC"}, + {"crzone", {link_lyr+".crzone", link_lyr+".crzone"}, "SUMFRAC"}} + Opts.Global.[Network Options].[Mode Field] = rte_lyr+".Mode" + Opts.Global.[Network Options].[Walk Mode] = link_lyr+".minmode" + Opts.Output.[Network File] = outputDir+"\\"+trnets[i] + RunMacro("HwycadLog",{"createtrnnet.rsc: Create rail net","Build Transit Network: "+trnets[i]}) + ok = RunMacro("TCB Run Operation", i, "Build Transit Network", Opts) + + if !ok then goto quit + end + + mode_tb = inputDir+"\\modenu061.dbf" + mode_vw = RunMacro("TCB OpenTable",,, {mode_tb}) + + // xfer_tb = path+"\\xferfares.dbf" + // xferf_vw = RunMacro("TCB OpenTable",,, {xfer_tb}) + + //transit network settings + impds = {"*tma", "*tma"} + impwts = {mode_vw+".wt_ivtpk", mode_vw+".wt_ivtpk"} + iwtwts = {mode_vw+".wt_fwtpk", mode_vw+".wt_fwtpk"} + xwaitwts = {mode_vw+".wt_xwtpk", mode_vw+".wt_xwtpk"} + modeused={mode_vw+".crmode",mode_vw+".lrmode"} + + for i = 1 to trnets.length do + Opts = null + Opts.Input.[Transit RS] = rte_file + Opts.Input.[Transit Network] = outputDir+"\\"+trnets[i] + Opts.Input.[Mode Table] = {mode_tb} + // Opts.Input.[Mode Cost Table] = {xfer_tb} + //Opts.Input.[Fare Currency] = {inputDir+"\\fare.mtx", "coaster fare", , } + Opts.Input.[Centroid Set] = {db_node_lyr,node_lyr, "Selection", "Select * where ID<"+i2s(mxtap)} + Opts.Field.[Link Impedance] = "*TM" + Opts.Field.[Route Headway] = headways[i] + Opts.Field.[Route Fare] = "Fare" + Opts.Field.[Stop Zone ID] = "farezone" + Opts.Field.[Mode Fare Type] = mode_vw+".faretype" + Opts.Field.[Mode Fare Core] = mode_vw+".farefield" + Opts.Field.[Mode Fare Weight] = farewts[i] + Opts.Field.[Mode Xfer Time] = mode_vw+".xferpentm" + Opts.Field.[Mode Xfer Weight] = mode_vw+".wtxfertm" + Opts.Field.[Mode Impedance] = trntime[i] //impedance by transit mode + Opts.Field.[Mode Imp Weight] = impwts[i] + Opts.Field.[Mode IWait Weight] = iwtwts[i] + Opts.Field.[Mode XWait Weight] = xwaitwts[i] + Opts.Field.[Mode Dwell Weight] = impwts[i] + Opts.Field.[Mode Dwell On Time] = mode_vw+".dwelltime" + Opts.Field.[Mode Used] = modeused[j] + Opts.Field.[Mode Access] = mode_vw+".mode_acces" + Opts.Field.[Mode Egress] = mode_vw+".mode_egres" + Opts.Field.[Inter-Mode Xfer From] =xferf_vw+".from" + Opts.Field.[Inter-Mode Xfer To] = xferf_vw+".to" + Opts.Field.[Inter-Mode Xfer Stop] = xferf_vw+".stop" + Opts.Field.[Inter-Mode Xfer Proh] = xferf_vw+".prohibitio" + Opts.Field.[Inter-Mode Xfer Time] = xferf_vw+".xfer_penal" + Opts.Field.[Inter-Mode Xfer Fare] = xferf_vw+".fare" + Opts.Field.[Inter-Mode Xfer Wait] = xferf_vw+".wait_time" + Opts.Global.[Class Names] = {"Class 1"} + Opts.Global.[Class Description] = {"Class 1"} + Opts.Global.[current class] = "Class 1" + Opts.Global.[Global Fare Type] = "Flat" + Opts.Global.[Global Fare Value] = 2.25 + Opts.Global.[Global Xfer Fare] = 0 + Opts.Global.[Global Fare Core] = "coaster fare" + Opts.Global.[Global Fare Weight] = 1 + Opts.Global.[Global Imp Weight] = 1 + Opts.Global.[Global Init Weight] = 1 + Opts.Global.[Global Xfer Weight] = 1 + Opts.Global.[Global IWait Weight] = 2 + Opts.Global.[Global XWait Weight] = 2 + Opts.Global.[Global Dwell Weight] = 1 + Opts.Global.[Global Dwell On Time] = 0 + Opts.Global.[Global Dwell Off Time] = 0 + Opts.Global.[Global Headway] = 30 + Opts.Global.[Global Init Time] = 0 + Opts.Global.[Global Xfer Time] = 10 + Opts.Global.[Global Max IWait] = 60 + Opts.Global.[Global Min IWait] = 2 + Opts.Global.[Global Max XWait] = 60 + Opts.Global.[Global Min XWait] = 2 + Opts.Global.[Global Layover Time] = 5 + Opts.Global.[Global Max WACC Path] = 20 + Opts.Global.[Global Max Access] = 30 + Opts.Global.[Global Max Egress] = 30 + Opts.Global.[Global Max Transfer] = 20 + Opts.Global.[Global Max Imp] = 180 + Opts.Global.[Value of Time] = vot[i] + Opts.Global.[Max Xfer Number] = 3 + Opts.Global.[Max Trip Time] = 999 + Opts.Global.[Walk Weight] = 1.8 + Opts.Global.[Zonal Fare Method] = 1 + Opts.Global.[Interarrival Para] = 0.5 + Opts.Global.[Path Threshold] = 0 + Opts.Flag.[Use All Walk Path] = "No" + Opts.Flag.[Use Mode] = "Yes" + Opts.Flag.[Use Mode Cost] = "Yes" + Opts.Flag.[Combine By Mode] = "Yes" + Opts.Flag.[Fare By Mode] = "No" + Opts.Flag.[M2M Fare Method] = 2 + Opts.Flag.[Fare System] = 3 + Opts.Flag.[Use Park and Ride] = "No" + Opts.Flag.[Use Egress Park and Ride] = "No" + Opts.Flag.[Use P&R Walk Access] = "No" + Opts.Flag.[Use P&R Walk Egress] = "No" + Opts.Flag.[Use Parking Capacity] = "No" + RunMacro("HwycadLog",{"createtrnnet.rsc: create rail net","Transit Network Setting PF: "+trnets[i]}) + ok = RunMacro("TCB Run Operation", i, "Transit Network Setting PF", Opts) + if !ok then goto quit + end + + ok=1 + quit: +// if fpr<> null then closefile(fpr) + Return(ok) +EndMacro + + +/******************************************************************************* +Create transit networks + +create 6 transit network from the route system: +local bus op, local bus pk, premium op, premium pk + +Input files: + output\transit.dbd + output\transitrt.rts + input\timexfer.dbf + input\mode3tod.dbf - dbf file for mode table + input\modexfer.dbf + output\fare.mtx + + +output files: + localop.tnw - off peak local bus transit network + localpk.tnw - peak local bus transit network + prepop.tnw - off peak premium service transit network + preppk.tnw - peak premium service transit network + +*****************************************************************************/ +Macro "Create transit networks" + shared path, inputDir, outputDir, mxtap + + db_file=outputDir+"\\transit.dbd" + rte_file=outputDir+"\\transitrt.rts" + timexfer_tb = inputDir+"\\timexfer.bin" + mode_tb = inputDir+"\\mode5tod.dbf" + modexfer_tb = inputDir+"\\modexfer.dbf" + + periods = {"_EA","_AM","_MD","_PM","_EV"} + modes = {"prem","locl"} + + // timexfer_per = {"NO", "YES", "NO", "YES", "NO"} + timexfer_per = {"NO", "YES", "NO", "NO", "NO"} + timexfer_mod = {"YES", "NO"} + + + + ftype = RunMacro("G30 table type", timexfer_tb) + view = OpenTable("test", ftype, {timexfer_tb}) + if view = null then do + RunMacro("TCB Error", "Can't open table " + timexfer_tb) + Return(0) + end + + {node_lyr, link_lyr} = RunMacro("TCB Add DB Layers", db_file,,) + ok = (node_lyr <> null && link_lyr <> null) + if !ok then goto quit + + db_link_lyr=db_file+"|"+link_lyr + db_node_lyr=db_file+"|"+node_lyr + rte_lyr = RunMacro("TCB Add RS Layers", rte_file, , ) + stp_lyr = GetStopsLayerFromRS(rte_lyr) + db_rte_lyr = rte_file + "|" + rte_lyr + db_stp_lyr = rte_file + "|" + stp_lyr + + /* + fpr=OpenFile(path+"\\hwycad.log","a") + mytime=GetDateAndTime() + writeline(fpr,mytime+", create trnets") + */ + + //selection query strings: vary by period + query_strs={"select * where op_headway >0", + "select * where am_headway >0", + "select * where op_headway >0", + "select * where pm_headway >0", + "select * where op_headway >0"} + + // Build Transit Networks + for i = 1 to periods.length do + for j = 1 to modes.length do + Opts = null + Opts.Input.[Transit RS] = rte_file + Opts.Input.[RS Set] = {db_rte_lyr, rte_lyr,modes[j]+periods[i],query_strs[i]} + Opts.Input.[Walk Link Set] = {db_link_lyr, link_lyr, "walklink", "Select * where MINMODE<4"} + Opts.Input.[Stop Set] = {db_stp_lyr, stp_lyr} + Opts.Global.[Network Options].[Route Attributes].mode = {rte_lyr+".mode"} + Opts.Global.[Network Options].[Route Attributes].OP_HEADWAY = {rte_lyr+".OP_HEADWAY"} + Opts.Global.[Network Options].[Route Attributes].AM_HEADWAY = {rte_lyr+".AM_HEADWAY"} + Opts.Global.[Network Options].[Route Attributes].PM_HEADWAY = {rte_lyr+".PM_HEADWAY"} + Opts.Global.[Network Options].[Route Attributes].FARE = {rte_lyr+".FARE"} + Opts.Global.[Network Options].[Stop Attributes].farezone = {stp_lyr+".farezone"} + Opts.Global.[Network Options].[Street Attributes].Length = {link_lyr+".Length",link_lyr+".Length"} + Opts.Global.[Network Options].[Street Attributes].FWYLEN = {link_lyr+".FWYLEN", link_lyr+".FWYLEN"} + Opts.Global.[Network Options].[Street Attributes].[*TM] = {link_lyr+".ABTM"+periods[i], link_lyr+".BATM"+periods[i]} + // Opts.Global.[Network Options].[Street Attributes].[*PRETIME] = {link_lyr+".ABPRETIME"+periods[i], link_lyr+".BAPRETIME"+periods[i]} + // Opts.Global.[Network Options].[Street Attributes].[*LOCTIME] = {link_lyr+".ABLOCTIME"+periods[i], link_lyr+".BALOCTIME"+periods[i]} + Opts.Global.[Network Options].[Street Attributes].LRTZONE = {link_lyr+".LRTZONE", link_lyr+".LRTZONE"} + Opts.Global.[Network Options].[Street Attributes].CRZONE = {link_lyr+".CRZONE", link_lyr+".CRZONE"} + Opts.Global.[Network Options].Walk = "Yes" + Opts.Global.[Network Options].Overide = {stp_lyr+".ID", stp_lyr+".nearnode"} + Opts.Global.[Network Options].[Link Attributes] = + {{"Length", {link_lyr+".Length",link_lyr+".Length"}, "SUMFRAC"}, + {"fwylen",{link_lyr+".fwylen", link_lyr+".fwylen"}, "SUMFRAC"}, + {"*TM", {link_lyr+".ABTM"+periods[i], link_lyr+".BATM"+periods[i]}, "SUMFRAC"}, + // {"*PRETIME", {link_lyr+".ABPRETIME"+periods[i], link_lyr+".BAPRETIME"+periods[i]}, "SUMFRAC"}, + // {"*LOCTIME", {link_lyr+".ABLOCTIME"+periods[i], link_lyr+".BALOCTIME"+periods[i]}, "SUMFRAC"}, + {"lrtzone",{link_lyr+".lrtzone", link_lyr+".lrtzone"}, "SUMFRAC"}, + {"crzone", {link_lyr+".crzone", link_lyr+".crzone"}, "SUMFRAC"}} + Opts.Global.[Network Options].[Mode Field] = rte_lyr+".Mode" + Opts.Global.[Network Options].[Walk Mode] = link_lyr+".minmode" + Opts.Output.[Network File] = outputDir+"\\"+modes[j]+periods[i]+".tnw" + + ok = RunMacro("TCB Run Operation", i, "Build Transit Network", Opts) + if !ok then goto quit + end + end + + dif2=GetDirectoryInfo(timexfer_tb,"file") + if dif2.length>0 then blnxfer=1 else blnxfer=0 + + mode_vw = RunMacro("TCB OpenTable",,, {mode_tb}) + xferf_vw = RunMacro("TCB OpenTable",,, {modexfer_tb}) + + // following vary by period + headways = {"op_headway", "am_headway", "op_headway", "pm_headway", "op_headway"} + trntime= {mode_vw+".TRNTIME_EA",mode_vw+".TRNTIME_AM",mode_vw+".TRNTIME_MD",mode_vw+".TRNTIME_PM",mode_vw+".TRNTIME_EV"}//transit travel time by mode + impwts = {mode_vw+".wt_ivtop", mode_vw+".wt_ivtpk", mode_vw+".wt_ivtop", mode_vw+".wt_ivtpk", mode_vw+".wt_ivtop"} + iwtwts = {mode_vw+".wt_fwtop", mode_vw+".wt_fwtpk", mode_vw+".wt_fwtop", mode_vw+".wt_fwtpk", mode_vw+".wt_fwtop"} + xwaitwts = {mode_vw+".wt_xwtop", mode_vw+".wt_xwtpk", mode_vw+".wt_xwtop", mode_vw+".wt_xwtpk", mode_vw+".wt_xwtop"} + farewts= {mode_vw+".wt_fareop", mode_vw+".wt_farepk", mode_vw+".wt_fareop", mode_vw+".wt_farepk", mode_vw+".wt_fareop"} + vot = {0.05, 0.1, 0.05, 0.1, 0.05} //PB recommended 0.1 + wt_walk = { 1.6, 1.8, 1.6, 1.8, 1.6} + + // following varies by mode + modeused={mode_vw+".premode",mode_vw+".locmode"} + faresys={3, 1} //3, mixed fare, 1, flat fare + + + //transit network settings in TransCAD 6.0 R2 + for i = 1 to periods.length do + for j = 1 to modes.length do + Opts = null + Opts.Input.[Transit RS] = rte_file + Opts.Input.[Transit Network] = outputDir+"\\"+modes[j]+periods[i]+".tnw" + Opts.Input.[Mode Table] = {mode_tb} + Opts.Input.[Mode Cost Table] = {modexfer_tb} + Opts.Input.[Fare Currency] = {inputDir+"\\fare.mtx", "coaster fare", , } + // add timed transfers to premium peak networks (?) + if blnxfer=1 and timexfer_per[i] ="YES" and timexfer_mod[j]="YES" then Opts.Input.[Xfer Wait Table] = {timexfer_tb} + Opts.Input.[Centroid Set] = {db_node_lyr,node_lyr, "Selection", "Select * where ID<"+i2s(mxtap)} + Opts.Field.[Link Impedance] = "*TM" + Opts.Field.[Route Headway] = headways[i] + Opts.Field.[Route Fare] = "Fare" + Opts.Field.[Stop Zone ID] = "farezone" + Opts.Field.[Mode Fare Type] = mode_vw+".faretype" + Opts.Field.[Mode Fare Core] = mode_vw+".farefield" + Opts.Field.[Mode Fare Weight] = farewts[i] + Opts.Field.[Mode Xfer Time] = mode_vw+".xferpentm" + Opts.Field.[Mode Xfer Weight] = mode_vw+".wtxfertm" + Opts.Field.[Mode Impedance] = trntime[i] //impedance by transit mode + Opts.Field.[Mode Imp Weight] = impwts[i] + Opts.Field.[Mode IWait Weight] = iwtwts[i] + Opts.Field.[Mode XWait Weight] = xwaitwts[i] + Opts.Field.[Mode Dwell Weight] = impwts[i] + Opts.Field.[Mode Dwell On Time] = mode_vw+".dwelltime" + Opts.Field.[Mode Used] = modeused[j] + Opts.Field.[Mode Access] = mode_vw+".mode_acces" + Opts.Field.[Mode Egress] = mode_vw+".mode_egres" + Opts.Field.[Inter-Mode Xfer From] =xferf_vw+".from" + Opts.Field.[Inter-Mode Xfer To] = xferf_vw+".to" + Opts.Field.[Inter-Mode Xfer Stop] = xferf_vw+".stop" + Opts.Field.[Inter-Mode Xfer Proh] = xferf_vw+".prohibitio" + Opts.Field.[Inter-Mode Xfer Time] = xferf_vw+".xfer_penal" + Opts.Field.[Inter-Mode Xfer Fare] = xferf_vw+".fare" + Opts.Field.[Inter-Mode Xfer Wait] = xferf_vw+".wait_time" + Opts.Global.[Class Names] = {"Class 1"} + Opts.Global.[Class Description] = {"Class 1"} + Opts.Global.[current class] = "Class 1" + Opts.Global.[Global Fare Type] = "Flat" + Opts.Global.[Global Fare Value] = 2.25 + Opts.Global.[Global Xfer Fare] = 0 + Opts.Global.[Global Fare Core] = "coaster fare" + Opts.Global.[Global Fare Weight] = 1 + Opts.Global.[Global Imp Weight] = 1 + Opts.Global.[Global Init Weight] = 1 + Opts.Global.[Global Xfer Weight] = 1 + Opts.Global.[Global IWait Weight] = 2 + Opts.Global.[Global XWait Weight] = 2 + Opts.Global.[Global Dwell Weight] = 1 + Opts.Global.[Global Dwell On Time] = 0 + Opts.Global.[Global Dwell Off Time] = 0 + Opts.Global.[Global Headway] = 30 + Opts.Global.[Global Init Time] = 0 + Opts.Global.[Global Xfer Time] = 10 + Opts.Global.[Global Max IWait] = 60 + Opts.Global.[Global Min IWait] = 2 + Opts.Global.[Global Max XWait] = 60 + Opts.Global.[Global Min XWait] = 2 + Opts.Global.[Global Layover Time] = 5 + Opts.Global.[Global Max WACC Path] = 20 + Opts.Global.[Global Max Access] = 30 + Opts.Global.[Global Max Egress] = 30 + Opts.Global.[Global Max Transfer] = 20 + Opts.Global.[Global Max Imp] = 180 + Opts.Global.[Value of Time] = vot[i] + Opts.Global.[Max Xfer Number] = 3 + Opts.Global.[Max Trip Time] = 999 + Opts.Global.[Walk Weight] = 1.8 + Opts.Global.[Zonal Fare Method] = 1 + Opts.Global.[Interarrival Para] = 0.5 + Opts.Global.[Path Threshold] = 0 + Opts.Flag.[Use All Walk Path] = "No" + Opts.Flag.[Use Mode] = "Yes" + Opts.Flag.[Use Mode Cost] = "Yes" + Opts.Flag.[Combine By Mode] = "Yes" + Opts.Flag.[Fare By Mode] = "No" + Opts.Flag.[M2M Fare Method] = 2 + Opts.Flag.[Fare System] = 3 + Opts.Flag.[Use Park and Ride] = "No" + Opts.Flag.[Use Egress Park and Ride] = "No" + Opts.Flag.[Use P&R Walk Access] = "No" + Opts.Flag.[Use P&R Walk Egress] = "No" + Opts.Flag.[Use Parking Capacity] = "No" + ok = RunMacro("TCB Run Operation", i, "Transit Network Setting PF", Opts) + if !ok then goto quit + end + end + + ok=1 + quit: + if fpr <> null then closefile(fpr) + RunMacro("close all") + Return(ok) +EndMacro diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AccessibilitiesDMU.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AccessibilitiesDMU.java new file mode 100644 index 0000000..8c13f8d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AccessibilitiesDMU.java @@ -0,0 +1,236 @@ +package org.sandag.abm.accessibilities; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Household; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; + +public class AccessibilitiesDMU + implements Serializable, VariableTable +{ + + + protected transient Logger logger = Logger.getLogger(AccessibilitiesDMU.class); + + protected HashMap methodIndexMap; + + private double[] workSizeTerms; + private double[] schoolSizeTerms; + private double[] sizeTerms; + // size + // terms + // purpose + // (as + // defined + // in + // uec), + // for + // a + // given + // mgra + + private double[] logsums; // logsums/accessibilities, + // for + // a + // given + // mgra-pair + + private Household hhObject; + + // the alternativeData tabledataset has the following fields + // sizeTermIndex: Used to index into the sizeTerms array + // logsumIndex: Used to index into the logsums array + private TableDataSet alternativeData; + private int logsumIndex, sizeIndex; + + private int autoSufficiency; + + public AccessibilitiesDMU() + { + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getAutoSufficiency", 0); + methodIndexMap.put("getSizeTerm", 1); + methodIndexMap.put("getLogsum", 2); + methodIndexMap.put("getNumPreschool", 3); + methodIndexMap.put("getNumGradeSchoolStudents", 4); + methodIndexMap.put("getNumHighSchoolStudents", 5); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getAutoSufficiency(); + case 1: + return getSizeTerm(arrayIndex); + case 2: + return getLogsum(arrayIndex); + case 3: + return getNumPreschool(); + case 4: + return getNumGradeSchoolStudents(); + case 5: + return getNumHighSchoolStudents(); + case 6: + return getWorkSizeTerm(arrayIndex); + case 7: + return getSchoolSizeTerm(arrayIndex); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public void setAlternativeData(TableDataSet alternativeData) + { + this.alternativeData = alternativeData; + logsumIndex = alternativeData.getColumnPosition("logsumIndex"); + sizeIndex = alternativeData.getColumnPosition("sizeTermIndex"); + + } + + public int getNumPreschool() + { + return hhObject.getNumPreschool(); + } + + public int getNumGradeSchoolStudents() + { + return hhObject.getNumGradeSchoolStudents(); + } + + public int getNumHighSchoolStudents() + { + return hhObject.getNumHighSchoolStudents(); + } + + public int getAutoSufficiency() + { + return autoSufficiency; + } + + public void setHouseholdObject(Household hh) + { + hhObject = hh; + } + + public void setAutoSufficiency(int autoSufficiency) + { + this.autoSufficiency = autoSufficiency; + } + + public void setSizeTerms(double[] sizeTerms) + { + this.sizeTerms = sizeTerms; + } + + public void setWorkSizeTerms(double[] sizeTerms) + { + workSizeTerms = sizeTerms; + } + + public void setSchoolSizeTerms(double[] sizeTerms) + { + schoolSizeTerms = sizeTerms; + } + + public void setLogsums(double[] logsums) + { + this.logsums = logsums; + } + + /** + * For the given alternative, look up the work size term and return it. + * + * @param alt + * @return + */ + public double getWorkSizeTerm(int alt) + { + + int index = (int) alternativeData.getValueAt(alt, sizeIndex); + + return workSizeTerms[index]; + } + + /** + * For the given alternative, look up the school size term and return it. + * + * @param alt + * @return + */ + public double getSchoolSizeTerm(int alt) + { + + int index = (int) alternativeData.getValueAt(alt, sizeIndex); + + return schoolSizeTerms[index]; + } + + /** + * For the given alternative, look up the size term and return it. + * + * @param alt + * @return + */ + public double getSizeTerm(int alt) + { + + int index = (int) alternativeData.getValueAt(alt, sizeIndex); + + return sizeTerms[index]; + } + + /** + * For the given alternative, look up the size term and return it. + * + * @param alt + * @return + */ + public double getLogsum(int alt) + { + + int index = (int) alternativeData.getValueAt(alt, logsumIndex); + + return logsums[index]; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AccessibilitiesTable.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AccessibilitiesTable.java new file mode 100644 index 0000000..d44f2fe --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AccessibilitiesTable.java @@ -0,0 +1,407 @@ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import org.apache.log4j.Logger; +import com.pb.common.datafile.CSVFileWriter; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class holds the accessibility table that is built, or reads it from a + * previously written file. + * + * @author Jim Hicks + * @version May, 2011 + */ +public final class AccessibilitiesTable + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(AccessibilitiesTable.class); + + private static final int NONMANDATORY_AUTO_ACCESSIBILITY_FIELD_NUMBER = 1; + private static final int NONMANDATORY_TRANSIT_ACCESSIBILITY_FIELD_NUMBER = 2; + private static final int NONMANDATORY_NONMOTOR_ACCESSIBILITY_FIELD_NUMBER = 3; + private static final int NONMANDATORY_SOV_0_ACCESSIBILITY_FIELD_NUMBER = 4; + private static final int NONMANDATORY_SOV_1_ACCESSIBILITY_FIELD_NUMBER = 5; + private static final int NONMANDATORY_SOV_2_ACCESSIBILITY_FIELD_NUMBER = 6; + private static final int NONMANDATORY_HOV_0_ACCESSIBILITY_FIELD_NUMBER = 7; + private static final int NONMANDATORY_HOV_1_ACCESSIBILITY_FIELD_NUMBER = 8; + private static final int NONMANDATORY_HOV_2_ACCESSIBILITY_FIELD_NUMBER = 9; + private static final int SHOP_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX = 10; + private static final int SHOP_ACCESSIBILITY_HOV_SUFFICIENT_INDEX = 11; + private static final int SHOP_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX = 12; + private static final int MAINT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX = 13; + private static final int MAINT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX = 14; + private static final int MAINT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX = 15; + private static final int EAT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX = 16; + private static final int EAT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX = 17; + private static final int EAT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX = 18; + private static final int VISIT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX = 19; + private static final int VISIT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX = 20; + private static final int VISIT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX = 21; + private static final int DISCR_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX = 22; + private static final int DISCR_ACCESSIBILITY_HOV_SUFFICIENT_INDEX = 23; + private static final int DISCR_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX = 24; + private static final int ESCORT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX = 25; + private static final int ESCORT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX = 26; + private static final int ESCORT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX = 27; + private static final int SHOP_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX = 28; + private static final int SHOP_ACCESSIBILITY_SOV_SUFFICIENT_INDEX = 29; + private static final int SHOP_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX = 30; + private static final int MAINT_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX = 31; + private static final int MAINT_ACCESSIBILITY_SOV_SUFFICIENT_INDEX = 32; + private static final int MAINT_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX = 33; + private static final int EAT_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX = 34; + private static final int EAT_ACCESSIBILITY_SOV_SUFFICIENT_INDEX = 35; + private static final int EAT_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX = 36; + private static final int VISIT_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX = 37; + private static final int VISIT_ACCESSIBILITY_SOV_SUFFICIENT_INDEX = 38; + private static final int VISIT_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX = 39; + private static final int DISCR_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX = 40; + private static final int DISCR_ACCESSIBILITY_SOV_SUFFICIENT_INDEX = 41; + private static final int DISCR_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX = 42; + private static final int ATWORK_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX = 43; + private static final int ATWORK_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX = 44; + private static final int TOTAL_EMPLOYMENT_ACCESSIBILITY_INDEX = 45; + private static final int ATWORK_ACCESSIBILITY_NMOT_INDEX = 46; + private static final int ALLHH_ACCESSIBILITY_TRANSIT_INDEX = 47; + private static final int NONMANDATORY_MAAS_ACCESSIBILITY_FIELD_NUMBER = 48; + + // accessibilities by mgra, accessibility alternative + private float[][] accessibilities; + + /** + * array of previously computed accessibilities + * + * @param computedAccessibilities + * array of accessibilities + * + * use this constructor if the accessibilities were calculated as + * opposed to read from a file. + */ + public AccessibilitiesTable(float[][] computedAccessibilities) + { + accessibilities = computedAccessibilities; + } + + /** + * file name for store accessibilities + * + * @param accessibilitiesInputFileName + * path and filename of file to read + * + * use this constructor if the accessibilities are to be read + * from a file. + */ + public AccessibilitiesTable(String accessibilitiesInputFileName) + { + readAccessibilityTableFromFile(accessibilitiesInputFileName); + } + + private void readAccessibilityTableFromFile(String fileName) + { + + File accFile = new File(fileName); + + // read in the csv table + TableDataSet accTable; + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + accTable = reader.readFile(accFile); + + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading accessibility data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(); + } + + // create accessibilities array as a 1-based array + float[][] temp = accTable.getValues(); + accessibilities = new float[temp.length + 1][]; + for (int i = 0; i < temp.length; i++) + { + accessibilities[i + 1] = new float[temp[i].length]; + for (int j = 0; j < temp[i].length; j++) + { + accessibilities[i + 1][j] = temp[i][j]; + } + } + + } + + public void writeAccessibilityTableToFile(String accFileName) + { + + File accFile = new File(accFileName); + + // the accessibilities array is indexed by mgra values which might no be + // consecutive. + // create an arraylist of data table rows, with the last field being the + // mgra value, + // convert to a tabledataset, then write to a csv file. + + ArrayList dataColumnHeadings = new ArrayList(); + dataColumnHeadings.add("NONMAN_AUTO"); + dataColumnHeadings.add("NONMAN_TRANSIT"); + dataColumnHeadings.add("NONMAN_NONMOTOR"); + dataColumnHeadings.add("NONMAN_SOV_0"); + dataColumnHeadings.add("NONMAN_SOV_1"); + dataColumnHeadings.add("NONMAN_SOV_2"); + dataColumnHeadings.add("NONMAN_HOV_0"); + dataColumnHeadings.add("NONMAN_HOV_1"); + dataColumnHeadings.add("NONMAN_HOV_2"); + dataColumnHeadings.add("SHOP_HOV_0"); + dataColumnHeadings.add("SHOP_HOV_1"); + dataColumnHeadings.add("SHOP_HOV_2"); + dataColumnHeadings.add("MAINT_HOV_0"); + dataColumnHeadings.add("MAINT_HOV_1"); + dataColumnHeadings.add("MAINT_HOV_2"); + dataColumnHeadings.add("EAT_HOV_0"); + dataColumnHeadings.add("EAT_HOV_1"); + dataColumnHeadings.add("EAT_HOV_2"); + dataColumnHeadings.add("VISIT_HOV_0"); + dataColumnHeadings.add("VISIT_HOV_1"); + dataColumnHeadings.add("VISIT_HOV_2"); + dataColumnHeadings.add("DISCR_HOV_0"); + dataColumnHeadings.add("DISCR_HOV_1"); + dataColumnHeadings.add("DISCR_HOV_2"); + dataColumnHeadings.add("ESCORT_HOV_0"); + dataColumnHeadings.add("ESCORT_HOV_1"); + dataColumnHeadings.add("ESCORT_HOV_2"); + dataColumnHeadings.add("SHOP_SOV_0"); + dataColumnHeadings.add("SHOP_SOV_1"); + dataColumnHeadings.add("SHOP_SOV_2"); + dataColumnHeadings.add("MAINT_SOV_0"); + dataColumnHeadings.add("MAINT_SOV_1"); + dataColumnHeadings.add("MAINT_SOV_2"); + dataColumnHeadings.add("EAT_SOV_0"); + dataColumnHeadings.add("EAT_SOV_1"); + dataColumnHeadings.add("EAT_SOV_2"); + dataColumnHeadings.add("VISIT_SOV_0"); + dataColumnHeadings.add("VISIT_SOV_1"); + dataColumnHeadings.add("VISIT_SOV_2"); + dataColumnHeadings.add("DISCR_SOV_0"); + dataColumnHeadings.add("DISCR_SOV_1"); + dataColumnHeadings.add("DISCR_SOV_2"); + dataColumnHeadings.add("ATWORK_SOV_0"); + dataColumnHeadings.add("ATWORK_SOV_2"); + dataColumnHeadings.add("TOTAL_EMP"); + dataColumnHeadings.add("ATWORK_NM"); + dataColumnHeadings.add("ALL_HHS_TRANSIT"); + dataColumnHeadings.add("NONMAN_MAAS"); + dataColumnHeadings.add("MGRA"); + + // copy accessibilities array into a 0-based array + float[][] dataTableValues = new float[accessibilities.length - 1][]; + for (int r = 1; r < accessibilities.length; r++) + { + dataTableValues[r - 1] = new float[accessibilities[r].length]; + for (int c = 0; c < accessibilities[r].length; c++) + { + dataTableValues[r - 1][c] = accessibilities[r][c]; + } + } + + TableDataSet accData = TableDataSet.create(dataTableValues, dataColumnHeadings); + CSVFileWriter csv = new CSVFileWriter(); + try + { + csv.writeFile(accData, accFile); + } catch (IOException e) + { + logger.error("Error trying to write accessiblities data file " + accFileName); + throw new RuntimeException(e); + } + + } + + public void writeLandUseAccessibilityTableToFile(String luAccFileName, float[][] luAccessibility) + { + + File accFile = new File(luAccFileName); + + // the accessibilities array is indexed by mgra values which might no be + // consecutive. + // create an arraylist of data table rows, with the last field being the + // mgra value, + // convert to a tabledataset, then write to a csv file. + + ArrayList dataTableRows = new ArrayList(); + ArrayList dataColumnHeadings = new ArrayList(); + dataColumnHeadings.add("AM_WORK_1"); + dataColumnHeadings.add("AM_WORK_2"); + dataColumnHeadings.add("AM_WORK_3"); + dataColumnHeadings.add("AM_WORK_4"); + dataColumnHeadings.add("AM_WORK_5"); + dataColumnHeadings.add("AM_WORK_6"); + dataColumnHeadings.add("AM_SCHOOL_1"); + dataColumnHeadings.add("AM_SCHOOL_2"); + dataColumnHeadings.add("AM_SCHOOL_3"); + dataColumnHeadings.add("AM_SCHOOL_4"); + dataColumnHeadings.add("AM_SCHOOL_5"); + dataColumnHeadings.add("MD_NONMAN_LS0"); + dataColumnHeadings.add("MD_NONMAN_LS1"); + dataColumnHeadings.add("MD_NONMAN_LS2"); + dataColumnHeadings.add("LUZ"); + + for (int r = 0; r < luAccessibility.length; r++) + { + + if (luAccessibility[r] != null) + { + + float[] values = new float[luAccessibility[r].length]; + for (int c = 0; c < luAccessibility[r].length; c++) + values[c] = luAccessibility[r][c]; + + dataTableRows.add(values); + + } + + } + + float[][] dataTableValues = new float[dataTableRows.size()][]; + for (int r = 0; r < dataTableValues.length; r++) + dataTableValues[r] = dataTableRows.get(r); + + TableDataSet accData = TableDataSet.create(dataTableValues, dataColumnHeadings); + CSVFileWriter csv = new CSVFileWriter(); + try + { + csv.writeFile(accData, accFile); + } catch (IOException e) + { + logger.error("Error trying to write land use accessiblities data file " + luAccFileName); + throw new RuntimeException(e); + } + + } + + public void writeLandUseLogsumTablesToFile(String luLogsumFileName, double[][][][] luLogsums) + { + + File accFile = new File(luLogsumFileName); + + // the accessibilities array is indexed by mgra values which might no be + // consecutive. + // create an arraylist of data table rows, with the last field being the + // mgra value, + // convert to a tabledataset, then write to a csv file. + + ArrayList dataTableRows = new ArrayList(); + ArrayList dataColumnHeadings = new ArrayList(); + dataColumnHeadings.add("OrigLuz"); + dataColumnHeadings.add("DestLuz"); + dataColumnHeadings.add("AM_LS0"); + dataColumnHeadings.add("AM_LS1"); + dataColumnHeadings.add("AM_LS2"); + dataColumnHeadings.add("MD_LS0"); + dataColumnHeadings.add("MD_LS1"); + dataColumnHeadings.add("MD_LS2"); + + for (int l = 1; l <= BuildAccessibilities.MAX_LUZ; l++) + { + for (int m = 1; m <= BuildAccessibilities.MAX_LUZ; m++) + { + float[] values = new float[8]; + values[0] = l; + values[1] = m; + values[2] = (float) luLogsums[0][0][l][m]; + values[3] = (float) luLogsums[0][1][l][m]; + values[4] = (float) luLogsums[0][2][l][m]; + values[5] = (float) luLogsums[1][0][l][m]; + values[6] = (float) luLogsums[1][1][l][m]; + values[7] = (float) luLogsums[1][2][l][m]; + dataTableRows.add(values); + } + } + + float[][] dataTableValues = new float[dataTableRows.size()][]; + for (int r = 0; r < dataTableValues.length; r++) + dataTableValues[r] = dataTableRows.get(r); + + TableDataSet accData = TableDataSet.create(dataTableValues, dataColumnHeadings); + CSVFileWriter csv = new CSVFileWriter(); + try + { + csv.writeFile(accData, accFile); + } catch (IOException e) + { + logger.error("Error trying to write land use logsums data file " + luLogsumFileName); + throw new RuntimeException(e); + } + + } + + public float getAggregateAccessibility(String type, int homeMgra) + { + float returnValue = 0; + + if (type.equalsIgnoreCase("auto")) returnValue = accessibilities[homeMgra][NONMANDATORY_AUTO_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("transit")) returnValue = accessibilities[homeMgra][NONMANDATORY_TRANSIT_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("maas")) returnValue = accessibilities[homeMgra][NONMANDATORY_MAAS_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("nonmotor")) returnValue = accessibilities[homeMgra][NONMANDATORY_NONMOTOR_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("sov0")) returnValue = accessibilities[homeMgra][NONMANDATORY_SOV_0_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("sov1")) returnValue = accessibilities[homeMgra][NONMANDATORY_SOV_1_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("sov2")) returnValue = accessibilities[homeMgra][NONMANDATORY_SOV_2_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("hov0")) returnValue = accessibilities[homeMgra][NONMANDATORY_HOV_0_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("hov1")) returnValue = accessibilities[homeMgra][NONMANDATORY_HOV_1_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("hov2")) returnValue = accessibilities[homeMgra][NONMANDATORY_HOV_2_ACCESSIBILITY_FIELD_NUMBER - 1]; + else if (type.equalsIgnoreCase("shop0")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("shop1")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("shop2")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maint0")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maint1")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maint2")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("eatOut0")) returnValue = accessibilities[homeMgra][EAT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("eatOut1")) returnValue = accessibilities[homeMgra][EAT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("eatOut2")) returnValue = accessibilities[homeMgra][EAT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("visit0")) returnValue = accessibilities[homeMgra][VISIT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("visit1")) returnValue = accessibilities[homeMgra][VISIT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("visit2")) returnValue = accessibilities[homeMgra][VISIT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discr0")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discr1")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discr2")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("escort0")) returnValue = accessibilities[homeMgra][ESCORT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("escort1")) returnValue = accessibilities[homeMgra][ESCORT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("escort2")) returnValue = accessibilities[homeMgra][ESCORT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("totEmp")) returnValue = accessibilities[homeMgra][TOTAL_EMPLOYMENT_ACCESSIBILITY_INDEX - 1]; + else if (type.equalsIgnoreCase("shopSov0")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("shopSov1")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_SOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("shopSov2")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maintSov0")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maintSov1")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_SOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maintSov2")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discrSov0")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_SOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discrSov1")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_SOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discrSov2")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_SOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("shopHov0")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("shopHov1")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("shopHov2")) returnValue = accessibilities[homeMgra][SHOP_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maintHov0")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maintHov1")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("maintHov2")) returnValue = accessibilities[homeMgra][MAINT_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discrHov0")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_HOV_INSUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discrHov1")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_HOV_SUFFICIENT_INDEX - 1]; + else if (type.equalsIgnoreCase("discrHov2")) returnValue = accessibilities[homeMgra][DISCR_ACCESSIBILITY_HOV_OVERSUFFICIENT_INDEX - 1]; + else + { + logger.error("argument type = " + + type + + " is not valid"); + throw new RuntimeException(); + } + + return returnValue; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoAndNonMotorizedSkimsCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoAndNonMotorizedSkimsCalculator.java new file mode 100644 index 0000000..78e29ee --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoAndNonMotorizedSkimsCalculator.java @@ -0,0 +1,1024 @@ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +/** + * This class is used to return auto skim values and non-motorized skim values + * for MGRA pairs associated with estimation data file records. + * + * @author Jim Hicks + * @version March, 2010 + */ +public class AutoAndNonMotorizedSkimsCalculator + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(AutoAndNonMotorizedSkimsCalculator.class); + + private static final int EA = ModelStructure.EA_SKIM_PERIOD_INDEX; + private static final int AM = ModelStructure.AM_SKIM_PERIOD_INDEX; + private static final int MD = ModelStructure.MD_SKIM_PERIOD_INDEX; + private static final int PM = ModelStructure.PM_SKIM_PERIOD_INDEX; + private static final int EV = ModelStructure.EV_SKIM_PERIOD_INDEX; + public static final int NUM_PERIODS = ModelStructure.SKIM_PERIOD_INDICES.length; + private static final String[] PERIODS = ModelStructure.SKIM_PERIOD_STRINGS; + + // set the indices used for the non-motorized names array and the return + // skims + // array + private static final int WALK_INDEX = 0; + private static final int BIKE_INDEX = 1; + + private static final double WALK_SPEED = 3.0; // mph + private static final double BIKE_SPEED = 12.0; // mph + + // declare an array of UEC objects, 1 for each time period + private UtilityExpressionCalculator[] autoSkimUECs; + private IndexValues iv; + + // A simple DMU with no variables + private VariableTable dmu = null; + private AutoSkimsDMU autoSkimsDMU = null; + + private MgraDataManager mgraManager; + + private static final String[] AUTO_SKIM_NAMES = { + "da_nt_time", + "da_nt_fftime", + "da_nt_dist", + "da_nt_toll", + "da_nt_tdist", + "da_nt_std", + "da_tr_time", + "da_tr_fftime", + "da_tr_dist", + "da_tr_toll", + "da_tr_tdist", + "da_tr_std", + "s2_time", + "s2_fftime", + "s2_dist", + "s2_hdist", + "s2_toll", + "s2_tdist", + "s2_std", + "s3_time", + "s3_fftime", + "s3_dist", + "s3_hdist", + "s3_toll", + "s3_tdist", + "s3_std"}; + private static final int NUM_AUTO_SKIMS = AUTO_SKIM_NAMES.length; + + private static final String[] AUTO_SKIM_DESCRIPTIONS = { + "SOV Non-transponder Time", //0 + "SOV Non-transponder Free-flow Time", //1 + "SOV Non-transponder Distance", //2 + "SOV Non-transponder Toll", //3 + "SOV Non-transponder Toll Distance", //4 + "SOV Non-transponder Std. Deviation", //5 + "SOV Transponder Time", //6 + "SOV Transponder Free-flow Time", //7 + "SOV Transponder Distance", //8 + "SOV Transponder Toll", //9 + "SOV Transponder Toll Distance", //10 + "SOV Transponder Std. Deviation", //11 + "Shared 2 Time", //12 + "Shared 2 Free-flow Time", //13 + "Shared 2 Distance", //14 + "Shared 2 HOV Distance", //15 + "Shared 2 Toll", //16 + "Shared 2 Toll Distance", //17 + "Shared 2 Std. Deviation", //18 + "Shared 3+ Time", //19 + "Shared 3+ Free-flow Time", //20 + "Shared 3+ Distance", //21 + "Shared 3+ HOV Distance", //22 + "Shared 3+ Toll", //23 + "Shared 3+ Toll Distance", //24 + "Shared 3+ Std. Deviation" //25 + }; + + private static final String[] NM_SKIM_NAMES = {"walkTime", "bikeTime"}; + private static final int NUM_NM_SKIMS = NM_SKIM_NAMES.length; + + private static final String[] NM_SKIM_DESCRIPTIONS = {"walk time", "bike time"}; + + private double[][][] storedFromTazDistanceSkims; + private double[][][] storedToTazDistanceSkims; + + /** + * Get distance from taz to all zones. + * + * @param taz + * @param period + * @return An array of distances to all other zones. + */ + public double[] getTazDistanceFromTaz(int taz, int period) + { + + return storedFromTazDistanceSkims[period][taz]; + } + + /** + * Get distance from taz to all zones. + * + * @param taz + * @param period + * @return An array of distances to all other zones. + */ + public double[] getTazDistanceToTaz(int taz, int period) + { + + return storedToTazDistanceSkims[period][taz]; + } + + public AutoAndNonMotorizedSkimsCalculator(HashMap rbMap) + { + + // Create the UECs + String uecPath = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = uecPath + + Util.getStringValueFromPropertyMap(rbMap, "skims.auto.uec.file"); + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, "skims.auto.data.page"); + int autoSkimEaPage = Util.getIntegerValueFromPropertyMap(rbMap, "skims.auto.ea.page"); + int autoSkimAmPage = Util.getIntegerValueFromPropertyMap(rbMap, "skims.auto.am.page"); + int autoSkimMdPage = Util.getIntegerValueFromPropertyMap(rbMap, "skims.auto.md.page"); + int autoSkimPmPage = Util.getIntegerValueFromPropertyMap(rbMap, "skims.auto.pm.page"); + int autoSkimEvPage = Util.getIntegerValueFromPropertyMap(rbMap, "skims.auto.ev.page"); + + File uecFile = new File(uecFileName); + autoSkimsDMU = new AutoSkimsDMU(); + autoSkimUECs = new UtilityExpressionCalculator[NUM_PERIODS]; + autoSkimUECs[EA] = new UtilityExpressionCalculator(uecFile, autoSkimEaPage, dataPage, + rbMap, autoSkimsDMU); + autoSkimUECs[AM] = new UtilityExpressionCalculator(uecFile, autoSkimAmPage, dataPage, + rbMap, autoSkimsDMU); + autoSkimUECs[MD] = new UtilityExpressionCalculator(uecFile, autoSkimMdPage, dataPage, + rbMap, autoSkimsDMU); + autoSkimUECs[PM] = new UtilityExpressionCalculator(uecFile, autoSkimPmPage, dataPage, + rbMap, autoSkimsDMU); + autoSkimUECs[EV] = new UtilityExpressionCalculator(uecFile, autoSkimEvPage, dataPage, + rbMap, autoSkimsDMU); + iv = new IndexValues(); + + mgraManager = MgraDataManager.getInstance(); + + // distances = new double[mgraManager.getMaxMgra()+1]; + } + + public void setTazDistanceSkimArrays(double[][][] storedFromTazDistanceSkims, + double[][][] storedToTazDistanceSkims) + { + this.storedFromTazDistanceSkims = storedFromTazDistanceSkims; + this.storedToTazDistanceSkims = storedToTazDistanceSkims; + } + + /** + * Return the array of auto skims for the origin MGRA, destination MGRA, and + * departure time period. Used for appending skims data to estimation files, + * not part of main ABM. + * + * @param origMgra + * Origin MGRA + * @param workMgra + * Destination MGRA + * @param departPeriod + * Departure skim period index (currently 1-5) + * @param vot Value-of-time ($/hr) + * @return Array of 9 skim values for the MGRA pair and departure period + */ + public double[] getAutoSkims(int origMgra, int destMgra, int departPeriod, float vot, boolean debug, + Logger logger) + { + + String separator = ""; + String header = ""; + if (debug) + { + logger.info(""); + logger.info(""); + header = "get auto skims debug info for origMgra=" + origMgra + ", destMgra=" + + destMgra + ", period index=" + departPeriod + ", period label=" + + PERIODS[departPeriod]; + for (int i = 0; i < header.length(); i++) + separator += "^"; + } + + // assign a helper UEC object to the array element for the desired + // departure + // time period + UtilityExpressionCalculator autoSkimUEC = autoSkimUECs[departPeriod]; + + // declare the array to hold the skim values, which will be returned + double[] autoSkims = null; + + if (origMgra > 0 && destMgra > 0) + { + + int oTaz = mgraManager.getTaz(origMgra); + int dTaz = mgraManager.getTaz(destMgra); + + iv.setOriginZone(oTaz); + iv.setDestZone(dTaz); + + autoSkimsDMU.setVOT(vot); + + // use the UEC to return skim values for the orign/destination TAZs + // associated with the MGRAs + autoSkims = autoSkimUEC.solve(iv, autoSkimsDMU, null); + if (debug) + autoSkimUEC.logAnswersArray(logger, String.format( + "autoSkimUEC: oMgra=%d, dMgra=%d, period=%d", origMgra, destMgra, + departPeriod)); + + } + + if (debug) + { + + logger.info(separator); + logger.info(header); + logger.info(separator); + + logger.info("auto skims array values"); + logger.info(String.format("%5s %40s %15s", "i", "skimName", "value")); + logger.info(String.format("%5s %40s %15s", "-----", "----------", "----------")); + for (int i = 0; i < autoSkims.length; i++) + { + logger.info(String.format("%5d %40s %15.2f", i, AUTO_SKIM_DESCRIPTIONS[i], + autoSkims[i])); + } + + } + + return autoSkims; + + } + + //Wu modified for xborder trips; 9/27/2019 + public double[] getAutoSkimsByTAZ(int origTAZ, int destTAZ, int departPeriod, float vot, boolean debug, + Logger logger) + { + + String separator = ""; + String header = ""; + if (debug) + { + logger.info(""); + logger.info(""); + header = "get auto skims debug info for origTaz=" + origTAZ + ", destTaz=" + + destTAZ + ", period index=" + departPeriod + ", period label=" + + PERIODS[departPeriod]; + for (int i = 0; i < header.length(); i++) + separator += "^"; + } + + // assign a helper UEC object to the array element for the desired + // departure + // time period + UtilityExpressionCalculator autoSkimUEC = autoSkimUECs[departPeriod]; + + // declare the array to hold the skim values, which will be returned + double[] autoSkims = null; + + if (origTAZ > 0 && destTAZ > 0) + { + + int oTaz = origTAZ; + int dTaz = destTAZ; + + iv.setOriginZone(oTaz); + iv.setDestZone(dTaz); + + autoSkimsDMU.setVOT(vot); + + // use the UEC to return skim values for the orign/destination TAZs + // associated with the MGRAs + autoSkims = autoSkimUEC.solve(iv, autoSkimsDMU, null); + if (debug) + autoSkimUEC.logAnswersArray(logger, String.format( + "autoSkimUEC: oTaz=%d, dTaz=%d, period=%d", origTAZ, destTAZ, + departPeriod)); + + } + + if (debug) + { + + logger.info(separator); + logger.info(header); + logger.info(separator); + + logger.info("auto skims array values"); + logger.info(String.format("%5s %40s %15s", "i", "skimName", "value")); + logger.info(String.format("%5s %40s %15s", "-----", "----------", "----------")); + for (int i = 0; i < autoSkims.length; i++) + { + logger.info(String.format("%5d %40s %15.2f", i, AUTO_SKIM_DESCRIPTIONS[i], + autoSkims[i])); + } + + } + + return autoSkims; + + } + + /** + * Get the non-motorized skims. + * + * Get all the mgras within walking distance of the origin mgra. If the set + * of mgras is not null, and the destination mgra is in the set, get the + * walk and bike times from the mgraManager; + * + * If the destination mgra is not within walking distance of the origin + * MGRA, get the drive-alone non-toll off-peak distance skim value for the + * mgra pair and calculate the walk time and bike time. + * + * @param origMgra + * The origin mgra + * @param destMgra + * The destination mgra + * @return An array of distances + */ + public double[] getNonMotorizedSkims(int origMgra, int destMgra, int departPeriod, + boolean debug, Logger logger) + { + + String separator = ""; + String header = ""; + if (debug) + { + logger.info(""); + logger.info(""); + header = "get non-motorized skims debug info for origMgra=" + origMgra + ", destMgra=" + + destMgra; + for (int i = 0; i < header.length(); i++) + separator += "^"; + } + + double[] nmSkims = new double[NUM_NM_SKIMS]; + + // get the array of mgras within walking distance of the origin + int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceFrom(origMgra); + + // if one of the walk mgras is the destination, set the skim values and + // return + if (walkMgras != null) + { + + for (int wMgra : walkMgras) + { + + if (wMgra == destMgra) + { + nmSkims[WALK_INDEX] = mgraManager.getMgraToMgraWalkTime(origMgra, destMgra); + nmSkims[BIKE_INDEX] = mgraManager.getMgraToMgraBikeTime(origMgra, destMgra); + + if (debug) + { + + logger.info(separator); + logger.info(header); + logger.info(separator); + + logger.info("non-motorized skims array values"); + logger.info("determined from the mgraManager for an mgra pair within walking distance of each other."); + logger.info(String.format("%5s %40s %15s", "i", "skimName", "value")); + logger.info(String.format("%5s %40s %15s", "-----", "----------", + "----------")); + for (int i = 0; i < nmSkims.length; i++) + { + logger.info(String.format("%5d %40s %15.2f", i, + NM_SKIM_DESCRIPTIONS[i], nmSkims[i])); + } + + } + + return nmSkims; + } + + } + + } + + // the destination was not within walk distance, so calculate walk and + // bike + // times from the TAZ-TAZ skim distance + int oTaz = mgraManager.getTaz(origMgra); + int dTaz = mgraManager.getTaz(destMgra); + + if (debug) + { + + logger.info(separator); + logger.info(header); + logger.info(separator); + + logger.info("non-motorized skims array values"); + logger.info("calculated for an mgra pair not within walking distance of each other."); + logger.info("origTaz = " + oTaz + ", destTaz = " + dTaz + ", period = " + departPeriod + + ", od distance = " + + (float) storedFromTazDistanceSkims[departPeriod][oTaz][dTaz]); + logger.info(String.format("%5s %40s %15s", "i", "skimName", "value")); + logger.info(String.format("%5s %40s %15s", "-----", "----------", "----------")); + for (int i = 0; i < nmSkims.length; i++) + { + logger.info(String + .format("%5d %40s %15.2f", i, NM_SKIM_DESCRIPTIONS[i], nmSkims[i])); + } + + } + + nmSkims[WALK_INDEX] = (storedFromTazDistanceSkims[departPeriod][oTaz][dTaz] / WALK_SPEED) * 60.0; + nmSkims[BIKE_INDEX] = (storedFromTazDistanceSkims[departPeriod][oTaz][dTaz] / BIKE_SPEED) * 60.0; + + return nmSkims; + + } + + /* + * public double[] getNonMotorizedSkims(int origMgra, int destMgra, int + * departPeriod, boolean debug, Logger logger) { + * + * String separator = ""; String header = ""; if (debug) { logger.info(""); + * logger.info(""); header = + * "get non-motorized skims debug info for origMgra=" + origMgra + + * ", destMgra=" + destMgra; for (int i = 0; i < header.length(); i++) + * separator += "^"; } + * + * double[] nmSkims = new double[NUM_NM_SKIMS]; + * + * // get the array of mgras within walking distance of the origin int[] + * walkMgras = mgraManager.getMgrasWithinWalkDistanceFrom(origMgra); + * + * // if one of the walk mgras is the destination, set the skim values and + * // return if (walkMgras != null) { + * + * for (int wMgra : walkMgras) { + * + * if (wMgra == destMgra) { nmSkims[WALK_INDEX] = + * mgraManager.getMgraToMgraWalkTime(origMgra, destMgra); + * nmSkims[BIKE_INDEX] = mgraManager.getMgraToMgraBikeTime(origMgra, + * destMgra); + * + * if (debug) { + * + * logger.info(separator); logger.info(header); logger.info(separator); + * + * logger.info("non-motorized skims array values"); logger .info( + * "determined from the mgraManager for an mgra pair within walking distance of each other." + * ); logger.info(String.format("%5s %40s %15s", "i", "skimName", "value")); + * logger.info(String.format("%5s %40s %15s", "-----", "----------", + * "----------")); for (int i = 0; i < nmSkims.length; i++) { + * logger.info(String.format("%5d %40s %15.2f", i, NM_SKIM_DESCRIPTIONS[i], + * nmSkims[i])); } + * + * } + * + * return nmSkims; } + * + * } + * + * } + * + * // the destination was not within walk distance, so calculate walk and + * bike // times from the TAZ-TAZ skim distance int oTaz = + * mgraManager.getTaz(origMgra); int dTaz = mgraManager.getTaz(destMgra); + * + * iv.setOriginZone(oTaz); iv.setDestZone(dTaz); + * + * // get the DA NT OP distance value for the mgra pair double[] autoSkims = + * autoSkimUECs[OP].solve(iv, dmu, null); double distance = autoSkims[2]; + * + * nmSkims[WALK_INDEX] = (distance / WALK_SPEED) * 60.0; nmSkims[BIKE_INDEX] + * = (distance / BIKE_SPEED) * 60.0; + * + * if (debug) { + * + * logger.info(separator); logger.info(header); logger.info(separator); + * + * logger.info("non-motorized skims array values"); logger.info( + * "calculated for an mgra pair not within walking distance of each other." + * ); logger.info("origTaz = " + oTaz + ", destTaz = " + dTaz + + * ", od distance = " + (float) distance); + * logger.info(String.format("%5s %40s %15s", "i", "skimName", "value")); + * logger.info(String.format("%5s %40s %15s", "-----", "----------", + * "----------")); for (int i = 0; i < nmSkims.length; i++) { + * logger.info(String .format("%5d %40s %15.2f", i, NM_SKIM_DESCRIPTIONS[i], + * nmSkims[i])); } + * + * } + * + * return nmSkims; + * + * } + */ + /** + * Get all the mgras within walking distance of the origin mgra and set the + * distances to those mgras. + * + * Then loop through all mgras without a distance and get the drive-alone + * non-toll off-peak distance skim value for the taz pair associated with + * each mgra pair. + * + * @param origMgra + * The origin mgra + * @param An + * array in which to put the distances + * @param tourModeIsAuto + * is a boolean set to true if tour mode is not non-motorized, + * transit, or school bus. if auto tour mode, then no need to + * determine walk distance, and drive skims can be used directly. + * public void getDistancesFromMgra( int origMgra, double[] + * distances, boolean tourModeIsAuto ) { + * + * Arrays.fill(distances, 0); + * + * if ( ! tourModeIsAuto ){ + * + * // get the array of mgras within walking distance of the + * destination int[] walkMgras = + * mgraManager.getMgrasWithinWalkDistanceFrom(origMgra); + * + * // set the distance values for the mgras walkable to the + * destination if (walkMgras != null) { + * + * // get distances, in feet, and convert to miles for (int wMgra + * : walkMgras) distances[wMgra] = + * mgraManager.getMgraToMgraWalkDistFrom(origMgra, wMgra) / + * 5280.0; + * + * } + * + * } + * + * + * int oTaz = mgraManager.getTaz(origMgra); + * iv.setOriginZone(oTaz); for (int wMgra=1; wMgra <= + * mgraManager.getMaxMgra(); wMgra++) { + * + * // skip mgras where distance has already been set if ( + * distances[wMgra] > 0 ) continue; + * + * // calculate distances from the TAZ-TAZ skim distance int dTaz + * = mgraManager.getTaz(wMgra); iv.setDestZone(dTaz); double[] + * autoSkims = autoSkimUECs[OP].solve(iv, dmu, null); + * + * distances[wMgra] = autoSkims[2]; } + * + * } + */ + + /** + * Get all the mgras within walking distance of the origin mgra and set the + * distances to those mgras. + * + * Then loop through all mgras without a distance and get the drive-alone + * non-toll off-peak distance skim value for the taz pair associated with + * each mgra pair. + * + * @param origMgra + * The origin mgra + * @param An + * array in which to put the distances + * @param tourModeIsAuto + * is a boolean set to true if tour mode is not non-motorized, + * transit, or school bus. if auto tour mode, then no need to + * determine walk distance, and drive skims can be used directly. + * + */ + + public void getDistancesFromMgra(int origMgra, double[] distances, boolean tourModeIsAuto) + { + + Arrays.fill(distances, 0); + + if (!tourModeIsAuto) + { + + // get the array of mgras within walking distance of the destination + int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceFrom(origMgra); + + // set the distance values for the mgras walkable to the destination + if (walkMgras != null) + { + + // get distances, in feet, and convert to miles + for (int wMgra : walkMgras) + distances[wMgra] = mgraManager.getMgraToMgraWalkDistFrom(origMgra, wMgra) / 5280.0; + + } + + } + + int oTaz = mgraManager.getTaz(origMgra); + + for (int wMgra = 1; wMgra <= mgraManager.getMaxMgra(); wMgra++) + { + + // skip mgras where distance has already been set + if (distances[wMgra] > 0) continue; + + int dTaz = mgraManager.getTaz(wMgra); + distances[wMgra] = storedFromTazDistanceSkims[MD][oTaz][dTaz]; + } + + } + + /** + * Get all the mgras within walking distance of the destination mgra and set + * the distances from those mgras. + * + * Then loop through all mgras without a distance and get the drive-alone + * non-toll off-peak distance skim value for the taz pair associated with + * each mgra pair. + * + * @param destMgra + * The destination mgra + * @param An + * array in which to put the distances + * @param tourModeIsAuto + * is a boolean set to true if tour mode is not non-motorized, + * transit, or school bus. if auto tour mode, then no need to + * determine walk distance, and drive skims can be used directly. + */ + + public void getDistancesToMgra(int destMgra, double[] distances, boolean tourModeIsAuto) + { + + Arrays.fill(distances, 0); + + if (!tourModeIsAuto) + { + + // get the array of mgras within walking distance of the destination + int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceTo(destMgra); + + // set the distance values for the mgras walkable to the destination + if (walkMgras != null) + { + + // get distances, in feet, and convert to miles + // get distances from destMgra since this is the direction of + // distances read from the data file + for (int wMgra : walkMgras) + distances[wMgra] = mgraManager.getMgraToMgraWalkDistTo(wMgra, destMgra) / 5280.0; + + } + + } + + // if the TAZ distances have not been computed yet for this destination + // TAZ, compute them from the UEC. + int dTaz = mgraManager.getTaz(destMgra); + + for (int wMgra = 1; wMgra <= mgraManager.getMaxMgra(); wMgra++) + { + + // skip mgras where distance has already been set + if (distances[wMgra] > 0) continue; + + int oTaz = mgraManager.getTaz(wMgra); + distances[wMgra] = storedToTazDistanceSkims[MD][dTaz][oTaz]; + + } + + } + + /* + * public void getDistancesToMgra( int destMgra, double[] distances, boolean + * tourModeIsAuto ) { + * + * Arrays.fill(distances, 0); + * + * if ( ! tourModeIsAuto ){ + * + * // get the array of mgras within walking distance of the destination + * int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceTo(destMgra); + * + * // set the distance values for the mgras walkable to the destination if + * (walkMgras != null) { + * + * // get distances, in feet, and convert to miles // get distances from + * destMgra since this is the direction of distances read from the data file + * for (int wMgra : walkMgras) distances[wMgra] = + * mgraManager.getMgraToMgraWalkDistTo(destMgra, wMgra) / 5280.0; + * + * } + * + * } + * + * + * int dTaz = mgraManager.getTaz(destMgra); iv.setDestZone(dTaz); for (int + * wMgra=1; wMgra <= mgraManager.getMaxMgra(); wMgra++) { + * + * // skip mgras where distance has already been set if ( distances[wMgra] > + * 0 ) continue; + * + * // calculate distances from the TAZ-TAZ skim distance int oTaz = + * mgraManager.getTaz(wMgra); iv.setOriginZone(oTaz); double[] autoSkims = + * autoSkimUECs[OP].solve(iv, dmu, null); + * + * distances[wMgra] = autoSkims[2]; } + * + * } + */ + + /* + * public double[] getDistancesToMgra( int destMgra, boolean tourModeIsAuto + * ) { + * + * + * Arrays.fill(distances, 0); + * + * if ( ! tourModeIsAuto ){ + * + * // get the array of mgras within walking distance of the destination + * int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceTo(destMgra); + * + * // set the distance values for the mgras walkable to the destination if + * (walkMgras != null) { + * + * // get distances, in feet, and convert to miles // get distances from + * destMgra since this is the direction of distances read from the data file + * for (int wMgra : walkMgras) distances[wMgra] = + * mgraManager.getMgraToMgraWalkDistTo(destMgra, wMgra) / 5280.0; + * + * } + * + * } + * + * + * + * // if the TAZ distances have not been computed yet for this destination + * TAZ, compute them from the UEC. int dTaz = mgraManager.getTaz(destMgra); + * + * for (int wMgra=1; wMgra <= mgraManager.getMaxMgra(); wMgra++) { + * + * // skip mgras where distance has already been set if ( distances[wMgra] > + * 0 ) continue; + * + * int oTaz = mgraManager.getTaz(wMgra); distances[wMgra] = + * storedToTazDistanceSkims[OP][dTaz][oTaz]; + * + * } + * + * return Arrays.copyOf( distances, distances.length ); + * + * } + * + * + * /** Calculate utility expressions for auto skims for a given origin to + * get distances to all destination mgras, and return off-peak sov distance. + * + * @param oMgra The origin mgra + * + * @return An array of off-peak sov distances + */ + /* + * public void getOpSkimDistancesFromMgra( int oMgra, double[] distances ) { + * + * int oTaz = mgraManager.getTaz(oMgra); + * + * for (int i=1; i <= mgraManager.getMaxMgra(); i++) { + * + * // calculate distances from the TAZ-TAZ skim distance int dTaz = + * mgraManager.getTaz(i); distances[i] = + * storedFromTazDistanceSkims[OP][oTaz][dTaz]; + * + * } + * + * } + */ + + /* + * public double[] getAmPkSkimDistancesFromMgra( int oMgra ) { + * + * int oTaz = mgraManager.getTaz(oMgra); + * + * for (int i=1; i <= mgraManager.getMaxMgra(); i++) { + * + * // calculate distances from the TAZ-TAZ skim distance int dTaz = + * mgraManager.getTaz(i); distances[i] = + * storedFromTazDistanceSkims[AM][oTaz][dTaz]; + * + * } + * + * return Arrays.copyOf( distances, distances.length ); + * + * } + */ + + /* + * public double[] getOpSkimDistancesFromMgra(int oMgra) { + * + * double[] distances = new double[mgraManager.getMaxMgra() + 1]; + * + * int oTaz = mgraManager.getTaz(oMgra); iv.setOriginZone(oTaz); + * + * for (int i = 1; i <= mgraManager.getMaxMgra(); i++) { + * + * int dTaz = mgraManager.getTaz(i); iv.setDestZone(dTaz); + * + * // sov distance double[] autoResults = autoSkimUECs[OP].solve(iv, dmu, + * null); distances[i] = autoResults[2]; + * + * } + * + * return distances; } + */ + + /* + * public void getOpSkimDistancesFromMgra(int oMgra, double[] distances) { + * + * Arrays.fill( distances, 0 ); + * + * int oTaz = mgraManager.getTaz(oMgra); iv.setOriginZone(oTaz); + * + * for (int i = 1; i <= mgraManager.getMaxMgra(); i++) { + * + * int dTaz = mgraManager.getTaz(i); iv.setDestZone(dTaz); + * + * // sov distance double[] autoResults = autoSkimUECs[OP].solve(iv, dmu, + * null); distances[i] = autoResults[2]; + * + * } + * + * } + */ + + public void getOpSkimDistancesFromMgra(int oMgra, double[] distances) + { + + int oTaz = mgraManager.getTaz(oMgra); + + for (int i = 1; i <= mgraManager.getMaxMgra(); i++) + { + + // calculate distances from the TAZ-TAZ skim distance + int dTaz = mgraManager.getTaz(i); + distances[i] = storedFromTazDistanceSkims[MD][oTaz][dTaz]; + + } + + } + + /** + * Calculate utility expressions for auto skims for a given origin to get + * distances to all destination mgras, and return am peak sov distance. + * + * @param oMgra + * The origin mgra + * @return An array of am peak sov distances public double[] + * getAmPkSkimDistancesFromMgra(int oMgra) { + * + * double[] distances = new double[mgraManager.getMaxMgra() + 1]; + * + * int oTaz = mgraManager.getTaz(oMgra); iv.setOriginZone(oTaz); + * + * for (int i = 1; i <= mgraManager.getMaxMgra(); i++) { + * + * int dTaz = mgraManager.getTaz(i); iv.setDestZone(dTaz); + * + * // sov distance double[] autoResults = autoSkimUECs[AM].solve(iv, + * dmu, null); distances[i] = autoResults[2]; + * + * } + * + * return distances; } + */ + + public void getAmPkSkimDistancesFromMgra(int oMgra, double[] distances) + { + + int oTaz = mgraManager.getTaz(oMgra); + + for (int i = 1; i <= mgraManager.getMaxMgra(); i++) + { + + // calculate distances from the TAZ-TAZ skim distance + int dTaz = mgraManager.getTaz(i); + distances[i] = storedFromTazDistanceSkims[AM][oTaz][dTaz]; + + } + + } + + /* + * public void getAmPkSkimDistancesFromMgra(int oMgra, double[] distances) { + * + * Arrays.fill( distances, 0 ); + * + * int oTaz = mgraManager.getTaz(oMgra); iv.setOriginZone(oTaz); + * + * for (int i = 1; i <= mgraManager.getMaxMgra(); i++) { + * + * int dTaz = mgraManager.getTaz(i); iv.setDestZone(dTaz); + * + * // sov distance double[] autoResults = autoSkimUECs[AM].solve(iv, dmu, + * null); distances[i] = autoResults[2]; + * + * } + * + * } + */ + + /** + * log a report of the final skim values for the MGRA odt + * + * @param orig + * is the origin mgra for the segment + * @param dest + * is the destination mgra for the segment + * @param depart + * is the departure period for the segment + * @param bestTapPairs + * is an int[][] of TAP values with the first dimesion the ride + * mode and second dimension a 2 element array with best orig and + * dest TAP + * @param returnedSkims + * is a double[][] of skim values with the first dimesion the + * ride mode indices and second dimention the skim categories + */ + public void logReturnedSkims(int orig, int dest, int depart, double[] skims, String skimLabel, + Logger logger) + { + + String separator = ""; + String header = ""; + + logger.info(""); + logger.info(""); + header = skimLabel + " skim value tables for origMgra=" + orig + ", destMgra=" + dest + + ", departperiod=" + depart; + for (int i = 0; i < header.length(); i++) + separator += "^"; + + logger.info(separator); + logger.info(header); + logger.info(""); + + String tableRecord = ""; + for (int i = 0; i < skims.length; i++) + { + tableRecord = String.format("%-5d %12.5f ", i + 1, skims[i]); + logger.info(tableRecord); + } + + logger.info(""); + logger.info(separator); + } + + public int getNumSkimPeriods() + { + return NUM_PERIODS; + } + + public int getNumAutoSkims() + { + return NUM_AUTO_SKIMS; + } + + public String[] getAutoSkimNames() + { + return AUTO_SKIM_NAMES; + } + + public int getNumNmSkims() + { + return NUM_NM_SKIMS; + } + + public String[] getNmSkimNames() + { + return NM_SKIM_NAMES; + } + + public int getNmWalkTimeSkimIndex() + { + return WALK_INDEX; + } + + public int getNmBikeTimeSkimIndex() + { + return BIKE_INDEX; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoSkimsDMU.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoSkimsDMU.java new file mode 100644 index 0000000..8467036 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoSkimsDMU.java @@ -0,0 +1,82 @@ +package org.sandag.abm.accessibilities; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.VariableTable; + +public class AutoSkimsDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(AutoSkimsDMU.class); + + protected HashMap methodIndexMap; + + protected float vot; + + public AutoSkimsDMU() + { + setupMethodIndexMap(); + } + + public float getVOT() + { + return vot; + } + + public void setVOT(float vot) + { + this.vot = vot; + } + + + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getVOT", 0); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getVOT(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoTazSkimsCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoTazSkimsCalculator.java new file mode 100644 index 0000000..9e0811d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/AutoTazSkimsCalculator.java @@ -0,0 +1,206 @@ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.io.Serializable; +import java.util.HashMap; + +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +/** + * This class is used to return auto skim values and non-motorized skim values + * for MGRA pairs associated with estimation data file records. + * + * @author Jim Hicks + * @version March, 2010 + */ +public class AutoTazSkimsCalculator + implements Serializable +{ + + private static final int EA = ModelStructure.EA_SKIM_PERIOD_INDEX; + private static final int AM = ModelStructure.AM_SKIM_PERIOD_INDEX; + private static final int MD = ModelStructure.MD_SKIM_PERIOD_INDEX; + private static final int PM = ModelStructure.PM_SKIM_PERIOD_INDEX; + private static final int EV = ModelStructure.EV_SKIM_PERIOD_INDEX; + public static final int NUM_PERIODS = ModelStructure.SKIM_PERIOD_INDICES.length; + + // declare an array of UEC objects, 1 for each time period + private UtilityExpressionCalculator[] autoDistOD_UECs; + + // The simple auto skims UEC does not use any DMU variables + private VariableTable dmu = null; + + private TazDataManager tazManager; + + private double[][][] storedFromTazDistanceSkims; + private double[][][] storedToTazDistanceSkims; + private int maxTaz; + + public AutoTazSkimsCalculator(HashMap rbMap) + { + + // Create the UECs + String uecPath = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = uecPath + + Util.getStringValueFromPropertyMap(rbMap, "taz.distance.uec.file"); + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, "taz.distance.data.page"); + int autoSkimEaOdPage = Util + .getIntegerValueFromPropertyMap(rbMap, "taz.od.distance.ea.page"); + int autoSkimAmOdPage = Util + .getIntegerValueFromPropertyMap(rbMap, "taz.od.distance.am.page"); + int autoSkimMdOdPage = Util + .getIntegerValueFromPropertyMap(rbMap, "taz.od.distance.md.page"); + int autoSkimPmOdPage = Util + .getIntegerValueFromPropertyMap(rbMap, "taz.od.distance.pm.page"); + int autoSkimEvOdPage = Util + .getIntegerValueFromPropertyMap(rbMap, "taz.od.distance.ev.page"); + + File uecFile = new File(uecFileName); + autoDistOD_UECs = new UtilityExpressionCalculator[NUM_PERIODS]; + autoDistOD_UECs[EA] = new UtilityExpressionCalculator(uecFile, autoSkimEaOdPage, dataPage, + rbMap, dmu); + autoDistOD_UECs[AM] = new UtilityExpressionCalculator(uecFile, autoSkimAmOdPage, dataPage, + rbMap, dmu); + autoDistOD_UECs[MD] = new UtilityExpressionCalculator(uecFile, autoSkimMdOdPage, dataPage, + rbMap, dmu); + autoDistOD_UECs[PM] = new UtilityExpressionCalculator(uecFile, autoSkimPmOdPage, dataPage, + rbMap, dmu); + autoDistOD_UECs[EV] = new UtilityExpressionCalculator(uecFile, autoSkimEvOdPage, dataPage, + rbMap, dmu); + + tazManager = TazDataManager.getInstance(); + maxTaz = tazManager.getMaxTaz(); + + storedFromTazDistanceSkims = new double[NUM_PERIODS + 1][maxTaz + 1][]; + storedToTazDistanceSkims = new double[NUM_PERIODS + 1][maxTaz + 1][]; + + } + + /** + * Get all the mgras within walking distance of the origin mgra and set the + * distances to those mgras. + * + * Then loop through all mgras without a distance and get the drive-alone + * non-toll off-peak distance skim value for the taz pair associated with + * each mgra pair. + * + * @param origMgra + * The origin mgra + * @param An + * array in which to put the distances + * @param tourModeIsAuto + * is a boolean set to true if tour mode is not non-motorized, + * transit, or school bus. if auto tour mode, then no need to + * determine walk distance, and drive skims can be used directly. + */ + public void computeTazDistanceArrays() + { + + IndexValues iv = new IndexValues(); + + for (int oTaz = 1; oTaz <= maxTaz; oTaz++) + { + + storedFromTazDistanceSkims[EA][oTaz] = new double[maxTaz + 1]; + storedToTazDistanceSkims[EA][oTaz] = new double[maxTaz + 1]; + storedFromTazDistanceSkims[AM][oTaz] = new double[maxTaz + 1]; + storedToTazDistanceSkims[AM][oTaz] = new double[maxTaz + 1]; + storedFromTazDistanceSkims[MD][oTaz] = new double[maxTaz + 1]; + storedToTazDistanceSkims[MD][oTaz] = new double[maxTaz + 1]; + storedFromTazDistanceSkims[PM][oTaz] = new double[maxTaz + 1]; + storedToTazDistanceSkims[PM][oTaz] = new double[maxTaz + 1]; + storedFromTazDistanceSkims[EV][oTaz] = new double[maxTaz + 1]; + storedToTazDistanceSkims[EV][oTaz] = new double[maxTaz + 1]; + + } + + for (int oTaz = 1; oTaz <= maxTaz; oTaz++) + { + + iv.setOriginZone(oTaz); + + double[] eaAutoDist = autoDistOD_UECs[EA].solve(iv, dmu, null); + double[] amAutoDist = autoDistOD_UECs[AM].solve(iv, dmu, null); + double[] mdAutoDist = autoDistOD_UECs[MD].solve(iv, dmu, null); + double[] pmAutoDist = autoDistOD_UECs[PM].solve(iv, dmu, null); + double[] evAutoDist = autoDistOD_UECs[EV].solve(iv, dmu, null); + + for (int d = 0; d < maxTaz; d++) + { + + storedFromTazDistanceSkims[EA][oTaz][d + 1] = eaAutoDist[d]; + storedFromTazDistanceSkims[AM][oTaz][d + 1] = amAutoDist[d]; + storedFromTazDistanceSkims[MD][oTaz][d + 1] = mdAutoDist[d]; + storedFromTazDistanceSkims[PM][oTaz][d + 1] = pmAutoDist[d]; + storedFromTazDistanceSkims[EV][oTaz][d + 1] = evAutoDist[d]; + + storedToTazDistanceSkims[EA][d + 1][oTaz] = eaAutoDist[d]; + storedToTazDistanceSkims[AM][d + 1][oTaz] = amAutoDist[d]; + storedToTazDistanceSkims[MD][d + 1][oTaz] = mdAutoDist[d]; + storedToTazDistanceSkims[PM][d + 1][oTaz] = pmAutoDist[d]; + storedToTazDistanceSkims[EV][d + 1][oTaz] = evAutoDist[d]; + + } + + // iv.setDestZone( oTaz ); + // + // amAutoDist = autoDistDO_UECs[AM].solve(iv, dmu, null); + // opAutoDist = autoDistDO_UECs[OP].solve(iv, dmu, null); + // + // for (int d=0; d < maxTaz; d++) + // { + // + // storedToTazDistanceSkims[AM][d+1][oTaz] = amAutoDist[d]; + // storedToTazDistanceSkims[OP][d+1][oTaz] = opAutoDist[d]; + // + // } + + } + + } + + public double getTazToTazDistance(int period, int oTaz, int dTaz){ + + return storedFromTazDistanceSkims[period][oTaz][dTaz]; + } + + public double[][][] getStoredFromTazToAllTazsDistanceSkims() + { + return storedFromTazDistanceSkims; + } + + public double[][][] getStoredToTazFromAllTazsDistanceSkims() + { + return storedToTazDistanceSkims; + } + + public void clearStoredTazsDistanceSkims() + { + + for (int i = 0; i < storedFromTazDistanceSkims.length; i++) + { + for (int j = 0; j < storedFromTazDistanceSkims[i].length; j++) + storedFromTazDistanceSkims[i][j] = null; + storedFromTazDistanceSkims[i] = null; + } + storedFromTazDistanceSkims = null; + + for (int i = 0; i < storedToTazDistanceSkims.length; i++) + { + for (int j = 0; j < storedToTazDistanceSkims[i].length; j++) + storedToTazDistanceSkims[i][j] = null; + storedToTazDistanceSkims[i] = null; + } + storedToTazDistanceSkims = null; + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/BestTransitPathCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/BestTransitPathCalculator.java new file mode 100644 index 0000000..a31110a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/BestTransitPathCalculator.java @@ -0,0 +1,1548 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You + * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.io.PrintWriter; +import java.io.Serializable; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.concurrent.ConcurrentHashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.util.Tracer; + +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.Modes.AccessMode; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; +import org.sandag.abm.reporting.OMXMatrixDao; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.matrix.Matrix; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.newmodel.Alternative; +import com.pb.common.newmodel.ConcreteAlternative; +import com.pb.common.newmodel.LogitModel; +/** + * WalkPathUEC calculates the best walk-transit utilities for a given MGRA pair. + * + * @author Joel Freedman + * @version 1.0, May 2009 + */ +public class BestTransitPathCalculator implements Serializable +{ + + private transient Logger logger = Logger.getLogger(BestTransitPathCalculator.class); + + //TODO: combine APP_TYPE_xxx constants into a enum structure + public static final int APP_TYPE_GENERIC = 0; + public static final int APP_TYPE_TOURMC = 1; + public static final int APP_TYPE_TRIPMC = 2; + + private static final int EA = ModelStructure.EA_SKIM_PERIOD_INDEX; + private static final int AM = ModelStructure.AM_SKIM_PERIOD_INDEX; + private static final int MD = ModelStructure.MD_SKIM_PERIOD_INDEX; + private static final int PM = ModelStructure.PM_SKIM_PERIOD_INDEX; + private static final int EV = ModelStructure.EV_SKIM_PERIOD_INDEX; + public static final int NUM_PERIODS = ModelStructure.SKIM_PERIOD_INDICES.length; + + public static final float NA = -999; + public static final int WTW = 0; + public static final int WTD = 1; + public static final int DTW = 2; + public static final int[] ACC_EGR = {WTW,WTD,DTW}; + public static final int NUM_ACC_EGR = ACC_EGR.length; + public static final String[] ACC_EGR_STRING = {"WTW","WTD","DTW"}; + + // seek and trace + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + protected Tracer tracer; + + private TazDataManager tazManager; + private TapDataManager tapManager; + private MgraDataManager mgraManager; + + private int maxMgra; + private int maxTap; + private int maxTaz; + + // piece-wise utilities are being computed + private UtilityExpressionCalculator walkAccessUEC; + private UtilityExpressionCalculator walkEgressUEC; + private UtilityExpressionCalculator driveAccessUEC; + private UtilityExpressionCalculator driveEgressUEC; + private UtilityExpressionCalculator tapToTapUEC; + private UtilityExpressionCalculator driveAccDisutilityUEC; + private UtilityExpressionCalculator driveEgrDisutilityUEC; + + private static final String TAPS_SKIM = "taps.skim"; + private static final String TAPS_SKIM_DIST = "taps.skim.dist"; + + + // utility data cache for each transit path segment + private StoredUtilityData storedDataObject; //Encapsulates data shared by the BestTransitPathCalculator objects created for each hh choice model object + // note that access/egress utilities are independent of transit skim set + private float[][] storedWalkAccessUtils; // references StoredUtilityData.storedWalkAccessUtils + private float[][] storedDriveAccessUtils;// references StoredUtilityData.storedDriveAccessUtils + private float[][] storedWalkEgressUtils; // references StoredUtilityData.storedWalkEgressUtils + private float[][] storedDriveEgressUtils;// references StoredUtilityData.storedDriveEgressUtils + private HashMap>> storedDepartPeriodTapTapUtils; //references StoredUtilityData.storedDepartPeriodTapTapUtils + + private IndexValues index = new IndexValues(); + + // arrays storing information about the n (array length) best paths + private double[] bestUtilities; + private double[] bestAccessUtilities; + private double[] bestEgressUtilities; + private int[] bestPTap; + private int[] bestATap; + private int[] bestSet; //since two of the best paths can be in the same set, need to store set as well + + private int numSkimSets; + private int numTransitAlts; + private int[] maxLogsumUtilitiesBySkimSet; //maximum number of utilities for each skims set in logsum calcs + private int[] utilityCount; //counter for utilities + private double[] expUtilities; //exponentiated utility array for path choice + + private double nestingCoefficient; + private static double WORST_UTILITY = -500; + + /** + * Constructor. + * + * @param rbMap HashMap + * @param UECFileName The path/name of the UEC containing the walk-transit model. + * @param modelSheet The sheet (0-indexed) containing the model specification. + * @param dataSheet The sheet (0-indexed) containing the data specification. + */ + public BestTransitPathCalculator(HashMap rbMap) + { + + // read in resource bundle properties + trace = Util.getBooleanValueFromPropertyMap(rbMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.dtaz"); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if ( trace ) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + + + String uecPath = Util.getStringValueFromPropertyMap(rbMap,CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = Paths.get(uecPath,rbMap.get("utility.bestTransitPath.uec.file")).toString(); + + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, + "utility.bestTransitPath.data.page"); + + int walkAccessPage = Util.getIntegerValueFromPropertyMap(rbMap, + "utility.bestTransitPath.walkAccess.page"); + int driveAccessPage = Util.getIntegerValueFromPropertyMap(rbMap, + "utility.bestTransitPath.driveAccess.page"); + int walkEgressPage = Util.getIntegerValueFromPropertyMap(rbMap, + "utility.bestTransitPath.walkEgress.page"); + int driveEgressPage = Util.getIntegerValueFromPropertyMap(rbMap, + "utility.bestTransitPath.driveEgress.page"); + int tapToTapPage = Util.getIntegerValueFromPropertyMap( rbMap, + "utility.bestTransitPath.tapToTap.page" ); + int driveAccDisutilityPage = Util.getIntegerValueFromPropertyMap( rbMap, + "utility.bestTransitPath.driveAccDisutility.page" ); + int driveEgrDisutilityPage = Util.getIntegerValueFromPropertyMap( rbMap, + "utility.bestTransitPath.driveEgrDisutility.page" ); + + + File uecFile = new File(uecFileName); + walkAccessUEC = createUEC(uecFile, walkAccessPage, dataPage, rbMap, new TransitWalkAccessDMU()); + driveAccessUEC = createUEC(uecFile, driveAccessPage, dataPage, rbMap, new TransitDriveAccessDMU()); + walkEgressUEC = createUEC(uecFile, walkEgressPage, dataPage, rbMap, new TransitWalkAccessDMU()); + driveEgressUEC = createUEC(uecFile, driveEgressPage, dataPage, rbMap, new TransitDriveAccessDMU()); + tapToTapUEC = createUEC(uecFile, tapToTapPage, dataPage, rbMap, new TransitWalkAccessDMU()); + driveAccDisutilityUEC = createUEC(uecFile, driveAccDisutilityPage, dataPage, rbMap, new TransitDriveAccessDMU()); + driveEgrDisutilityUEC = createUEC(uecFile, driveEgrDisutilityPage, dataPage, rbMap, new TransitDriveAccessDMU()); + + mgraManager = MgraDataManager.getInstance(rbMap); + tazManager = TazDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + + maxMgra = mgraManager.getMaxMgra(); + maxTap = mgraManager.getMaxTap(); + maxTaz = tazManager.getMaxTaz(); + + // these arrays are shared by the BestTransitPathCalculator objects created for each hh choice model object + storedDataObject = StoredUtilityData.getInstance( maxMgra, maxTap, maxTaz, ACC_EGR, ModelStructure.PERIODCODES); + storedWalkAccessUtils = storedDataObject.getStoredWalkAccessUtils(); + storedDriveAccessUtils = storedDataObject.getStoredDriveAccessUtils(); + storedWalkEgressUtils = storedDataObject.getStoredWalkEgressUtils(); + storedDriveEgressUtils = storedDataObject.getStoredDriveEgressUtils(); + storedDepartPeriodTapTapUtils = storedDataObject.getStoredDepartPeriodTapTapUtils(); + + //setup arrays + numSkimSets = Util.getIntegerValueFromPropertyMap( rbMap, "utility.bestTransitPath.skim.sets" ); + numTransitAlts = Util.getIntegerValueFromPropertyMap( rbMap, "utility.bestTransitPath.alts" ); + + bestUtilities = new double[numTransitAlts]; + bestPTap = new int[numTransitAlts]; + bestATap = new int[numTransitAlts]; + bestSet = new int[numTransitAlts]; + maxLogsumUtilitiesBySkimSet = Util.getIntegerArrayFromPropertyMap(rbMap, "utility.bestTransitPath.maxPathsPerSkimSetForLogsum"); + utilityCount = new int[numSkimSets]; + expUtilities = new double[numTransitAlts]; + + nestingCoefficient = new Double(Util.getStringValueFromPropertyMap(rbMap, "utility.bestTransitPath.nesting.coeff")).floatValue(); + + } + + + + /** + * This is the main method that finds the best N TAP-pairs. It + * cycles through walk TAPs at the origin end (associated with the origin MGRA) + * and alighting TAPs at the destination end (associated with the destination + * MGRA) and calculates a utility for every available alt for each TAP + * pair. It stores the N origin and destination TAP that had the best utility. + * + * @param pMgra The origin/production MGRA. + * @param aMgra The destination/attraction MGRA. + * + */ + public void findBestWalkTransitWalkTaps(TransitWalkAccessDMU walkDmu, int period, int pMgra, int aMgra, boolean debug, Logger myLogger) + { + + clearBestArrays(Double.NEGATIVE_INFINITY); + + int[] pMgraSet = mgraManager.getMgraWlkTapsDistArray()[pMgra][0]; + int[] aMgraSet = mgraManager.getMgraWlkTapsDistArray()[aMgra][0]; + + if (pMgraSet == null || aMgraSet == null) + { + return; + } + + int pTaz = mgraManager.getTaz(pMgra); + int aTaz = mgraManager.getTaz(aMgra); + + boolean writeCalculations = false; + if ((tracer.isTraceOn() && tracer.isTraceZonePair(pTaz, aTaz))|| debug) + { + writeCalculations = true; + } + + //create transit path collection + ArrayList paths = new ArrayList(); + + for (int pTap : pMgraSet) + { + + // Calculate the pMgra to pTap walk access utility values + float accUtil; + if (storedWalkAccessUtils[pMgra][pTap] == StoredUtilityData.default_utility) { + accUtil = calcWalkAccessUtility(walkDmu, pMgra, pTap, writeCalculations, myLogger); + storedWalkAccessUtils[pMgra][pTap] = accUtil; + } else { + accUtil = storedWalkAccessUtils[pMgra][pTap]; + if(writeCalculations){ + myLogger.info("Stored walk access utility from Mgra "+pMgra+" to Tap "+pTap+" is "+accUtil); + } + } + + for (int aTap : aMgraSet) + { + + // Calculate the aTap to aMgra walk egress utility values + float egrUtil; + if (storedWalkEgressUtils[aTap][aMgra] == StoredUtilityData.default_utility) { + egrUtil = calcWalkEgressUtility(walkDmu, aTap, aMgra, writeCalculations, myLogger); + storedWalkEgressUtils[aTap][aMgra] = egrUtil; + } else { + egrUtil = storedWalkEgressUtils[aTap][aMgra]; + if(writeCalculations){ + myLogger.info("Stored walk egress utility from Tap "+aTap+" to Mgra "+aMgra+" is "+egrUtil); + } + } + + // Calculate the pTap to aTap utility values + float tapTapUtil[] = new float[numSkimSets]; + if(!storedDepartPeriodTapTapUtils.get(WTW).get(period).containsKey(storedDataObject.paTapKey(pTap, aTap))) { + + //loop across number of skim sets the pTap to aTap utility values + for (int set=0; set paths = new ArrayList(); + + float[][][] tapParkingInfo = tapManager.getTapParkingInfo(); + + int[] pTapArray = tazManager.getParkRideOrKissRideTapsForZone(pTaz, accMode); + for ( int pTap : pTapArray ) + { + // Calculate the pTaz to pTap drive access utility values + float accUtil; + float accDisutil; + if (storedDriveAccessUtils[pTaz][pTap] == StoredUtilityData.default_utility) { + accUtil = calcDriveAccessUtility(driveDmu, pMgra, pTaz, pTap, accMode, writeCalculations, myLogger); + storedDriveAccessUtils[pTaz][pTap] = accUtil; + } else { + accUtil = storedDriveAccessUtils[pTaz][pTap]; + if(writeCalculations) + myLogger.info("Stored drive access utility from TAZ "+pTaz+" to Tap "+pTap+" is "+accUtil); + } + + + int lotID = (int)tapParkingInfo[pTap][0][0]; // lot ID + float lotCapacity = tapParkingInfo[pTap][2][0]; // lot capacity + + if ((accMode == AccessMode.PARK_N_RIDE && tapManager.getLotUse(lotID) < lotCapacity) + || (accMode == AccessMode.KISS_N_RIDE)) + { + + //always calculate the access disutility since it changes based on od + accDisutil = calcDriveAccessRatioDisutility(driveDmu, pMgra, pTaz, pTap, odDistance, accMode, writeCalculations, myLogger); + + for (int aTap : mgraManager.getMgraWlkTapsDistArray()[aMgra][0]) + { + + // Calculate the aTap to aMgra walk egress utility values + float egrUtil; + if (storedWalkEgressUtils[aTap][aMgra] == StoredUtilityData.default_utility) { + egrUtil = calcWalkEgressUtility(walkDmu, aTap, aMgra, writeCalculations, myLogger); + storedWalkEgressUtils[aTap][aMgra] = egrUtil; + } else { + egrUtil = storedWalkEgressUtils[aTap][aMgra]; + if(writeCalculations){ + myLogger.info("Stored walk egress utility from Tap "+aTap+" to Mgra "+aMgra+" is "+egrUtil); + } + } + // Calculate the pTap to aTap utility values + float tapTapUtil[] = new float[numSkimSets]; + if(!storedDepartPeriodTapTapUtils.get(DTW).get(period).containsKey(storedDataObject.paTapKey(pTap, aTap))) { + + //loop across number of skim sets the pTap to aTap utility values + for (int set=0; set paths = new ArrayList(); + + for (int pTap : mgraManager.getMgraWlkTapsDistArray()[pMgra][0]) + { + // Calculate the pMgra to pTap walk access utility values + float accUtil; + if (storedWalkAccessUtils[pMgra][pTap] == StoredUtilityData.default_utility) { + accUtil = calcWalkAccessUtility(walkDmu, pMgra, pTap, writeCalculations, myLogger); + storedWalkAccessUtils[pMgra][pTap] = accUtil; + } else { + accUtil = storedWalkAccessUtils[pMgra][pTap]; + if(writeCalculations){ + myLogger.info("Stored walk access utility from Mgra "+pMgra+" to Tap "+pTap+" is "+accUtil); + } + } + for (int aTap : tazManager.getParkRideOrKissRideTapsForZone(aTaz, accMode)) + { + + int lotID = (int) tapManager.getTapParkingInfo()[aTap][0][0]; // lot + // ID + float lotCapacity = tapManager.getTapParkingInfo()[aTap][2][0]; // lot + // capacity + if ((accMode == AccessMode.PARK_N_RIDE && tapManager.getLotUse(lotID) < lotCapacity) + || (accMode == AccessMode.KISS_N_RIDE)) + { + + // Calculate the aTap to aMgra drive egress utility values + float egrUtil; + float egrDisutil; + if (storedDriveEgressUtils[aTap][aTaz] == StoredUtilityData.default_utility) { + egrUtil = calcDriveEgressUtility(driveDmu, aTap, aTaz, aMgra, accMode, writeCalculations, myLogger); + storedDriveEgressUtils[aTap][aTaz] = egrUtil; + } else { + egrUtil = storedDriveEgressUtils[aTap][aTaz]; + if(writeCalculations){ + myLogger.info("Stored drive egress utility from Tap "+aTap+" to TAZ "+aTaz+" is "+egrUtil); + } + } + + //always calculate the access disutility since it changes based on od + egrDisutil = calcDriveEgressRatioDisutility(driveDmu, aTap, aMgra, aTaz, odDistance, accMode, writeCalculations, myLogger); + + // Calculate the pTap to aTap utility values + float tapTapUtil[] = new float[numSkimSets]; + if(!storedDepartPeriodTapTapUtils.get(WTD).get(period).containsKey(storedDataObject.paTapKey(pTap, aTap))) { + + //loop across number of skim sets the pTap to aTap utility values + for (int set=0; set paths Collection of paths + */ + public void trimPaths(ArrayList paths) + { + + //sort paths by total utility in reverse order to get highest utility first + Collections.sort(paths, Collections.reverseOrder()); + + //get best N paths + int count = 0; + for(TransitPath path : paths) { + + if (path.getTotalUtility() > NA) { + + //get data + bestUtilities[count] = path.getTotalUtility(); + bestPTap[count] = path.pTap; + bestATap[count] = path.aTap; + bestSet[count] = path.set; + + count = count + 1; + if(count == numTransitAlts) { + break; + } + } + } + } + + public float calcPathUtility(TransitWalkAccessDMU walkDmu, TransitDriveAccessDMU driveDmu, int accEgr, int period, int origMgra, int pTap, int aTap, int destMgra, int set, boolean myTrace, Logger myLogger, float odDistance) { + + float accUtil =NA; + float egrUtil =NA; + float tapTapUtil =NA; + float accDisutil =0f; + float egrDisutil =0f; + + + if(accEgr==WTW) { + accUtil = calcWalkAccessUtility(walkDmu, origMgra, pTap, myTrace, myLogger); + egrUtil = calcWalkEgressUtility(walkDmu, aTap, destMgra, myTrace, myLogger); + tapTapUtil = calcUtilitiesForTapPair(walkDmu, period, WTW, pTap, aTap, set, origMgra, destMgra, myTrace, myLogger); + } else if(accEgr==WTD) { + int aTaz = mgraManager.getTaz(destMgra); + AccessMode accMode = AccessMode.PARK_N_RIDE; + accUtil = calcWalkAccessUtility(walkDmu, origMgra, pTap, myTrace, myLogger); + egrUtil = calcDriveEgressUtility(driveDmu, aTap, aTaz, destMgra, accMode, myTrace, myLogger); + egrDisutil = calcDriveEgressRatioDisutility(driveDmu, aTap, destMgra,aTaz, odDistance, accMode, myTrace, myLogger); + tapTapUtil = calcUtilitiesForTapPair(walkDmu, period, WTD, pTap, aTap, set, origMgra, destMgra, myTrace, myLogger); + } else if(accEgr==DTW) { + int pTaz = mgraManager.getTaz(origMgra); + AccessMode accMode = AccessMode.PARK_N_RIDE; + accUtil = calcDriveAccessUtility(driveDmu, origMgra, pTaz, pTap, accMode, myTrace, myLogger); + accDisutil = calcDriveAccessRatioDisutility(driveDmu, origMgra, pTaz, pTap, odDistance, accMode, myTrace, myLogger); + egrUtil = calcWalkEgressUtility(walkDmu, aTap, destMgra, myTrace, myLogger); + tapTapUtil = calcUtilitiesForTapPair(walkDmu, period, DTW, pTap, aTap, set, origMgra, destMgra, myTrace, myLogger); + } + return(accUtil + tapTapUtil + egrUtil + accDisutil + egrDisutil); + } + + /** + * Return the array of transit best tap pairs for the given access/egress mode, origin MGRA, + * destination MGRA, and departure time period. + * + * @param TransitWalkAccessDMU walkDmu + * @param TransitDriveAccessDMU driveDmu + * @param Modes.AccessMode accMode + * @param origMgra Origin MGRA + * @param workMgra Destination MGRA + * @param departPeriod Departure time period - 1 = AM period, 2 = PM period, 3 =OffPeak period + * @param debug boolean flag to indicate if debugging reports should be logged + * @param logger Logger to which debugging reports should be logged if debug is true + * @return double[][] Array of best tap pair values - rows are N-path, columns are orig tap, dest tap, skim set, utility + */ + public double[][] getBestTapPairs(TransitWalkAccessDMU walkDmu, TransitDriveAccessDMU driveDmu, int accMode, int origMgra, int destMgra, int departPeriod, boolean debug, Logger myLogger, float odDistance) + { + + String separator = ""; + String header = ""; + if (debug) + { + myLogger.info(""); + myLogger.info(""); + header = ACC_EGR[accMode] + " best tap pairs debug info for origMgra=" + origMgra + + ", destMgra=" + destMgra + ", period index=" + departPeriod + + ", period label=" + ModelStructure.SKIM_PERIOD_STRINGS[departPeriod]; + for (int i = 0; i < header.length(); i++) + separator += "^"; + + myLogger.info(""); + myLogger.info(separator); + myLogger.info("Calculating " + header); + } + + double[][] bestTaps = null; + + if(accMode==WTW) { + findBestWalkTransitWalkTaps(walkDmu, departPeriod, origMgra, destMgra, debug, myLogger); + } else if(accMode==DTW) { + findBestDriveTransitWalkTaps(walkDmu, driveDmu, departPeriod, origMgra, destMgra, debug, myLogger, odDistance); + } else if(accMode==WTD) { + findBestWalkTransitDriveTaps(walkDmu, driveDmu, departPeriod, origMgra, destMgra, debug, myLogger, odDistance); + } + + // get and log the best tap-tap utilities by alt + double[] bestUtilities = getBestUtilities(); + bestTaps = new double[bestUtilities.length][]; + + for (int i = 0; i < bestUtilities.length; i++) + { + //only initialize tap data if valid; otherwise null array + if (bestUtilities[i] > NA) bestTaps[i] = getBestTaps(i); + } + + // log the best utilities and tap pairs for each alt + if (debug) + { + myLogger.info(""); + myLogger.info(separator); + myLogger.info(header); + myLogger.info("Final Best Utilities:"); + myLogger.info("Alt, Alt, Utility, bestITap, bestJTap, bestSet"); + for (int i = 0; i < bestUtilities.length; i++) + { + myLogger.info(i + "," + i + "," + bestUtilities[i] + "," + + (bestTaps[i] == null ? "NA" : bestTaps[i][0]) + "," + + (bestTaps[i] == null ? "NA" : bestTaps[i][1]) + "," + + (bestTaps[i] == null ? "NA" : bestTaps[i][2])); + } + + myLogger.info(separator); + } + return bestTaps; + } + + /** + * Calculate utilities for the best tap pairs using person specific attributes. + * + * @param double[][] bestTapPairs + * @param TransitWalkAccessDMU walkDmu + * @param TransitDriveAccessDMU driveDmu + * @param Modes.AccessMode accMode + * @param origMgra Origin MGRA + * @param workMgra Destination MGRA + * @param departPeriod Departure time period - 1 = AM period, 2 = PM period, 3 =OffPeak period + * @param debug boolean flag to indicate if debugging reports should be logged + * @param logger Logger to which debugging reports should be logged if debug is true + * @return double[][] Array of best tap pair values - rows are N-path, columns are orig tap, dest tap, skim set, utility + */ + public double[][] calcPersonSpecificUtilities(double[][] bestTapPairs, TransitWalkAccessDMU walkDmu, TransitDriveAccessDMU driveDmu, int accMode, int origMgra, int destMgra, int departPeriod, boolean debug, Logger myLogger, float odDistance) + { + + String separator = ""; + String header = ""; + if (debug) + { + myLogger.info(""); + myLogger.info(""); + header = accMode + " best tap pairs person specific utility info for origMgra=" + origMgra + + ", destMgra=" + destMgra + ", period index=" + departPeriod + + ", period label=" + ModelStructure.SKIM_PERIOD_STRINGS[departPeriod]; + for (int i = 0; i < header.length(); i++) + separator += "^"; + + myLogger.info(""); + myLogger.info(separator); + myLogger.info("Calculating " + header); + } + + //re-calculate utilities + for (int i = 0; i < bestTapPairs.length; i++) { + if (bestTapPairs[i] != null) { + int pTap = (int)bestTapPairs[i][0]; + int aTap = (int)bestTapPairs[i][1]; + int set = (int)bestTapPairs[i][2]; + double utility = calcPathUtility(walkDmu, driveDmu, accMode, departPeriod, origMgra, pTap, aTap, destMgra, set, debug, myLogger, odDistance); + bestTapPairs[i][3] = utility; + } + } + + // log the best utilities and tap pairs for each alt + if (debug) + { + myLogger.info(""); + myLogger.info(separator); + myLogger.info(header); + myLogger.info("Final Person Specific Best Utilities:"); + myLogger.info("Alt, Alt, Utility, bestITap, bestJTap, bestSet"); + int availableModeCount = 0; + for (int i = 0; i < bestUtilities.length; i++) + { + if (bestTapPairs[i] != null) availableModeCount++; + + myLogger.info(i + "," + i + "," + + (bestTapPairs[i] == null ? "NA" : bestTapPairs[i][3]) + "," + + (bestTapPairs[i] == null ? "NA" : bestTapPairs[i][0]) + "," + + (bestTapPairs[i] == null ? "NA" : bestTapPairs[i][1]) + "," + + (bestTapPairs[i] == null ? "NA" : bestTapPairs[i][2])); + } + + myLogger.info(separator); + } + return bestTapPairs; + } + + /* + private LogitModel setupTripLogSum(double[][] bestTapPairs, boolean myTrace, Logger myLogger) { + + //must size logit model ahead of time + int alts = 0; + for (int i=0; i0){ + double cumProb=0; + //re-iterate through paths and calculate probability, choose alternative based on rnum + for(int i = 0; i0) + logsum = Math.log(sumExpUtility); + return logsum; + } + + /** + * Get the best path logsum, subject to constraints. The constraints + * are that the logsum only include a certain number of paths for each + * skim set, as defined in the property utility.bestTransitPath.maxPathsPerSkimSetForLogsum. + * This allows the logsum + * to reduce or eliminate path overlap should any exist in the path set, without having + * access to actual route data in the utility calculation. Transit trips + * are still subject to choice across all paths in the best utility set. + * + * @return The constrained transit logsum. + */ + public double getTransitBestPathLogsum(double[][] bestTapPairs, boolean myTrace, Logger myLogger){ + + double logsum = NA; + double sumExpUtility = getSumExpUtilities(bestTapPairs, myTrace, myLogger); + if(sumExpUtility>0.0) + logsum = Math.log(sumExpUtility); + + if(myTrace) + myLogger.info("Best Transit Path Logsum "+logsum); + return logsum; + } + + + /** + * Get the sum of exponentiated utilities, subject to constraints. The constraints + * are that the sum only include a certain number of paths for each + * skim set, as defined in the property utility.bestTransitPath.maxPathsPerSkimSetForLogsum. + * to reduce or eliminate path overlap should any exist in the path set, without having + * access to actual route data in the utility calculation. Transit trips + * are still subject to choice across all paths in the best utility set. + * + * @param bestTapPairs The tap pairs to calculate the sum exponentiated utility over + * @param myTrace Trace calculations + * @param myLogger The logger to write tracing to + * + * @return The constrained sum of exponentiated utilities. + */ + public double getSumExpUtilities(double[][] bestTapPairs, boolean myTrace, Logger myLogger){ + double sumExpUtility=0; + + if(myTrace){ + myLogger.info("Calculating sum of exponentiated utilities for transit best TAP pairs"); + myLogger.info("Best_Path Utility Skim_Set Included? ExpUtility Sum"); + } + + //utilityCount tracks how many utilities included in logsum calc by skimset + Arrays.fill(utilityCount,0); + for(int i = 0; i WORST_UTILITY){ + int skimSet = bestSet[i]; + + //only include the utility in the logsum if the count + //by skimset hasn't been met yet. + if(utilityCount[skimSet] rbMap, VariableTable dmu) + { + return new UtilityExpressionCalculator(uecSpreadsheet, modelSheet, dataSheet, rbMap, dmu); + } + + /** + * Clears the arrays. This method gets called for two different purposes. One is + * to compare alternatives based on utilities and the other based on + * exponentiated utilities. For this reason, the bestUtilities will be + * initialized by the value passed in as an argument set by the calling method. + * + * @param initialization value + */ + public void clearBestArrays(double initialValue) + { + Arrays.fill(bestUtilities, initialValue); + Arrays.fill(bestPTap, 0); + Arrays.fill(bestATap, 0); + Arrays.fill(bestSet, 0); + } + + /** + * Get the best ptap, atap, and skim set in an array. Only to be called after trimPaths() has been called. + * + * @param alt. + * @return element 0 = best ptap, element 1 = best atap, element 2 = set, element 3= utility + */ + public double[] getBestTaps(int alt) + { + + double[] bestTaps = new double[4]; + + bestTaps[0] = bestPTap[alt]; + bestTaps[1] = bestATap[alt]; + bestTaps[2] = bestSet[alt]; + bestTaps[3] = bestUtilities[alt]; + + return bestTaps; + } + + /** + * Get the best transit alt. Returns null if no transit alt has a valid utility. + * Call only after calling findBestWalkTransitWalkTaps(). + * + * @return The best transit alt (highest utility), or null if no alt have a valid utility. + */ + public int getBestTransitAlt() + { + + int best = -1; + double bestUtility = Double.NEGATIVE_INFINITY; + for (int i = 0; i < bestUtilities.length; ++i) + { + if (bestUtilities[i] > bestUtility) { + best = i; + bestUtility = bestUtilities[i]; + } + } + + int returnSet = best; + if (best > -1) { + returnSet = best; + } + return returnSet; + } + + + /** + * This method writes the utilities for all TAP-pairs for each ride mode. + * It cycles through walk TAPs at the origin end (associated with the origin + * MGRA) and alighting TAPs at the destination end (associated with the + * destination MGRA) and calculates a utility for every available ride mode + * for each TAP pair and writes the result to the outwriter. + * + * The results written will be as follows: + * label,WTW,period,pTap,aTap,mode,combinedUtilities[mode] + * + * @param period The time period (AM, PM, Off) + * @param pMgra + * The origin/production MGRA. + * @param aMgra + * The destination/attraction MGRA. + * @param myLogger A logger for logging problems + * @param outwriter A printwriter for writing results + * @param label A label for the record. + */ + public void writeAllWalkTransitWalkTaps(int period, int pMgra, int aMgra, Logger myLogger, PrintWriter outwriter, String label) + { + + //TODO: Fix this + + /* + + clearBestArrays(Double.NEGATIVE_INFINITY); + + int[] pMgraSet = mgraManager.getMgraWlkTapsDistArray()[pMgra][0]; + int[] aMgraSet = mgraManager.getMgraWlkTapsDistArray()[aMgra][0]; + + if (pMgraSet == null || aMgraSet == null) + { + return; + } + + int pPos = -1; + for (int pTap : pMgraSet) + { + // used to know where we are in time/dist arrays for taps + pPos++; + + // Set the pMgra to pTap walk access utility values, if they haven't + // already been computed. + setWalkAccessUtility(pMgra, pPos, pTap, false, myLogger); + + int aPos = -1; + for (int aTap : aMgraSet) + { + // used to know where we are in time/dist arrays for taps + aPos++; + + // set the pTap to aTap utility values, if they haven't already + // been computed. + setUtilitiesForTapPair(WTW, period, pTap, aTap, false, myLogger); + + // Set the aTap to aMgra walk egress utility values, if they + // haven't already been computed. + setWalkEgressUtility(aTap, aMgra, aPos, false, myLogger); + + // write the utilities for each ride mode + try + { + for (int i = 0; i < combinedUtilities.length; i++){ + combinedUtilities[i] = storedWalkAccessUtils[pMgra][pTap][i] + + storedTapToTapUtils[WTW][period][pTap][aTap][i] + + storedWalkEgressUtils[aTap][aMgra][i]; + + if(combinedUtilities[i]>-500){ + outwriter.print(label); + outwriter.format(",%d,%d,%d,%d,%d,%9.4f\n",WTW,period,pTap,aTap,i,combinedUtilities[i]); + } + } + } catch (Exception e) + { + logger.error("exception computing combinedUtilities for WTW"); + logger.error("aTap=" + aTap + "pTap=" + pTap + "aMgra=" + aMgra + "pMgra=" + + pMgra + "period=" + period, e); + throw new RuntimeException(); + } + + + + } + } + */ + } + + /** + * This method writes all TAP-pairs for each ride mode. It cycles + * through drive access TAPs at the origin end (associated with the origin + * MGRA) and alighting TAPs at the destination end (associated with the + * destination MGRA) and calculates a utility for every available ride mode + * for each TAP pair. + * The results written will be as follows: + * + * label,DTW,period,pTap,aTap,mode,combinedUtilities[mode] + * + * @param period The time period (AM, PM, Off) + * @param pMgra + * The origin/production MGRA. + * @param aMgra + * The destination/attraction MGRA. + * @param myLogger A logger for logging problems + * @param outwriter A printwriter for writing results + * @param label A label for the record. + * + */ + public void writeAllDriveTransitWalkTaps(int period, int pMgra, int aMgra, + Logger myLogger, PrintWriter outwriter, String label) + { + + // TODO: Fix this + + /* + + clearBestArrays(Double.NEGATIVE_INFINITY); + + Modes.AccessMode accMode = AccessMode.PARK_N_RIDE; + + int pTaz = mgraManager.getTaz(pMgra); + + if (tazManager.getParkRideOrKissRideTapsForZone(pTaz, accMode) == null + || mgraManager.getMgraWlkTapsDistArray()[aMgra][0] == null) + { + return; + } + + float[][][] tapParkingInfo = tapManager.getTapParkingInfo(); + + int pPos = -1; + int[] pTapArray = tazManager.getParkRideOrKissRideTapsForZone(pTaz, accMode); + for (int pTap : pTapArray) + { + pPos++; // used to know where we are in time/dist arrays for taps + + // Set the pTaz to pTap drive access utility values, if they haven't + // already been computed. + setDriveAccessUtility(pTaz, pPos, pTap, accMode, false, myLogger); + + int lotID = (int) tapParkingInfo[pTap][0][0]; // lot ID + float lotCapacity = tapParkingInfo[pTap][2][0]; // lot capacity + + if ((accMode == AccessMode.PARK_N_RIDE && tapManager.getLotUse(lotID) < lotCapacity) + || (accMode == AccessMode.KISS_N_RIDE)) + { + + int aPos = -1; + for (int aTap : mgraManager.getMgraWlkTapsDistArray()[aMgra][0]) + { + aPos++; + + // Set the aTap to aMgra walk egress utility values, if they + // haven't already been computed. + setWalkEgressUtility(aTap, aMgra, aPos, false, myLogger); + + + // set the pTap to aTap utility values, if they haven't + // already been computed. + setUtilitiesForTapPair(DTW, period, pTap, aTap, false, myLogger); + + // compare the utilities for this TAP pair to previously + // calculated utilities for each ride mode and store the TAP numbers if + // this TAP pair is the best. + try + { + for (int i = 0; i < combinedUtilities.length; i++){ + combinedUtilities[i] = storedDriveAccessUtils[pTaz][pTap][i] + + storedTapToTapUtils[DTW][period][pTap][aTap][i] + + storedWalkEgressUtils[aTap][aMgra][i]; + if(combinedUtilities[i]>-500){ + outwriter.print(label); + outwriter.format(",%d,%d,%d,%d,%d,%9.4f\n",DTW,period,pTap,aTap,i,combinedUtilities[i]); + } + } + } catch (Exception e) + { + logger.error("exception computing combinedUtilities for DTW"); + logger.error("aTap=" + aTap + ",pTap=" + pTap + ",aMgra=" + aMgra + + ",pMgra=" + pMgra + ",period=" + period, e); + throw new RuntimeException(); + } + + } + } + + } + */ + } + + /** + * This method finds the best TAP-pairs for each ride mode. It cycles + * through drive access TAPs at the origin end (associated with the origin + * MGRA) and alighting TAPs at the destination end (associated with the + * destination MGRA) and calculates a utility for every available ride mode + * for each TAP pair. + * The results written will be as follows: + * + * label,WTD,period,pTap,aTap,mode,combinedUtilities[mode] + * + * @param period The time period (AM, PM, Off) + * @param pMgra + * The origin/production MGRA. + * @param aMgra + * The destination/attraction MGRA. + * @param myLogger A logger for logging problems + * @param outwriter A printwriter for writing results + * @param label A label for the record. + + * + */ + public void writeAllWalkTransitDriveTaps(int period, int pMgra, int aMgra, + Logger myLogger, PrintWriter outwriter, String label) + { + + // TODO: Fix this + + /* + clearBestArrays(Double.NEGATIVE_INFINITY); + + Modes.AccessMode accMode = AccessMode.PARK_N_RIDE; + + int aTaz = mgraManager.getTaz(aMgra); + + if (mgraManager.getMgraWlkTapsDistArray()[pMgra][0] == null + || tazManager.getParkRideOrKissRideTapsForZone(aTaz, accMode) == null) + { + return; + } + + int pPos = -1; + for (int pTap : mgraManager.getMgraWlkTapsDistArray()[pMgra][0]) + { + pPos++; // used to know where we are in time/dist arrays for taps + + // Set the pMgra to pTap walk access utility values, if they haven't + // already been computed. + setWalkAccessUtility(pMgra, pPos, pTap, false, myLogger); + + int aPos = -1; + for (int aTap : tazManager.getParkRideOrKissRideTapsForZone(aTaz, accMode)) + { + aPos++; + + int lotID = (int) tapManager.getTapParkingInfo()[aTap][0][0]; // lot + // ID + float lotCapacity = tapManager.getTapParkingInfo()[aTap][2][0]; // lot + // capacity + if ((accMode == AccessMode.PARK_N_RIDE && tapManager.getLotUse(lotID) < lotCapacity) + || (accMode == AccessMode.KISS_N_RIDE)) + { + + // Set the pTaz to pTap drive access utility values, if they + // haven't already been computed. + setDriveEgressUtility(aTap, aTaz, aPos, accMode, false, myLogger); + + // set the pTap to aTap utility values, if they haven't + // already + // been computed. + setUtilitiesForTapPair(WTD, period, pTap, aTap, false, myLogger); + + // compare the utilities for this TAP pair to previously + // calculated utilities for each ride mode and store the TAP numbers if + // this TAP pair is the best. + try + { + for (int i = 0; i < combinedUtilities.length; i++){ + combinedUtilities[i] = storedWalkAccessUtils[pMgra][pTap][i] + + storedTapToTapUtils[WTD][period][pTap][aTap][i] + + storedDriveEgressUtils[aTap][aTaz][i]; + if(combinedUtilities[i]>-500){ + outwriter.print(label); + outwriter.format(",%d,%d,%d,%d,%d,%9.4f\n",WTD,period,pTap,aTap,i,combinedUtilities[i]); + } + } + } catch (Exception e) + { + logger.error("exception computing combinedUtilities for WTD"); + logger.error("aTap=" + aTap + ",pTap=" + pTap + ",aMgra=" + aMgra + + ",pMgra=" + pMgra + ",period=" + period, e); + throw new RuntimeException(); + } + + } + } + + } + */ + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/BuildAccessibilities.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/BuildAccessibilities.java new file mode 100644 index 0000000..ae7c5da --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/BuildAccessibilities.java @@ -0,0 +1,1534 @@ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.IndexValues; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + +/** + * This class builds accessibility components for all modes. + * + * @author Joel Freedman + * @version May, 2009 + */ +public final class BuildAccessibilities + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(BuildAccessibilities.class); + + /* + * OLD names private static final String[] WORK_OCCUP_SEGMENT_NAME_LIST = { + * "White Collar", "Services", "Health", "Retail and Food", "Blue Collar", + * "Military" }; private static final int[] WORK_OCCUP_SEGMENT_VALUE_LIST = + * { 71, 72,74, 75, 76, 77 }; + */ + private static final String[] WORK_OCCUP_SEGMENT_NAME_LIST = { + "Management Business Science and Arts", "Services", "Sales and Office", + "Natural Resources Construction and Maintenance", + "Production Transportation and Material Moving", "Military" }; + private static final int[] WORK_OCCUP_SEGMENT_VALUE_LIST = {50, 51, 53, + 54, 55, 56 }; + + // these segment group labels and indices are used for creating all the + // school location choice segments + public static final String[] SCHOOL_DC_SIZE_SEGMENT_NAME_LIST = {"preschool", + "k-8", "unified k-8", "9-12", "unified 9-12", "univ typical", "univ non-typical"}; + public static final int PRESCHOOL_SEGMENT_GROUP_INDEX = 0; + public static final int GRADE_SCHOOL_SEGMENT_GROUP_INDEX = 1; + public static final int UNIFIED_GRADE_SCHOOL_SEGMENT_GROUP_INDEX = 2; + public static final int HIGH_SCHOOL_SEGMENT_GROUP_INDEX = 3; + public static final int UNIFIED_HIGH_SCHOOL_SEGMENT_GROUP_INDEX = 4; + public static final int UNIV_TYPICAL_SEGMENT_GROUP_INDEX = 5; + public static final int UNIV_NONTYPICAL_SEGMENT_GROUP_INDEX = 6; + + private static final int UNIFIED_DISTRICT_OFFSET = 1000000; + + // these indices define the alternative numbers and size term calculation + // indices + public static final int PRESCHOOL_ALT_INDEX = 0; + public static final int GRADE_SCHOOL_ALT_INDEX = 1; + public static final int HIGH_SCHOOL_ALT_INDEX = 2; + public static final int UNIV_TYPICAL_ALT_INDEX = 3; + public static final int UNIV_NONTYPICAL_ALT_INDEX = 4; + + // school segments: preschool, grade school, high school, university + // typical, university non-typical + private static final int[] SCHOOL_LOC_SEGMENT_TO_UEC_SHEET_INDEX = {3, 4, 5, 6, 6}; + private static final int[] SCHOOL_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX = {5, 4, 3, 2, 2}; + private static final int[] SCHOOL_SEGMENT_TO_STF_UEC_SHEET_INDEX = {3, 3, 3, 2, 2}; + + // MAX_LUZ is the largest LUZ value, including external LUZs. + public static final int MAX_LUZ = 236; + + // using trip mode choice IVT coefficient value + public static final double TIME_COEFFICIENT = -0.032; + + public static final int[] EXTERNAL_LUZS = {230, 231, 232, + 233, 234, 235, 236 }; + + public static final int[] EXTERNAL_LUZ_CORDON_LUZS = {156, 156, 213, + 157, 122, 156, 156 }; + + public static final int[] MINUTES_TO_ADD_TO_CORDON_FOR_EXTERNAL_LUZ = {105, 480, + 1800, 1740, 155, 8160, 8760 }; + + public static final int[] CORDON_LUZS = {122, 156, 157, + 213 }; + + public static final int[][] EXTERNAL_LUZS_FOR_CORDON_LUZ = { {234}, + {230, 231, 235, 236}, {233}, {232} }; + + // in the LU logsums array, 1st dimension is averaging type, 2nd is pk or + // op, 3rd is auto sufficiency segment, 4th is orig LUZ, 5th is dest LUZ. + public static final int SIMPLE = 0; + public static final int LOGIT = 1; + public static final int PK = 0; + public static final int OP = 1; + public static final int LS0 = 0; + public static final int LS1 = 1; + public static final int LS2 = 2; + + private int[][] externalLuzsForCordonLuz; + private int[] cordonLuzForExternalLuz; + private int[] cordonLuzMinutesForExternalLuz; + + public static final int NUM_AVG_METHODS = 2; + public static final int NUM_PERIODS = 2; + public static final int NUM_SUFFICIENCY_SEGMENTS = 3; + + private static BuildAccessibilities objInstance = null; + + private int[] nonUniversitySegments; + private int[] universitySegments; + + private int univTypicalSegment; + private int univNonTypicalSegment; + + private int[] mgraGsDistrict; + private int[] mgraHsDistrict; + private HashMap gsDistrictIndexMap = new HashMap(); + private HashMap hsDistrictIndexMap = new HashMap(); + + private String[] schoolSegmentSizeNames; + private int[] schoolDcSoaUecSheets; + private int[] schoolDcUecSheets; + private int[] schoolStfUecSheets; + + // a set of school segment indices for which shadow pricing is not done - + // currently includes pre-school segment only. + private HashSet noShadowPriceSchoolSegmentIndices; + + private HashMap psSegmentIndexNameMap; + private HashMap psSegmentNameIndexMap; + private HashMap gsSegmentIndexNameMap; + private HashMap gsSegmentNameIndexMap; + private HashMap hsSegmentIndexNameMap; + private HashMap hsSegmentNameIndexMap; + private HashMap univTypSegmentIndexNameMap; + private HashMap univTypSegmentNameIndexMap; + private HashMap univNonTypSegmentIndexNameMap; + private HashMap univNonTypSegmentNameIndexMap; + + private HashMap schoolSegmentIndexNameMap; + private HashMap schoolSegmentNameIndexMap; + + private HashMap workSegmentIndexNameMap; + private HashMap workSegmentNameIndexMap; + + public static final int TOTAL_LOGSUM_FIELD_NUMBER = 13; + + private static int numThreads = 10; + private static final int DISTRIBUTED_PACKET_SIZE = 1000; + + private HashMap workerOccupValueSegmentIndexMap; + + private UtilityExpressionCalculator constantsUEC; + private UtilityExpressionCalculator sizeTermUEC; + private UtilityExpressionCalculator workerSizeTermUEC; + private UtilityExpressionCalculator schoolSizeTermUEC; + + private AccessibilitiesDMU aDmu; + + private IndexValues iv; + + private double[][][] sovExpUtilities; + private double[][][] hovExpUtilities; + private double[][][] nMotorExpUtilities; + + private MgraDataManager mgraManager; + + // purpose (defined in UEC) + private double[][] sizeTerms; // mgra, + + // indicates whether this mgra has a size term + private boolean[] hasSizeTerm; // mgra, + + // purpose (defined in UEC) + private double[][] workerSizeTerms; // mgra, + + // purpose (defined in UEC) + private double[][] schoolSizeTerms; // mgra, + + // Land Use size terms for school are not segmented by school district + private double[][] luSchoolSizeTerms; + + // auto sufficiency (0 autos, autos=adults), + // and mode (SOV,HOV,Walk-Transit,Non-Motorized) + private double[][] expConstants; + + // accessibilities by mgra, accessibility alternative + private AccessibilitiesTable accessibilitiesTableObject; + + // array for storing land use accessibility mode choice logsum values + private double[][][][][] landUseLogsums; + private int[][] landUseLogsumsCount; + private float[][] landUseAccessibilities; + + private boolean calculateLuAccessibilities; + + private static final int MARKET_SEGMENTS = 3; + + public static final int ESCORT_INDEX = 0; + public static final int SHOP_INDEX = 1; + public static final int OTH_MAINT_INDEX = 2; + public static final int EATOUT_INDEX = 3; + public static final int VISIT_INDEX = 4; + public static final int OTH_DISCR_INDEX = 5; + + private HashMap nonMandatorySizeSegmentNameIndexMap; + + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + private Tracer tracer; + private boolean seek; + + private int maxMgra; + + private boolean accessibilitiesBuilt = false; + private boolean logResults=false; + + private BuildAccessibilities() + { + } + + public static synchronized BuildAccessibilities getInstance() + { + if (objInstance == null) + { + objInstance = new BuildAccessibilities(); + objInstance.accessibilitiesBuilt = false; + return objInstance; + } else + { + objInstance.accessibilitiesBuilt = true; + return objInstance; + } + } + + public void setupBuildAccessibilities(HashMap rbMap, + boolean calculateLuAccessibilities) + { + + this.calculateLuAccessibilities = calculateLuAccessibilities; + + logResults = Util.getStringValueFromPropertyMap(rbMap, "RunModel.LogResults") + .equalsIgnoreCase("true"); + + Runtime runtime = Runtime.getRuntime(); + if (numThreads < 0) + { + int nrOfProcessors = runtime.availableProcessors(); + numThreads = nrOfProcessors; + } + + gsDistrictIndexMap = new HashMap(); + hsDistrictIndexMap = new HashMap(); + workerOccupValueSegmentIndexMap = new HashMap(); + + for (int i = 0; i < WORK_OCCUP_SEGMENT_VALUE_LIST.length; ++i) + { + workerOccupValueSegmentIndexMap.put(WORK_OCCUP_SEGMENT_VALUE_LIST[i], i); + } + aDmu = new AccessibilitiesDMU(); + + // Create the UECs + String uecFileName = Util.getStringValueFromPropertyMap(rbMap, "acc.uec.file"); + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.data.page"); + int constantsPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.constants.page"); + int sizeTermPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.sizeTerm.page"); + int workerSizeTermPage = Util.getIntegerValueFromPropertyMap(rbMap, + "acc.workerSizeTerm.page"); + int schoolSizeTermPage = Util.getIntegerValueFromPropertyMap(rbMap, + "acc.schoolSizeTerm.page"); + + File uecFile = new File(uecFileName); + constantsUEC = new UtilityExpressionCalculator(uecFile, constantsPage, dataPage, rbMap, + aDmu); + sizeTermUEC = new UtilityExpressionCalculator(uecFile, sizeTermPage, dataPage, rbMap, aDmu); + workerSizeTermUEC = new UtilityExpressionCalculator(uecFile, workerSizeTermPage, dataPage, + rbMap, aDmu); + schoolSizeTermUEC = new UtilityExpressionCalculator(uecFile, schoolSizeTermPage, dataPage, + rbMap, aDmu); + + mgraManager = MgraDataManager.getInstance(rbMap); + maxMgra = mgraManager.getMaxMgra(); + + trace = Util.getBooleanValueFromPropertyMap(rbMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.dtaz"); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + seek = Util.getBooleanValueFromPropertyMap(rbMap, "Seek"); + + iv = new IndexValues(); + + workSegmentIndexNameMap = new HashMap(); + workSegmentNameIndexMap = new HashMap(); + + noShadowPriceSchoolSegmentIndices = new HashSet(); + + schoolSegmentIndexNameMap = new HashMap(); + schoolSegmentNameIndexMap = new HashMap(); + + psSegmentIndexNameMap = new HashMap(); + psSegmentNameIndexMap = new HashMap(); + gsSegmentIndexNameMap = new HashMap(); + gsSegmentNameIndexMap = new HashMap(); + hsSegmentIndexNameMap = new HashMap(); + hsSegmentNameIndexMap = new HashMap(); + univTypSegmentIndexNameMap = new HashMap(); + univTypSegmentNameIndexMap = new HashMap(); + univNonTypSegmentIndexNameMap = new HashMap(); + univNonTypSegmentNameIndexMap = new HashMap(); + + nonMandatorySizeSegmentNameIndexMap = new HashMap(); + nonMandatorySizeSegmentNameIndexMap.put(ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME, + ESCORT_INDEX); + nonMandatorySizeSegmentNameIndexMap.put(ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME, + SHOP_INDEX); + nonMandatorySizeSegmentNameIndexMap.put(ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME, + OTH_MAINT_INDEX); + nonMandatorySizeSegmentNameIndexMap.put(ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME, + EATOUT_INDEX); + nonMandatorySizeSegmentNameIndexMap.put(ModelStructure.VISITING_PRIMARY_PURPOSE_NAME, + VISIT_INDEX); + nonMandatorySizeSegmentNameIndexMap.put(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME, + OTH_DISCR_INDEX); + + } + + + // This method is only called if the main ABM command line argument for + // calculating land use accessibilities is true + // otherwise, the array lanUseLogsums is null and serves as an indicator + // that LU accessibilities are not needed + public void setCalculatedLandUseAccessibilities() + { + + landUseLogsums = new double[NUM_AVG_METHODS][NUM_PERIODS][NUM_SUFFICIENCY_SEGMENTS][MAX_LUZ + 1][MAX_LUZ + 1]; + landUseLogsumsCount = new int[MAX_LUZ + 1][MAX_LUZ + 1]; + + int maxMgra = mgraManager.getMaxMgra(); + landUseAccessibilities = new float[maxMgra + 1][]; + + externalLuzsForCordonLuz = new int[MAX_LUZ + 1][]; + cordonLuzForExternalLuz = new int[MAX_LUZ + 1]; + cordonLuzMinutesForExternalLuz = new int[MAX_LUZ + 1]; + + // associate the array of external LUZs that belong to each cordon LUZ. + for (int i = 0; i < CORDON_LUZS.length; i++) + { + int cordonLuz = CORDON_LUZS[i]; + externalLuzsForCordonLuz[cordonLuz] = EXTERNAL_LUZS_FOR_CORDON_LUZ[i]; + } + + // associate the cordon LUZ that belongs to each external LUZ. + for (int i = 0; i < EXTERNAL_LUZS.length; i++) + { + int externalLuz = EXTERNAL_LUZS[i]; + cordonLuzForExternalLuz[externalLuz] = EXTERNAL_LUZ_CORDON_LUZS[i]; + } + + // associate the minutes to add to cordon LUZ to represent time to each + // external LUZ. + for (int i = 0; i < EXTERNAL_LUZS.length; i++) + { + int externalLuz = EXTERNAL_LUZS[i]; + cordonLuzMinutesForExternalLuz[externalLuz] = MINUTES_TO_ADD_TO_CORDON_FOR_EXTERNAL_LUZ[i]; + } + + } + + /** + * Calculate size terms and store in sizeTerms array. This method + * initializes the sizeTerms array and loops through mgras in the + * mgraManager, calculates the size term for all size term purposes as + * defined in the size term uec, and stores the results in the sizeTerms + * array. + * + */ + public void calculateSizeTerms() + { + + logger.info("Calculating Size Terms"); + + ArrayList mgras = mgraManager.getMgras(); + int[] mgraTaz = mgraManager.getMgraTaz(); + int maxMgra = mgraManager.getMaxMgra(); + int alternatives = sizeTermUEC.getNumberOfAlternatives(); + sizeTerms = new double[maxMgra + 1][alternatives]; + hasSizeTerm = new boolean[maxMgra + 1]; + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + int taz = mgraTaz[mgra]; + iv.setZoneIndex(mgra); + double[] utilities = sizeTermUEC.solve(iv, aDmu, null); + + // if ( mgra < 100 ) + // sizeTermUEC.logAnswersArray(logger, + // "NonMandatory Size Terms, MGRA = " + mgra ); + + // store the size terms + for (int purp = 0; purp < alternatives; ++purp) + { + sizeTerms[mgra][purp] = utilities[purp]; + if (sizeTerms[mgra][purp] > 0) hasSizeTerm[mgra] = true; + } + + // log + if (tracer.isTraceOn() && tracer.isTraceZone(taz)) + { + + logger.info("Size Term calculations for mgra " + mgra); + sizeTermUEC.logResultsArray(logger, 0, mgra); + + } + } + } + + /** + * Calculate size terms used for worker DC and store in workerSizeTerms + * array. This method initializes the workerSizeTerms array and loops + * through mgras in the mgraManager, calculates the size term for all work + * size term occupation categories as defined in the worker size term uec, + * and stores the results in the workerSizeTerms array. + * + */ + public void calculateWorkerSizeTerms() + { + + logger.info("Calculating Worker DC Size Terms"); + + ArrayList mgras = mgraManager.getMgras(); + int[] mgraTaz = mgraManager.getMgraTaz(); + int maxMgra = mgraManager.getMaxMgra(); + int alternatives = workerSizeTermUEC.getNumberOfAlternatives(); + workerSizeTerms = new double[alternatives][maxMgra + 1]; + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + int taz = mgraTaz[mgra]; + iv.setZoneIndex(mgra); + double[] utilities = workerSizeTermUEC.solve(iv, aDmu, null); + + // store the size terms + for (int segment = 0; segment < alternatives; segment++) + { + workerSizeTerms[segment][mgra] = utilities[segment]; + } + + // log + if (tracer.isTraceOn() && tracer.isTraceZone(taz)) + { + logger.info("Worker Size Term calculations for mgra " + mgra); + workerSizeTermUEC.logResultsArray(logger, 0, mgra); + } + } + } + + /** + * Calculate size terms used for school DC and store in schoolSizeTerms + * array. This method initializes the schoolSizeTerms array and loops + * through mgras in the mgraManager, calculates the size term for all school + * size term categories, preschool is defined in the preschool size term + * uec, K-8 and 9-12 use their respective enrollments as size terms, and + * university uses a size term uec, segmented by "typical student". Size + * terms for preschool, k-8, 9-12, university typical amd university + * non-typical are stored in the studentSizeTerms array. + * + */ + public void calculateSchoolSizeTerms() + { + + logger.info("Calculating Student DC Size Terms"); + + ArrayList mgras = mgraManager.getMgras(); + int[] mgraTaz = mgraManager.getMgraTaz(); + int maxMgra = mgraManager.getMaxMgra(); + + String[] schoolSizeNames = getSchoolSegmentNameList(); + schoolSizeTerms = new double[schoolSizeNames.length][maxMgra + 1]; + luSchoolSizeTerms = new double[UNIV_NONTYPICAL_ALT_INDEX + 1][maxMgra + 1]; + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + // int dummy=0; + // if ( mgra == 1801 ){ + // dummy = 1; + // } + + int gsDistrict = getMgraGradeSchoolDistrict(mgra); + int hsDistrict = getMgraHighSchoolDistrict(mgra); + + int taz = mgraTaz[mgra]; + iv.setZoneIndex(mgra); + double[] utilities = schoolSizeTermUEC.solve(iv, aDmu, null); + + // store the preschool size terms + schoolSizeTerms[PRESCHOOL_ALT_INDEX][mgra] = utilities[PRESCHOOL_ALT_INDEX]; + luSchoolSizeTerms[PRESCHOOL_ALT_INDEX][mgra] = utilities[PRESCHOOL_ALT_INDEX]; + + // store the grade school size term for the district this mgra is in + int seg = getGsDistrictIndex(gsDistrict); + schoolSizeTerms[seg][mgra] = utilities[GRADE_SCHOOL_ALT_INDEX]; + luSchoolSizeTerms[GRADE_SCHOOL_ALT_INDEX][mgra] = utilities[GRADE_SCHOOL_ALT_INDEX]; + + // store the high school size term for the district this mgra is in + seg = getHsDistrictIndex(hsDistrict); + schoolSizeTerms[seg][mgra] = utilities[HIGH_SCHOOL_ALT_INDEX]; + luSchoolSizeTerms[HIGH_SCHOOL_ALT_INDEX][mgra] = utilities[HIGH_SCHOOL_ALT_INDEX]; + + // store the university typical size terms + schoolSizeTerms[univTypicalSegment][mgra] = utilities[UNIV_TYPICAL_ALT_INDEX]; + luSchoolSizeTerms[UNIV_TYPICAL_ALT_INDEX][mgra] = utilities[UNIV_TYPICAL_ALT_INDEX]; + + // store the university non-typical size terms + schoolSizeTerms[univNonTypicalSegment][mgra] = utilities[UNIV_NONTYPICAL_ALT_INDEX]; + luSchoolSizeTerms[UNIV_NONTYPICAL_ALT_INDEX][mgra] = utilities[UNIV_NONTYPICAL_ALT_INDEX]; + + // log + if (tracer.isTraceOn() && tracer.isTraceZone(taz)) + { + logger.info("School Size Term calculations for mgra " + mgra); + schoolSizeTermUEC.logResultsArray(logger, 0, mgra); + } + } + } + + public double[][] calculateSchoolSegmentFactors() + { + + ArrayList mgras = mgraManager.getMgras(); + int maxMgra = mgraManager.getMaxMgra(); + String[] schoolSizeNames = getSchoolSegmentNameList(); + double[][] schoolFactors = new double[schoolSizeNames.length][maxMgra + 1]; + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + // store the size terms + double univEnrollment = getTotalMgraUniversityEnrollment(mgra); + + for (int seg : nonUniversitySegments) + schoolFactors[seg][mgra] = 1.0; + + double totalSize = 0.0; + for (int seg : universitySegments) + totalSize += schoolSizeTerms[seg][mgra]; + + for (int seg : universitySegments) + if (totalSize == 0) schoolFactors[seg][mgra] = 0; + else schoolFactors[seg][mgra] = univEnrollment / totalSize; + + } + + return schoolFactors; + + } + + /** + * Calculate constant terms, exponentiate, and store in constants array. + */ + public void calculateConstants() + { + + logger.info("Calculating constants"); + + int modes = constantsUEC.getNumberOfAlternatives(); + expConstants = new double[MARKET_SEGMENTS + 1][modes]; // last element + // in + // market segments is + // for total + + for (int i = 0; i < MARKET_SEGMENTS + 1; ++i) + { + + aDmu.setAutoSufficiency(i); + + double[] utilities = constantsUEC.solve(iv, aDmu, null); + + // exponentiate the constants + for (int j = 0; j < modes; ++j) + { + expConstants[i][j] = Math.exp(utilities[j]); + logger.info("Exp. Constant, market " + i + " mode " + j + " = " + + expConstants[i][j]); + } + } + } + + public void calculateDCUtilitiesDistributed(HashMap rbMap) + { + + int packetSize = DISTRIBUTED_PACKET_SIZE; + int numPackets = mgraManager.getMgras().size(); + + int startIndex = 0; + int endIndex = 0; + + ArrayList startEndIndexList = new ArrayList(); + + // assign start, end MGRA ranges to be used to assign to tasks + while (endIndex < numPackets - 1) + { + endIndex = startIndex + packetSize - 1; + + if (endIndex + packetSize > numPackets) endIndex = numPackets - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += packetSize; + } + + float[][] accessibilities = submitTasks(startEndIndexList, rbMap); + accessibilitiesTableObject = new AccessibilitiesTable(accessibilities); + + // output data + String projectDirectory = rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(rbMap, "acc.output.file"); + accessibilitiesTableObject.writeAccessibilityTableToFile(accFileName); + accessibilitiesBuilt = true; + + if (landUseLogsums != null) + { + + boolean useSimpleMethod = false; + useSimpleMethod = Util.getBooleanValueFromPropertyMap(rbMap, + "lu.acc.simple.averaging.method"); + + boolean useLogitMethod = false; + useLogitMethod = Util.getBooleanValueFromPropertyMap(rbMap, + "lu.acc.logit.averaging.method"); + + // output land use data + String luAccFileName = projectDirectory + + Util.getStringValueFromPropertyMap(rbMap, "lu.acc.output.file"); + float[][][] luzAccessibilities = aggregateMgraAccessibilitiesToLuz(landUseAccessibilities); + if (useSimpleMethod) + accessibilitiesTableObject + .writeLandUseAccessibilityTableToFile( + luAccFileName.substring(0, luAccFileName.indexOf('.')) + "_simple" + + ".csv", luzAccessibilities[SIMPLE]); + if (useLogitMethod) + accessibilitiesTableObject.writeLandUseAccessibilityTableToFile( + luAccFileName.substring(0, luAccFileName.indexOf('.')) + "_logit" + ".csv", + luzAccessibilities[LOGIT]); + + // output land use mode choice logsums + String luMcLogsumsFileName = projectDirectory + + Util.getStringValueFromPropertyMap(rbMap, "lu.acc.mc.logsums.output.file"); + if (useSimpleMethod) + accessibilitiesTableObject.writeLandUseLogsumTablesToFile( + luMcLogsumsFileName.substring(0, luMcLogsumsFileName.indexOf('.')) + + "_simple" + ".csv", landUseLogsums[SIMPLE]); + if (useLogitMethod) + accessibilitiesTableObject.writeLandUseLogsumTablesToFile( + luMcLogsumsFileName.substring(0, luMcLogsumsFileName.indexOf('.')) + + "_logit" + ".csv", landUseLogsums[LOGIT]); + + } + + } + + private float[][][] aggregateMgraAccessibilitiesToLuz(float[][] landUseAccessibilities) + { + + // simple averaging uses accumulated logsum values, logit averaging uses + // accumulated utility values + float[][][] returnValues = new float[NUM_AVG_METHODS][MAX_LUZ + 1][]; + int[] numberOfMgraValues = new int[MAX_LUZ + 1]; + + for (int i = 1; i < landUseAccessibilities.length; i++) + { + + if (landUseAccessibilities[i] == null) continue; + + // the last column of accessibilities holds the mgra value + int numColumns = landUseAccessibilities[i].length; + int mgra = (int) landUseAccessibilities[i][numColumns - 1]; + int luz = mgraManager.getMgraLuz(mgra); + + // allocate the columns for aggregate arrays + for (int k = 0; k < NUM_AVG_METHODS; k++) + { + if (returnValues[k][luz] == null) + { + returnValues[k][luz] = new float[numColumns]; + returnValues[k][luz][numColumns - 1] = luz; + } + } + + numberOfMgraValues[luz]++; + + // aggregate the mgra column values in the corresponding luz row of + // the return array - excluding the last column + for (int j = 0; j < numColumns - 1; j++) + { + returnValues[SIMPLE][luz][j] += landUseAccessibilities[i][j]; + returnValues[LOGIT][luz][j] += Math.exp(landUseAccessibilities[i][j]); + } + + // calculate logsums from external LUZs to all destination LUZs if + // the origin LUZ is a cordon LUZ + if (externalLuzsForCordonLuz[luz] != null) + { + + for (int exLuz : externalLuzsForCordonLuz[luz]) + { + + // allocate the columns for aggregate arrays + for (int k = 0; k < NUM_AVG_METHODS; k++) + { + if (returnValues[k][exLuz] == null) + { + returnValues[k][exLuz] = new float[numColumns]; + returnValues[k][exLuz][numColumns - 1] = exLuz; + } + } + + numberOfMgraValues[exLuz]++; + + for (int j = 0; j < numColumns - 1; j++) + { + returnValues[SIMPLE][exLuz][j] += landUseAccessibilities[i][j]; + returnValues[LOGIT][exLuz][j] += Math.exp(landUseAccessibilities[i][j]); + } + + } + + } + + } + + for (int i = 0; i < returnValues[SIMPLE].length; i++) + { + + if (returnValues[SIMPLE][i] == null) continue; + + // the last column of accessibilities holds the mgra value + int numColumns = returnValues[SIMPLE][i].length; + int luz = (int) returnValues[SIMPLE][i][numColumns - 1]; + + // average the the luz values of the return array - excluding the + // last column + for (int j = 0; j < numColumns - 1; j++) + { + returnValues[SIMPLE][luz][j] /= numberOfMgraValues[luz]; + returnValues[LOGIT][luz][j] = (float) Math.log(returnValues[LOGIT][luz][j]); + } + + // calculate logsums from external LUZs to all destination LUZs if + // the origin LUZ is a cordon LUZ + if (externalLuzsForCordonLuz[luz] != null) + { + + for (int exLuz : externalLuzsForCordonLuz[luz]) + { + + for (int j = 0; j < numColumns - 1; j++) + { + returnValues[SIMPLE][exLuz][j] /= numberOfMgraValues[exLuz]; + returnValues[LOGIT][exLuz][j] = (float) Math + .log(returnValues[LOGIT][exLuz][j]); + } + + } + + } + + } + + return returnValues; + + } + + public void readAccessibilityTableFromFile(String accFileName) + { + accessibilitiesTableObject = new AccessibilitiesTable(accFileName); + logger.info("accessibilities table read from file."); + } + + public boolean getAccessibilitiesAreBuilt() + { + return objInstance.accessibilitiesBuilt; + } + + public AccessibilitiesTable getAccessibilitiesTableObject() + { + return accessibilitiesTableObject; + } + + /** + * @param client + * is a JPPFClient object which is used to establish a connection + * to a computing node, submit tasks, and receive results. + */ + private float[][] submitTasks(ArrayList startEndIndexList, HashMap rbMap) + { + + // Create a setup task object and submit it to the computing node. + // This setup task creates the HouseholdChoiceModelManager and causes it + // to + // create the necessary numuber + // of HouseholdChoiceModels objects which will operate in parallel on + // the + // computing node. + + ExecutorService exec = Executors.newFixedThreadPool(numThreads); + ArrayList>> results = new ArrayList>>(); + + float[][][][][] accumulatedLandUseLogsums; + int[][] accumulatedLandUseLogsumsCount; + + int startIndex = 0; + int endIndex = 0; + int taskIndex = 1; + for (int[] startEndIndices : startEndIndexList) + { + startIndex = startEndIndices[0]; + endIndex = startEndIndices[1]; + + logger.info(String.format("creating TASK: %d range: %d to %d.", taskIndex, startIndex, + endIndex)); + + DcUtilitiesTaskJppf task = new DcUtilitiesTaskJppf(taskIndex, startIndex, endIndex, + sovExpUtilities, hovExpUtilities, nMotorExpUtilities, hasSizeTerm, + expConstants, sizeTerms, workerSizeTerms, luSchoolSizeTerms, + externalLuzsForCordonLuz, cordonLuzForExternalLuz, + cordonLuzMinutesForExternalLuz, rbMap, calculateLuAccessibilities); + + results.add(exec.submit(task)); + taskIndex++; + } + + float[][] accessibilities = new float[maxMgra + 1][]; + + for (Future> fs : results) + { + + try + { + List resultBundle = fs.get(); + int task = (Integer) resultBundle.get(0); + int start = (Integer) resultBundle.get(1); + int end = (Integer) resultBundle.get(2); + if (logResults) logger.info(String.format("returned TASK: %d, start=%d, end=%d.", task, start, end)); + float[][] taskAccessibilities = (float[][]) resultBundle.get(3); + for (int i = 0; i < taskAccessibilities.length; i++) + { + if (taskAccessibilities[i] == null) continue; + int numColumns = taskAccessibilities[i].length; + int mgra = (int) taskAccessibilities[i][numColumns - 1]; + accessibilities[mgra] = taskAccessibilities[i]; + } + + if (landUseLogsums != null) + { + + // get land use accessibilities result if they were + // calculated + taskAccessibilities = (float[][]) resultBundle.get(4); + if (taskAccessibilities != null) + { + for (int i = 0; i < taskAccessibilities.length; i++) + { + if (taskAccessibilities[i] == null) continue; + int numColumns = taskAccessibilities[i].length; + int mgra = (int) taskAccessibilities[i][numColumns - 1]; + landUseAccessibilities[mgra] = taskAccessibilities[i]; + } + } + + // store the land use logsums array + accumulatedLandUseLogsums = (float[][][][][]) resultBundle.get(5); + accumulatedLandUseLogsumsCount = (int[][]) resultBundle.get(6); + accumulateLandUseModeChoiceLogsums(accumulatedLandUseLogsums, + accumulatedLandUseLogsumsCount); + + } + + } catch (InterruptedException e) + { + e.printStackTrace(); + throw new RuntimeException(); + } catch (ExecutionException e) + { + logger.error("Exception returned in place of result object.", e); + throw new RuntimeException(); + } finally + { + exec.shutdown(); + } + + } // future + + // calculate the averages for the land use mode choice logsums + if (landUseLogsums != null) averageLandUseModeChoiceLogsums(); + + return accessibilities; + + } + + private void averageLandUseModeChoiceLogsums() + { + + for (int i = 0; i < NUM_PERIODS; i++) + { + for (int j = 0; j < NUM_SUFFICIENCY_SEGMENTS; j++) + { + for (int k = 1; k <= MAX_LUZ; k++) + { + for (int m = 1; m <= MAX_LUZ; m++) + { + landUseLogsums[SIMPLE][i][j][k][m] = landUseLogsums[SIMPLE][i][j][k][m] + / landUseLogsumsCount[k][m]; + landUseLogsums[LOGIT][i][j][k][m] = Math + .log(landUseLogsums[LOGIT][i][j][k][m]); + } + } + } + } + } + + private void accumulateLandUseModeChoiceLogsums(float[][][][][] accumulatedLandUseLogsums, + int[][] accumulatedLandUseLogsumsCount) + { + + for (int k = 1; k <= MAX_LUZ; k++) + { + for (int m = 1; m <= MAX_LUZ; m++) + { + landUseLogsumsCount[k][m] += accumulatedLandUseLogsumsCount[k][m]; + for (int i = 0; i < NUM_PERIODS; i++) + { + for (int j = 0; j < NUM_SUFFICIENCY_SEGMENTS; j++) + { + landUseLogsums[SIMPLE][i][j][k][m] += accumulatedLandUseLogsums[SIMPLE][i][j][k][m]; + landUseLogsums[LOGIT][i][j][k][m] += accumulatedLandUseLogsums[LOGIT][i][j][k][m]; + } + } + } + } + + } + + public double[][] getExpConstants() + { + return expConstants; + } + + /** + * @return the array of alternative labels from the UEC used to calculate + * work tour destination choice size terms. + */ + public String[] getWorkSegmentNameList() + { + return WORK_OCCUP_SEGMENT_NAME_LIST; + } + + /** + * @return the table, MGRAs by occupations, of size terms calcuated for + * worker DC. + */ + public double[][] getWorkerSizeTerms() + { + return workerSizeTerms; + } + + /** + * @return the array of alternative labels from the UEC used to calculate + * work tour destination choice size terms. + */ + public String[] getSchoolSegmentNameList() + { + return schoolSegmentSizeNames; + } + + /** + * Specify the mapping between PECAS occupation codes, occupation segment + * labels, and work location choice segment indices. + */ + public void createWorkSegmentNameIndices() + { + + // get the list of segment names for worker tour destination choice size + String[] occupNameList = WORK_OCCUP_SEGMENT_NAME_LIST; + + // get the list of segment values for worker tour destination choice + // size + int[] occupValueList = WORK_OCCUP_SEGMENT_VALUE_LIST; + + for (int value : occupValueList) + { + int index = workerOccupValueSegmentIndexMap.get(value); + String name = occupNameList[index]; + workSegmentIndexNameMap.put(index, name); + workSegmentNameIndexMap.put(name, index); + } + + } + + /** + * Specify/create the mapping between school segment labels, and school + * location choice segment indices. + */ + public void createSchoolSegmentNameIndices() + { + + ArrayList segmentNames = new ArrayList(); + Set gsDistrictSet = getGradeSchoolDistrictIndices(); + Set hsDistrictSet = getHighSchoolDistrictIndices(); + + String segmentName = ""; + + // add preschool segment to list of segments which will not be shadow + // price adjusted + int sizeSegmentIndex = 0; + segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[PRESCHOOL_SEGMENT_GROUP_INDEX]; + noShadowPriceSchoolSegmentIndices.add(sizeSegmentIndex); + + // add preschool segment as the first segment, with index=0. + segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[PRESCHOOL_SEGMENT_GROUP_INDEX]; + segmentNames.add(segmentName); + schoolSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + schoolSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + psSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + psSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + + // increment the segmentIndex so it's new value is the first grade + // school index + // add grade school segments to list + sizeSegmentIndex++; + gsDistrictIndexMap = new HashMap(); + for (int gsDist : gsDistrictSet) + { + if (gsDist > UNIFIED_DISTRICT_OFFSET) segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[UNIFIED_GRADE_SCHOOL_SEGMENT_GROUP_INDEX] + + "_" + (gsDist - UNIFIED_DISTRICT_OFFSET); + else segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[GRADE_SCHOOL_SEGMENT_GROUP_INDEX] + + "_" + gsDist; + segmentNames.add(segmentName); + schoolSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + schoolSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + gsSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + gsSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + gsDistrictIndexMap.put(gsDist, sizeSegmentIndex); + sizeSegmentIndex++; + } + + // add high school segments to list + hsDistrictIndexMap = new HashMap(); + for (int hsDist : hsDistrictSet) + { + if (hsDist > UNIFIED_DISTRICT_OFFSET) segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[UNIFIED_HIGH_SCHOOL_SEGMENT_GROUP_INDEX] + + "_" + (hsDist - UNIFIED_DISTRICT_OFFSET); + else segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[HIGH_SCHOOL_SEGMENT_GROUP_INDEX] + + "_" + hsDist; + segmentNames.add(segmentName); + schoolSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + schoolSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + hsSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + hsSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + hsDistrictIndexMap.put(hsDist, sizeSegmentIndex); + sizeSegmentIndex++; + } + + // add typical university/colleger segments to list + segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[UNIV_TYPICAL_SEGMENT_GROUP_INDEX]; + segmentNames.add(segmentName); + schoolSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + schoolSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + univTypSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + univTypSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + univTypicalSegment = sizeSegmentIndex; + sizeSegmentIndex++; + + // add non-typical university/colleger segments to list + segmentName = SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[UNIV_NONTYPICAL_SEGMENT_GROUP_INDEX]; + segmentNames.add(segmentName); + schoolSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + schoolSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + univNonTypSegmentIndexNameMap.put(sizeSegmentIndex, segmentName); + univNonTypSegmentNameIndexMap.put(segmentName, sizeSegmentIndex); + univNonTypicalSegment = sizeSegmentIndex; + + // create arrays dimensioned as the number of school segments created + // and assign their values + + // 2 university segments + universitySegments = new int[2]; + + // num GS Dists + num HS dists + preschool non-university segments + nonUniversitySegments = new int[segmentNames.size() - universitySegments.length]; + + int u = 0; + int nu = 0; + + schoolSegmentSizeNames = new String[segmentNames.size()]; + for (int i = 0; i < schoolSegmentSizeNames.length; i++) + schoolSegmentSizeNames[i] = segmentNames.get(i); + + schoolDcSoaUecSheets = new int[schoolSegmentSizeNames.length]; + schoolDcUecSheets = new int[schoolSegmentSizeNames.length]; + schoolStfUecSheets = new int[schoolSegmentSizeNames.length]; + + sizeSegmentIndex = 0; + schoolDcSoaUecSheets[sizeSegmentIndex] = SCHOOL_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX[PRESCHOOL_ALT_INDEX]; + schoolDcUecSheets[sizeSegmentIndex] = SCHOOL_LOC_SEGMENT_TO_UEC_SHEET_INDEX[PRESCHOOL_ALT_INDEX]; + schoolStfUecSheets[sizeSegmentIndex] = SCHOOL_SEGMENT_TO_STF_UEC_SHEET_INDEX[PRESCHOOL_ALT_INDEX]; + nonUniversitySegments[nu++] = sizeSegmentIndex; + sizeSegmentIndex++; + + for (int segmentIndex : gsDistrictIndexMap.values()) + { + schoolDcSoaUecSheets[segmentIndex] = SCHOOL_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX[GRADE_SCHOOL_ALT_INDEX]; + schoolDcUecSheets[segmentIndex] = SCHOOL_LOC_SEGMENT_TO_UEC_SHEET_INDEX[GRADE_SCHOOL_ALT_INDEX]; + schoolStfUecSheets[segmentIndex] = SCHOOL_SEGMENT_TO_STF_UEC_SHEET_INDEX[GRADE_SCHOOL_ALT_INDEX]; + nonUniversitySegments[nu++] = segmentIndex; + sizeSegmentIndex++; + } + + for (int segmentIndex : hsDistrictIndexMap.values()) + { + schoolDcSoaUecSheets[segmentIndex] = SCHOOL_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX[HIGH_SCHOOL_ALT_INDEX]; + schoolDcUecSheets[segmentIndex] = SCHOOL_LOC_SEGMENT_TO_UEC_SHEET_INDEX[HIGH_SCHOOL_ALT_INDEX]; + schoolStfUecSheets[segmentIndex] = SCHOOL_SEGMENT_TO_STF_UEC_SHEET_INDEX[HIGH_SCHOOL_ALT_INDEX]; + nonUniversitySegments[nu++] = segmentIndex; + sizeSegmentIndex++; + } + + schoolDcSoaUecSheets[sizeSegmentIndex] = SCHOOL_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX[UNIV_TYPICAL_ALT_INDEX]; + schoolDcUecSheets[sizeSegmentIndex] = SCHOOL_LOC_SEGMENT_TO_UEC_SHEET_INDEX[UNIV_TYPICAL_ALT_INDEX]; + schoolStfUecSheets[sizeSegmentIndex] = SCHOOL_SEGMENT_TO_STF_UEC_SHEET_INDEX[UNIV_TYPICAL_ALT_INDEX]; + universitySegments[u++] = sizeSegmentIndex; + sizeSegmentIndex++; + + schoolDcSoaUecSheets[sizeSegmentIndex] = SCHOOL_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX[UNIV_NONTYPICAL_ALT_INDEX]; + schoolDcUecSheets[sizeSegmentIndex] = SCHOOL_LOC_SEGMENT_TO_UEC_SHEET_INDEX[UNIV_NONTYPICAL_ALT_INDEX]; + schoolStfUecSheets[sizeSegmentIndex] = SCHOOL_SEGMENT_TO_STF_UEC_SHEET_INDEX[UNIV_NONTYPICAL_ALT_INDEX]; + universitySegments[u++] = sizeSegmentIndex; + + } + + public HashSet getNoShadowPriceSchoolSegmentIndexSet() + { + return noShadowPriceSchoolSegmentIndices; + } + + public HashMap getSchoolSegmentIndexNameMap() + { + return schoolSegmentIndexNameMap; + } + + public HashMap getSchoolSegmentNameIndexMap() + { + return schoolSegmentNameIndexMap; + } + + /** + * @return pre-school segment index to segment name hashmap + */ + public HashMap getPsSegmentIndexNameMap() + { + return psSegmentIndexNameMap; + } + + /** + * @return pre-school segment name to segment index hashmap + */ + public HashMap getPsSegmentNameIndexMap() + { + return psSegmentNameIndexMap; + } + + /** + * @return grade school segment index to segment name hashmap + */ + public HashMap getGsSegmentIndexNameMap() + { + return gsSegmentIndexNameMap; + } + + /** + * @return grade school segment name to segment index hashmap + */ + public HashMap getGsSegmentNameIndexMap() + { + return gsSegmentNameIndexMap; + } + + /** + * @return high school segment index to segment name hashmap + */ + public HashMap getHsSegmentIndexNameMap() + { + return hsSegmentIndexNameMap; + } + + /** + * @return high school segment name to segment index hashmap + */ + public HashMap getHsSegmentNameIndexMap() + { + return hsSegmentNameIndexMap; + } + + /** + * @return university typical segment index to segment name hashmap + */ + public HashMap getUnivTypicalSegmentIndexNameMap() + { + return univTypSegmentIndexNameMap; + } + + /** + * @return university typical segment name to segment index hashmap + */ + public HashMap getUnivTypicalSegmentNameIndexMap() + { + return univTypSegmentNameIndexMap; + } + + /** + * @return university non typical segment index to segment name hashmap + */ + public HashMap getUnivNonTypicalSegmentIndexNameMap() + { + return univNonTypSegmentIndexNameMap; + } + + /** + * @return university non typical segment name to segment index hashmap + */ + public HashMap getUnivNonTypicalSegmentNameIndexMap() + { + return univNonTypSegmentNameIndexMap; + } + + public HashMap getWorkSegmentIndexNameMap() + { + return workSegmentIndexNameMap; + } + + public HashMap getWorkSegmentNameIndexMap() + { + return workSegmentNameIndexMap; + } + + public HashMap getWorkOccupValueIndexMap() + { + return workerOccupValueSegmentIndexMap; + } + + public int getGsDistrictIndex(int district) + { + return gsDistrictIndexMap.get(district); + } + + public int getHsDistrictIndex(int district) + { + return hsDistrictIndexMap.get(district); + } + + public int[] getSchoolDcSoaUecSheets() + { + return schoolDcSoaUecSheets; + } + + public int[] getSchoolDcUecSheets() + { + return schoolDcUecSheets; + } + + /** + * @return the array of stop frequency uec model sheet indices, indexed by + * school segment + */ + public int[] getSchoolStfUecSheets() + { + return schoolStfUecSheets; + } + + /** + * @return the table, MGRAs by school types, of size terms calcuated for + * school DC. + */ + public double[][] getSchoolSizeTerms() + { + return schoolSizeTerms; + } + + /** + * @return the table, MGRAs by non-mandatory types, of size terms calcuated. + */ + public double[][] getSizeTerms() + { + return sizeTerms; + } + + /** + * @param mgra + * for which table data is desired + * @return population for the specified mgra. + */ + public double getMgraPopulation(int mgra) + { + return mgraManager.getMgraPopulation(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return households for the specified mgra. + */ + public double getMgraHouseholds(int mgra) + { + return mgraManager.getMgraHouseholds(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return grade school enrollment for the specified mgra. + */ + public double getMgraGradeSchoolEnrollment(int mgra) + { + return mgraManager.getMgraGradeSchoolEnrollment(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return high school enrollment for the specified mgra. + */ + public double getMgraHighSchoolEnrollment(int mgra) + { + return mgraManager.getMgraHighSchoolEnrollment(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return university enrollment for the specified mgra. + */ + public double getTotalMgraUniversityEnrollment(int mgra) + { + return mgraManager.getMgraUniversityEnrollment(mgra) + + mgraManager.getMgraOtherCollegeEnrollment(mgra) + + mgraManager.getMgraAdultSchoolEnrollment(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return university enrollment for the specified mgra. + */ + public double getMgraUniversityEnrollment(int mgra) + { + return mgraManager.getMgraUniversityEnrollment(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return other college enrollment for the specified mgra. + */ + public double getMgraOtherCollegeEnrollment(int mgra) + { + return mgraManager.getMgraOtherCollegeEnrollment(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return adult school enrollment for the specified mgra. + */ + public double getMgraAdultSchoolEnrollment(int mgra) + { + return mgraManager.getMgraAdultSchoolEnrollment(mgra); + } + + /** + * @param mgra + * for which table data is desired + * @return grade school district for the specified mgra. + */ + public int getMgraGradeSchoolDistrict(int mgra) + { + int gsDist = mgraManager.getMgraGradeSchoolDistrict(mgra); + int hsDist = mgraManager.getMgraHighSchoolDistrict(mgra); + if (gsDist == 0) gsDist = UNIFIED_DISTRICT_OFFSET + hsDist; + return gsDist; + } + + /** + * @param mgra + * for which table data is desired + * @return high school district for the specified mgra. + */ + public int getMgraHighSchoolDistrict(int mgra) + { + int gsDist = mgraManager.getMgraGradeSchoolDistrict(mgra); + int hsDist = mgraManager.getMgraHighSchoolDistrict(mgra); + if (gsDist == 0) hsDist = UNIFIED_DISTRICT_OFFSET + hsDist; + return hsDist; + } + + /** + * @param mgra + * for which table data is desired + * @return school location choice model segment for the specified mgra. + */ + public int getMgraGradeSchoolSegmentIndex(int mgra) + { + int gsDist = mgraManager.getMgraGradeSchoolDistrict(mgra); + int hsDist = mgraManager.getMgraHighSchoolDistrict(mgra); + if (gsDist == 0) gsDist = UNIFIED_DISTRICT_OFFSET + hsDist; + + return gsDistrictIndexMap.get(gsDist); + } + + /** + * @param mgra + * for which table data is desired + * @return school location choice model segment for the specified mgra. + */ + public int getMgraHighSchoolSegmentIndex(int mgra) + { + int gsDist = mgraManager.getMgraGradeSchoolDistrict(mgra); + int hsDist = mgraManager.getMgraHighSchoolDistrict(mgra); + if (gsDist == 0) hsDist = UNIFIED_DISTRICT_OFFSET + hsDist; + + return hsDistrictIndexMap.get(hsDist); + } + + /** + * @return set of unique grade school district indices + */ + private TreeSet getGradeSchoolDistrictIndices() + { + int maxMgra = mgraManager.getMaxMgra(); + mgraGsDistrict = new int[maxMgra + 1]; + TreeSet set = new TreeSet(); + for (int r = 1; r <= maxMgra; r++) + { + int gsDist = mgraManager.getMgraGradeSchoolDistrict(r); + int hsDist = mgraManager.getMgraHighSchoolDistrict(r); + if (gsDist == 0) gsDist = UNIFIED_DISTRICT_OFFSET + hsDist; + set.add(gsDist); + mgraGsDistrict[r] = gsDist; + } + return set; + } + + /** + * @return set of unique high school district indices + */ + private TreeSet getHighSchoolDistrictIndices() + { + int maxMgra = mgraManager.getMaxMgra(); + mgraHsDistrict = new int[maxMgra + 1]; + TreeSet set = new TreeSet(); + for (int r = 1; r <= maxMgra; r++) + { + int gsDist = mgraManager.getMgraGradeSchoolDistrict(r); + int hsDist = mgraManager.getMgraHighSchoolDistrict(r); + if (gsDist == 0) hsDist = UNIFIED_DISTRICT_OFFSET + hsDist; + set.add(hsDist); + mgraHsDistrict[r] = hsDist; + } + return set; + } + + public int[] getMgraGsDistrict() + { + return mgraGsDistrict; + } + + public int[] getMgraHsDistrict() + { + return mgraHsDistrict; + } + + public HashMap getGsDistrictIndexMap() + { + return gsDistrictIndexMap; + } + + public HashMap getHsDistrictIndexMap() + { + return hsDistrictIndexMap; + } + + public HashMap getNonMandatoryPurposeNameIndexMap() + { + return nonMandatorySizeSegmentNameIndexMap; + } + + public int getEscortSizeArraySegmentIndex() + { + return nonMandatorySizeSegmentNameIndexMap.get(ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/DcUtilitiesTaskJppf.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/DcUtilitiesTaskJppf.java new file mode 100644 index 0000000..9d05d1a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/DcUtilitiesTaskJppf.java @@ -0,0 +1,880 @@ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.io.PrintWriter; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.concurrent.Callable; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + + +public class DcUtilitiesTaskJppf + implements Callable> +{ + + private static final int MIN_EXP_FUNCTION_ARGUMENT = -500; + + private static final String[] LOGSUM_SEGMENTS = {"SOV ", + "HOV ", "Transit ", "NMotorized", "SOVLS_0 ", "SOVLS_1 ", "SOVLS_2 ", + "HOVLS_0_OP", "HOVLS_1_OP", "HOVLS_2_OP", "HOVLS_0_PK", "HOVLS_1_PK", "HOVLS_2_PK", + "TOTAL", "MAAS" }; + + public static final String[] LU_LOGSUM_SEGMENTS = {"LS_0_PK", "LS_1_PK", + "LS_2_PK", "LS_0_OP", "LS_1_OP", "LS_2_OP", "All_PK " }; + + // setting to -1 will prevent debug files from being written + private static final int DEBUG_ILUZ = -1; + private static final int DEBUG_JLUZ = -1; + // private static final int DEBUG_ILUZ = 66; + // private static final int DEBUG_JLUZ = 82; + + private static final int MAX_LU_SIZE_TERM_INDEX = 23; + private static final int MAX_LU_NONMAN_SIZE_TERM_INDEX = 12; + private static final int MAX_LU_WORK_SIZE_TERM_INDEX = 18; + private static final int MAX_LU_SCHOOL_SIZE_TERM_INDEX = 23; + + private MgraDataManager mgraManager; + private boolean[] hasSizeTerm; + private double[][] expConstants; + private double[][] sizeTerms; + private double[][] luSizeTerms; + + // store taz-taz exponentiated utilities (period, from taz, to taz) + private double[][][] sovExpUtilities; + private double[][][] hovExpUtilities; + private double[][][] nMotorExpUtilities; + private double[][][] maasExpUtilities; + + + private float[][] accessibilities; + private float[][] luAccessibilities; + + private int startRange; + private int endRange; + private int taskIndex; + + private boolean seek; + private Tracer tracer; + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + + private BestTransitPathCalculator bestPathCalculator; + + private UtilityExpressionCalculator dcUEC; + private AccessibilitiesDMU aDmu; + + private UtilityExpressionCalculator luUEC; + private AccessibilitiesDMU luDmu; + + private HashMap rbMap; + + private int[][] externalLuzsForCordonLuz; + private int[] cordonLuzForExternalLuz; + private int[] cordonLuzMinutesForExternalLuz; + + private boolean calculateLuAccessibilities; + private PrintWriter outStream; + + public DcUtilitiesTaskJppf(int taskIndex, int startRange, int endRange, + double[][][] mySovExpUtilities, double[][][] myHovExpUtilities, + double[][][] myNMotorExpUtilities, boolean[] hasSizeTerm, double[][] expConstants, + double[][] sizeTerms, double[][] workSizeTerms, double[][] schoolSizeTerms, + int[][] myExternalLuzsForCordonLuz, int[] myCordonLuzForExternalLuz, + int[] myCordonLuzMinutesForExternalLuz, HashMap myRbMap, + boolean myCalculateLuAccessibilities) + { + + rbMap = myRbMap; + sovExpUtilities = mySovExpUtilities; + hovExpUtilities = myHovExpUtilities; + nMotorExpUtilities = myNMotorExpUtilities; + externalLuzsForCordonLuz = myExternalLuzsForCordonLuz; + cordonLuzForExternalLuz = myCordonLuzForExternalLuz; + cordonLuzMinutesForExternalLuz = myCordonLuzMinutesForExternalLuz; + calculateLuAccessibilities = myCalculateLuAccessibilities; + + mgraManager = MgraDataManager.getInstance(rbMap); + + aDmu = new AccessibilitiesDMU(); + + String dcUecFileName = Util.getStringValueFromPropertyMap(rbMap, "acc.dcUtility.uec.file"); + int dcDataPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.dcUtility.data.page"); + int dcUtilityPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.dcUtility.page"); + + File dcUecFile = new File(dcUecFileName); + dcUEC = new UtilityExpressionCalculator(dcUecFile, dcUtilityPage, dcDataPage, rbMap, aDmu); + + accessibilities = new float[mgraManager.getMaxMgra() + 1][]; + + if (calculateLuAccessibilities) + { + + luDmu = new AccessibilitiesDMU(); + + dcUecFileName = Util.getStringValueFromPropertyMap(rbMap, "lu.acc.dcUtility.uec.file"); + dcDataPage = Util.getIntegerValueFromPropertyMap(rbMap, "lu.acc.dcUtility.data.page"); + dcUtilityPage = Util.getIntegerValueFromPropertyMap(rbMap, "lu.acc.dcUtility.page"); + + File luUecFile = new File(dcUecFileName); + luUEC = new UtilityExpressionCalculator(luUecFile, dcUtilityPage, dcDataPage, rbMap, + luDmu); + + TableDataSet luAltData = luUEC.getAlternativeData(); + luDmu.setAlternativeData(luAltData); + int luAlts = luUEC.getNumberOfAlternatives(); + + luAccessibilities = new float[mgraManager.getMaxMgra() + 1][luAlts + 1]; + + // combine non-mandatory, work, and school size terms into one array + // to be indexed into as follows + // 0-12 non-mandatory, 13-18 work, 19-23 school + luSizeTerms = new double[sizeTerms.length][MAX_LU_SIZE_TERM_INDEX + 1]; + for (int c = 0; c <= MAX_LU_NONMAN_SIZE_TERM_INDEX; c++) + for (int r = 0; r < sizeTerms.length; r++) + luSizeTerms[r][c] = sizeTerms[r][c]; + + for (int c = 0; c < workSizeTerms.length; c++) + for (int r = 0; r < workSizeTerms[c].length; r++) + luSizeTerms[r][c + MAX_LU_NONMAN_SIZE_TERM_INDEX + 1] = workSizeTerms[c][r]; + + for (int c = 0; c < schoolSizeTerms.length; c++) + for (int r = 0; r < schoolSizeTerms[c].length; r++) + luSizeTerms[r][c + MAX_LU_WORK_SIZE_TERM_INDEX + 1] = schoolSizeTerms[c][r]; + + // for ( int c=MAX_LU_NONMAN_SIZE_TERM_INDEX+1; c <= + // MAX_LU_WORK_SIZE_TERM_INDEX; c++ ) + // for ( int r=0; r < workSizeTerms.length; r++ ) + // luSizeTerms[r][c] = + // workSizeTerms[r][c-MAX_LU_NONMAN_SIZE_TERM_INDEX-1]; + // + // for ( int c=MAX_LU_WORK_SIZE_TERM_INDEX+1; c <= + // MAX_LU_SCHOOL_SIZE_TERM_INDEX; c++ ) + // for ( int r=0; r < schoolSizeTerms.length; r++ ) + // luSizeTerms[r][c] = + // schoolSizeTerms[r][c-MAX_LU_WORK_SIZE_TERM_INDEX-1]; + + // try { + // outStream = new PrintWriter( new BufferedWriter( new FileWriter( + // "landUseModeChoiceLogsumCheck" + "_" + taskIndex + ".csv" ) ) ); + // } + // catch (IOException e) { + // System.out.println("IO Exception writing file for checking integerizing procedure: " + // ); + // e.printStackTrace(); + // System.exit(-1); + // } + + } + + this.taskIndex = taskIndex; + this.startRange = startRange; + this.endRange = endRange; + this.hasSizeTerm = hasSizeTerm; + this.expConstants = expConstants; + this.sizeTerms = sizeTerms; + + trace = Util.getBooleanValueFromPropertyMap(rbMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.dtaz"); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + seek = Util.getBooleanValueFromPropertyMap(rbMap, "Seek"); + + } + + public String getId() + { + return Integer.toString(taskIndex); + } + + public List call() + { + + Logger logger = Logger.getLogger(this.getClass()); + + String threadName = null; + try + { + threadName = "[" + java.net.InetAddress.getLocalHost().getHostName() + ", task:" + + taskIndex + "] " + Thread.currentThread().getName(); + } catch (UnknownHostException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + logger.info(threadName + " - Calculating Accessibilities"); + + NonTransitUtilities ntUtilities = new NonTransitUtilities(rbMap, sovExpUtilities, + hovExpUtilities, nMotorExpUtilities, maasExpUtilities); + // ntUtilities.setAllUtilities(ntUtilitiesArrays); + // ntUtilities.setNonMotorUtilsMap(ntUtilitiesMap); + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(rbMap); + bestPathCalculator = logsumHelper.getBestTransitPathCalculator(); + AutoAndNonMotorizedSkimsCalculator anm = logsumHelper.getAnmSkimCalculator(); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + + // get the accessibilities alternatives + int alts = dcUEC.getNumberOfAlternatives(); + TableDataSet altData = dcUEC.getAlternativeData(); + aDmu.setAlternativeData(altData); + + int luAlts = -1; + double[] luUtilities = null; + ArrayList luUtilityList = null; + float[][][][][] accumulatedLandUseLogsums = null; + int[][] accumulatedLandUseLogsumsCount = null; + + if (calculateLuAccessibilities) + { + // get the land use accessibilities alternatives + luAlts = luUEC.getNumberOfAlternatives(); + TableDataSet luAltData = luUEC.getAlternativeData(); + luDmu.setAlternativeData(luAltData); + + // declare logsums array for LU accessibility + luUtilities = new double[LU_LOGSUM_SEGMENTS.length]; + + luUtilityList = new ArrayList(); + + accumulatedLandUseLogsums = new float[BuildAccessibilities.NUM_AVG_METHODS][BuildAccessibilities.NUM_PERIODS][BuildAccessibilities.NUM_SUFFICIENCY_SEGMENTS][BuildAccessibilities.MAX_LUZ + 1][BuildAccessibilities.MAX_LUZ + 1]; + + accumulatedLandUseLogsumsCount = new int[BuildAccessibilities.MAX_LUZ + 1][BuildAccessibilities.MAX_LUZ + 1]; + + } + + // declare logsums array for ABM + double[] logsums = new double[LOGSUM_SEGMENTS.length]; + + float[] luUtilityResult = new float[LU_LOGSUM_SEGMENTS.length + 2]; + + // DMUs for this UEC + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + // LOOP OVER RANGE OF ORIGIN MGRA + ArrayList mgraValues = mgraManager.getMgras(); + for (int i = startRange; i <= endRange; i++) + { // Origin MGRA + + int iMgra = mgraValues.get(i); + + accessibilities[iMgra] = new float[alts + 1]; + + // pre-calculate the hov, sov, and non-motorized exponentiated + // utilities for the origin MGRA. + // the method called returns cached values if they were already + // calculated. + ntUtilities.buildUtilitiesForOrigMgraAndPeriod(iMgra, + NonTransitUtilities.PEAK_PERIOD_INDEX); + ntUtilities.buildUtilitiesForOrigMgraAndPeriod(iMgra, + NonTransitUtilities.OFFPEAK_PERIOD_INDEX); + + // if(originMgras<=10 || (originMgras % 500) ==0 ) + // logger.info("...Origin MGRA "+iMgra); + + int iTaz = mgraManager.getTaz(iMgra); + boolean trace = false; + + if (tracer.isTraceOn() && tracer.isTraceZone(iTaz)) + { + + logger.info("origMGRA, destMGRA, OPSOV, OPHOV, WTRAN, NMOT, SOV0OP, SOV1OP, SOV2OP, HOV0OP, HOV1OP, HOV2OP, HOV0PK, HOV1PK, HOV2PK, ALL"); + trace = true; + } + // for tracing accessibility and logsum calculations + String accString = null; + + // LOOP OVER DESTINATION MGRA + for (Integer jMgra : mgraManager.getMgras()) + { // Destination MGRA + + if (!hasSizeTerm[jMgra]) continue; + + int jTaz = mgraManager.getTaz(jMgra); + + if (seek && !trace) continue; + + double opSovExpUtility = 0; + double opHovExpUtility = 0; + double opMaasExpUtility = 0; + try + { + opSovExpUtility = ntUtilities.getSovExpUtility(iTaz, jTaz, + NonTransitUtilities.OFFPEAK_PERIOD_INDEX); + opHovExpUtility = ntUtilities.getHovExpUtility(iTaz, jTaz, + NonTransitUtilities.OFFPEAK_PERIOD_INDEX); + opMaasExpUtility = ntUtilities.getMaasExpUtility(iTaz, jTaz, + NonTransitUtilities.OFFPEAK_PERIOD_INDEX); + // opSovExpUtility = + // ntUtilities.getAllUtilities()[0][0][iTaz][jTaz]; + // opHovExpUtility = + // ntUtilities.getAllUtilities()[1][0][iTaz][jTaz]; + } catch (Exception e) + { + logger.error("exception for op sov/hov utilitiy taskIndex=" + taskIndex + + ", i=" + i + ", startRange=" + startRange + ", endRange=" + endRange, + e); + System.exit(-1); + } + + // calculate walk-transit exponentiated utility + // determine the best transit path, which also stores the best utilities array and the best mode + bestPathCalculator.findBestWalkTransitWalkTaps(walkDmu, ModelStructure.MD_SKIM_PERIOD_INDEX, iMgra, jMgra, trace, logger); + + // sum the exponentiated utilities over modes + double opWTExpUtility = bestPathCalculator.getSumExpUtilities(); + + double pkSovExpUtility = 0; + double pkHovExpUtility = 0; + double pkMaasExpUtility = 0; + try + { + pkSovExpUtility = ntUtilities.getSovExpUtility(iTaz, jTaz, + NonTransitUtilities.PEAK_PERIOD_INDEX); + pkHovExpUtility = ntUtilities.getHovExpUtility(iTaz, jTaz, + NonTransitUtilities.PEAK_PERIOD_INDEX); + + pkMaasExpUtility = ntUtilities.getMaasExpUtility(iTaz, jTaz, + NonTransitUtilities.PEAK_PERIOD_INDEX); + + // pkSovExpUtility = + // ntUtilities.getAllUtilities()[0][1][iTaz][jTaz]; + // pkHovExpUtility = + // ntUtilities.getAllUtilities()[1][1][iTaz][jTaz]; + } catch (Exception e) + { + logger.error("exception for pk sov/hov utility taskIndex=" + taskIndex + ", i=" + + i + ", startRange=" + startRange + ", endRange=" + endRange, e); + System.exit(-1); + } + + // determine the best transit path, which also stores the best utilities array and the best mode + bestPathCalculator.findBestWalkTransitWalkTaps(walkDmu, ModelStructure.AM_SKIM_PERIOD_INDEX, iMgra, jMgra, trace, logger); + + // sum the exponentiated utilities over modes + double pkWTExpUtility = bestPathCalculator.getSumExpUtilities(); + + double pkDTExpUtility = 0; + double opDTExpUtility = 0; + + if (calculateLuAccessibilities) + { + + float odDistance = (float) anm.getTazDistanceFromTaz(iTaz, ModelStructure.AM_SKIM_PERIOD_INDEX)[jTaz]; + + // determine the best transit path, which also stores the best utilities array and the best mode + bestPathCalculator.findBestDriveTransitWalkTaps(walkDmu, driveDmu, ModelStructure.AM_SKIM_PERIOD_INDEX, iMgra, jMgra, trace, logger, odDistance); + + // sum the exponentiated utilities over modes + double driveTransitWalkUtilities[] = bestPathCalculator.getBestUtilities(); + if(trace){ + logger.info("PK Drive Transit Utilities (TAP pair number,utility, sum)"); + } + for (int k=0; k < driveTransitWalkUtilities.length; k++){ + if ( driveTransitWalkUtilities[k] > MIN_EXP_FUNCTION_ARGUMENT ) + pkDTExpUtility += Math.exp(driveTransitWalkUtilities[k]); + if(trace) + logger.info(k+","+driveTransitWalkUtilities[k]+","+pkDTExpUtility); + } + + // determine the best transit path, which also stores the best utilities array and the best mode + bestPathCalculator.findBestDriveTransitWalkTaps(walkDmu, driveDmu, ModelStructure.MD_SKIM_PERIOD_INDEX, iMgra, jMgra, trace, logger, odDistance); + + // sum the exponentiated utilities over modes + driveTransitWalkUtilities = bestPathCalculator.getBestUtilities(); + if(trace){ + logger.info("OP Drive Transit Utilities (TAP pair number,utility, sum)"); + } + for (int k=0; k < driveTransitWalkUtilities.length; k++){ + if ( driveTransitWalkUtilities[k] > MIN_EXP_FUNCTION_ARGUMENT ) + opDTExpUtility += Math.exp(driveTransitWalkUtilities[k]); + if(trace) + logger.info(k+","+driveTransitWalkUtilities[k]+","+opDTExpUtility); + } + + } + + double nmExpUtility = 0; + try + { + nmExpUtility = ntUtilities.getNMotorExpUtility(iMgra, jMgra, + NonTransitUtilities.OFFPEAK_PERIOD_INDEX); + } catch (Exception e) + { + logger.error("exception for non-motorized utilitiy taskIndex=" + taskIndex + + ", i=" + i + ", startRange=" + startRange + ", endRange=" + endRange, + e); + System.exit(-1); + } + + Arrays.fill(logsums, -999f); + + // 0: OP SOV + logsums[0] = Math.log(opSovExpUtility); + + // 1: OP HOV + logsums[1] = Math.log(opHovExpUtility); + + // 2: Walk-Transit + if (opWTExpUtility > 0) logsums[2] = Math.log(opWTExpUtility); + + // 3: Non-Motorized + if (nmExpUtility > 0) logsums[3] = Math.log(nmExpUtility); + + // 4: SOVLS_0 + logsums[4] = Math.log(opSovExpUtility * expConstants[0][0] + opWTExpUtility + * expConstants[0][2] + nmExpUtility * expConstants[0][3]); + // 5: SOVLS_1 + logsums[5] = Math.log(opSovExpUtility * expConstants[1][0] + opWTExpUtility + * expConstants[1][2] + nmExpUtility * expConstants[1][3]); + + // 6: SOVLS_2 + logsums[6] = Math.log(opSovExpUtility * expConstants[2][0] + opWTExpUtility + * expConstants[2][2] + nmExpUtility * expConstants[2][3]); + + // 7: HOVLS_0_OP + logsums[7] = Math.log(opHovExpUtility * expConstants[0][1] + opWTExpUtility + * expConstants[0][2] + nmExpUtility * expConstants[0][3]); + + // 8: HOVLS_1_OP + logsums[8] = Math.log(opHovExpUtility * expConstants[1][1] + opWTExpUtility + * expConstants[1][2] + nmExpUtility * expConstants[1][3]); + + // 9: HOVLS_2_OP + logsums[9] = Math.log(opHovExpUtility * expConstants[2][1] + opWTExpUtility + * expConstants[2][2] + nmExpUtility * expConstants[2][3]); + + // 10: HOVLS_0_PK + logsums[10] = Math.log(pkHovExpUtility * expConstants[0][1] + pkWTExpUtility + * expConstants[0][2] + nmExpUtility * expConstants[0][3]); + + // 11: HOVLS_1_PK + logsums[11] = Math.log(pkHovExpUtility * expConstants[1][1] + pkWTExpUtility + * expConstants[1][2] + nmExpUtility * expConstants[1][3]); + + // 12: HOVLS_2_PK + logsums[12] = Math.log(pkHovExpUtility * expConstants[2][1] + pkWTExpUtility + * expConstants[2][2] + nmExpUtility * expConstants[2][3]); + + // 13: ALL + logsums[13] = Math.log(pkSovExpUtility * expConstants[3][0] + pkHovExpUtility + * expConstants[3][1] + pkWTExpUtility * expConstants[3][2] + nmExpUtility + * expConstants[3][3]); + + // 14: MAAS + logsums[14] = Math.log(opMaasExpUtility); + + aDmu.setLogsums(logsums); + aDmu.setSizeTerms(sizeTerms[jMgra]); + // double[] utilities = dcUEC.solve(iv, aDmu, null); + + if (trace) + { + String printString = new String(); + printString += (iMgra + "," + jMgra); + for (int j = 0; j < 14; ++j) + { + printString += "," + String.format("%9.2f", logsums[j]); + } + logger.info(printString); + + accString = new String(); + accString = "iMgra, jMgra, Alternative, Logsum, SizeTerm, Accessibility\n"; + + } + // add accessibilities for origin mgra + for (int alt = 0; alt < alts; ++alt) + { + + double logsum = aDmu.getLogsum(alt + 1); + double sizeTerm = aDmu.getSizeTerm(alt + 1); + + accessibilities[iMgra][alt] += (Math.exp(logsum) * sizeTerm); + + if (trace) + { + accString += iMgra + "," + alt + "," + logsum + "," + sizeTerm + "," + + accessibilities[iMgra][alt] + "\n"; + } + + } + + // if luModeChoiceLogsums is null, is has not been initialized, + // meaning that LU accessibility calculations are not needed + if (calculateLuAccessibilities) + { + + // 0: AM Mode Choice utility for 0-autos auto sufficiency + luUtilities[0] = pkSovExpUtility * expConstants[0][0] + pkHovExpUtility + * expConstants[0][1] + pkWTExpUtility * expConstants[0][2] + + pkDTExpUtility * expConstants[0][4] + nmExpUtility + * expConstants[0][3]; + + // 1: AM Mode Choice utility for autos=adults auto + // sufficiency + luUtilities[2] = pkSovExpUtility * expConstants[2][0] + pkHovExpUtility + * expConstants[2][1] + pkWTExpUtility * expConstants[2][2] + + pkDTExpUtility * expConstants[2][4] + nmExpUtility + * expConstants[2][3]; + + // 3: MD Mode Choice utility for 0-autos auto sufficiency + luUtilities[3] = opSovExpUtility * expConstants[0][0] + opHovExpUtility + * expConstants[0][1] + opWTExpUtility * expConstants[0][2] + + opDTExpUtility * expConstants[0][4] + nmExpUtility + * expConstants[0][3]; + + // 4: MD Mode Choice utility for autos=adults auto + // sufficiency + luUtilities[5] = opSovExpUtility * expConstants[2][0] + opHovExpUtility + * expConstants[2][1] + opWTExpUtility * expConstants[2][2] + + opDTExpUtility * expConstants[2][4] + nmExpUtility + * expConstants[2][3]; + + // 6: AM Mode Choice utility for all households + luUtilities[6] = pkSovExpUtility * expConstants[3][0] + pkHovExpUtility + * expConstants[3][1] + pkWTExpUtility * expConstants[3][2] + + pkDTExpUtility * expConstants[3][4] + nmExpUtility + * expConstants[3][3]; + + // calculate non-mandatory destination choice logsums + + luDmu.setLogsums(luUtilities); + luDmu.setSizeTerms(luSizeTerms[jMgra]); + + if (trace) + { + String printString = new String(); + printString += (iMgra + "," + jMgra); + for (int j = 0; j < luUtilities.length; ++j) + { + printString += "," + String.format("%9.2f", luUtilities[j]); + } + logger.info(printString); + + accString = new String(); + accString = "Non-mandatory: iMgra, jMgra, Alternative, LU_Logsum, SizeTerm, LU_Accessibility\n"; + + } + // add accessibilities for origin mgra + for (int alt = 0; alt < luAlts; ++alt) + { + + double logsum = luDmu.getLogsum(alt + 1); + double sizeTerm = luDmu.getSizeTerm(alt + 1); + + luAccessibilities[iMgra][alt] += (logsum * sizeTerm); + + if (trace) + { + accString += iMgra + "," + alt + "," + logsum + "," + sizeTerm + "," + + luAccessibilities[iMgra][alt] + "\n"; + } + } + + // save calculated utilities in a table to return tot the + // calling method for accumulating + luUtilityResult[0] = iMgra; + luUtilityResult[1] = jMgra; + for (int k = 0; k < luUtilities.length; k++) + luUtilityResult[2 + k] = (float) luUtilities[k]; + + accumulateLandUseModeChoiceLogsums(luUtilityResult, + accumulatedLandUseLogsumsCount, accumulatedLandUseLogsums); + + } + + } // end for destinations + + if (trace) + { + logger.info(accString); + } + + // calculate the logsum + for (int alt = 0; alt < alts; ++alt) + { + if (accessibilities[iMgra][alt] > 0) + accessibilities[iMgra][alt] = (float) Math.log(accessibilities[iMgra][alt]); + } + accessibilities[iMgra][alts] = iMgra; + + if (calculateLuAccessibilities) + { + // calculate the land use accessibility logsums + for (int alt = 0; alt < luAlts; ++alt) + { + if (luAccessibilities[iMgra][alt] > 0) + luAccessibilities[iMgra][alt] = (float) Math + .log(luAccessibilities[iMgra][alt]); + + } + luAccessibilities[iMgra][luAlts] = iMgra; + } + + } + + List resultBundle = new ArrayList(7); + resultBundle.add(taskIndex); + resultBundle.add(startRange); + resultBundle.add(endRange); + resultBundle.add(accessibilities); + + if (calculateLuAccessibilities) + { + resultBundle.add(luAccessibilities); + resultBundle.add(accumulatedLandUseLogsums); + resultBundle.add(accumulatedLandUseLogsumsCount); + } else + { + resultBundle.add(null); + resultBundle.add(null); + resultBundle.add(null); + } + + // outStream.close(); + + return resultBundle; + + } + + // private void debugLandUseModeChoiceLogsums( int iMgra, int jMgra, int + // iLuz, int jLuz, float[] luUtilities ) { + // + // String record = ( iLuz + "," + jLuz + "," + iMgra + "," + jMgra + "," + + // luUtilities[0] ); + // // don't need to report the last logsum (not used for mode choice + // logsums) + // for( int j=1; j < luUtilities.length - 1; j++ ) + // record += ( "," + luUtilities[j] ); + // outStream.println ( record ); + // + // } + + private void accumulateLandUseModeChoiceLogsums(float[] luUtilitiesValues, + int[][] accumulatedLandUseLogsumsCount, float[][][][][] accumulatedLandUseLogsums) + { + + float[] luUtilities = new float[DcUtilitiesTaskJppf.LU_LOGSUM_SEGMENTS.length]; + + int iMgra = (int) luUtilitiesValues[0]; + int jMgra = (int) luUtilitiesValues[1]; + + int iLuz = mgraManager.getMgraLuz(iMgra); + int jLuz = mgraManager.getMgraLuz(jMgra); + + for (int i = 0; i < luUtilities.length; i++) + luUtilities[i] = luUtilitiesValues[i + 2]; + + accumulatedLandUseLogsumsCount[iLuz][jLuz]++; + + accumulateSimple(iLuz, jLuz, luUtilities, accumulatedLandUseLogsumsCount, + accumulatedLandUseLogsums); + accumulateLogit(iLuz, jLuz, luUtilities, accumulatedLandUseLogsumsCount, + accumulatedLandUseLogsums); + + // if ( iLuz == DEBUG_ILUZ && jLuz == DEBUG_JLUZ ) + // debugLandUseModeChoiceLogsums( iMgra, jMgra, iLuz, jLuz, luUtilities + // ); + + } + + private void accumulateSimple(int iLuz, int jLuz, float[] luUtilities, + int[][] accumulatedLandUseLogsumsCount, float[][][][][] accumulatedLandUseLogsums) + { + + // simple averaging uses accumulated logsum values + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS0][iLuz][jLuz] += Math + .log(luUtilities[0]); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS1][iLuz][jLuz] += Math + .log(luUtilities[1]); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS2][iLuz][jLuz] += Math + .log(luUtilities[2]); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS0][iLuz][jLuz] += Math + .log(luUtilities[3]); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS1][iLuz][jLuz] += Math + .log(luUtilities[4]); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS2][iLuz][jLuz] += Math + .log(luUtilities[5]); + + // calculate logsums from external LUZs to all destination LUZs if the + // origin LUZ is a cordon LUZ + if (externalLuzsForCordonLuz[iLuz] != null) + { + + for (int exLuz : externalLuzsForCordonLuz[iLuz]) + { + + double additionalUtility = Math.exp(cordonLuzMinutesForExternalLuz[exLuz] + * BuildAccessibilities.TIME_COEFFICIENT); + + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS0][exLuz][jLuz] += Math + .log(luUtilities[0] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS1][exLuz][jLuz] += Math + .log(luUtilities[1] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS2][exLuz][jLuz] += Math + .log(luUtilities[2] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS0][exLuz][jLuz] += Math + .log(luUtilities[3] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS1][exLuz][jLuz] += Math + .log(luUtilities[4] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS2][exLuz][jLuz] += Math + .log(luUtilities[5] + additionalUtility); + + accumulatedLandUseLogsumsCount[exLuz][jLuz]++; + + } + + } + + // calculate logsums to external LUZs from all origin LUZs if the + // destination LUZ is a cordon LUZ + if (externalLuzsForCordonLuz[jLuz] != null) + { + + for (int exLuz : externalLuzsForCordonLuz[jLuz]) + { + + double additionalUtility = Math.exp(cordonLuzMinutesForExternalLuz[exLuz] + * BuildAccessibilities.TIME_COEFFICIENT); + + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS0][iLuz][exLuz] += Math + .log(luUtilities[0] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS1][iLuz][exLuz] += Math + .log(luUtilities[1] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.PK][BuildAccessibilities.LS2][iLuz][exLuz] += Math + .log(luUtilities[2] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS0][iLuz][exLuz] += Math + .log(luUtilities[3] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS1][iLuz][exLuz] += Math + .log(luUtilities[4] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.SIMPLE][BuildAccessibilities.OP][BuildAccessibilities.LS2][iLuz][exLuz] += Math + .log(luUtilities[5] + additionalUtility); + + accumulatedLandUseLogsumsCount[iLuz][exLuz]++; + + } + + } + + } + + private void accumulateLogit(int iLuz, int jLuz, float[] luUtilities, + int[][] accumulatedLandUseLogsumsCount, float[][][][][] accumulatedLandUseLogsums) + { + + // logit averaging uses accumulated utility values + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS0][iLuz][jLuz] += luUtilities[0]; + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS1][iLuz][jLuz] += luUtilities[1]; + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS2][iLuz][jLuz] += luUtilities[2]; + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS0][iLuz][jLuz] += luUtilities[3]; + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS1][iLuz][jLuz] += luUtilities[4]; + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS2][iLuz][jLuz] += luUtilities[5]; + + // calculate logsums from external LUZs to all destination LUZs if the + // origin LUZ is a cordon LUZ + if (externalLuzsForCordonLuz[iLuz] != null) + { + + for (int exLuz : externalLuzsForCordonLuz[iLuz]) + { + + double additionalUtility = Math.exp(cordonLuzMinutesForExternalLuz[exLuz] + * BuildAccessibilities.TIME_COEFFICIENT); + + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS0][exLuz][jLuz] += (luUtilities[0] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS1][exLuz][jLuz] += (luUtilities[1] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS2][exLuz][jLuz] += (luUtilities[2] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS0][exLuz][jLuz] += (luUtilities[3] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS1][exLuz][jLuz] += (luUtilities[4] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS2][exLuz][jLuz] += (luUtilities[5] + additionalUtility); + + accumulatedLandUseLogsumsCount[exLuz][jLuz]++; + + } + + } + + // calculate logsums to external LUZs from all origin LUZs if the + // destination LUZ is a cordon LUZ + if (externalLuzsForCordonLuz[jLuz] != null) + { + + for (int exLuz : externalLuzsForCordonLuz[jLuz]) + { + + double additionalUtility = Math.exp(cordonLuzMinutesForExternalLuz[exLuz] + * BuildAccessibilities.TIME_COEFFICIENT); + + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS0][iLuz][exLuz] += (luUtilities[0] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS1][iLuz][exLuz] += (luUtilities[1] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.PK][BuildAccessibilities.LS2][iLuz][exLuz] += (luUtilities[2] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS0][iLuz][exLuz] += (luUtilities[3] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS1][iLuz][exLuz] += (luUtilities[4] + additionalUtility); + accumulatedLandUseLogsums[BuildAccessibilities.LOGIT][BuildAccessibilities.OP][BuildAccessibilities.LS2][iLuz][exLuz] += (luUtilities[5] + additionalUtility); + + accumulatedLandUseLogsumsCount[iLuz][exLuz]++; + + } + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/DriveTransitWalkSkimsCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/DriveTransitWalkSkimsCalculator.java new file mode 100644 index 0000000..d28d05c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/DriveTransitWalkSkimsCalculator.java @@ -0,0 +1,313 @@ +package org.sandag.abm.accessibilities; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.util.ResourceUtil; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +import java.io.File; +import java.io.Serializable; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; + +/** + * This class is used to return drive-transit-walk skim values for MGRA pairs + * associated with estimation data file records. + * + * @author Jim Hicks + * @version March, 2010 + */ +public class DriveTransitWalkSkimsCalculator + implements Serializable +{ + + private transient Logger primaryLogger; + + private static final int EA = ModelStructure.EA_SKIM_PERIOD_INDEX; + private static final int AM = ModelStructure.AM_SKIM_PERIOD_INDEX; + private static final int MD = ModelStructure.MD_SKIM_PERIOD_INDEX; + private static final int PM = ModelStructure.PM_SKIM_PERIOD_INDEX; + private static final int EV = ModelStructure.EV_SKIM_PERIOD_INDEX; + public static final int NUM_PERIODS = ModelStructure.SKIM_PERIOD_INDICES.length; + private static final String[] PERIODS = ModelStructure.SKIM_PERIOD_STRINGS; + + private static final int ACCESS_TIME_INDEX = 0; + private static final int EGRESS_TIME_INDEX = 1; + private static final int NA = -999; + + private int maxDTWSkimSets = 5; + private int[] NUM_SKIMS; + private double[] defaultSkims; + + // declare UEC object + private UtilityExpressionCalculator driveWalkSkimUEC; + private IndexValues iv; + + // The simple auto skims UEC does not use any DMU variables + private TransitDriveAccessDMU dmu = new TransitDriveAccessDMU(); // DMU + // for + // this + // UEC + + private MgraDataManager mgraManager; + private int maxTap; + private String[] skimNames; + + + // skim values array for transit service type(local, premium), + // depart skim period(am, pm, op), + // and Tap-Tap pair. + private double[][][][][] storedDepartPeriodTapTapSkims; + + private BestTransitPathCalculator bestPathUEC; + + private MatrixDataServerIf ms; + + public DriveTransitWalkSkimsCalculator(HashMap rbMap) + { + mgraManager = MgraDataManager.getInstance(); + maxTap = mgraManager.getMaxTap(); + } + + public void setup(HashMap rbMap, Logger logger, + BestTransitPathCalculator myBestPathUEC) + { + + primaryLogger = logger; + + // set the best transit path utility UECs + bestPathUEC = myBestPathUEC; + + // Create the skim UECs + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap,"skim.drive.transit.walk.data.page"); + int skimPage = Util.getIntegerValueFromPropertyMap(rbMap,"skim.drive.transit.walk.skim.page"); + int dtwNumSkims = Util.getIntegerValueFromPropertyMap(rbMap, "skim.drive.transit.walk.skims"); + String uecPath = Util.getStringValueFromPropertyMap(rbMap, CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = Paths.get(uecPath,Util.getStringValueFromPropertyMap(rbMap, "skim.drive.transit.walk.uec.file")).toString(); + File uecFile = new File(uecFileName); + driveWalkSkimUEC = new UtilityExpressionCalculator(uecFile, skimPage, dataPage, rbMap, dmu); + + skimNames = driveWalkSkimUEC.getAlternativeNames(); + + //setup index values + iv = new IndexValues(); + + //setup default skim values + defaultSkims = new double[dtwNumSkims]; + for (int j = 0; j < dtwNumSkims; j++) { + defaultSkims[j] = NA; + } + + // point the stored Array of skims: by Prem or Local, DepartPeriod, O tap, D tap, skim values[] to a shared data store + StoredTransitSkimData storedDataObject = StoredTransitSkimData.getInstance( maxDTWSkimSets, NUM_PERIODS, maxTap ); + storedDepartPeriodTapTapSkims = storedDataObject.getStoredDtwDepartPeriodTapTapSkims(); + + } + + + + /** + * Return the array of drive-transit-walk skims for the ride mode, origin TAP, + * destination TAP, and departure time period. + * + * @param set for set source skims + * @param origTap best Origin TAP for the MGRA pair + * @param workTap best Destination TAP for the MGRA pair + * @param departPeriod Departure time period - 1 = AM period, 2 = PM period, 3 = + * OffPeak period + * @return Array of 55 skim values for the MGRA pair and departure period + */ + public double[] getDriveTransitWalkSkims(int set, double pDriveTime, double aWalkTime, int origTap, int destTap, + int departPeriod, boolean debug) + { + + dmu.setDriveTimeToTap(pDriveTime); + dmu.setMgraTapWalkTime(aWalkTime); + + iv.setOriginZone(origTap); + iv.setDestZone(destTap); + + // allocate space for the origin tap if it hasn't been allocated already + if (storedDepartPeriodTapTapSkims[set][departPeriod][origTap] == null) + { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap] = new double[maxTap + 1][]; + } + + // if the destTap skims are not already stored, calculate them and store + // them + if (storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap] == null) + { + dmu.setTOD(departPeriod); + dmu.setSet(set); + double[] results = driveWalkSkimUEC.solve(iv, dmu, null); + if (debug) + driveWalkSkimUEC.logAnswersArray(primaryLogger, "Drive-Walk Skims"); + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap] = results; + } + + try { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap][ACCESS_TIME_INDEX] = pDriveTime; + } + catch ( Exception e ) { + primaryLogger.error ("departPeriod=" + departPeriod + ", origTap=" + origTap + ", destTap=" + destTap + ", pDriveTime=" + pDriveTime); + primaryLogger.error ("exception setting drive-transit-walk drive access time in stored array.", e); + } + + try { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap][EGRESS_TIME_INDEX] = aWalkTime; + } + catch ( Exception e ) { + primaryLogger.error ("departPeriod=" + departPeriod + ", origTap=" + origTap + ", destTap=" + destTap + ", aWalkTime=" + aWalkTime); + primaryLogger.error ("exception setting drive-transit-walk walk egress time in stored array.", e); + } + return storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap]; + + + } + + + public double[] getNullTransitSkims() + { + return defaultSkims; + } + + /** + * Start the matrix server + * + * @param rb is a ResourceBundle for the properties file for this application + */ + private void startMatrixServer(ResourceBundle rb) + { + + primaryLogger.info(""); + primaryLogger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + primaryLogger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + primaryLogger.error(String + .format("exception caught running ctramp model components -- exiting."), e); + throw new RuntimeException(); + + } + + } + + /** + * log a report of the final skim values for the MGRA odt + * + * @param odt is an int[] with the first element the origin mgra and the second + * element the dest mgra and third element the departure period index + * @param bestTapPairs is an int[][] of TAP values with the first dimesion the + * ride mode and second dimension a 2 element array with best orig and + * dest TAP + * @param returnedSkims is a double[][] of skim values with the first dimesion + * the ride mode indices and second dimention the skim categories + */ + public void logReturnedSkims(int[] odt, int[][] bestTapPairs, double[][] skims) + { + + Modes.TransitMode[] mode = Modes.TransitMode.values(); + + int nrows = skims.length; + int ncols = 0; + for (int i = 0; i < nrows; i++) + if (skims[i].length > ncols) ncols = skims[i].length; + + String separator = ""; + String header = ""; + + primaryLogger.info(""); + primaryLogger.info(""); + header = "Returned drive-transit-walk skim value tables for origMgra=" + odt[0] + + ", destMgra=" + odt[1] + ", period index=" + odt[2] + ", period label=" + + PERIODS[odt[2]]; + for (int i = 0; i < header.length(); i++) + separator += "^"; + + primaryLogger.info(separator); + primaryLogger.info(header); + primaryLogger.info(""); + + String modeHeading = String.format("%-12s %3s ", "RideMode:", mode[0]); + for (int i = 1; i < bestTapPairs.length; i++) + modeHeading += String.format(" %3s ", mode[i]); + primaryLogger.info(modeHeading); + + String[] logValues = {"NA", "NA"}; + if (bestTapPairs[0] != null) + { + logValues[0] = String.valueOf(bestTapPairs[0][0]); + logValues[1] = String.valueOf(bestTapPairs[0][1]); + } + String tapHeading = String.format("%-12s %4s-%4s ", "TAP Pair:", logValues[0], + logValues[1]); + + for (int i = 1; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] != null) + { + logValues[0] = String.valueOf(bestTapPairs[i][0]); + logValues[1] = String.valueOf(bestTapPairs[i][1]); + } else + { + logValues[0] = "NA"; + logValues[1] = "NA"; + } + tapHeading += String.format(" %4s-%4s ", logValues[0], logValues[1]); + } + primaryLogger.info(tapHeading); + + String underLine = String.format("%-12s %9s ", "---------", "---------"); + for (int i = 1; i < bestTapPairs.length; i++) + underLine += String.format(" %9s ", "---------"); + primaryLogger.info(underLine); + + for (int j = 0; j < ncols; j++) + { + String tableRecord = ""; + if (j < skims[0].length) tableRecord = String.format("%-12d %12.5f ", j + 1, + skims[0][j]); + else tableRecord = String.format("%-12d %12s ", j + 1, ""); + for (int i = 1; i < bestTapPairs.length; i++) + { + if (j < skims[i].length) tableRecord += String.format(" %12.5f ", skims[i][j]); + else tableRecord += String.format(" %12s ", ""); + } + primaryLogger.info(tableRecord); + } + + primaryLogger.info(""); + primaryLogger.info(separator); + } + + public String[] getSkimNames() { + return skimNames; + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/MandatoryAccessibilitiesCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/MandatoryAccessibilitiesCalculator.java new file mode 100644 index 0000000..c158ad1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/MandatoryAccessibilitiesCalculator.java @@ -0,0 +1,593 @@ +package org.sandag.abm.accessibilities; + +import com.pb.common.util.Tracer; +import com.pb.common.calculator.IndexValues; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +import java.io.File; +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; +import org.sandag.abm.modechoice.Modes; + +/** + * This class builds accessibility components for all modes. + * + * @author Joel Freedman + * @version May, 2009 + */ +public class MandatoryAccessibilitiesCalculator + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(MandatoryAccessibilitiesCalculator.class); + + private static final int MIN_EXP_FUNCTION_ARGUMENT = -500; + + private static final int PEAK_NONTOLL_SOV_TIME_INDEX = 0; + private static final int PEAK_NONTOLL_SOV_DIST_INDEX = 1; + private static final int OFFPEAK_NONTOLL_SOV_TIME_INDEX = 2; + private static final int OFFPEAK_NONTOLL_SOV_DIST_INDEX = 3; + + private UtilityExpressionCalculator autoSkimUEC; + private UtilityExpressionCalculator bestWalkTransitUEC; + private UtilityExpressionCalculator bestDriveTransitUEC; + private UtilityExpressionCalculator autoLogsumUEC; + private UtilityExpressionCalculator transitLogsumUEC; + + private MandatoryAccessibilitiesDMU dmu; + private IndexValues iv; + + private NonTransitUtilities ntUtilities; + + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private TapDataManager tapManager; + + // auto sufficiency (0 autos, autos=adults), + // and mode (SOV,HOV,Walk-Transit,Non-Motorized) + private double[][] expConstants; + + private String[] accNames = { + "SovTime", // 0 + "SovDist", // 1 + "WTTime", // 2 + "DTTime", // 3 + "SovUtility", // 4 + "WTUtility", // 5 + "AutoLogsum", // 6 + "WTLogsum", // 7 + "TransitLogsum", // 8 + "WTRailShare", // 9 + "DTRailShare", // 10 + "DTLogsum", // 11 + "HovUtility" // 12 + }; + + private BestTransitPathCalculator bestPathCalculator; + + + public MandatoryAccessibilitiesCalculator(HashMap rbMap, + NonTransitUtilities aNtUtilities, double[][] aExpConstants, BestTransitPathCalculator myBestPathCalculator) + { + + ntUtilities = aNtUtilities; + expConstants = aExpConstants; + + // Create the UECs + String uecFileName = Util.getStringValueFromPropertyMap(rbMap, "acc.mandatory.uec.file"); + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.mandatory.data.page"); + int autoSkimPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.mandatory.auto.page"); + int bestWalkTransitPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.mandatory.bestWalkTransit.page"); + int bestDriveTransitPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.mandatory.bestDriveTransit.page"); + int autoLogsumPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.mandatory.autoLogsum.page"); + int transitLogsumPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.mandatory.transitLogsum.page"); + + + dmu = new MandatoryAccessibilitiesDMU(); + + File uecFile = new File(uecFileName); + autoSkimUEC = new UtilityExpressionCalculator(uecFile, autoSkimPage, dataPage, rbMap, dmu); + bestWalkTransitUEC = new UtilityExpressionCalculator(uecFile, bestWalkTransitPage, dataPage, rbMap, dmu); + bestDriveTransitUEC = new UtilityExpressionCalculator(uecFile, bestDriveTransitPage, dataPage, rbMap, dmu); + autoLogsumUEC = new UtilityExpressionCalculator(uecFile, autoLogsumPage, dataPage, rbMap, dmu); + transitLogsumUEC = new UtilityExpressionCalculator(uecFile, transitLogsumPage, dataPage, rbMap, dmu); + + iv = new IndexValues(); + + tazManager = TazDataManager.getInstance(); + tapManager = TapDataManager.getInstance(); + mgraManager = MgraDataManager.getInstance(); + + bestPathCalculator = myBestPathCalculator; + } + + + public double[] calculateWorkerMandatoryAccessibilities(int hhMgra, int workMgra) + { + return calculateAccessibilitiesForMgraPair(hhMgra, workMgra, false, null); + } + + public double[] calculateStudentMandatoryAccessibilities(int hhMgra, int schoolMgra) + { + return calculateAccessibilitiesForMgraPair(hhMgra, schoolMgra, false, null); + } + + /** + * Calculate the work logsum for the household MGRA and sampled work location + * MGRA. + * + * @param hhMgra Household MGRA + * @param workMgra Sampled work MGRA + * @param autoSufficiency Auto sufficiency category + * @return Work mode choice logsum + */ + public double calculateWorkLogsum(int hhMgra, int workMgra, int autoSufficiency, boolean debug, Logger aLogger) + { + + String separator = ""; + String header = ""; + if (debug) + { + aLogger.info(""); + aLogger.info(""); + header = "calculateWorkLogsum() debug info for homeMgra=" + hhMgra + ", workMgra=" + workMgra; + for (int i = 0; i < header.length(); i++) + separator += "^"; + } + + double[] accessibilities = calculateAccessibilitiesForMgraPair(hhMgra, workMgra, debug, aLogger); + + double sovUtility = accessibilities[4]; + double hovUtility = accessibilities[12]; + double transitLogsum = accessibilities[8]; // includes both walk and drive access + double nmExpUtility = ntUtilities.getNMotorExpUtility(hhMgra, workMgra, NonTransitUtilities.OFFPEAK_PERIOD_INDEX); + + // constrain auto sufficiency to 0,1,2 + autoSufficiency = Math.min(autoSufficiency, 2); + + double utilSum = Math.exp(sovUtility) * expConstants[autoSufficiency][0] + + Math.exp(hovUtility) * expConstants[autoSufficiency][1] + + Math.exp(transitLogsum) * expConstants[autoSufficiency][2] + + nmExpUtility * expConstants[autoSufficiency][3]; + + double logsum = Math.log(utilSum); + + if (debug) + { + + aLogger.info(separator); + aLogger.info(header); + aLogger.info(separator); + + aLogger.info("accessibilities array values"); + aLogger.info(String.format("%5s %15s %15s", "i", "accName", "value")); + aLogger.info(String.format("%5s %15s %15s", "-----", "----------", "----------")); + for (int i = 0; i < accessibilities.length; i++) + { + aLogger.info(String.format("%5d %15s %15.5e", i, accNames[i], accessibilities[i])); + } + + aLogger.info(""); + aLogger.info(""); + aLogger.info("logsum component values"); + aLogger.info(String.format("autoSufficiency = %d", autoSufficiency)); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e, %-18s = %15.5e", + "sovUtility", sovUtility, "exp(sovUtility)", Math.exp(sovUtility), String + .format("expConst suff=%d 0", autoSufficiency), + expConstants[autoSufficiency][0])); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e, %-18s = %15.5e", + "hovUtility", hovUtility, "exp(hovUtility)", Math.exp(hovUtility), String + .format("expConst suff=%d 1", autoSufficiency), + expConstants[autoSufficiency][1])); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e, %-18s = %15.5e", + "transitLogsum", transitLogsum, "exp(transitLogsum)", Math.exp(transitLogsum), + String.format("expConst suff=%d 2", autoSufficiency), + expConstants[autoSufficiency][2])); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e", "nmExpUtility", + nmExpUtility, String.format("expConst suff=%d 3", autoSufficiency), + expConstants[autoSufficiency][3])); + aLogger.info(String.format("%-15s = %15.5e", "utilSum", utilSum)); + aLogger.info(String.format("%-15s = %15.5e", "logsum", logsum)); + aLogger.info(separator); + } + + return logsum; + } + + /** + * Calculate the school logsum for the household MGRA and sampled school location + * MGRA. + * + * @param hhMgra Household MGRA + * @param schoolMgra Sampled work MGRA + * @param autoSufficiency Auto sufficiency category + * @param studentType Student type 0=Pre-school (SOV not available) 1=K-8 (SOV + * not available) 2=9-12 (Normal car-sufficiency-based logsum) + * 3=College/university(typical) (Normal car-sufficiency-based logsum) + * 4=College/university(non-typical) (Normal car-sufficiency-based + * logsum) + * @return School mode choice logsum + */ + public double calculateSchoolLogsum(int hhMgra, int schoolMgra, int autoSufficiency, int studentType, boolean debug, Logger aLogger) + { + + String separator = ""; + String header = ""; + if (debug) + { + aLogger.info(""); + aLogger.info(""); + header = "calculateSchoolLogsum() debug info for homeMgra=" + hhMgra + ", schoolMgra=" + + schoolMgra; + for (int i = 0; i < header.length(); i++) + separator += "^"; + } + + double[] accessibilities = calculateAccessibilitiesForMgraPair(hhMgra, schoolMgra, debug, aLogger); + + double sovUtility = accessibilities[4]; + double hovUtility = accessibilities[12]; + double transitLogsum = accessibilities[8]; // includes both walk and drive access + double nmExpUtility = ntUtilities.getNMotorExpUtility(hhMgra, schoolMgra, NonTransitUtilities.OFFPEAK_PERIOD_INDEX); + + // constrain auto sufficiency to 0,1,2 + autoSufficiency = Math.min(autoSufficiency, 2); + + double logsum = Math.exp(hovUtility) * expConstants[autoSufficiency][1] + + Math.exp(transitLogsum) * expConstants[autoSufficiency][2] + + nmExpUtility * expConstants[autoSufficiency][3]; + + // used for debugging + double logsum1 = logsum; + + if (studentType >= 2) + { + logsum = logsum + Math.exp(sovUtility) * expConstants[autoSufficiency][0]; + } + + // used for debugging + double logsum2 = logsum; + + logsum = Math.log(logsum); + + if (debug) + { + + aLogger.info(separator); + aLogger.info(header); + aLogger.info(separator); + + aLogger.info("accessibilities array values"); + aLogger.info(String.format("%5s %15s %15s", "i", "accName", "value")); + aLogger.info(String.format("%5s %15s %15s", "-----", "----------", "----------")); + for (int i = 0; i < accessibilities.length; i++) + { + aLogger.info(String.format("%5d %15s %15.5e", i, accNames[i], accessibilities[i])); + } + + aLogger.info(""); + aLogger.info(""); + aLogger.info("logsum component values"); + aLogger.info(String.format("autoSufficiency = %d", autoSufficiency)); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e, %-18s = %15.5e", + "hovUtility", hovUtility, "exp(hovUtility)", Math.exp(hovUtility), + String.format("expConst suff=%d 1", autoSufficiency), + expConstants[autoSufficiency][1])); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e, %-18s = %15.5e", + "transitLogsum", transitLogsum, "exp(transitLogsum)", Math.exp(transitLogsum), + String.format("expConst suff=%d 2", autoSufficiency), + expConstants[autoSufficiency][2])); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e", "nmExpUtility", + nmExpUtility, String.format("expConst suff=%d 3", autoSufficiency), + expConstants[autoSufficiency][3])); + aLogger.info(String.format("%s = %15.5e", "utility sum (before adding sovUtility)", + logsum1)); + if (studentType >= 2) + { + aLogger.info(String.format("studentType = %d", studentType)); + aLogger.info(String.format("%-15s = %15.5e, %-18s = %15.5e, %-18s = %15.5e", + "sovUtility", sovUtility, "exp(sovUtility)", Math.exp(sovUtility), String.format("expConst suff=%d 0", autoSufficiency), + expConstants[autoSufficiency][0])); + aLogger.info(String.format("%s = %15.5e", "utility sum (after adding sovUtility)", logsum2)); + } else + { + aLogger.info(String.format( + "studentType = %d, no additional contribution to utility sum", + studentType)); + } + aLogger.info(String.format("%s = %15.5e, %s = %15.5e", "final utility sum", logsum2, + "final logsum", logsum)); + aLogger.info(separator); + } + + return logsum; + } + + /** + * Calculate the accessibilities for a given origin and destination mgra + * + * @param oMgra The origin mgra + * @param dMgra The destination mgra + * @return An array of accessibilities + */ + public double[] calculateAccessibilitiesForMgraPair(int oMgra, int dMgra, boolean debug, Logger aLogger) + { + + double[] accessibilities = new double[accNames.length]; + + // DMUs for this UEC + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + if (oMgra > 0 && dMgra > 0) + { + + int oTaz = mgraManager.getTaz(oMgra); + int dTaz = mgraManager.getTaz(dMgra); + + iv.setOriginZone(oTaz); + iv.setDestZone(dTaz); + + // sov time and distance + double[] autoResults = autoSkimUEC.solve(iv, dmu, null); + if (debug) + autoSkimUEC.logAnswersArray( aLogger, String.format( "autoSkimUEC: oMgra=%d, dMgra=%d", oMgra, dMgra ) ); + + // autoResults[0] is peak non-toll sov time, autoResults[1] is peak non-toll sov dist + // autoResults[2] is off-peak non-toll sov time, autoResults[3] is off-peak non-toll sov dist + accessibilities[0] = autoResults[PEAK_NONTOLL_SOV_TIME_INDEX]; + accessibilities[1] = autoResults[PEAK_NONTOLL_SOV_DIST_INDEX]; + + // pre-calculate the hov, sov, and non-motorized exponentiated utilities for the origin MGRA. + // the method called returns cached values if they were already calculated. + ntUtilities.buildUtilitiesForOrigMgraAndPeriod( oMgra, NonTransitUtilities.PEAK_PERIOD_INDEX ); + + // auto logsum + double pkSovExpUtility = ntUtilities.getSovExpUtility(oTaz, dTaz, NonTransitUtilities.PEAK_PERIOD_INDEX); + double pkHovExpUtility = ntUtilities.getHovExpUtility(oTaz, dTaz, NonTransitUtilities.PEAK_PERIOD_INDEX); + + dmu.setSovNestLogsum(-999); + if (pkSovExpUtility > 0) + { + dmu.setSovNestLogsum(Math.log(pkSovExpUtility)); + accessibilities[4] = dmu.getSovNestLogsum(); + } + dmu.setHovNestLogsum(-999); + if (pkHovExpUtility > 0) + { + dmu.setHovNestLogsum(Math.log(pkHovExpUtility)); + accessibilities[12] = dmu.getHovNestLogsum(); + } + + double[] autoLogsum = autoLogsumUEC.solve(iv, dmu, null); + if (debug) + autoLogsumUEC.logAnswersArray(aLogger, String.format( + "autoLogsumUEC: oMgra=%d, dMgra=%d", oMgra, dMgra)); + accessibilities[6] = autoLogsum[0]; + + + ////////////////////////////////////////////////////////////////////////// + // walk transit + ////////////////////////////////////////////////////////////////////////// + + // determine the best transit path, which also stores the best utilities array and the best mode + bestPathCalculator.findBestWalkTransitWalkTaps(walkDmu, ModelStructure.AM_SKIM_PERIOD_INDEX, oMgra, dMgra, debug, aLogger); + + // sum the exponentiated utilities over modes + double sumWlkExpUtilities = bestPathCalculator.getSumExpUtilities(); + double[] walkTransitWalkUtilities = bestPathCalculator.getBestUtilities(); + + // calculate ln( sum of exponentiated utilities ) and set in accessibilities array and the dmu object + if (sumWlkExpUtilities > 0) + accessibilities[7] = Math.log(sumWlkExpUtilities); + else + accessibilities[7] = -999; + + dmu.setWlkNestLogsum(accessibilities[7]); + + + int bestAlt = bestPathCalculator.getBestTransitAlt(); + + if (bestAlt >= 0) + { + double[] bestTaps = bestPathCalculator.getBestTaps(bestAlt); + int oTapPosition = mgraManager.getTapPosition(oMgra, (int)bestTaps[0]); + int dTapPosition = mgraManager.getTapPosition(dMgra, (int)bestTaps[1]); + int set = (int)bestTaps[2]; + + if (oTapPosition == -1 || dTapPosition == -1) + { + logger.fatal("Error: Best walk transit alt " + bestAlt + " found for origin mgra " + + oMgra + " to destination mgra " + dMgra + " but oTap pos " + + oTapPosition + " and dTap pos " + dTapPosition); + throw new RuntimeException(); + } + + if (walkTransitWalkUtilities[bestAlt] <= MIN_EXP_FUNCTION_ARGUMENT) + { + logger.fatal("Error: Best walk transit alt " + bestAlt + " found for origin mgra " + + oMgra + " to destination mgra " + dMgra + " but Utility = " + + walkTransitWalkUtilities[bestAlt]); + throw new RuntimeException(); + } + accessibilities[5] = Math.log(walkTransitWalkUtilities[bestAlt]); + + //set access and egress times + int oPos = mgraManager.getTapPosition(oMgra, (int)bestTaps[0]); + float mgraTapWalkTime = mgraManager.getMgraToTapWalkTime(oMgra, oPos); + dmu.setMgraTapWalkTime(mgraTapWalkTime); + + int dPos = mgraManager.getTapPosition(dMgra, (int)bestTaps[1]); + float tapMgraWalkTime = mgraManager.getMgraToTapWalkTime(dMgra, dPos); + dmu.setTapMgraWalkTime(tapMgraWalkTime); + + dmu.setBestSet(set); + iv.setOriginZone((int)bestTaps[0]); + iv.setDestZone((int)bestTaps[1]); + double[] wlkTransitTimes = bestWalkTransitUEC.solve(iv, dmu, null); + + if (debug){ + bestWalkTransitUEC.logAnswersArray(aLogger, String.format("bestWalkTransitUEC: oMgra=%d, dMgra=%d", oMgra, dMgra)); + } + + accessibilities[2] = wlkTransitTimes[0]; + accessibilities[9] = wlkTransitTimes[1]; + + } + + ////////////////////////////////////////////////////////////////////////// + // drive transit + ////////////////////////////////////////////////////////////////////////// + + // determine the best transit path, which also stores the best utilities array and the best mode + bestPathCalculator.findBestDriveTransitWalkTaps(walkDmu, driveDmu, ModelStructure.AM_SKIM_PERIOD_INDEX, oMgra, dMgra, debug, aLogger, (float) autoResults[PEAK_NONTOLL_SOV_DIST_INDEX]); + + // sum the exponentiated utilities over modes + double sumDrvExpUtilities = 0; + double[] driveTransitWalkUtilities = bestPathCalculator.getBestUtilities(); + for (int i=0; i < driveTransitWalkUtilities.length; i++){ + if ( driveTransitWalkUtilities[i] > MIN_EXP_FUNCTION_ARGUMENT ) + sumDrvExpUtilities += Math.exp(driveTransitWalkUtilities[i]); + } + + + // calculate ln( sum of exponentiated utilities ) and set in accessibilities array and the dmu object + if (sumDrvExpUtilities > 0) + accessibilities[11] = Math.log(sumDrvExpUtilities); + else + accessibilities[11] = -999; + + dmu.setDrvNestLogsum(accessibilities[11]); + + + bestAlt = bestPathCalculator.getBestTransitAlt(); + + if (bestAlt >= 0) + { + double[] bestTaps = bestPathCalculator.getBestTaps(bestAlt); + int oTapPosition = tazManager.getTapPosition(oTaz, (int)bestTaps[0], Modes.AccessMode.PARK_N_RIDE); + int dTapPosition = mgraManager.getTapPosition(dMgra, (int)bestTaps[1]); + int set = (int)bestTaps[2]; + + if (oTapPosition == -1 || dTapPosition == -1) + { + logger.fatal("Error: Best drive transit alt " + bestAlt + " found for origin mgra " + + oMgra + " to destination mgra " + dMgra + " but oTap pos " + + oTapPosition + " and dTap pos " + dTapPosition); + throw new RuntimeException(); + } + + if (driveTransitWalkUtilities[bestAlt] <= MIN_EXP_FUNCTION_ARGUMENT) + { + logger.fatal("Error: Best drive transit alt " + bestAlt + " found for origin mgra " + + oMgra + " to destination mgra " + dMgra + " but Utility = " + + driveTransitWalkUtilities[bestAlt]); + throw new RuntimeException(); + } + + //set access and egress times + dmu.setDriveTimeToTap(tazManager.getTapTime(oTaz, oTapPosition, Modes.AccessMode.PARK_N_RIDE)); + dmu.setDriveDistToTap(tazManager.getTapDist(oTaz, oTapPosition, Modes.AccessMode.PARK_N_RIDE)); + + int dPos = mgraManager.getTapPosition(dMgra, (int)bestTaps[1]); + float tapMgraWalkTime = mgraManager.getMgraToTapWalkTime(dMgra, dPos); + dmu.setTapMgraWalkTime(tapMgraWalkTime); + + dmu.setBestSet(set); + iv.setOriginZone((int)bestTaps[0]); + iv.setDestZone((int)bestTaps[1]); + double[] drvTransitTimes = bestDriveTransitUEC.solve(iv, dmu, null); + + if (debug){ + bestDriveTransitUEC.logAnswersArray(aLogger, String.format("bestDriveTransitUEC: oMgra=%d, dMgra=%d", oMgra, dMgra)); + } + + accessibilities[3] = drvTransitTimes[0]; + accessibilities[10] = drvTransitTimes[1]; + + } + + + double[] transitLogsumResults = transitLogsumUEC.solve(iv, dmu, null); + if (debug){ + transitLogsumUEC.logAnswersArray(aLogger, String.format("transitLogsumUEC: oMgra=%d, dMgra=%d", oMgra, dMgra)); + } + + // transit logsum results array has only 1 alternative, so result is in 0 element. + accessibilities[8] = transitLogsumResults[0]; + + } // end if oMgra and dMgra > 0 + + return accessibilities; + } + + /** + * Calculate auto skims for a given origin to all destination mgras, and return + * auto distance. + * + * @param oMgra The origin mgra + * @return An array of distances + */ + public double[] calculateDistancesForAllMgras(int oMgra) + { + + double[] distances = new double[mgraManager.getMaxMgra() + 1]; + + int oTaz = mgraManager.getTaz(oMgra); + iv.setOriginZone(oTaz); + + for (int i = 0; i < mgraManager.getMgras().size(); i++) + { + + int dTaz = mgraManager.getTaz(mgraManager.getMgras().get(i)); + iv.setDestZone(dTaz); + + // sov distance + double[] autoResults = autoSkimUEC.solve(iv, dmu, null); + distances[dTaz] = autoResults[PEAK_NONTOLL_SOV_DIST_INDEX]; + + } + + return distances; + } + + /** + * Calculate auto skims for a given origin to all destination mgras, and return + * auto distance. + * + * @param oMgra The origin mgra + * @return An array of distances + */ + public double[] calculateOffPeakDistancesForAllMgras(int oMgra) + { + + double[] distances = new double[mgraManager.getMaxMgra() + 1]; + + int oTaz = mgraManager.getTaz(oMgra); + iv.setOriginZone(oTaz); + + for (int i = 0; i < mgraManager.getMgras().size(); i++) + { + + int dTaz = mgraManager.getTaz(mgraManager.getMgras().get(i)); + iv.setDestZone(dTaz); + + // sov distance + double[] autoResults = autoSkimUEC.solve(iv, dmu, null); + distances[dTaz] = autoResults[OFFPEAK_NONTOLL_SOV_DIST_INDEX]; + + } + + return distances; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/MandatoryAccessibilitiesDMU.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/MandatoryAccessibilitiesDMU.java new file mode 100644 index 0000000..cc68cf4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/MandatoryAccessibilitiesDMU.java @@ -0,0 +1,206 @@ +package org.sandag.abm.accessibilities; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.VariableTable; + +public class MandatoryAccessibilitiesDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(MandatoryAccessibilitiesDMU.class); + + protected HashMap methodIndexMap; + + protected double sovNestLogsum; + protected double hovNestLogsum; + protected double wlkNestLogsum; + protected double drvNestLogsum; + protected int bestSet; + protected float mgraTapWalkTime; + protected float tapMgraWalkTime; + protected float driveDistToTap; + protected float driveTimeToTap; + protected int autoSufficiency; + + public MandatoryAccessibilitiesDMU() + { + setupMethodIndexMap(); + } + + public int getAutoSufficiency() + { + return autoSufficiency; + } + + public void setAutoSufficiency(int autoSufficiency) + { + this.autoSufficiency = autoSufficiency; + } + + public double getSovNestLogsum() + { + return sovNestLogsum; + } + + public void setSovNestLogsum(double sovNestLogsum) + { + this.sovNestLogsum = sovNestLogsum; + } + + public double getHovNestLogsum() + { + return hovNestLogsum; + } + + public void setHovNestLogsum(double hovNestLogsum) + { + this.hovNestLogsum = hovNestLogsum; + } + + public double getWlkNestLogsum() + { + return wlkNestLogsum; + } + + public void setWlkNestLogsum(double wlkNestLogsum) + { + this.wlkNestLogsum = wlkNestLogsum; + } + + public double getDrvNestLogsum() + { + return drvNestLogsum; + } + + public void setDrvNestLogsum(double drvNestLogsum) + { + this.drvNestLogsum = drvNestLogsum; + } + + public int getBestSet() + { + return bestSet; + } + + public void setBestSet(int bestSet) + { + this.bestSet = bestSet; + } + + public float getMgraTapWalkTime() + { + return mgraTapWalkTime; + } + + public void setMgraTapWalkTime(float mgraTapWalkTime) + { + this.mgraTapWalkTime = mgraTapWalkTime; + } + + public float getTapMgraWalkTime() + { + return tapMgraWalkTime; + } + + public void setTapMgraWalkTime(float tapMgraWalkTime) + { + this.tapMgraWalkTime = tapMgraWalkTime; + } + + public float getDriveDistToTap() + { + return driveDistToTap; + } + + public void setDriveDistToTap(float drvDistToTap) + { + this.driveDistToTap = drvDistToTap; + } + + public float getDriveTimeToTap() + { + return driveTimeToTap; + } + + public void setDriveTimeToTap(float drvTimeToTap) + { + this.driveTimeToTap = drvTimeToTap; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getBestSet", 0); + methodIndexMap.put("getDriveDistToTap", 1); + methodIndexMap.put("getDriveTimeToTap", 2); + methodIndexMap.put("getWlkNestLogsum", 3); + methodIndexMap.put("getDrvNestLogsum", 4); + methodIndexMap.put("getSovNestLogsum", 5); + methodIndexMap.put("getHovNestLogsum", 6); + methodIndexMap.put("getMgraTapWalkTime", 7); + methodIndexMap.put("getTapMgraWalkTime", 8); + methodIndexMap.put("getAutoSufficiency", 9); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getBestSet(); + case 1: + return getDriveDistToTap(); + case 2: + return getDriveTimeToTap(); + case 3: + return getWlkNestLogsum(); + case 4: + return getDrvNestLogsum(); + case 5: + return getSovNestLogsum(); + case 6: + return getHovNestLogsum(); + case 7: + return getMgraTapWalkTime(); + case 8: + return getTapMgraWalkTime(); + case 9: + return getAutoSufficiency(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/McLogsumsAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/McLogsumsAppender.java new file mode 100644 index 0000000..f2af9c9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/McLogsumsAppender.java @@ -0,0 +1,980 @@ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagAppendMcLogsumDMU; +import org.sandag.abm.application.SandagTripModeChoiceDMU; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class McLogsumsAppender + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(McLogsumsAppender.class); + protected transient Logger slcSoaLogger = Logger.getLogger("slcSoa"); + protected transient Logger nonManLogsumsLogger = Logger.getLogger("nonManLogsums"); + + protected int debugEstimationFileRecord1; + protected int debugEstimationFileRecord2; + + protected static final String ESTIMATION_DATA_RECORDS_FILE_KEY = "homeInterview.survey.file"; + public static final String PROPERTIES_UEC_TOUR_MODE_CHOICE = "tourModeChoice.uec.file"; + public static final String PROPERTIES_UEC_TRIP_MODE_CHOICE = "tripModeChoice.uec.file"; + + public static final int WORK_SHEET = 1; + public static final int UNIVERSITY_SHEET = 2; + public static final int SCHOOL_SHEET = 3; + public static final int MAINTENANCE_SHEET = 4; + public static final int DISCRETIONARY_SHEET = 5; + public static final int SUBTOUR_SHEET = 6; + public static final int[] MC_PURPOSE_SHEET_INDICES = {-1, WORK_SHEET, + UNIVERSITY_SHEET, SCHOOL_SHEET, MAINTENANCE_SHEET, MAINTENANCE_SHEET, + MAINTENANCE_SHEET, DISCRETIONARY_SHEET, DISCRETIONARY_SHEET, DISCRETIONARY_SHEET, + SUBTOUR_SHEET }; + + public static final int WORK_CATEGORY = 0; + public static final int UNIVERSITY_CATEGORY = 1; + public static final int SCHOOL_CATEGORY = 2; + public static final int MAINTENANCE_CATEGORY = 3; + public static final int DISCRETIONARY_CATEGORY = 4; + public static final int SUBTOUR_CATEGORY = 5; + public static final String[] PURPOSE_CATEGORY_LABELS = {"work", "university", + "school", "maintenance", "discretionary", "subtour" }; + public static final int[] PURPOSE_CATEGORIES = {-1, WORK_CATEGORY, + UNIVERSITY_CATEGORY, SCHOOL_CATEGORY, MAINTENANCE_CATEGORY, MAINTENANCE_CATEGORY, + MAINTENANCE_CATEGORY, DISCRETIONARY_CATEGORY, DISCRETIONARY_CATEGORY, + DISCRETIONARY_CATEGORY, SUBTOUR_CATEGORY }; + + protected static final int ORIG_MGRA = 1; + protected static final int DEST_MGRA = 2; + protected static final int ADULTS = 3; + protected static final int AUTOS = 4; + protected static final int HHSIZE = 5; + protected static final int FEMALE = 6; + protected static final int AGE = 7; + protected static final int JOINT = 8; + protected static final int PARTYSIZE = 9; + protected static final int TOUR_PURPOSE = 10; + protected static final int INCOME = 11; + protected static final int ESCORT = 12; + protected static final int DEPART_PERIOD = 13; + protected static final int ARRIVE_PERIOD = 14; + protected static final int SAMPNO = 15; + protected static final int WORK_TOUR_MODE = 16; + protected static final int OUT_STOPS = 17; + protected static final int IN_STOPS = 18; + protected static final int FIRST_TRIP = 19; + protected static final int LAST_TRIP = 20; + protected static final int TOUR_MODE = 21; + protected static final int TRIP_PERIOD = 22; + protected static final int CHOSEN_MGRA = 23; + protected static final int DIRECTION = 24; + protected static final int PORTION = 25; + protected static final int PERNO = 26; + protected static final int TOUR_ID = 27; + protected static final int TRIPNO = 28; + protected static final int STOPID = 29; + protected static final int STOPNO = 30; + protected static final int STOP_PURPOSE = 31; + protected static final int NUM_FIELDS = 32; + + private static final int INBOUND_DIRCETION_CODE = 2; + + // estimation file defines time periods as: + // 1 | Early AM: 3:00 AM - 5:59 AM | + // 2 | AM Peak: 6:00 AM - 8:59 AM | + // 3 | Early MD: 9:00 AM - 11:59 PM | + // 4 | Late MD: 12:00 PM - 3:29 PM | + // 5 | PM Peak: 3:30 PM - 6:59 PM | + // 6 | Evening: 7:00 PM - 2:59 AM | + + protected static final int LAST_EA_INDEX = 3; + protected static final int LAST_AM_INDEX = 9; + protected static final int LAST_MD_INDEX = 22; + protected static final int LAST_PM_INDEX = 29; + + protected static final int EA = 1; + protected static final int AM = 2; + protected static final int MD = 3; + protected static final int PM = 4; + protected static final int EV = 5; + + protected static final int EA_D = 1; // 5am + protected static final int AM_D = 5; // 7am + protected static final int MD_D = 15; // 12pm + protected static final int PM_D = 27; // 6pm + protected static final int EV_D = 35; // 10pm + protected static final int[] DEFAULT_DEPART_INDICES = {-1, EA_D, AM_D, MD_D, + PM_D, EV_D }; + + protected static final int EA_A = 2; // 5:30am + protected static final int AM_A = 6; // 7:30am + protected static final int MD_A = 16; // 12:30pm + protected static final int PM_A = 28; // 6:30pm + protected static final int EV_A = 36; // 10:30pm + protected static final int[] DEFAULT_ARRIVE_INDICES = {-1, EA_A, AM_A, MD_A, + PM_A, EV_A }; + + protected String[][] departArriveCombinationLabels = { {"EA", "EA"}, + {"EA", "AM"}, {"EA", "MD"}, {"EA", "PM"}, {"EA", "EV"}, {"AM", "AM"}, {"AM", "MD"}, + {"AM", "PM"}, {"AM", "EV"}, {"MD", "MD"}, {"MD", "PM"}, {"MD", "EV"}, {"PM", "PM"}, + {"PM", "EV"}, {"EV", "EV"} }; + + protected int[][] departArriveCombinations = { {EA, EA}, {EA, AM}, + {EA, MD}, {EA, PM}, {EA, EV}, {AM, AM}, {AM, MD}, {AM, PM}, {AM, EV}, {MD, MD}, + {MD, PM}, {MD, EV}, {PM, PM}, {PM, EV}, {EV, EV} }; + + private BestTransitPathCalculator bestPathUEC; + + // modeChoiceLogsums is an array of logsums for each unique depart/arrive + // skim + // period combination, for each sample destination + protected double[][] modeChoiceLogsums; + protected double[][] tripModeChoiceLogsums; + + protected double[] tripModeChoiceSegmentLogsums = new double[2]; + + protected double[] tripModeChoiceSegmentStoredProbabilities; + + // departArriveLogsums is the array of values for all 15 depart/arrive + // combinations + protected double[][] departArriveLogsums; + + protected int chosenLogsumTodIndex = 0; + + protected int[] chosenDepartArriveCombination = new int[2]; + + protected int numMgraFields; + protected int[] mgraSetForLogsums; + + protected int[][] mgras; + + protected TazDataManager tazs; + protected MgraDataManager mgraManager; + protected TapDataManager tapManager; + protected MatrixDataServerIf ms; + + protected ModelStructure modelStructure; + + protected int[][] bestTapPairs; + protected double[] nmSkimsOut; + protected double[] nmSkimsIn; + protected double[] lbSkimsOut; + protected double[] lbSkimsIn; + protected double[] ebSkimsOut; + protected double[] ebSkimsIn; + protected double[] brSkimsOut; + protected double[] brSkimsIn; + protected double[] lrSkimsOut; + protected double[] lrSkimsIn; + protected double[] crSkimsOut; + protected double[] crSkimsIn; + + protected double[] lsWgtAvgCostM; + protected double[] lsWgtAvgCostD; + protected double[] lsWgtAvgCostH; + + protected int totalTime1 = 0; + protected int totalTime2 = 0; + + private McLogsumsCalculator logsumHelper; + + public McLogsumsAppender(HashMap propertyMap) + { + logsumHelper = new McLogsumsCalculator(); + + logsumHelper.setupSkimCalculators(propertyMap); + + } + + public BestTransitPathCalculator getBestTransitPathCalculator() + { + return bestPathUEC; + } + + protected TableDataSet getEstimationDataTableDataSet(HashMap rbMap) + { + + String estFileName = Util.getStringValueFromPropertyMap(rbMap, + ESTIMATION_DATA_RECORDS_FILE_KEY); + if (estFileName == null) + { + logger.error("Error getting the filename from the properties file for the Sandag home interview survey data records file."); + logger.error("Properties file target: " + ESTIMATION_DATA_RECORDS_FILE_KEY + + " not found."); + logger.error("Please specify a filename value for the " + + ESTIMATION_DATA_RECORDS_FILE_KEY + " property."); + throw new RuntimeException(); + } + + try + { + TableDataSet inTds = null; + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + inTds = reader.readFile(new File(estFileName)); + return inTds; + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading Sandag home interview survey data records file: %s into TableDataSet object.", + estFileName)); + throw new RuntimeException(e); + } + + } + + protected void calculateModeChoiceLogsums(HashMap rbMap, + ChoiceModelApplication mcModel, SandagAppendMcLogsumDMU mcDmuObject, int[] odt, + int[] mgraSample, int[] departAvailable, int[] arriveAvailable, boolean chosenTodOnly) + { + + boolean isChosenDepartArriveCombo = false; + + int origMgra = odt[ORIG_MGRA]; + int chosenMgra = odt[DEST_MGRA]; + + int inc = 0; + if (odt[INCOME] == 1) inc = 7500; + else if (odt[INCOME] == 2) inc = 22500; + else if (odt[INCOME] == 3) inc = 37500; + else if (odt[INCOME] == 4) inc = 52500; + else if (odt[INCOME] == 5) inc = 67500; + else if (odt[INCOME] == 6) inc = 87500; + else if (odt[INCOME] == 7) inc = 112500; + else if (odt[INCOME] == 8) inc = 137500; + else if (odt[INCOME] == 9) inc = 175000; + else if (odt[INCOME] == 10) inc = 250000; + else if (odt[INCOME] == 99) inc = 37500; + + mcDmuObject.setIncomeInDollars(inc); + mcDmuObject.setAdults(odt[ADULTS]); + mcDmuObject.setAutos(odt[AUTOS]); + mcDmuObject.setHhSize(odt[HHSIZE]); + mcDmuObject.setPersonIsFemale(odt[FEMALE]); + mcDmuObject.setAge(odt[AGE]); + mcDmuObject.setTourCategoryJoint(odt[JOINT]); + mcDmuObject.setTourCategoryEscort(odt[ESCORT]); + mcDmuObject.setNumberOfParticipantsInJointTour(odt[PARTYSIZE]); + + mcDmuObject.setWorkTourModeIsSOV(odt[WORK_TOUR_MODE] == 1 || odt[WORK_TOUR_MODE] == 2 ? 1 + : 0); + mcDmuObject.setWorkTourModeIsBike(odt[WORK_TOUR_MODE] == 10 ? 1 : 0); + mcDmuObject.setWorkTourModeIsHOV(odt[WORK_TOUR_MODE] >= 3 || odt[WORK_TOUR_MODE] <= 8 ? 1 + : 0); + + mcDmuObject.setOrigDuDen(mgraManager.getDuDenValue(origMgra)); + mcDmuObject.setOrigEmpDen(mgraManager.getEmpDenValue(origMgra)); + mcDmuObject.setOrigTotInt(mgraManager.getTotIntValue(origMgra)); + + mcDmuObject + .setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(origMgra))); + + chosenDepartArriveCombination[0] = odt[DEPART_PERIOD]; + chosenDepartArriveCombination[1] = odt[ARRIVE_PERIOD]; + + // create an array with the chosen dest and the sample dests, for which + // to + // compute the logsums + mgraSetForLogsums[0] = chosenMgra; + for (int m = 0; m < mgraSample.length; m++) + mgraSetForLogsums[m + 1] = mgraSample[m]; + + int m = 0; + for (int destMgra : mgraSetForLogsums) + { + + if (mcModel != null && destMgra > 0) + { + // set the mode choice attributes needed by @variables in the + // UEC + // spreadsheets + mcDmuObject.setDmuIndexValues(odt[0], origMgra, origMgra, destMgra, false); + + mcDmuObject.setDestDuDen(mgraManager.getDuDenValue(destMgra)); + mcDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(destMgra)); + mcDmuObject.setDestTotInt(mgraManager.getTotIntValue(destMgra)); + + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager + .getTaz(destMgra))); + + modeChoiceLogsums[m] = new double[modelStructure.getSkimPeriodCombinationIndices().length]; + Arrays.fill(modeChoiceLogsums[m], -999); + } + + // compute the logsum for each depart/arrival time combination for + // the + // selected destination mgra + int i = 0; + for (int[] combo : departArriveCombinations) + { + + // mcModel might be null in the case where an estimation file + // record + // contains multiple purposes and the logsums are not desired + // for + // some purposes. + // destMgra might be null in the case of destination choice + // where + // some sample destinations are repeated, so the set of 30 or 40 + // contain 0s to reflect that. + if (mcModel == null || destMgra == 0) + { + continue; + } + + if (combo[0] == chosenDepartArriveCombination[0] + && combo[1] == chosenDepartArriveCombination[1]) + { + isChosenDepartArriveCombo = true; + chosenLogsumTodIndex = i; + } + + if (!chosenTodOnly || isChosenDepartArriveCombo) + { + + int departPeriod = DEFAULT_DEPART_INDICES[combo[0]]; + int arrivePeriod = DEFAULT_ARRIVE_INDICES[combo[1]]; + + // if the depart/arrive combination was flagged as + // unavailable, + // can skip the logsum calculation + if (unavailableCombination(departPeriod, arrivePeriod, departAvailable, + arriveAvailable)) + { + departArriveLogsums[m][i++] = -999; + continue; + } + + int logsumIndex = modelStructure.getSkimPeriodCombinationIndex(departPeriod, + arrivePeriod); + + // if a depart/arrive period combination results in a logsum + // index that's already had logsums computed, skip to next + // combination. + if (modeChoiceLogsums[m][logsumIndex] > -999) + { + departArriveLogsums[m][i++] = modeChoiceLogsums[m][logsumIndex]; + continue; + } + + mcDmuObject.setDepartPeriod(departPeriod); + mcDmuObject.setArrivePeriod(arrivePeriod); + + double logsum = logsumHelper.calculateTourMcLogsum(origMgra, destMgra, + departPeriod, arrivePeriod, mcModel, mcDmuObject); + + modeChoiceLogsums[m][logsumIndex] = logsum; + departArriveLogsums[m][i] = logsum; + + // write UEC calculation results to logsum specific log file + // if + // its the chosen dest and its the chosen time combo + if ((odt[0] == debugEstimationFileRecord1 || odt[0] == debugEstimationFileRecord2) + && (m == 0) /* && isChosenDepartArriveCombo */) + { + + nonManLogsumsLogger.info("Logsum[" + i + + "] calculation for estimation file record number " + odt[0]); + nonManLogsumsLogger.info(""); + nonManLogsumsLogger + .info("--------------------------------------------------------------------------------------------------------"); + nonManLogsumsLogger.info("tour purpose = " + odt[TOUR_PURPOSE]); + nonManLogsumsLogger.info("mc purpose sheet = " + + MC_PURPOSE_SHEET_INDICES[odt[TOUR_PURPOSE]]); + nonManLogsumsLogger.info("purpose category = " + + PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]] + ": " + + PURPOSE_CATEGORY_LABELS[PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]]]); + nonManLogsumsLogger.info("origin mgra = " + odt[ORIG_MGRA]); + nonManLogsumsLogger.info("destination mgra = " + odt[DEST_MGRA]); + nonManLogsumsLogger.info("origin taz = " + mgraManager.getTaz(origMgra)); + nonManLogsumsLogger.info("destination taz = " + + mgraManager.getTaz(destMgra)); + nonManLogsumsLogger.info("depart interval = " + + departArriveCombinationLabels[i][0] + ", @timeOutbound = " + + mcDmuObject.getTimeOutbound() + ", chosen depart = " + + departPeriod); + nonManLogsumsLogger.info("arrive interval = " + + departArriveCombinationLabels[i][1] + ", @timeInbound = " + + mcDmuObject.getTimeInbound() + ", chosen arrive = " + + arrivePeriod); + nonManLogsumsLogger.info("income category = " + odt[INCOME] + + ", @income = " + mcDmuObject.getIncome()); + nonManLogsumsLogger.info("adults = " + odt[ADULTS]); + nonManLogsumsLogger.info("autos = " + odt[AUTOS]); + nonManLogsumsLogger.info("hhsize = " + odt[HHSIZE]); + nonManLogsumsLogger.info("gender = " + odt[FEMALE] + ", @female = " + + mcDmuObject.getFemale()); + nonManLogsumsLogger.info("jointTourCategory = " + odt[JOINT] + + ", @tourcategoryJoint = " + mcDmuObject.getTourCategoryJoint()); + nonManLogsumsLogger.info("partySize = " + odt[PARTYSIZE]); + nonManLogsumsLogger + .info("--------------------------------------------------------------------------------------------------------"); + nonManLogsumsLogger.info(""); + + mcModel.logUECResults(nonManLogsumsLogger, "Est Record: " + odt[0]); + nonManLogsumsLogger.info("Logsum Calculation for index: " + logsumIndex + + " , Logsum value: " + modeChoiceLogsums[m][logsumIndex]); + nonManLogsumsLogger.info(""); + nonManLogsumsLogger.info(""); + + isChosenDepartArriveCombo = false; + } + + } + i++; + } + + m++; + } + + } + + protected void calculateTripModeChoiceLogsums(HashMap rbMap, + ChoiceModelApplication mcModel, SandagTripModeChoiceDMU mcDmuObject, int[] odt, + int[] mgraSample) + { + + int origMgra = odt[ORIG_MGRA]; + int destMgra = odt[DEST_MGRA]; + int chosenMgra = odt[CHOSEN_MGRA]; + + for (int m = 0; m < tripModeChoiceLogsums.length; m++) + { + tripModeChoiceLogsums[m][0] = -999; + tripModeChoiceLogsums[m][1] = -999; + } + + if (origMgra == 0 || destMgra == 0 || odt[TOUR_MODE] == 0) return; + + int inc = 0; + if (odt[INCOME] == 1) inc = 7500; + else if (odt[INCOME] == 2) inc = 22500; + else if (odt[INCOME] == 3) inc = 37500; + else if (odt[INCOME] == 4) inc = 52500; + else if (odt[INCOME] == 5) inc = 67500; + else if (odt[INCOME] == 6) inc = 87500; + else if (odt[INCOME] == 7) inc = 112500; + else if (odt[INCOME] == 8) inc = 137500; + else if (odt[INCOME] == 9) inc = 175000; + else if (odt[INCOME] == 10) inc = 250000; + else if (odt[INCOME] == 99) inc = 37500; + + mcDmuObject.setOutboundHalfTourDirection(odt[DIRECTION]); + + mcDmuObject.setJointTour(odt[JOINT]); + mcDmuObject + .setEscortTour(odt[TOUR_PURPOSE] == ModelStructure.ESCORT_PRIMARY_PURPOSE_INDEX ? 1 + : 0); + + mcDmuObject.setIncomeInDollars(inc); + mcDmuObject.setAdults(odt[ADULTS]); + mcDmuObject.setAutos(odt[AUTOS]); + mcDmuObject.setAge(odt[AGE]); + mcDmuObject.setHhSize(odt[HHSIZE]); + mcDmuObject.setPersonIsFemale(odt[FEMALE] == 2 ? 1 : 0); + + mcDmuObject.setTourModeIsDA(modelStructure.getTourModeIsSov(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsS2(modelStructure.getTourModeIsS2(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsS3(modelStructure.getTourModeIsS3(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsWalk(modelStructure.getTourModeIsWalk(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsBike(modelStructure.getTourModeIsBike(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsWTran(modelStructure.getTourModeIsWalkTransit(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsPnr(modelStructure.getTourModeIsPnr(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsKnr(modelStructure.getTourModeIsKnr(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsSchBus(modelStructure.getTourModeIsSchoolBus(odt[TOUR_MODE]) ? 1 + : 0); + + mcDmuObject.setOrigDuDen(mgraManager.getDuDenValue(origMgra)); + mcDmuObject.setOrigEmpDen(mgraManager.getEmpDenValue(origMgra)); + mcDmuObject.setOrigTotInt(mgraManager.getTotIntValue(origMgra)); + + mcDmuObject + .setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(origMgra))); + + mcDmuObject.setDepartPeriod(odt[DEPART_PERIOD]); + mcDmuObject.setTripPeriod(odt[TRIP_PERIOD]); + + int departPeriod = odt[TRIP_PERIOD]; + + // create an array with the chosen dest and the sample dests, for which + // to + // compute the logsums + mgraSetForLogsums[0] = chosenMgra; + for (int m = 0; m < mgraSample.length; m++) + { + mgraSetForLogsums[m + 1] = mgraSample[m]; + } + + if (mcModel == null || origMgra == 0) return; + + int m = 0; + for (int sampleMgra : mgraSetForLogsums) + { + + tripModeChoiceLogsums[m][0] = -999; + tripModeChoiceLogsums[m][1] = -999; + + if (mcModel != null && sampleMgra > 0) + { + // set the mode choice attributes needed by @variables in the + // UEC + // spreadsheets + mcDmuObject.setDmuIndexValues(odt[0], origMgra, origMgra, sampleMgra, false); + + mcDmuObject.setDestDuDen(mgraManager.getDuDenValue(sampleMgra)); + mcDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(sampleMgra)); + mcDmuObject.setDestTotInt(mgraManager.getTotIntValue(sampleMgra)); + + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager + .getTaz(sampleMgra))); + + if(odt[DIRECTION]==INBOUND_DIRCETION_CODE) + mcDmuObject.setInbound(true); + else + mcDmuObject.setInbound(false); + } + + // mcModel might be null in the case where an estimation file record + // contains multiple purposes and the logsums are not desired for + // some purposes. + // destMgra might be null in the case of destination choice where + // some sample destinations are repeated, so the set of 30 or 40 + // contain 0s to reflect that. + if (mcModel == null || sampleMgra == 0) + { + continue; + } + + // write UEC calculation results to logsum specific log file if + // its the chosen dest and its the chosen time combo + if ((odt[0] == debugEstimationFileRecord1 || odt[0] == debugEstimationFileRecord2)) + { + + nonManLogsumsLogger.info("IK Logsum calculation for estimation file record number " + + odt[0]); + nonManLogsumsLogger.info(""); + nonManLogsumsLogger + .info("--------------------------------------------------------------------------------------------------------"); + nonManLogsumsLogger.info("tour purpose = " + odt[TOUR_PURPOSE]); + nonManLogsumsLogger.info("mc purpose sheet = " + + MC_PURPOSE_SHEET_INDICES[odt[TOUR_PURPOSE]]); + nonManLogsumsLogger.info("purpose category = " + + PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]] + ": " + + PURPOSE_CATEGORY_LABELS[PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]]]); + nonManLogsumsLogger.info("tour mode = " + odt[TOUR_MODE]); + nonManLogsumsLogger.info("origin mgra = " + origMgra); + nonManLogsumsLogger.info("sample destination mgra = " + sampleMgra); + nonManLogsumsLogger.info("final destination mgra = " + destMgra); + nonManLogsumsLogger.info("origin taz = " + mgraManager.getTaz(origMgra)); + nonManLogsumsLogger.info("sample destination taz = " + + mgraManager.getTaz(sampleMgra)); + nonManLogsumsLogger.info("final destination taz = " + mgraManager.getTaz(destMgra)); + nonManLogsumsLogger.info("depart interval = " + departPeriod); + nonManLogsumsLogger.info("income category = " + odt[INCOME] + ", @income = " + + mcDmuObject.getIncome()); + nonManLogsumsLogger.info("adults = " + odt[ADULTS]); + nonManLogsumsLogger.info("autos = " + odt[AUTOS]); + nonManLogsumsLogger.info("hhsize = " + odt[HHSIZE]); + nonManLogsumsLogger.info("gender = " + odt[FEMALE] + ", @female = " + + mcDmuObject.getFemale()); + nonManLogsumsLogger + .info("--------------------------------------------------------------------------------------------------------"); + nonManLogsumsLogger.info(""); + + mcDmuObject.getDmuIndexValues().setDebug(true); + } + + if ((odt[DIRECTION] == INBOUND_DIRCETION_CODE)) + { + logsumHelper.setWtdTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, + departPeriod, mcDmuObject.getDmuIndexValues().getDebug()); + } else logsumHelper.setDtwTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, + departPeriod, mcDmuObject.getDmuIndexValues().getDebug()); + + logsumHelper.setWtwTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, departPeriod, + mcDmuObject.getDmuIndexValues().getDebug()); + + double logsum = logsumHelper.calculateTripMcLogsum(origMgra, sampleMgra, departPeriod, + mcModel, mcDmuObject, nonManLogsumsLogger); + tripModeChoiceLogsums[m][0] = logsum; + + if ((odt[0] == debugEstimationFileRecord1 || odt[0] == debugEstimationFileRecord2)) + { + nonManLogsumsLogger.info("IK Logsum value: " + tripModeChoiceLogsums[m][0]); + nonManLogsumsLogger.info(""); + nonManLogsumsLogger.info(""); + } + + // write UEC calculation results to logsum specific log file if + // its the chosen dest and its the chosen time combo + if ((odt[0] == debugEstimationFileRecord1 || odt[0] == debugEstimationFileRecord2)) + { + + nonManLogsumsLogger.info("KJ Logsum calculation for estimation file record number " + + odt[0]); + nonManLogsumsLogger.info(""); + nonManLogsumsLogger + .info("--------------------------------------------------------------------------------------------------------"); + nonManLogsumsLogger.info("tour purpose = " + odt[TOUR_PURPOSE]); + nonManLogsumsLogger.info("mc purpose sheet = " + + MC_PURPOSE_SHEET_INDICES[odt[TOUR_PURPOSE]]); + nonManLogsumsLogger.info("purpose category = " + + PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]] + ": " + + PURPOSE_CATEGORY_LABELS[PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]]]); + nonManLogsumsLogger.info("origin mgra = " + sampleMgra); + nonManLogsumsLogger.info("sample destination mgra = " + destMgra); + nonManLogsumsLogger.info("final destination mgra = " + destMgra); + nonManLogsumsLogger.info("origin taz = " + mgraManager.getTaz(sampleMgra)); + nonManLogsumsLogger + .info("sample destination taz = " + mgraManager.getTaz(destMgra)); + nonManLogsumsLogger.info("final destination taz = " + mgraManager.getTaz(destMgra)); + nonManLogsumsLogger.info("depart interval = " + departPeriod); + nonManLogsumsLogger.info("income category = " + odt[INCOME] + ", @income = " + + mcDmuObject.getIncome()); + nonManLogsumsLogger.info("adults = " + odt[ADULTS]); + nonManLogsumsLogger.info("autos = " + odt[AUTOS]); + nonManLogsumsLogger.info("hhsize = " + odt[HHSIZE]); + nonManLogsumsLogger.info("gender = " + odt[FEMALE] + ", @female = " + + mcDmuObject.getFemale()); + nonManLogsumsLogger + .info("--------------------------------------------------------------------------------------------------------"); + nonManLogsumsLogger.info(""); + + mcDmuObject.getDmuIndexValues().setDebug(true); + } + + if ((odt[DIRECTION] == INBOUND_DIRCETION_CODE)) + { + logsumHelper.setWtdTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, + departPeriod, mcDmuObject.getDmuIndexValues().getDebug()); + } else logsumHelper.setDtwTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, + departPeriod, mcDmuObject.getDmuIndexValues().getDebug()); + + logsumHelper.setWtwTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, departPeriod, + mcDmuObject.getDmuIndexValues().getDebug()); + + logsum = logsumHelper.calculateTripMcLogsum(origMgra, sampleMgra, departPeriod, + mcModel, mcDmuObject, nonManLogsumsLogger); + tripModeChoiceLogsums[m][1] = logsum; + + if ((odt[0] == debugEstimationFileRecord1 || odt[0] == debugEstimationFileRecord2)) + { + nonManLogsumsLogger.info("KJ Logsum value: " + tripModeChoiceLogsums[m][1]); + nonManLogsumsLogger.info(""); + nonManLogsumsLogger.info(""); + } + + m++; + } + + } + + protected double[] calculateTripModeChoiceLogsumForEstimationRecord( + HashMap rbMap, ChoiceModelApplication mcModel, + SandagTripModeChoiceDMU mcDmuObject, int[] odt, int sampleMgra) + { + + int origMgra = odt[ORIG_MGRA]; + int destMgra = odt[DEST_MGRA]; + + double[] tripModeChoiceLogsums = new double[2]; + tripModeChoiceLogsums[0] = -999; + tripModeChoiceLogsums[1] = -999; + + // mcModel would be null if the estimation file record has a stop + // purpose for which no ChoiceModelApplication has been defined. + if (origMgra == 0 || destMgra == 0 || sampleMgra == 0 || odt[TOUR_MODE] == 0 + || mcModel == null) return tripModeChoiceLogsums; + + mcDmuObject.setOutboundHalfTourDirection(odt[DIRECTION]); + + mcDmuObject.setJointTour(odt[JOINT]); + mcDmuObject + .setEscortTour(odt[TOUR_PURPOSE] == ModelStructure.ESCORT_PRIMARY_PURPOSE_INDEX ? 1 + : 0); + + int inc = 0; + if (odt[INCOME] == 1) inc = 7500; + else if (odt[INCOME] == 2) inc = 22500; + else if (odt[INCOME] == 3) inc = 37500; + else if (odt[INCOME] == 4) inc = 52500; + else if (odt[INCOME] == 5) inc = 67500; + else if (odt[INCOME] == 6) inc = 87500; + else if (odt[INCOME] == 7) inc = 112500; + else if (odt[INCOME] == 8) inc = 137500; + else if (odt[INCOME] == 9) inc = 175000; + else if (odt[INCOME] == 10) inc = 250000; + else if (odt[INCOME] == 99) inc = 37500; + + mcDmuObject.setIncomeInDollars(inc); + mcDmuObject.setAdults(odt[ADULTS]); + mcDmuObject.setAutos(odt[AUTOS]); + mcDmuObject.setAge(odt[AGE]); + mcDmuObject.setHhSize(odt[HHSIZE]); + mcDmuObject.setPersonIsFemale(odt[FEMALE] == 2 ? 1 : 0); + + mcDmuObject.setTourModeIsDA(modelStructure.getTourModeIsSov(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsS2(modelStructure.getTourModeIsS2(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsS3(modelStructure.getTourModeIsS3(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsWalk(modelStructure.getTourModeIsWalk(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsBike(modelStructure.getTourModeIsBike(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsWTran(modelStructure.getTourModeIsWalkTransit(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsPnr(modelStructure.getTourModeIsPnr(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsKnr(modelStructure.getTourModeIsKnr(odt[TOUR_MODE]) ? 1 : 0); + mcDmuObject.setTourModeIsSchBus(modelStructure.getTourModeIsSchoolBus(odt[TOUR_MODE]) ? 1 + : 0); + + mcDmuObject.setOrigDuDen(mgraManager.getDuDenValue(origMgra)); + mcDmuObject.setOrigEmpDen(mgraManager.getEmpDenValue(origMgra)); + mcDmuObject.setOrigTotInt(mgraManager.getTotIntValue(origMgra)); + + mcDmuObject + .setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(origMgra))); + + mcDmuObject.setDepartPeriod(odt[DEPART_PERIOD]); + mcDmuObject.setTripPeriod(odt[TRIP_PERIOD]); + + int departPeriod = odt[TRIP_PERIOD]; + + // set the mode choice attributes needed by @variables in the UEC + // spreadsheets + mcDmuObject.setDmuIndexValues(odt[0], origMgra, origMgra, sampleMgra, false); + + mcDmuObject.setDestDuDen(mgraManager.getDuDenValue(sampleMgra)); + mcDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(sampleMgra)); + mcDmuObject.setDestTotInt(mgraManager.getTotIntValue(sampleMgra)); + + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager + .getTaz(sampleMgra))); + + if (mcDmuObject.getDmuIndexValues().getDebug()) + { + + // write UEC calculation results to logsum specific log file if + // its the chosen dest and its the chosen time combo + slcSoaLogger.info("IK Logsum calculation for estimation file record number " + odt[0]); + slcSoaLogger.info(""); + slcSoaLogger + .info("--------------------------------------------------------------------------------------------------------"); + slcSoaLogger.info("tour purpose = " + odt[TOUR_PURPOSE]); + slcSoaLogger.info("mc purpose sheet = " + MC_PURPOSE_SHEET_INDICES[odt[TOUR_PURPOSE]]); + slcSoaLogger.info("purpose category = " + PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]] + ": " + + PURPOSE_CATEGORY_LABELS[PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]]]); + slcSoaLogger.info("tour mode = " + odt[TOUR_MODE]); + slcSoaLogger.info("origin mgra = " + origMgra); + slcSoaLogger.info("sample destination mgra = " + sampleMgra); + slcSoaLogger.info("final destination mgra = " + destMgra); + slcSoaLogger.info("origin taz = " + mgraManager.getTaz(origMgra)); + slcSoaLogger.info("sample destination taz = " + mgraManager.getTaz(sampleMgra)); + slcSoaLogger.info("final destination taz = " + mgraManager.getTaz(destMgra)); + slcSoaLogger.info("depart interval = " + departPeriod); + slcSoaLogger.info("income category = " + odt[INCOME] + ", @income = " + + mcDmuObject.getIncome()); + slcSoaLogger.info("adults = " + odt[ADULTS]); + slcSoaLogger.info("autos = " + odt[AUTOS]); + slcSoaLogger.info("hhsize = " + odt[HHSIZE]); + slcSoaLogger.info("gender = " + odt[FEMALE] + ", @female = " + mcDmuObject.getFemale()); + slcSoaLogger + .info("--------------------------------------------------------------------------------------------------------"); + slcSoaLogger.info(""); + + } + + if ((odt[DIRECTION] == INBOUND_DIRCETION_CODE)) + { + logsumHelper.setWtdTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, departPeriod, + mcDmuObject.getDmuIndexValues().getDebug()); + } else logsumHelper.setDtwTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, + departPeriod, mcDmuObject.getDmuIndexValues().getDebug()); + + logsumHelper.setWtwTripMcDmuAttributes(mcDmuObject, origMgra, sampleMgra, departPeriod, + mcDmuObject.getDmuIndexValues().getDebug()); + + double logsum = logsumHelper.calculateTripMcLogsum(origMgra, sampleMgra, departPeriod, + mcModel, mcDmuObject, nonManLogsumsLogger); + tripModeChoiceLogsums[0] = logsum; + + if (mcDmuObject.getDmuIndexValues().getDebug()) + { + + slcSoaLogger.info("IK Mode Choice Logsum value: " + tripModeChoiceLogsums[0]); + slcSoaLogger.info(""); + slcSoaLogger.info(""); + + // write UEC calculation results to logsum specific log file if + // its the chosen dest and its the chosen time combo + slcSoaLogger.info("KJ Logsum calculation for estimation file record number " + odt[0]); + slcSoaLogger.info(""); + slcSoaLogger + .info("--------------------------------------------------------------------------------------------------------"); + slcSoaLogger.info("tour purpose = " + odt[TOUR_PURPOSE]); + slcSoaLogger.info("mc purpose sheet = " + MC_PURPOSE_SHEET_INDICES[odt[TOUR_PURPOSE]]); + slcSoaLogger.info("purpose category = " + PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]] + ": " + + PURPOSE_CATEGORY_LABELS[PURPOSE_CATEGORIES[odt[TOUR_PURPOSE]]]); + slcSoaLogger.info("origin mgra = " + sampleMgra); + slcSoaLogger.info("sample destination mgra = " + destMgra); + slcSoaLogger.info("final destination mgra = " + destMgra); + slcSoaLogger.info("origin taz = " + mgraManager.getTaz(sampleMgra)); + slcSoaLogger.info("sample destination taz = " + mgraManager.getTaz(destMgra)); + slcSoaLogger.info("final destination taz = " + mgraManager.getTaz(destMgra)); + slcSoaLogger.info("depart interval = " + departPeriod); + slcSoaLogger.info("income category = " + odt[INCOME] + ", @income = " + + mcDmuObject.getIncome()); + slcSoaLogger.info("adults = " + odt[ADULTS]); + slcSoaLogger.info("autos = " + odt[AUTOS]); + slcSoaLogger.info("hhsize = " + odt[HHSIZE]); + slcSoaLogger.info("gender = " + odt[FEMALE] + ", @female = " + mcDmuObject.getFemale()); + slcSoaLogger + .info("--------------------------------------------------------------------------------------------------------"); + slcSoaLogger.info(""); + + } + + if ((odt[DIRECTION] == INBOUND_DIRCETION_CODE)) + { + logsumHelper.setWtdTripMcDmuAttributes(mcDmuObject, sampleMgra, destMgra, departPeriod, + mcDmuObject.getDmuIndexValues().getDebug()); + } else logsumHelper.setDtwTripMcDmuAttributes(mcDmuObject, sampleMgra, destMgra, + departPeriod, mcDmuObject.getDmuIndexValues().getDebug()); + + logsumHelper.setWtwTripMcDmuAttributes(mcDmuObject, sampleMgra, destMgra, departPeriod, + mcDmuObject.getDmuIndexValues().getDebug()); + + logsum = logsumHelper.calculateTripMcLogsum(sampleMgra, destMgra, departPeriod, mcModel, + mcDmuObject, nonManLogsumsLogger); + tripModeChoiceLogsums[1] = logsum; + + if (mcDmuObject.getDmuIndexValues().getDebug()) + { + + slcSoaLogger.info("KJ Mode Choice Logsum value: " + tripModeChoiceLogsums[1]); + slcSoaLogger.info(""); + slcSoaLogger.info(""); + + } + + return tripModeChoiceLogsums; + + } + + protected int getModelPeriodFromTodIndex(int index) + { + int returnValue = -1; + if (index <= LAST_EA_INDEX) returnValue = EA; + else if (index <= LAST_AM_INDEX) returnValue = AM; + else if (index <= LAST_MD_INDEX) returnValue = MD; + else if (index <= LAST_PM_INDEX) returnValue = PM; + else returnValue = EV; + + return returnValue; + } + + /** + * + * @param departPeriod + * is the departure interval + * @param arrivePeriod + * is the arrival interval + * @param departAvailable + * is the model time period the departure interval belongs to + * (EA, AM, MD, PM, EV) + * @param arriveAvailable + * is the model time period the arrival interval belongs to (EA, + * AM, MD, PM, EV) + * @return true if the depart and/or arrival periods are unavailable, false + * if both are available. + */ + protected boolean unavailableCombination(int departPeriod, int arrivePeriod, + int[] departAvailable, int[] arriveAvailable) + { + + int departModelPeriod = getModelPeriodFromTodIndex(departPeriod); + int arriveModelPeriod = getModelPeriodFromTodIndex(arrivePeriod); + + boolean returnValue = true; + if (departAvailable[departModelPeriod] == 1 && arriveAvailable[arriveModelPeriod] == 1) + returnValue = false; + + return returnValue; + + } + + /** + * return the array of mode choice model cumulative probabilities determined + * while computing the mode choice logsum for the trip segmen during stop + * location choice. These probabilities arrays are stored for each sampled + * stop location so that when the selected sample stop location is known, + * the mode choice can be drawn from the already computed probabilities. + * + * @return mode choice cumulative probabilities array + */ + public double[] getStoredSegmentCumulativeProbabilities() + { + return tripModeChoiceSegmentStoredProbabilities; + } + + /** + * Start the matrix server + * + * @param rb + * is a ResourceBundle for the properties file for this + * application + */ + protected void startMatrixServer(ResourceBundle rb) + { + + logger.info(""); + logger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + logger.error("exception caught running ctramp model components -- exiting.", e); + throw new RuntimeException(); + + } + + } + + public AutoAndNonMotorizedSkimsCalculator getAnmSkimCalculator() + { + return logsumHelper.getAnmSkimCalculator(); + } + + public void setTazDistanceSkimArrays(double[][][] storedFromTazDistanceSkims, + double[][][] storedToTazDistanceSkims) + { + AutoAndNonMotorizedSkimsCalculator anm = logsumHelper.getAnmSkimCalculator(); + anm.setTazDistanceSkimArrays(storedFromTazDistanceSkims, storedToTazDistanceSkims); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonMandatoryDcEstimationMcLogsumsAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonMandatoryDcEstimationMcLogsumsAppender.java new file mode 100644 index 0000000..8a9f4dd --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonMandatoryDcEstimationMcLogsumsAppender.java @@ -0,0 +1,368 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.sandag.abm.application.SandagAppendMcLogsumDMU; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; + +public final class NonMandatoryDcEstimationMcLogsumsAppender + extends McLogsumsAppender +{ + + private static final int DEBUG_EST_RECORD1 = 1; + private static final int DEBUG_EST_RECORD2 = -1; + + /* + * for DC estimation file + */ + private static final int SEQ_FIELD = 2; + + // for Atwork subtour DC + // private static final int ORIG_MGRA_FIELD = 79; + // private static final int DEST_MGRA_FIELD = 220; + // private static final int MGRA1_FIELD = 221; + // private static final int PURPOSE_INDEX_OFFSET = 4; + + // for Escort DC + private static final int ORIG_MGRA_FIELD = 76; + private static final int DEST_MGRA_FIELD = 79; + private static final int MGRA1_FIELD = 217; + private static final int PURPOSE_INDEX_OFFSET = 0; + + // for NonMandatory DC + // private static final int ORIG_MGRA_FIELD = 76; + // private static final int DEST_MGRA_FIELD = 79; + // private static final int MGRA1_FIELD = 221; + // private static final int PURPOSE_INDEX_OFFSET = 0; + + private static final int DEPART_PERIOD_FIELD = 189; + private static final int ARRIVE_PERIOD_FIELD = 190; + private static final int INCOME_FIELD = 20; + private static final int ADULTS_FIELD = 32; + private static final int AUTOS_FIELD = 6; + private static final int HHSIZE_FIELD = 5; + private static final int GENDER_FIELD = 38; + private static final int AGE_FIELD = 39; + private static final int PURPOSE_FIELD = 80; + private static final int JOINT_ID_FIELD = 125; + private static final int JOINT_PURPOSE_FIELD = 126; + private static final int JOINT_P1_FIELD = 151; + private static final int JOINT_P2_FIELD = 152; + private static final int JOINT_P3_FIELD = 153; + private static final int JOINT_P4_FIELD = 154; + private static final int JOINT_P5_FIELD = 155; + private static final int NUM_MGRA_FIELDS = 30; + + private static final String OUTPUT_SAMPLE_DEST_LOGSUMS = "output.sample.dest.logsums"; + + public NonMandatoryDcEstimationMcLogsumsAppender(HashMap rbMap) + { + super(rbMap); + + debugEstimationFileRecord1 = DEBUG_EST_RECORD1; + debugEstimationFileRecord2 = DEBUG_EST_RECORD2; + + numMgraFields = NUM_MGRA_FIELDS; + } + + private void runLogsumAppender(ResourceBundle rb) + { + + totalTime1 = 0; + totalTime2 = 0; + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + tazs = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + mgraSetForLogsums = new int[numMgraFields + 1]; + + // allocate the logsums array for the chosen destination alternative + modeChoiceLogsums = new double[NUM_MGRA_FIELDS + 1][]; + + departArriveLogsums = new double[NUM_MGRA_FIELDS + 1][departArriveCombinations.length]; + + String outputAllKey = Util.getStringValueFromPropertyMap(rbMap, OUTPUT_SAMPLE_DEST_LOGSUMS); + + String outputFileName = Util.getStringValueFromPropertyMap(rbMap, + "dc.est.skims.output.file"); + if (outputFileName == null) + { + logger.info("no output file name was specified in the properties file. Nothing to do."); + return; + } + + int dotIndex = outputFileName.indexOf("."); + String baseName = outputFileName.substring(0, dotIndex); + String extension = outputFileName.substring(dotIndex); + + // output1 is only written if "all" was set in propoerties file + String outputName1 = ""; + if (outputAllKey.equalsIgnoreCase("all")) outputName1 = baseName + "_" + "all" + extension; + + // output1 is written in any case + String outputName2 = baseName + "_" + "chosen" + extension; + + PrintWriter outStream1 = null; + PrintWriter outStream2 = null; + + try + { + if (outputAllKey.equalsIgnoreCase("all")) + outStream1 = new PrintWriter(new BufferedWriter(new FileWriter( + new File(outputName1)))); + outStream2 = new PrintWriter(new BufferedWriter(new FileWriter(new File(outputName2)))); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileName)); + throw new RuntimeException(e); + } + + writeDcFile(rbMap, outStream1, outStream2); + + logger.info("total part 1 runtime = " + (totalTime1 / 1000) + " seconds."); + logger.info("total part 2 runtime = " + (totalTime2 / 1000) + " seconds."); + + } + + private void writeDcFile(HashMap rbMap, PrintWriter outStream1, + PrintWriter outStream2) + { + + // print the chosen destMgra and the depart/arrive logsum field names to + // both + // files + if (outStream1 != null) outStream1.print("seq,sampno,chosenMgra"); + + // attach the OB and IB period labels to the logsum field names for each + // period + if (outStream1 != null) + { + for (String[] labels : departArriveCombinationLabels) + outStream1.print(",logsum" + labels[0] + labels[1]); + } + + outStream2.print("seq,sampno,chosenMgra,chosenTodLogsum"); + + // print each set of sample destMgra and the depart/arrive logsum + // fieldnames + // to file 1. + // print each set of sample destMgra and the chosen depart/arrive logsum + // fieldname to file 2. + for (int m = 1; m < departArriveLogsums.length; m++) + { + if (outStream1 != null) + { + outStream1.print(",sampleMgra" + m); + for (String[] labels : departArriveCombinationLabels) + outStream1.print(",logsum" + m + labels[0] + labels[1]); + } + + outStream2.print(",sampleMgra" + m); + outStream2.print(",sampleLogsum" + m); + } + if (outStream1 != null) outStream1.print("\n"); + outStream2.print("\n"); + + TableDataSet estTds = getEstimationDataTableDataSet(rbMap); + int[][] estDataOdts = getDcEstimationDataOrigDestTimes(estTds); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = rbMap.get(PROPERTIES_UEC_TOUR_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + SandagAppendMcLogsumDMU mcDmuObject = new SandagAppendMcLogsumDMU(modelStructure, null); + + ChoiceModelApplication[] mcModel = new ChoiceModelApplication[5 + 1]; + mcModel[WORK_CATEGORY] = new ChoiceModelApplication(mcUecFile, WORK_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[UNIVERSITY_CATEGORY] = new ChoiceModelApplication(mcUecFile, UNIVERSITY_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[SCHOOL_CATEGORY] = new ChoiceModelApplication(mcUecFile, SCHOOL_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[MAINTENANCE_CATEGORY] = new ChoiceModelApplication(mcUecFile, MAINTENANCE_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[DISCRETIONARY_CATEGORY] = new ChoiceModelApplication(mcUecFile, + DISCRETIONARY_SHEET, 0, rbMap, (VariableTable) mcDmuObject); + mcModel[SUBTOUR_CATEGORY] = new ChoiceModelApplication(mcUecFile, SUBTOUR_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + + // write skims data for estimation data file records + int seq = 1; + for (int i = 0; i < estDataOdts.length; i++) + { + + int[] odtSet = estDataOdts[i]; + int[] mgraSet = mgras[i]; + + odtSet[0] = seq; + + if (outStream1 != null) + { + outStream1.print(seq + "," + odtSet[SAMPNO]); + } + outStream2.print(seq + "," + odtSet[SAMPNO]); + + int category = PURPOSE_CATEGORIES[odtSet[TOUR_PURPOSE]]; + + int[] departAvailable = {-1, 1, 1, 1, 1, 1}; + int[] arriveAvailable = {-1, 1, 1, 1, 1, 1}; + calculateModeChoiceLogsums(rbMap, category == -1 ? null : mcModel[category], + mcDmuObject, odtSet, mgraSet, departAvailable, arriveAvailable, false); + + // write chosen dest and logsums to both files + if (outStream1 != null) + { + outStream1.print("," + odtSet[DEST_MGRA]); + for (double logsum : departArriveLogsums[0]) + outStream1.printf(",%.8f", logsum); + } + + outStream2.print("," + odtSet[DEST_MGRA]); + outStream2.printf(",%.8f", departArriveLogsums[0][chosenLogsumTodIndex]); + + // write logsum sets for each dest in the sample to file 1 + for (int m = 1; m < departArriveLogsums.length; m++) + { + if (outStream1 != null) + { + outStream1.print("," + mgraSet[m - 1]); + for (double logsum : departArriveLogsums[m]) + outStream1.printf(",%.8f", logsum); + } + + outStream2.print("," + mgraSet[m - 1]); + outStream2.printf(",%.8f", departArriveLogsums[m][chosenLogsumTodIndex]); + } + if (outStream1 != null) outStream1.print("\n"); + outStream2.print("\n"); + + if (seq % 1000 == 0) logger.info("wrote DC Estimation file record: " + seq); + + seq++; + } + + if (outStream1 != null) outStream1.close(); + outStream2.close(); + + } + + private int[][] getDcEstimationDataOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][NUM_FIELDS]; + mgras = new int[hisTds.getRowCount()][NUM_MGRA_FIELDS]; + int[][] mgraData = new int[NUM_MGRA_FIELDS][]; + + int[] departs = hisTds.getColumnAsInt(DEPART_PERIOD_FIELD); + int[] arrives = hisTds.getColumnAsInt(ARRIVE_PERIOD_FIELD); + + int[] hisseq = hisTds.getColumnAsInt(SEQ_FIELD); + int[] purpose = hisTds.getColumnAsInt(PURPOSE_FIELD); + int[] jtPurpose = hisTds.getColumnAsInt(JOINT_PURPOSE_FIELD); + int[] income = hisTds.getColumnAsInt(INCOME_FIELD); + int[] origs = hisTds.getColumnAsInt(ORIG_MGRA_FIELD); + int[] dests = hisTds.getColumnAsInt(DEST_MGRA_FIELD); + int[] adults = hisTds.getColumnAsInt(ADULTS_FIELD); + int[] autos = hisTds.getColumnAsInt(AUTOS_FIELD); + int[] hhsize = hisTds.getColumnAsInt(HHSIZE_FIELD); + int[] gender = hisTds.getColumnAsInt(GENDER_FIELD); + int[] age = hisTds.getColumnAsInt(AGE_FIELD); + int[] jointId = hisTds.getColumnAsInt(JOINT_ID_FIELD); + int[] jointPerson1Participates = hisTds.getColumnAsInt(JOINT_P1_FIELD); + int[] jointPerson2Participates = hisTds.getColumnAsInt(JOINT_P2_FIELD); + int[] jointPerson3Participates = hisTds.getColumnAsInt(JOINT_P3_FIELD); + int[] jointPerson4Participates = hisTds.getColumnAsInt(JOINT_P4_FIELD); + int[] jointPerson5Participates = hisTds.getColumnAsInt(JOINT_P5_FIELD); + + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgraData[i] = hisTds.getColumnAsInt(MGRA1_FIELD + i); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgras[r - 1][i] = mgraData[i][r - 1]; + + odts[r - 1][SAMPNO] = hisseq[r - 1]; + + odts[r - 1][DEPART_PERIOD] = departs[r - 1]; + odts[r - 1][ARRIVE_PERIOD] = arrives[r - 1]; + + odts[r - 1][ORIG_MGRA] = origs[r - 1]; + odts[r - 1][DEST_MGRA] = dests[r - 1]; + odts[r - 1][INCOME] = income[r - 1]; + odts[r - 1][ADULTS] = adults[r - 1]; + odts[r - 1][AUTOS] = autos[r - 1]; + odts[r - 1][HHSIZE] = hhsize[r - 1]; + odts[r - 1][FEMALE] = gender[r - 1] == 2 ? 1 : 0; + odts[r - 1][AGE] = age[r - 1]; + odts[r - 1][JOINT] = jointId[r - 1] > 0 ? 1 : 0; + + // the offest constant is used because at-work subtours in + // estimation file are coded as work purpose index (=1), + // but the model index to use is 5. Nonmandatory and escort files + // have correct purpose codes, so offset is 0. + int purposeIndex = purpose[r - 1] + PURPOSE_INDEX_OFFSET; + + odts[r - 1][ESCORT] = purposeIndex == 4 ? 1 : 0; + + odts[r - 1][PARTYSIZE] = jointPerson1Participates[r - 1] + + jointPerson2Participates[r - 1] + jointPerson3Participates[r - 1] + + jointPerson4Participates[r - 1] + jointPerson5Participates[r - 1]; + + odts[r - 1][TOUR_PURPOSE] = odts[r - 1][JOINT] == 1 && purposeIndex > 4 ? jtPurpose[r - 1] + : purposeIndex; + + } + + return odts; + } + + public static void main(String[] args) + { + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + NonMandatoryDcEstimationMcLogsumsAppender appender = new NonMandatoryDcEstimationMcLogsumsAppender( + rbMap); + + appender.startMatrixServer(rb); + appender.runLogsumAppender(rb); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonMandatoryTodEstimationMcLogsumsAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonMandatoryTodEstimationMcLogsumsAppender.java new file mode 100644 index 0000000..f66cd14 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonMandatoryTodEstimationMcLogsumsAppender.java @@ -0,0 +1,277 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.sandag.abm.application.SandagAppendMcLogsumDMU; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; + +public final class NonMandatoryTodEstimationMcLogsumsAppender + extends McLogsumsAppender +{ + + private static final int DEBUG_EST_RECORD1 = 1; + private static final int DEBUG_EST_RECORD2 = -1; + + private static final int SEQ_FIELD = 7; + private static final int ORIG_MGRA_FIELD = 42; + private static final int DEST_MGRA_FIELD = 44; + private static final int DEPART_PERIOD_FIELD = 4; + private static final int ARRIVE_PERIOD_FIELD = 5; + private static final int INCOME_FIELD = 149; + private static final int ADULTS_FT_FIELD = 150; + private static final int ADULTS_PT_FIELD = 151; + private static final int ADULTS_UN_FIELD = 152; + private static final int ADULTS_RT_FIELD = 153; + private static final int ADULTS_NW_FIELD = 154; + private static final int AUTOS_FIELD = 146; + private static final int HHSIZE_FIELD = 147; + private static final int GENDER_FIELD = 24; + private static final int AGE_FIELD = 25; + private static final int PURPOSE_FIELD = 45; + private static final int JOINT_PURPOSE_FIELD = 58; + private static final int JOINT_ID_FIELD = 57; + private static final int JOINT_PARTICIPANTS_FIELD = 104; + private static final int MGRA1_FIELD = 1; + private static final int NUM_MGRA_FIELDS = 0; + + private NonMandatoryTodEstimationMcLogsumsAppender(HashMap rbMap) + { + super(rbMap); + + debugEstimationFileRecord1 = DEBUG_EST_RECORD1; + debugEstimationFileRecord2 = DEBUG_EST_RECORD2; + + numMgraFields = NUM_MGRA_FIELDS; + + } + + private void runLogsumAppender(ResourceBundle rb) + { + + totalTime1 = 0; + totalTime2 = 0; + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + tazs = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + mgraSetForLogsums = new int[numMgraFields + 1]; + + // allocate the logsums array for the chosen destination alternative + modeChoiceLogsums = new double[NUM_MGRA_FIELDS + 1][]; + + departArriveLogsums = new double[NUM_MGRA_FIELDS + 1][departArriveCombinations.length]; + + String outputFileName = Util.getStringValueFromPropertyMap(rbMap, + "tod.est.skims.output.file"); + + PrintWriter outStream = null; + + if (outputFileName == null) + { + logger.info("no output file name was specified in the properties file. Nothing to do."); + return; + } + + try + { + outStream = new PrintWriter( + new BufferedWriter(new FileWriter(new File(outputFileName)))); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileName)); + throw new RuntimeException(e); + } + + writeTodFile(rbMap, outStream); + + logger.info("total part 1 runtime = " + (totalTime1 / 1000) + " seconds."); + logger.info("total part 2 runtime = " + (totalTime2 / 1000) + " seconds."); + + } + + private void writeTodFile(HashMap rbMap, PrintWriter outStream2) + { + + // print the chosen destMgra and the depart/arrive logsum field names to + // the + // file + outStream2.print("seq,hisseq,chosenMgra"); + for (String[] labels : departArriveCombinationLabels) + { + outStream2.print(",logsum" + labels[0] + labels[1]); + } + outStream2.print("\n"); + + TableDataSet estTds = getEstimationDataTableDataSet(rbMap); + int[][] estDataOdts = getTodEstimationDataOrigDestTimes(estTds); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = rbMap.get(PROPERTIES_UEC_TOUR_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + SandagAppendMcLogsumDMU mcDmuObject = new SandagAppendMcLogsumDMU(modelStructure, null); + + ChoiceModelApplication[] mcModel = new ChoiceModelApplication[5]; + mcModel[WORK_CATEGORY] = new ChoiceModelApplication(mcUecFile, WORK_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[UNIVERSITY_CATEGORY] = new ChoiceModelApplication(mcUecFile, UNIVERSITY_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[SCHOOL_CATEGORY] = new ChoiceModelApplication(mcUecFile, SCHOOL_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[MAINTENANCE_CATEGORY] = new ChoiceModelApplication(mcUecFile, MAINTENANCE_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[DISCRETIONARY_CATEGORY] = new ChoiceModelApplication(mcUecFile, + DISCRETIONARY_SHEET, 0, rbMap, (VariableTable) mcDmuObject); + + // write skims data for estimation data file records + int seq = 1; + for (int i = 0; i < estDataOdts.length; i++) + { + + int[] odtSet = estDataOdts[i]; + int[] mgraSet = mgras[i]; + + odtSet[0] = seq; + + outStream2.print(seq + "," + odtSet[SAMPNO]); + + int category = PURPOSE_CATEGORIES[odtSet[TOUR_PURPOSE]]; + + int[] departAvailable = {-1, 1, 1, 1, 1, 1}; + int[] arriveAvailable = {-1, 1, 1, 1, 1, 1}; + calculateModeChoiceLogsums(rbMap, category == -1 ? null : mcModel[category], + mcDmuObject, odtSet, mgraSet, departAvailable, arriveAvailable, false); + + // write chosen dest and logsums to both files + outStream2.print("," + odtSet[DEST_MGRA]); + for (double logsum : departArriveLogsums[0]) + { + outStream2.printf(",%.8f", logsum); + } + outStream2.print("\n"); + + if (seq % 1000 == 0) logger.info("wrote TOD Estimation file record: " + seq); + + seq++; + } + + outStream2.close(); + + } + + private int[][] getTodEstimationDataOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][NUM_FIELDS]; + mgras = new int[hisTds.getRowCount()][NUM_MGRA_FIELDS]; + int[][] mgraData = new int[NUM_MGRA_FIELDS][]; + + int[] departs = hisTds.getColumnAsInt(DEPART_PERIOD_FIELD); + int[] arrives = hisTds.getColumnAsInt(ARRIVE_PERIOD_FIELD); + + int[] hisseq = hisTds.getColumnAsInt(SEQ_FIELD); + int[] purpose = hisTds.getColumnAsInt(PURPOSE_FIELD); + int[] jtPurpose = hisTds.getColumnAsInt(JOINT_PURPOSE_FIELD); + int[] income = hisTds.getColumnAsInt(INCOME_FIELD); + int[] origs = hisTds.getColumnAsInt(ORIG_MGRA_FIELD); + int[] dests = hisTds.getColumnAsInt(DEST_MGRA_FIELD); + int[] adultsFt = hisTds.getColumnAsInt(ADULTS_FT_FIELD); + int[] adultsPt = hisTds.getColumnAsInt(ADULTS_PT_FIELD); + int[] adultsUn = hisTds.getColumnAsInt(ADULTS_UN_FIELD); + int[] adultsRt = hisTds.getColumnAsInt(ADULTS_RT_FIELD); + int[] adultsNw = hisTds.getColumnAsInt(ADULTS_NW_FIELD); + int[] autos = hisTds.getColumnAsInt(AUTOS_FIELD); + int[] hhsize = hisTds.getColumnAsInt(HHSIZE_FIELD); + int[] gender = hisTds.getColumnAsInt(GENDER_FIELD); + int[] age = hisTds.getColumnAsInt(AGE_FIELD); + int[] jointId = hisTds.getColumnAsInt(JOINT_ID_FIELD); + int[] jointParticipants = hisTds.getColumnAsInt(JOINT_PARTICIPANTS_FIELD); + + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgraData[i] = hisTds.getColumnAsInt(MGRA1_FIELD + i); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgras[r - 1][i] = mgraData[i][r - 1]; + + odts[r - 1][SAMPNO] = hisseq[r - 1]; + + odts[r - 1][DEPART_PERIOD] = departs[r - 1]; + odts[r - 1][ARRIVE_PERIOD] = arrives[r - 1]; + + odts[r - 1][ORIG_MGRA] = origs[r - 1]; + odts[r - 1][DEST_MGRA] = dests[r - 1]; + odts[r - 1][INCOME] = income[r - 1]; + odts[r - 1][ADULTS] = adultsFt[r - 1] + adultsPt[r - 1] + adultsUn[r - 1] + + adultsRt[r - 1] + adultsNw[r - 1]; + odts[r - 1][AUTOS] = autos[r - 1]; + odts[r - 1][HHSIZE] = hhsize[r - 1]; + odts[r - 1][FEMALE] = gender[r - 1] == 2 ? 1 : 0; + odts[r - 1][AGE] = age[r - 1]; + odts[r - 1][JOINT] = jointId[r - 1] > 0 ? 1 : 0; + odts[r - 1][ESCORT] = purpose[r - 1] == 4 ? 1 : 0; + odts[r - 1][PARTYSIZE] = jointParticipants[r - 1]; + + odts[r - 1][TOUR_PURPOSE] = odts[r - 1][JOINT] == 1 && purpose[r - 1] > 4 ? jtPurpose[r - 1] + : purpose[r - 1]; + + } + + return odts; + } + + public static void main(String[] args) + { + + long startTime = System.currentTimeMillis(); + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + NonMandatoryTodEstimationMcLogsumsAppender appender = new NonMandatoryTodEstimationMcLogsumsAppender( + rbMap); + + appender.startMatrixServer(rb); + appender.runLogsumAppender(rb); + + System.out.println("total runtime = " + ((System.currentTimeMillis() - startTime) / 1000) + + " seconds."); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonTransitUtilities.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonTransitUtilities.java new file mode 100644 index 0000000..d7f07be --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/NonTransitUtilities.java @@ -0,0 +1,641 @@ +package org.sandag.abm.accessibilities; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; +import java.io.File; +import java.io.Serializable; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.Random; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.TNCAndTaxiWaitTimeCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.AutoUEC; +import org.sandag.abm.modechoice.MaasUEC; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.NonMotorUEC; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; +import com.pb.common.util.Tracer; + +/** + * This class builds utility components for auto modes (SOV and HOV). + * + * @author Joel Freedman + * @version May, 2009 + */ +public class NonTransitUtilities + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(NonTransitUtilities.class); + + public static final int OFFPEAK_PERIOD_INDEX = 0; + public static final int PEAK_PERIOD_INDEX = 1; + + private static final String[] SOVPERIODS = {"OP", "PK"}; + private static final String[] HOVPERIODS = {"OP", "PK"}; + private static final String[] NMTPERIODS = {"OP"}; + private static final String[] MAASPERIODS = {"OP", "PK"}; + + + // store taz-taz exponentiated utilities (period, from taz, to taz) + private double[][][] sovExpUtilities; + private double[][][] hovExpUtilities; + private double[][][] nMotorExpUtilities; + private double[][][] maasExpUtilities; + + private double[] avgTazHourlyParkingCost; + private float[] avgTazTaxiWaitTime; + private float[] avgTazSingleTNCWaitTime; + private float[] avgTazSharedTNCWaitTime; + + // A HashMap of non-motorized utilities, period,oMgra,dMgra (where dMgra is + // ragged) + private HashMap[][] mgraNMotorExpUtilities; + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private AutoUEC[] sovUEC; + private AutoUEC[] hovUEC; + private NonMotorUEC[] nMotorUEC; + private MaasUEC[] maasUEC; + + private int maxTaz; + + private boolean trace, seek; + private Tracer tracer; + + //added for TNC and Taxi modes + TNCAndTaxiWaitTimeCalculator tncTaxiWaitTimeCalculator = null; + + + /** + * Constructor. + * + * @param rb + * Resourcebundle with path to acc.uec.file, acc.data.page, + * acc.sov.offpeak.page, and acc.hov.offpeak.page + */ + + public NonTransitUtilities(HashMap rbMap, double[][][] mySovExpUtilities, + double[][][] myHovExpUtilities, double[][][] myNMotorExpUtilities, double[][][] myMaasExpUtilities) + { + + sovExpUtilities = mySovExpUtilities; + hovExpUtilities = myHovExpUtilities; + nMotorExpUtilities = myNMotorExpUtilities; + maasExpUtilities = myMaasExpUtilities; + + mgraManager = MgraDataManager.getInstance(); + tazManager = TazDataManager.getInstance(rbMap); + + maxTaz = tazManager.maxTaz; + + logger.info("max Taz " + maxTaz); + + // Create the peak and off-peak UECs + String uecFileName = Util.getStringValueFromPropertyMap(rbMap, "acc.uec.file"); + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.data.page"); + int offpeakSOVPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.sov.offpeak.page"); + int offpeakHOVPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.hov.offpeak.page"); + int peakSOVPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.sov.peak.page"); + int peakHOVPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.hov.peak.page"); + int nonMotorPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.nonmotorized.page"); + int peakMaasPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.maas.peak.page"); + int offpeakMaasPage = Util.getIntegerValueFromPropertyMap(rbMap, "acc.maas.offpeak.page"); + + sovUEC = new AutoUEC[SOVPERIODS.length]; + hovUEC = new AutoUEC[HOVPERIODS.length]; + nMotorUEC = new NonMotorUEC[NMTPERIODS.length]; + maasUEC = new MaasUEC[MAASPERIODS.length]; + + sovUEC[OFFPEAK_PERIOD_INDEX] = new AutoUEC(rbMap, uecFileName, offpeakSOVPage, dataPage); + sovUEC[PEAK_PERIOD_INDEX] = new AutoUEC(rbMap, uecFileName, peakSOVPage, dataPage); + hovUEC[OFFPEAK_PERIOD_INDEX] = new AutoUEC(rbMap, uecFileName, offpeakHOVPage, dataPage); + hovUEC[PEAK_PERIOD_INDEX] = new AutoUEC(rbMap, uecFileName, peakHOVPage, dataPage); + nMotorUEC[OFFPEAK_PERIOD_INDEX] = new NonMotorUEC(rbMap, uecFileName, nonMotorPage, + dataPage); + maasUEC[OFFPEAK_PERIOD_INDEX] = new MaasUEC(rbMap, uecFileName, offpeakMaasPage, dataPage); + maasUEC[PEAK_PERIOD_INDEX] = new MaasUEC(rbMap, uecFileName, peakMaasPage, dataPage); + + trace = Util.getBooleanValueFromPropertyMap(rbMap, "Trace"); + int[] traceOtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.otaz"); + int[] traceDtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.dtaz"); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + logger.info("Setting trace zone pair in NonTransitUtilities Object for i: "+ traceOtaz[i] + " j: " + traceDtaz[j]); + } + } + } + seek = Util.getBooleanValueFromPropertyMap(rbMap, "Seek"); + + int maxMgra = mgraManager.getMaxMgra(); +// logger.info("max Mgra " + maxMgra); + + mgraNMotorExpUtilities = new HashMap[NMTPERIODS.length][maxMgra + 1]; + + sovExpUtilities = new double[SOVPERIODS.length][maxTaz + 1][]; + hovExpUtilities = new double[HOVPERIODS.length][maxTaz + 1][]; + nMotorExpUtilities = new double[NMTPERIODS.length][maxTaz + 1][]; + + maasExpUtilities = new double[MAASPERIODS.length][maxTaz + 1][]; + + calculateAverageTazParkingCosts(); + + tncTaxiWaitTimeCalculator = new TNCAndTaxiWaitTimeCalculator(); + tncTaxiWaitTimeCalculator.createWaitTimeDistributions(rbMap); + + calculateAverageMaasWaitTimes(); + + + + } + + /** + * set the utilities values created by another object by calling + * buildUtilities() + */ + public void setAllUtilities(double[][][][] ntUtilities) + { + this.sovExpUtilities = ntUtilities[0]; + this.hovExpUtilities = ntUtilities[1]; + this.nMotorExpUtilities = ntUtilities[2]; + this.maasExpUtilities = ntUtilities[3]; + } + + /** + * get the set of utilities arrays built by calling buildUtilities(). + * + * @return array of 4 utilities arrays: sovExpUtilities, hovExpUtilities, + * nMotorExpUtilities, maasExpUtilities + */ + public double[][][][] getAllUtilities() + { + double[][][][] allUtilities = new double[3][][][]; + allUtilities[0] = sovExpUtilities; + allUtilities[1] = hovExpUtilities; + allUtilities[2] = nMotorExpUtilities; + allUtilities[3] = maasExpUtilities; + return allUtilities; + } + + /** + * set the HashMap of non-motorized utilities, period,oMgra,dMgra (where + * dMgra is ragged) + * + * @param mgraNMotorExpUtilities + */ + public void setNonMotorUtilsMap(HashMap[][] aMgraNMotorExpUtilities) + { + this.mgraNMotorExpUtilities = aMgraNMotorExpUtilities; + } + + /** + * get the HashMap of non-motorized utilities, period,oMgra,dMgra (where + * dMgra is ragged) that was built by calling buildUtilities(). + * + * @return mgraNMotorExpUtilities + */ + public HashMap[][] getNonMotorUtilsMap() + { + return mgraNMotorExpUtilities; + } + + /** + * Build SOV, HOV, and non-motorized exponentiated utilities for all + * TAZ-pairs. Also builds non-motorized exponentiated utilities for close-in + * mgra pairs. + * + */ + public void buildUtilities() + { + } + + /* + * public void buildUtilities() { + * + * logger.info("Calculating Non-Transit Zonal Utilities"); + * + * // first calculate the Tap-Tap utilities, exponentiate, and store + * logger.info("Calculating Taz-Taz utilities"); + * + * int maxMgra = mgraManager.getMaxMgra(); logger.info("max Mgra " + + * maxMgra); + * + * mgraNMotorExpUtilities = new HashMap[NMTPERIODS.length][maxMgra + 1]; + * + * sovExpUtilities = new double[SOVPERIODS.length][maxTaz + 1][maxTaz + 1]; + * hovExpUtilities = new double[HOVPERIODS.length][maxTaz + 1][maxTaz + 1]; + * nMotorExpUtilities = new double[NMTPERIODS.length][maxTaz + 1][maxTaz + + * 1]; + * + * for (int iTaz = 1; iTaz <= maxTaz; ++iTaz) { + * + * if (iTaz <= 10 || (iTaz % 500) == 0) logger.info("...Origin TAZ " + + * iTaz); + * + * // calculate the utilities for close-in mgras int[] oMgras = + * tazManager.getMgraArray(iTaz); if ( oMgras == null ) continue; + * + * for (int oMgra : oMgras) { + * + * // if there are mgras within walking distance if + * (mgraManager.getMgrasWithinWalkDistanceFrom(oMgra) != null) { int[] + * dMgras = mgraManager.getMgrasWithinWalkDistanceFrom(oMgra); + * + * int mgraNumber = 0; + * + * // cycle through periods, and calculate utilities for (int period = 0; + * period < NMTPERIODS.length; ++period) { + * + * mgraNMotorExpUtilities[period][oMgra] = new HashMap(); + * + * // cycle through the destination mgras for (int dMgra : dMgras) { + * + * double nmtUtility = nMotorUEC[period].calculateUtilitiesForMgraPair( + * oMgra, dMgra ); + * + * // exponentiate the utility if (nmtUtility > -500) + * mgraNMotorExpUtilities[period][oMgra].put( dMgra, Math.exp(nmtUtility) ); + * ++mgraNumber; + * + * } + * + * } + * + * } } + * + * for (int jTaz = 1; jTaz <= maxTaz; ++jTaz) { + * + * if (seek && !tracer.isTraceZonePair(iTaz, jTaz)) continue; + * + * for (int period = 0; period < SOVPERIODS.length; ++period) { + * + * double sovUtility = sovUEC[period].calculateUtilitiesForTazPair(iTaz, + * jTaz); // exponentiate the SOV utility if (sovUtility > -500) + * sovExpUtilities[period][iTaz][jTaz] = Math.exp(sovUtility); } + * + * for (int period = 0; period < HOVPERIODS.length; ++period) { + * + * double hovUtility = hovUEC[period].calculateUtilitiesForTazPair(iTaz, + * jTaz); // exponentiate the SOV utility if (hovUtility > -500) + * hovExpUtilities[period][iTaz][jTaz] = Math.exp(hovUtility); } + * + * for (int period = 0; period < NMTPERIODS.length; ++period) { + * + * double nmtUtility = nMotorUEC[period].calculateUtilitiesForTazPair(iTaz, + * jTaz); // exponentiate the SOV utility if (nmtUtility > -500) + * nMotorExpUtilities[period][iTaz][jTaz] = Math.exp(nmtUtility); } + * + * } } + * + * } + */ + + /** + * calculate an average TAZ parking cost to use in accessibilities + * calculation which are done at TAZ level. + */ + private void calculateAverageTazParkingCosts() + { + + avgTazHourlyParkingCost = new double[maxTaz + 1]; + + for (int jTaz = 1; jTaz <= maxTaz; ++jTaz) + { + + int[] mgras = tazManager.getMgraArray(jTaz); + if (mgras == null || mgras.length == 0) continue; + + double cost = 0; + int count = 0; + for (int mgra : mgras) + { + float mgraCost = mgraManager.getMgraHourlyParkingCost(mgra); + if (mgraCost > 0) + { + cost += mgraCost; + count++; + } + if (count > 0) cost /= count; + } + + avgTazHourlyParkingCost[jTaz] = cost; + + } + + } + + /** + * calculate an average TAZ parking cost to use in accessibilities + * calculation which are done at TAZ level. + */ + private void calculateAverageMaasWaitTimes() + { + + avgTazTaxiWaitTime = new float[maxTaz + 1]; + avgTazSingleTNCWaitTime = new float[maxTaz + 1]; + avgTazSharedTNCWaitTime = new float[maxTaz + 1]; + + for (int jTaz = 1; jTaz <= maxTaz; ++jTaz) + { + + int[] mgras = tazManager.getMgraArray(jTaz); + if (mgras == null || mgras.length == 0) continue; + + float taxiWait = 0; + float singleTNCWait = 0; + float sharedTNCWait = 0; + int singleTNCCount = 0; + int sharedTNCCount = 0; + int taxiCount = 0; + + + for (int mgra : mgras) + { + float popEmpDen = (float) mgraManager.getPopEmpPerSqMi(mgra); + float singleTNCWaitTime = (float) tncTaxiWaitTimeCalculator.getMeanSingleTNCWaitTime( popEmpDen); + float sharedTNCWaitTime = (float) tncTaxiWaitTimeCalculator.getMeanSharedTNCWaitTime( popEmpDen); + float taxiWaitTime = (float) tncTaxiWaitTimeCalculator.getMeanTaxiWaitTime( popEmpDen); + + if (taxiWaitTime > 0) + { + taxiWait += taxiWaitTime; + taxiCount++; + } + if (singleTNCWaitTime > 0) + { + singleTNCWait += singleTNCWaitTime; + singleTNCCount++; + } + if (sharedTNCWaitTime > 0) + { + sharedTNCWait += sharedTNCWaitTime; + sharedTNCCount++; + } + if (taxiCount > 0) taxiWait /= taxiCount; + if (singleTNCCount > 0) singleTNCWait /= singleTNCCount; + if (sharedTNCCount > 0) sharedTNCWait /= sharedTNCCount; + } + + avgTazTaxiWaitTime[jTaz] = taxiWait; + avgTazSingleTNCWaitTime[jTaz] = singleTNCWait; + avgTazSharedTNCWaitTime[jTaz] = sharedTNCWait; + } + + } + + public void buildUtilitiesForOrigMgraAndPeriod(int iMgra, int period) + { + + int iTaz = mgraManager.getTaz(iMgra); + if (sovExpUtilities[period][iTaz] != null) return; + + sovExpUtilities[period][iTaz] = new double[maxTaz + 1]; + hovExpUtilities[period][iTaz] = new double[maxTaz + 1]; + maasExpUtilities[period][iTaz] = new double[maxTaz + 1]; + + for (int jTaz = 1; jTaz <= maxTaz; ++jTaz) + { + + double sovUtility = sovUEC[period].calculateUtilitiesForTazPair(iTaz, jTaz, + avgTazHourlyParkingCost[jTaz]); + // exponentiate the SOV utility + if (sovUtility > -500) sovExpUtilities[period][iTaz][jTaz] = Math.exp(sovUtility); + + double hovUtility = hovUEC[period].calculateUtilitiesForTazPair(iTaz, jTaz, + avgTazHourlyParkingCost[jTaz]); + // exponentiate the HOV utility + if (hovUtility > -500) hovExpUtilities[period][iTaz][jTaz] = Math.exp(hovUtility); + + double maasUtility = maasUEC[period].calculateUtilitiesForTazPair(iTaz, jTaz, + avgTazTaxiWaitTime[jTaz], avgTazSingleTNCWaitTime[jTaz], avgTazSharedTNCWaitTime[jTaz]); + // exponentiate the SOV utility + if (maasUtility > -500) maasExpUtilities[period][iTaz][jTaz] = Math.exp(maasUtility); + + + } + + // non-motorized utilities are only needed for off-peak period, so if + // period index == 1 (peak) no nead to calculate off-peak + if (nMotorExpUtilities[OFFPEAK_PERIOD_INDEX][iTaz] == null) + { + + nMotorExpUtilities[OFFPEAK_PERIOD_INDEX][iTaz] = new double[maxTaz + 1]; + + for (int jTaz = 1; jTaz <= maxTaz; ++jTaz) + { + + double nmtUtility = nMotorUEC[OFFPEAK_PERIOD_INDEX].calculateUtilitiesForTazPair( + iTaz, jTaz); + // exponentiate the SOV utility + if (nmtUtility > -500) + nMotorExpUtilities[OFFPEAK_PERIOD_INDEX][iTaz][jTaz] = Math.exp(nmtUtility); + + } + + } + + } + + /** + * Get the non-motorized exponentiated utility for the mgra-pair and period. + * This method will return the taz-taz exponentiated non-motorized utility + * if the mgra-mgra exp utility doesn't exist. Otherwise the mgra-mgra exp. + * utility will be returned. + * + * @param iMgra + * Origin/production mgra. + * @param jMgra + * Destination/attraction mgra. + * @param period + * Period. + * @return The non-motorized exponentiated utility. + */ + /* + * public double getNMotorExpUtility(int iMgra, int jMgra, int period) { // + * no mgra-mgra utilities for this origin if + * (mgraNMotorExpUtilities[period][iMgra] == null) { int iTaz = + * mgraManager.getTaz(iMgra); int jTaz = mgraManager.getTaz(jMgra); return + * nMotorExpUtilities[period][iTaz][jTaz]; } + * + * // mgra-mgra utilities exist if + * (mgraNMotorExpUtilities[period][iMgra].containsKey(jMgra)) { return + * mgraNMotorExpUtilities[period][iMgra].get(jMgra); } + * + * // no mgra-mgra utilities for this destination int iTaz = + * mgraManager.getTaz(iMgra); int jTaz = mgraManager.getTaz(jMgra); return + * nMotorExpUtilities[period][iTaz][jTaz]; } + */ + public double getNMotorExpUtility(int iMgra, int jMgra, int period) + { + + // if no utilities exist for period and origin mgra, try to compute them + if (mgraNMotorExpUtilities[period][iMgra] == null) + { + + // get the mgras within walking distance of the iMgra + int[] dMgras = mgraManager.getMgrasWithinWalkDistanceFrom(iMgra); + + if (dMgras == null) + { + mgraNMotorExpUtilities[period][iMgra] = new HashMap(0); + } else + { + mgraNMotorExpUtilities[period][iMgra] = new HashMap(dMgras.length); + + // cycle through the destination mgras + for (int dMgra : dMgras) + { + // calculate utility for the specified mgra and period + double nmtUtility = nMotorUEC[period].calculateUtilitiesForMgraPair(iMgra, + dMgra); + + // exponentiate the utility + if (nmtUtility > -500) + mgraNMotorExpUtilities[period][iMgra].put(dMgra, Math.exp(nmtUtility)); + } + + } + + } + + // if jMgra is in the HashMap, return its utility value + if (mgraNMotorExpUtilities[period][iMgra].containsKey(jMgra)) + return mgraNMotorExpUtilities[period][iMgra].get(jMgra); + + // otherwise, get exponentiated utilities based on highway skim values + // for the taz pair associated with iMgra and jMgra. + int iTaz = mgraManager.getTaz(iMgra); + int jTaz = mgraManager.getTaz(jMgra); + return nMotorExpUtilities[period][iTaz][jTaz]; + + } + + /** + * Get the SOV Exponentiated Utility for a given ptaz, ataz, and period + * + * @param pTaz + * Production/Origin TAZ + * @param aTaz + * Attraction/Destination TAZ + * @param period + * Period + * @return SOV Exponentiated Utility. + */ + public double getSovExpUtility(int pTaz, int aTaz, int period) + { + return sovExpUtilities[period][pTaz][aTaz]; + } + + /** + * Get the HOV Exponentiated Utility for a given ptaz, ataz, and period + * + * @param pTaz + * Production/Origin TAZ + * @param aTaz + * Attraction/Destination TAZ + * @param period + * Period + * @return SOV Exponentiated Utility. + */ + public double getHovExpUtility(int pTaz, int aTaz, int period) + { + return hovExpUtilities[period][pTaz][aTaz]; + } + + /** + * Get the Maas Exponentiated Utility for a given ptaz, ataz, and period + * + * @param pTaz + * Production/Origin TAZ + * @param aTaz + * Attraction/Destination TAZ + * @param period + * Period + * @return Maas Exponentiated Utility. + */ + public double getMaasExpUtility(int pTaz, int aTaz, int period) + { + return maasExpUtilities[period][pTaz][aTaz]; + } + /** + * The main method runs this class, for testing purposes. + * + * @param args + * args[0] is the property file for this test run. + */ + public static void main(String[] args) + { + + ResourceBundle rb = ResourceUtil.getPropertyBundle(new File(args[0])); + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + boolean os64bit = false; + MatrixDataServer matrixServer = null; + + os64bit = Boolean.parseBoolean(Util.getStringValueFromPropertyMap(rbMap, + "operatingsystem.64bit")); + if (os64bit) + { + + String serverAddress = Util.getStringValueFromPropertyMap(rbMap, "server.address"); + + int serverPort = Util.getIntegerValueFromPropertyMap(rbMap, "server.port"); + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + + matrixServer = new MatrixDataServer(); + + // bind this concrete object with the cajo library objects for + // managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + System.out.println(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort)); + e.printStackTrace(); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + System.out.println(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort)); + e.printStackTrace(); + throw new RuntimeException(); + } + } + + double[][][] sovExpUtilities = null; + double[][][] hovExpUtilities = null; + double[][][] nMotorExpUtilities = null; + double[][][] maasExpUtilities = null; + + NonTransitUtilities au = new NonTransitUtilities(rbMap, sovExpUtilities, hovExpUtilities, + nMotorExpUtilities, maasExpUtilities); + au.buildUtilities(); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/ParkLocationEstimationAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/ParkLocationEstimationAppender.java new file mode 100644 index 0000000..3023ff4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/ParkLocationEstimationAppender.java @@ -0,0 +1,297 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +public final class ParkLocationEstimationAppender +{ + + private transient Logger logger = Logger.getLogger(ParkLocationEstimationAppender.class); + + private static final int DEBUG_EST_RECORD = 1; + + private static final String ESTIMATION_DATA_RECORDS_FILE_KEY = "plc.estimation.data.file"; + private static final String OUTPUT_DATA_RECORDS_FILE_KEY = "plc.est.skims.output.file"; + + // define input table field indices + private static final int ID_FIELD = 1; + private static final int DEPART_PERIOD_FIELD = 2; + private static final int TYPE_FIELD = 4; + private static final int ORIG_FIELD = 7; + private static final int DEST_FIELD = 8; + + // define indices for storing input data in an internal table. + // start field indices at 1; reserve 0 for the input file record sequence + // number. + private static final int ID = 1; + private static final int DEPART = 2; + private static final int TYPE = 3; + private static final int ORIG = 4; + private static final int DEST = 5; + private static final int NUM_FIELDS = 5; + + private static final int OD_TYPE_INDEX = 0; + private static final int OP_TYPE_INDEX = 1; + private static final int PD_TYPE_INDEX = 2; + private static final int[] TYPE_INDICES = {OD_TYPE_INDEX, OP_TYPE_INDEX, + PD_TYPE_INDEX }; + private static final String OD_TYPE = "OD"; + private static final String OP_TYPE = "OP"; + private static final String PD_TYPE = "PD"; + private static final String[] TYPE_LABELS = {OD_TYPE, OP_TYPE, PD_TYPE}; + + private static final int AUTO_TIME_SKIM_INDEX = 0; + private static final int AUTO_DIST_SKIM_INDEX = 2; + + private static final double WALK_SPEED = 3.0; // mph; + + private static final float defaultVOT = 15.0f; + private MatrixDataServerIf ms; + + public ParkLocationEstimationAppender() + { + } + + private void runAppender(ResourceBundle rb) + { + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + MgraDataManager mgraManager = MgraDataManager.getInstance(rbMap); + SandagModelStructure modelStructure = new SandagModelStructure(); + + double[] distances = new double[mgraManager.getMaxMgra() + 1]; + + String outputFileName = Util.getStringValueFromPropertyMap(rbMap, + OUTPUT_DATA_RECORDS_FILE_KEY); + if (outputFileName == null) + { + logger.info("no output file name was specified in the properties file. Nothing to do."); + return; + } + + int dotIndex = outputFileName.indexOf("."); + String baseName = outputFileName.substring(0, dotIndex); + String extension = outputFileName.substring(dotIndex); + String outputName = baseName + extension; + + PrintWriter outStream = null; + + try + { + outStream = new PrintWriter(new BufferedWriter(new FileWriter(new File(outputName)))); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileName)); + throw new RuntimeException(e); + } + + outStream + .println("seq,id,origMgra,destMgra,departPeriod,index,autoDist,autoTime,walkDist,walkTime"); + + TableDataSet estTds = getEstimationDataTableDataSet(rbMap); + int[][] estDataOdts = getPlcEstimationData(estTds); + + AutoAndNonMotorizedSkimsCalculator anm = new AutoAndNonMotorizedSkimsCalculator(rbMap); + + // write skims data for estimation data file records + int seq = 1; + for (int i = 0; i < estDataOdts.length; i++) + { + + int[] odtSet = estDataOdts[i]; + odtSet[0] = seq; + + double aDist = 999; + double aTime = 999; + double wDist = 999; + double wTime = 999; + if (odtSet[ORIG] > 0 && odtSet[DEST] > 0) + { + + int skimPeriodIndex = modelStructure.getSkimPeriodIndex(odtSet[DEPART]) + 1; // depart + // skim + // period + double[] autoSkims = anm.getAutoSkims(odtSet[ORIG], odtSet[DEST], skimPeriodIndex, defaultVOT, + (seq == DEBUG_EST_RECORD), logger); + aDist = autoSkims[AUTO_DIST_SKIM_INDEX]; + aTime = autoSkims[AUTO_TIME_SKIM_INDEX]; + + // get the array of mgras within walking distance of the + // destination + int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceFrom(odtSet[ORIG]); + + // set the distance values for the mgras walkable to the + // destination + if (walkMgras != null) + { + + // get distances, in feet, and convert to miles + for (int wMgra : walkMgras) + { + if (wMgra == odtSet[DEST]) + { + wDist = mgraManager.getMgraToMgraWalkDistFrom(odtSet[ORIG], wMgra) / 5280.0; + wTime = (wDist / WALK_SPEED) * 60.0; + break; + } + } + } + + } + + outStream.println(seq + "," + odtSet[ID] + "," + odtSet[ORIG] + "," + odtSet[DEST] + + "," + odtSet[DEPART] + "," + TYPE_LABELS[odtSet[TYPE]] + "," + aDist + "," + + aTime + "," + wDist + "," + wTime); + + if (seq % 1000 == 0) logger.info("wrote PLC Estimation file record: " + seq); + + seq++; + } + + outStream.close(); + + } + + private int[][] getPlcEstimationData(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][NUM_FIELDS + 1]; + + int[] ids = hisTds.getColumnAsInt(ID_FIELD); + int[] departs = hisTds.getColumnAsInt(DEPART_PERIOD_FIELD); + String[] types = hisTds.getColumnAsString(TYPE_FIELD); + int[] origs = hisTds.getColumnAsInt(ORIG_FIELD); + int[] dests = hisTds.getColumnAsInt(DEST_FIELD); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + odts[r - 1][ID] = ids[r - 1]; + odts[r - 1][DEPART] = departs[r - 1]; + + for (int i = 0; i < TYPE_INDICES.length; i++) + { + if (types[r - 1].equalsIgnoreCase(TYPE_LABELS[i])) + { + odts[r - 1][TYPE] = TYPE_INDICES[i]; + break; + } + } + + odts[r - 1][ORIG] = origs[r - 1]; + odts[r - 1][DEST] = dests[r - 1]; + + } + + return odts; + } + + protected TableDataSet getEstimationDataTableDataSet(HashMap rbMap) + { + + String estFileName = Util.getStringValueFromPropertyMap(rbMap, + ESTIMATION_DATA_RECORDS_FILE_KEY); + if (estFileName == null) + { + logger.error("Error getting the filename from the properties file for the Sandag estimation data records file."); + logger.error("Properties file target: " + ESTIMATION_DATA_RECORDS_FILE_KEY + + " not found."); + logger.error("Please specify a filename value for the " + + ESTIMATION_DATA_RECORDS_FILE_KEY + " property."); + throw new RuntimeException(); + } + + try + { + TableDataSet inTds = null; + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + inTds = reader.readFile(new File(estFileName)); + return inTds; + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading Sandag estimation data records file: %s into TableDataSet object.", + estFileName)); + throw new RuntimeException(e); + } + + } + + /** + * Start the matrix server + * + * @param rb + * is a ResourceBundle for the properties file for this + * application + */ + protected void startMatrixServer(ResourceBundle rb) + { + + logger.info(""); + logger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + logger.error("exception caught running ctramp model components -- exiting.", e); + throw new RuntimeException(); + + } + + } + + public static void main(String[] args) + { + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + ParkLocationEstimationAppender appender = new ParkLocationEstimationAppender(); + + appender.startMatrixServer(rb); + appender.runAppender(rb); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/SkimsAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/SkimsAppender.java new file mode 100644 index 0000000..95726b6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/SkimsAppender.java @@ -0,0 +1,788 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +public final class SkimsAppender +{ + + protected transient Logger logger = Logger.getLogger(SkimsAppender.class); + + private static final String OBS_DATA_RECORDS_FILE_KEY = "onBoard.survey.file"; + private static final String HIS_DATA_RECORDS_FILE_KEY = "homeInterview.survey.file"; + + private static final int OBS_UNIQUE_ID = 1; + private static final int OBS_ORIG_MGRA = 78; + private static final int OBS_DEST_MGRA = 79; + + // used for trip file: + private static final int OBS_OUT_TOUR_PERIOD = 133; + private static final int OBS_IN_TOUR_PERIOD = 134; + + // used for tour file: + // private static final int OBS_DEPART_PERIOD = 132; + // private static final int OBS_ARRIVE_PERIOD = 133; + + /* + * for home based tour mode choice estimation files private static final int + * HIS_ORIG_MGRA = 72; private static final int HIS_DEST_MGRA = 75; private + * static final int HIS_DEPART_PERIOD = 185; private static final int + * HIS_ARRIVE_PERIOD = 186; + */ + + /* + * for work based tour mode choice estimation files + */ + private static final int HIS_ORIG_MGRA = 76; + private static final int HIS_DEST_MGRA = 84; + private static final int HIS_DEPART_PERIOD = 159; + private static final int HIS_ARRIVE_PERIOD = 160; + + // survey periods are: 0=not used, 1=03:00-05:59, 2=06:00-08:59, + // 3=09:00-11:59, + // 4=12:00-15:29, 5=15:30-18:59, 6=19:00-02:59 + // skim periods are: 0=0(N/A), 1=3(OP), 2=1(AM), 3=3(OP), 4=3(OP), 5=2(PM), + // 6=3(OP) + + // define a conversion array to convert period values in the survey file to + // skim + // period indices used in this propgram: 1=am peak, 2=pm peak, + // 3=off-peak. + private static final String[] SKIM_PERIOD_LABELS = {"am", "pm", "op"}; + private static final int[] SURVEY_PERIOD_TO_SKIM_PERIOD = {0, 3, 1, 3, 3, 2, 3}; + + private MatrixDataServerIf ms; + private BestTransitPathCalculator bestPathUEC; + + TransitWalkAccessDMU walkDmu; + + private SkimsAppender() + { + } + + private void runSkimsAppender(ResourceBundle rb) + { + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + // instantiate these objects right away + TazDataManager tazs = TazDataManager.getInstance(rbMap); + MgraDataManager mgraManager = MgraDataManager.getInstance(rbMap); + TapDataManager tapManager = TapDataManager.getInstance(rbMap); + + AutoAndNonMotorizedSkimsCalculator anm = null; + WalkTransitWalkSkimsCalculator wtw = null; + WalkTransitDriveSkimsCalculator wtd = null; + DriveTransitWalkSkimsCalculator dtw = null; + + Logger autoLogger = Logger.getLogger("auto"); + Logger wtwLogger = Logger.getLogger("wtw"); + Logger wtdLogger = Logger.getLogger("wtd"); + Logger dtwLogger = Logger.getLogger("dtw"); + + String outputFileNameObs = Util.getStringValueFromPropertyMap(rbMap, + "obs.skims.output.file"); + String outputFileNameHis = Util.getStringValueFromPropertyMap(rbMap, + "his.skims.output.file"); + + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + + FileWriter writer; + PrintWriter outStreamObs = null; + PrintWriter outStreamHis = null; + + PrintWriter[] outStreamObsTod = new PrintWriter[SKIM_PERIOD_LABELS.length]; + PrintWriter[] outStreamHisTod = new PrintWriter[SKIM_PERIOD_LABELS.length]; + + if (!outputFileNameObs.isEmpty() || !outputFileNameHis.isEmpty()) + { + + anm = new AutoAndNonMotorizedSkimsCalculator(rbMap); + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + bestPathUEC = logsumHelper.getBestTransitPathCalculator(); + + wtw = new WalkTransitWalkSkimsCalculator(rbMap); + wtw.setup(rbMap, wtwLogger, bestPathUEC); + + wtd = new WalkTransitDriveSkimsCalculator(rbMap); + wtd.setup(rbMap, wtdLogger, bestPathUEC); + + dtw = new DriveTransitWalkSkimsCalculator(rbMap); + dtw.setup(rbMap, dtwLogger, bestPathUEC); + + String heading = "Seq,Id"; + + heading += ",obOrigMgra,obDestMgra,obPeriod"; + heading += getAutoSkimsHeaderRecord("auto", anm.getAutoSkimNames()); + heading += getNonMotorizedSkimsHeaderRecord("nm", anm.getNmSkimNames()); + heading += getTransitSkimsHeaderRecord("wtw", wtw.getSkimNames()); + heading += getTransitSkimsHeaderRecord("wtd", wtd.getSkimNames()); + heading += getTransitSkimsHeaderRecord("dtw", dtw.getSkimNames()); + + heading += ",ObsSeq,Id,ibOrigMgra,ibDestMgra,ibPeriod"; + heading += getAutoSkimsHeaderRecord("auto", anm.getAutoSkimNames()); + heading += getNonMotorizedSkimsHeaderRecord("nm", anm.getNmSkimNames()); + heading += getTransitSkimsHeaderRecord("wtw", wtw.getSkimNames()); + heading += getTransitSkimsHeaderRecord("wtd", wtd.getSkimNames()); + heading += getTransitSkimsHeaderRecord("dtw", dtw.getSkimNames()); + + if (!outputFileNameObs.isEmpty()) + { + try + { + // create an output stream for the mode choice estimation + // file + // with + // observed TOD + writer = new FileWriter(new File(outputFileNameObs)); + outStreamObs = new PrintWriter(new BufferedWriter(writer)); + + // create an array of similar files, 1 for each TOD period, + // for + // TOD + // choice estimation + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + { + int dotIndex = outputFileNameObs.lastIndexOf('.'); + String newName = outputFileNameObs.substring(0, dotIndex) + "_" + + SKIM_PERIOD_LABELS[i] + outputFileNameObs.substring(dotIndex); + writer = new FileWriter(new File(newName)); + outStreamObsTod[i] = new PrintWriter(new BufferedWriter(writer)); + } + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileNameObs)); + throw new RuntimeException(e); + } + + outStreamObs.println("obs" + heading); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamObsTod[i].println("obs" + heading); + } + + if (!outputFileNameHis.isEmpty()) + { + try + { + writer = new FileWriter(new File(outputFileNameHis)); + outStreamHis = new PrintWriter(new BufferedWriter(writer)); + + // create an array of similar files, 1 for each TOD period, + // for + // TOD + // choice estimation + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + { + int dotIndex = outputFileNameHis.lastIndexOf('.'); + String newName = outputFileNameHis.substring(0, dotIndex) + "_" + + SKIM_PERIOD_LABELS[i] + outputFileNameHis.substring(dotIndex); + writer = new FileWriter(new File(newName)); + outStreamHisTod[i] = new PrintWriter(new BufferedWriter(writer)); + } + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileNameHis)); + throw new RuntimeException(e); + } + + outStreamHis.println("his" + heading); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamHisTod[i].println("his" + heading); + } + + } + + Logger[] loggers = new Logger[4]; + loggers[0] = autoLogger; + loggers[1] = autoLogger; + loggers[2] = wtdLogger; + loggers[3] = dtwLogger; + + float defaultVOT= 15f; //$15 default VOT + + int[] odt = new int[5]; + + if (!outputFileNameObs.isEmpty()) + { + TableDataSet obsTds = getOnBoardSurveyTableDataSet(rbMap); + int[][] obsOdts = getOnBoardSurveyOrigDestTimes(obsTds); + + // write skims data for on-board survey records + int seq = 1; + for (int[] obsOdt : obsOdts) + { + // write outbound direction + odt[0] = obsOdt[0]; // orig + odt[1] = obsOdt[1]; // dest + odt[2] = SURVEY_PERIOD_TO_SKIM_PERIOD[obsOdt[2]]; // depart skim + // period + odt[3] = obsOdt[3]; + odt[4] = obsOdt[4]; + + if (odt[0] == 0 || odt[1] == 0) + { + outStreamObs.println(String.format("%d,%d,%d,%d,%d", seq, odt[4], odt[0], + odt[1], odt[2])); + seq++; + continue; + } + + // index + + // for debugging a specific mgra pair + // odt[0] = 25646; + // odt[1] = 4319; + // odt[2] = 1; + + boolean debugFlag = false; + if (odt[0] == 25646 && odt[1] == 4319) debugFlag = true; + + writeSkimsToFile(seq, outStreamObs, debugFlag, odt, anm, wtw, wtd, dtw, defaultVOT, loggers); + + // set odt[2] to be each skim priod index (1,2,3) and write a + // separate + // output file + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + { + odt[2] = i + 1; + writeSkimsToFile(seq, outStreamObsTod[i], false, odt, anm, wtw, wtd, dtw, defaultVOT, + loggers); + } + + // write inbound direction + odt[0] = obsOdt[1]; // dest + odt[1] = obsOdt[0]; // orig + odt[2] = SURVEY_PERIOD_TO_SKIM_PERIOD[obsOdt[3]]; // arrival + // skim + // period + // index + + outStreamObs.print(","); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamObsTod[i].print(","); + + writeSkimsToFile(seq, outStreamObs, debugFlag, odt, anm, wtw, wtd, dtw, defaultVOT, loggers); + + // set odt[2] to be each skim priod index (1,2,3) and write a + // separate + // output file + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + { + odt[2] = i + 1; + writeSkimsToFile(seq, outStreamObsTod[i], false, odt, anm, wtw, wtd, dtw, defaultVOT, + loggers); + } + + if (outStreamObs != null) + { + outStreamObs.println(""); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamObsTod[i].println(""); + } + + if (seq % 1000 == 0) logger.info("wrote OBS record: " + seq); + + seq++; + } + if (outStreamObs != null) + { + outStreamObs.close(); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamObsTod[i].close(); + } + } + + if (!outputFileNameHis.isEmpty()) + { + TableDataSet hisTds = getHomeInterviewSurveyTableDataSet(rbMap); + int[][] hisOdts = getHomeInterviewSurveyOrigDestTimes(hisTds); + + // write skims data for home interview survey records + int seq = 1; + for (int[] hisOdt : hisOdts) + { + // write outbound direction + odt[0] = hisOdt[0]; // orig + odt[1] = hisOdt[1]; // dest + odt[2] = SURVEY_PERIOD_TO_SKIM_PERIOD[hisOdt[2]]; // depart skim + // period + // index + writeSkimsToFile(seq, outStreamHis, false, odt, anm, wtw, wtd, dtw, defaultVOT, loggers); + + // set odt[2] to be each skim priod index (1,2,3) and write a + // separate + // output file + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + { + odt[2] = i + 1; + writeSkimsToFile(seq, outStreamHisTod[i], false, odt, anm, wtw, wtd, dtw, defaultVOT, + loggers); + } + + // write inbound direction + odt[0] = hisOdt[1]; // dest + odt[1] = hisOdt[0]; // orig + odt[2] = SURVEY_PERIOD_TO_SKIM_PERIOD[hisOdt[3]]; // arrival + // skim + // period + // index + + outStreamHis.print(","); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamHisTod[i].print(","); + + writeSkimsToFile(seq, outStreamHis, false, odt, anm, wtw, wtd, dtw, defaultVOT, loggers); + + // set odt[2] to be each skim priod index (1,2,3) and write a + // separate + // output file + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + { + odt[2] = i + 1; + writeSkimsToFile(seq, outStreamHisTod[i], false, odt, anm, wtw, wtd, dtw, defaultVOT, + loggers); + } + + if (outStreamHis != null) + { + outStreamHis.println(""); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamHisTod[i].println(""); + } + + if (seq % 1000 == 0) logger.info("wrote HIS record: " + seq); + + seq++; + } + if (outStreamHis != null) + { + outStreamHis.close(); + for (int i = 0; i < SKIM_PERIOD_LABELS.length; i++) + outStreamHisTod[i].close(); + } + } + + } + + private void writeSkimsToFile(int sequence, PrintWriter outStream, boolean loggingEnabled, + int[] odt, AutoAndNonMotorizedSkimsCalculator anm, WalkTransitWalkSkimsCalculator wtw, + WalkTransitDriveSkimsCalculator wtd, DriveTransitWalkSkimsCalculator dtw, float vot, + Logger[] loggers) + { + + Logger autoLogger = loggers[0]; + Logger wtwLogger = loggers[1]; + Logger wtdLogger = loggers[2]; + Logger dtwLogger = loggers[3]; + + int[][] bestTapPairs = null; + double[][] returnedSkims = null; + + if (outStream != null) + outStream.print(String.format("%d,%d,%d,%d,%d", sequence, odt[4], odt[0], odt[1], + odt[2])); + + double[] skims = anm.getAutoSkims(odt[0], odt[1], odt[2], vot,loggingEnabled, autoLogger); + if (loggingEnabled) + anm.logReturnedSkims(odt[0], odt[1], odt[2], skims, "auto", autoLogger); + + if (outStream != null) + { + String autoRecord = getAutoSkimsRecord(skims); + outStream.print(autoRecord); + } + + skims = anm.getNonMotorizedSkims(odt[0], odt[1], odt[2], loggingEnabled, autoLogger); + if (loggingEnabled) + anm.logReturnedSkims(odt[0], odt[1], odt[2], skims, "non-motorized", autoLogger); + + if (outStream != null) + { + String nmRecord = getAutoSkimsRecord(skims); + outStream.print(nmRecord); + } + + /* TODO: + * Fix the following code + + + BestTransitPathCalculator bestTransitPathCalculator = wtw.getBestPathUEC(); + + bestTransitPathCalculator.findBestWalkTransitWalkTaps(walkDmu, odt[2], odt[0], odt[1], loggingEnabled, wtwLogger); + returnedSkims = new double[bestTapPairs.length][]; + for (int i = 0; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] == null) returnedSkims[i] = wtw.getNullTransitSkims(i); + else + { + returnedSkims[i] = wtw.getWalkTransitWalkSkims(i, bestPathUEC.getBestAccessTime(i), + bestPathUEC.getBestEgressTime(i), bestTapPairs[i][0], bestTapPairs[i][1], + odt[2], loggingEnabled); + } + } + if (loggingEnabled) wtw.logReturnedSkims(odt, bestTapPairs, returnedSkims); + + if (outStream != null) + { + String wtwRecord = getTransitSkimsRecord(odt, returnedSkims); + outStream.print(wtwRecord); + } + + bestTapPairs = wtd.getBestTapPairs(odt[0], odt[1], odt[2], loggingEnabled, wtdLogger); + returnedSkims = new double[bestTapPairs.length][]; + for (int i = 0; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] == null) returnedSkims[i] = wtd.getNullTransitSkims(i); + else + { + returnedSkims[i] = wtd.getWalkTransitDriveSkims(i, + bestPathUEC.getBestAccessTime(i), bestPathUEC.getBestEgressTime(i), + bestTapPairs[i][0], bestTapPairs[i][1], odt[2], loggingEnabled); + } + } + if (loggingEnabled) wtd.logReturnedSkims(odt, bestTapPairs, returnedSkims); + + if (outStream != null) + { + String wtdRecord = getTransitSkimsRecord(odt, returnedSkims); + outStream.print(wtdRecord); + } + + bestTapPairs = dtw.getBestTapPairs(odt[0], odt[1], odt[2], loggingEnabled, dtwLogger); + returnedSkims = new double[bestTapPairs.length][]; + for (int i = 0; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] == null) returnedSkims[i] = dtw.getNullTransitSkims(i); + else + { + returnedSkims[i] = dtw.getDriveTransitWalkSkims(i, + bestPathUEC.getBestAccessTime(i), bestPathUEC.getBestEgressTime(i), + bestTapPairs[i][0], bestTapPairs[i][1], odt[2], loggingEnabled); + } + } + if (loggingEnabled) dtw.logReturnedSkims(odt, bestTapPairs, returnedSkims); + + if (outStream != null) + { + String dtwRecord = getTransitSkimsRecord(odt, returnedSkims); + outStream.print(dtwRecord); + } + */ + } + + /** + * Start the matrix server + * + * @param rb + * is a ResourceBundle for the properties file for this + * application + */ + private void startMatrixServer(ResourceBundle rb) + { + + logger.info(""); + logger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + } + + /** + * create a String which can be written to an output file with all the skim + * values for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + * @param skims + * is a double[][] of skim values with the first dimesion the + * ride mode indices and second dimention the skim categories + */ + private String getTransitSkimsRecord(int[] odt, double[][] skims) + { + + int nrows = skims.length; + int ncols = 0; + for (int i = 0; i < nrows; i++) + if (skims[i].length > ncols) ncols = skims[i].length; + + String tableRecord = ""; + for (int i = 0; i < skims.length; i++) + { + for (int j = 0; j < skims[i].length; j++) + tableRecord += String.format(",%.5f", skims[i][j]); + } + + return tableRecord; + + } + + /** + * create a String which can be written to an output file with all the skim + * values for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + * @param skims + * is a double[] of skim values + */ + private String getAutoSkimsRecord(double[] skims) + { + + String tableRecord = ""; + for (int i = 0; i < skims.length; i++) + { + tableRecord += String.format(",%.5f", skims[i]); + } + + return tableRecord; + + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getTransitSkimsHeaderRecord(String transitServiceLabel, String[] skimNames) + { + + Modes.TransitMode[] mode = Modes.TransitMode.values(); + + String heading = ""; + + for (int i = 0; i < mode.length; i++) + { + for (int j = 0; j < skimNames.length; j++) + heading += String.format(",%s_%s_%s", transitServiceLabel, mode[i], + skimNames[j]); + } + + return heading; + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getAutoSkimsHeaderRecord(String label, String[] names) + { + + String heading = ""; + + for (int i = 0; i < names.length; i++) + heading += String.format(",%s_%s", label, names[i]); + + return heading; + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getNonMotorizedSkimsHeaderRecord(String label, String[] names) + { + + String heading = ""; + + for (int i = 0; i < names.length; i++) + heading += String.format(",%s_%s", label, names[i]); + + return heading; + } + + private TableDataSet getOnBoardSurveyTableDataSet(HashMap rbMap) + { + + String obsFileName = Util.getStringValueFromPropertyMap(rbMap, OBS_DATA_RECORDS_FILE_KEY); + if (obsFileName == null) + { + logger.error("Error getting the filename from the properties file for the Sandag on-board survey data records file."); + logger.error("Properties file target: " + OBS_DATA_RECORDS_FILE_KEY + " not found."); + logger.error("Please specify a filename value for the " + OBS_DATA_RECORDS_FILE_KEY + + " property."); + throw new RuntimeException(); + } + + try + { + TableDataSet inTds = null; + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + inTds = reader.readFile(new File(obsFileName)); + return inTds; + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading Sandag on-board survey data records file: %s into TableDataSet object.", + obsFileName)); + throw new RuntimeException(e); + } + + } + + private TableDataSet getHomeInterviewSurveyTableDataSet(HashMap rbMap) + { + + String hisFileName = Util.getStringValueFromPropertyMap(rbMap, HIS_DATA_RECORDS_FILE_KEY); + if (hisFileName == null) + { + logger.error("Error getting the filename from the properties file for the Sandag home interview survey data records file."); + logger.error("Properties file target: " + HIS_DATA_RECORDS_FILE_KEY + " not found."); + logger.error("Please specify a filename value for the " + HIS_DATA_RECORDS_FILE_KEY + + " property."); + throw new RuntimeException(); + } + + try + { + TableDataSet inTds = null; + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + inTds = reader.readFile(new File(hisFileName)); + return inTds; + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading Sandag home interview survey data records file: %s into TableDataSet object.", + hisFileName)); + throw new RuntimeException(e); + } + + } + + private int[][] getOnBoardSurveyOrigDestTimes(TableDataSet obsTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[obsTds.getRowCount()][5]; + + int[] origs = obsTds.getColumnAsInt(OBS_ORIG_MGRA); + int[] dests = obsTds.getColumnAsInt(OBS_DEST_MGRA); + int[] departs = obsTds.getColumnAsInt(OBS_OUT_TOUR_PERIOD); + int[] arrives = obsTds.getColumnAsInt(OBS_IN_TOUR_PERIOD); + int[] ids = obsTds.getColumnAsInt(OBS_UNIQUE_ID); + + for (int r = 1; r <= obsTds.getRowCount(); r++) + { + odts[r - 1][0] = origs[r - 1]; + odts[r - 1][1] = dests[r - 1]; + odts[r - 1][2] = departs[r - 1]; + odts[r - 1][3] = arrives[r - 1]; + odts[r - 1][4] = ids[r - 1]; + } + + return odts; + } + + private int[][] getHomeInterviewSurveyOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][4]; + + int[] origs = hisTds.getColumnAsInt(HIS_ORIG_MGRA); + int[] dests = hisTds.getColumnAsInt(HIS_DEST_MGRA); + int[] departs = hisTds.getColumnAsInt(HIS_DEPART_PERIOD); + int[] arrives = hisTds.getColumnAsInt(HIS_ARRIVE_PERIOD); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + odts[r - 1][0] = origs[r - 1]; + odts[r - 1][1] = dests[r - 1]; + odts[r - 1][2] = departs[r - 1]; + odts[r - 1][3] = arrives[r - 1]; + } + + return odts; + } + + public static void main(String[] args) + { + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + SkimsAppender appender = new SkimsAppender(); + + appender.startMatrixServer(rb); + appender.runSkimsAppender(rb); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StopLocationEstimationMcLogsumsAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StopLocationEstimationMcLogsumsAppender.java new file mode 100644 index 0000000..deeb3b8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StopLocationEstimationMcLogsumsAppender.java @@ -0,0 +1,331 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.application.SandagTripModeChoiceDMU; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; + +public final class StopLocationEstimationMcLogsumsAppender + extends McLogsumsAppender +{ + + private static final int DEBUG_EST_RECORD1 = 266; + private static final int DEBUG_EST_RECORD2 = -1; + + /* + * for stop location choice estimation file + */ + private static final int PORTION_FIELD = 1; + private static final int SAMPNO_FIELD = 2; + private static final int PERNO_FIELD = 3; + private static final int TOUR_ID_FIELD = 4; + private static final int TRIPNO_FIELD = 5; + private static final int STOPID_FIELD = 6; + private static final int STOPNO_FIELD = 7; + + private static final int ORIG_MGRA_FIELD = 16; + private static final int DEST_MGRA_FIELD = 23; + private static final int CHOSEN_MGRA_FIELD = 17; + private static final int MGRA1_FIELD = 49; + + private static final int TOUR_DEPART_PERIOD_FIELD = 40; + private static final int TOUR_ARRIVE_PERIOD_FIELD = 41; + private static final int TRIP_START_PERIOD_FIELD = 29; + private static final int TOUR_MODE_FIELD = 30; + private static final int INCOME_FIELD = 24; + private static final int ADULTS_FIELD = 47; + private static final int AUTOS_FIELD = 28; + private static final int HHSIZE_FIELD = 27; + private static final int GENDER_FIELD = 26; + private static final int OUT_STOPS_FIELD = 45; + private static final int IN_STOPS_FIELD = 46; + private static final int FIRST_TRIP_FIELD = 43; + private static final int LAST_TRIP_FIELD = 44; + private static final int PURPOSE_FIELD = 12; + private static final int AGE_FIELD = 25; + private static final int DIR_FIELD = 42; + private static final int J_TOUR_ID_FIELD = 10; + private static final int J_TOUR_PARTICIPANTS_FIELD = 11; + private static final int NUM_MGRA_FIELDS = 30; + + public StopLocationEstimationMcLogsumsAppender(HashMap rbMap) + { + super(rbMap); + + debugEstimationFileRecord1 = DEBUG_EST_RECORD1; + debugEstimationFileRecord2 = DEBUG_EST_RECORD2; + + numMgraFields = NUM_MGRA_FIELDS; + } + + private void runLogsumAppender(ResourceBundle rb) + { + + totalTime1 = 0; + totalTime2 = 0; + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + tazs = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + mgraSetForLogsums = new int[numMgraFields + 1]; + + // allocate the logsums array for the chosen destination alternative + tripModeChoiceLogsums = new double[NUM_MGRA_FIELDS + 1][2]; + + departArriveLogsums = new double[NUM_MGRA_FIELDS + 1][departArriveCombinations.length]; + + String outputFileName = Util.getStringValueFromPropertyMap(rbMap, + "slc.est.skims.output.file"); + if (outputFileName == null) + { + logger.info("no output file name was specified in the properties file. Nothing to do."); + return; + } + + int dotIndex = outputFileName.indexOf("."); + String baseName = outputFileName.substring(0, dotIndex); + String extension = outputFileName.substring(dotIndex); + + String outputName = baseName + extension; + + PrintWriter outStream = null; + + try + { + outStream = new PrintWriter(new BufferedWriter(new FileWriter(new File(outputName)))); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileName)); + throw new RuntimeException(e); + } + + writeDcFile(rbMap, outStream); + + logger.info("total part 1 runtime = " + (totalTime1 / 1000) + " seconds."); + logger.info("total part 2 runtime = " + (totalTime2 / 1000) + " seconds."); + + } + + private void writeDcFile(HashMap rbMap, PrintWriter outStream) + { + + outStream + .print("seq,portion,sampn,perno,tour_id,tripno,stopid,stopno,chosenMgra,chosenMgraLogsumIK,chosenMgraLogsumKJ"); + + // print each set of sample destMgra and the depart/arrive logsum + // fieldnames + // to file 1. + // print each set of sample destMgra and the chosen depart/arrive logsum + // fieldname to file 2. + for (int m = 1; m < tripModeChoiceLogsums.length; m++) + { + outStream.print(",sampleMgra_" + m); + outStream.print(",sampleLogsumIK_" + m); + outStream.print(",sampleLogsumKJ_" + m); + } + outStream.print("\n"); + + TableDataSet estTds = getEstimationDataTableDataSet(rbMap); + int[][] estDataOdts = getDcEstimationDataOrigDestTimes(estTds); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = rbMap.get(PROPERTIES_UEC_TRIP_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + SandagTripModeChoiceDMU mcDmuObject = new SandagTripModeChoiceDMU(modelStructure, null); + + ChoiceModelApplication[] mcModel = new ChoiceModelApplication[5 + 1]; + mcModel[WORK_CATEGORY] = new ChoiceModelApplication(mcUecFile, WORK_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[UNIVERSITY_CATEGORY] = new ChoiceModelApplication(mcUecFile, UNIVERSITY_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[SCHOOL_CATEGORY] = new ChoiceModelApplication(mcUecFile, SCHOOL_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[MAINTENANCE_CATEGORY] = new ChoiceModelApplication(mcUecFile, MAINTENANCE_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[DISCRETIONARY_CATEGORY] = new ChoiceModelApplication(mcUecFile, + DISCRETIONARY_SHEET, 0, rbMap, (VariableTable) mcDmuObject); + mcModel[SUBTOUR_CATEGORY] = new ChoiceModelApplication(mcUecFile, SUBTOUR_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + + // write skims data for estimation data file records + int seq = 1; + for (int i = 0; i < estDataOdts.length; i++) + { + + int[] odtSet = estDataOdts[i]; + int[] mgraSet = mgras[i]; + + odtSet[0] = seq; + + outStream.print(seq + "," + odtSet[PORTION] + "," + odtSet[SAMPNO] + "," + + odtSet[PERNO] + "," + odtSet[TOUR_ID] + "," + odtSet[TRIPNO] + "," + + odtSet[STOPID] + "," + odtSet[STOPNO]); + + int category = PURPOSE_CATEGORIES[odtSet[TOUR_PURPOSE]]; + + try + { + calculateTripModeChoiceLogsums(rbMap, mcModel[category], mcDmuObject, odtSet, + mgraSet); + } catch (Exception e) + { + logger.error("exception caught processing survey record for i = " + i); + throw new RuntimeException(); + } + + outStream.print("," + odtSet[CHOSEN_MGRA]); + outStream + .printf(",%.8f,%.8f", tripModeChoiceLogsums[0][0], tripModeChoiceLogsums[0][1]); + + // write logsum sets for each dest in the sample to file 1 + for (int m = 1; m < tripModeChoiceLogsums.length; m++) + { + outStream.print("," + mgraSet[m - 1]); + outStream.printf(",%.8f,%.8f", tripModeChoiceLogsums[m][0], + tripModeChoiceLogsums[m][1]); + } + outStream.print("\n"); + + if (seq % 1000 == 0) logger.info("wrote DC Estimation file record: " + seq); + + seq++; + } + + outStream.close(); + + } + + private int[][] getDcEstimationDataOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][NUM_FIELDS]; + mgras = new int[hisTds.getRowCount()][NUM_MGRA_FIELDS]; + int[][] mgraData = new int[NUM_MGRA_FIELDS][]; + + int[] tourDeparts = hisTds.getColumnAsInt(TOUR_DEPART_PERIOD_FIELD); + int[] tourArrives = hisTds.getColumnAsInt(TOUR_ARRIVE_PERIOD_FIELD); + int[] tripStarts = hisTds.getColumnAsInt(TRIP_START_PERIOD_FIELD); + + int[] direction = hisTds.getColumnAsInt(DIR_FIELD); + + int[] portion = hisTds.getColumnAsInt(PORTION_FIELD); + int[] sampno = hisTds.getColumnAsInt(SAMPNO_FIELD); + int[] perno = hisTds.getColumnAsInt(PERNO_FIELD); + int[] tour_id = hisTds.getColumnAsInt(TOUR_ID_FIELD); + int[] tripno = hisTds.getColumnAsInt(TRIPNO_FIELD); + int[] stopid = hisTds.getColumnAsInt(STOPID_FIELD); + int[] stopno = hisTds.getColumnAsInt(STOPNO_FIELD); + int[] purpose = hisTds.getColumnAsInt(PURPOSE_FIELD); + int[] jTourId = hisTds.getColumnAsInt(J_TOUR_ID_FIELD); + int[] jTourParticipants = hisTds.getColumnAsInt(J_TOUR_PARTICIPANTS_FIELD); + int[] income = hisTds.getColumnAsInt(INCOME_FIELD); + int[] mode = hisTds.getColumnAsInt(TOUR_MODE_FIELD); + int[] origs = hisTds.getColumnAsInt(ORIG_MGRA_FIELD); + int[] dests = hisTds.getColumnAsInt(DEST_MGRA_FIELD); + int[] chosen = hisTds.getColumnAsInt(CHOSEN_MGRA_FIELD); + int[] adults = hisTds.getColumnAsInt(ADULTS_FIELD); + int[] age = hisTds.getColumnAsInt(AGE_FIELD); + int[] autos = hisTds.getColumnAsInt(AUTOS_FIELD); + int[] hhsize = hisTds.getColumnAsInt(HHSIZE_FIELD); + int[] gender = hisTds.getColumnAsInt(GENDER_FIELD); + int[] outStops = hisTds.getColumnAsInt(OUT_STOPS_FIELD); + int[] inStops = hisTds.getColumnAsInt(IN_STOPS_FIELD); + int[] firstTrip = hisTds.getColumnAsInt(FIRST_TRIP_FIELD); + int[] lastTrip = hisTds.getColumnAsInt(LAST_TRIP_FIELD); + + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgraData[i] = hisTds.getColumnAsInt(MGRA1_FIELD + i); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgras[r - 1][i] = mgraData[i][r - 1]; + + odts[r - 1][PORTION] = portion[r - 1]; + odts[r - 1][SAMPNO] = sampno[r - 1]; + odts[r - 1][PERNO] = perno[r - 1]; + odts[r - 1][TOUR_ID] = tour_id[r - 1]; + odts[r - 1][TRIPNO] = tripno[r - 1]; + odts[r - 1][STOPID] = stopid[r - 1]; + odts[r - 1][STOPNO] = stopno[r - 1]; + + odts[r - 1][DEPART_PERIOD] = tourDeparts[r - 1]; + odts[r - 1][ARRIVE_PERIOD] = tourArrives[r - 1]; + odts[r - 1][TRIP_PERIOD] = tripStarts[r - 1]; + + odts[r - 1][DIRECTION] = direction[r - 1]; + + odts[r - 1][ORIG_MGRA] = origs[r - 1]; + odts[r - 1][DEST_MGRA] = dests[r - 1]; + odts[r - 1][CHOSEN_MGRA] = chosen[r - 1]; + odts[r - 1][TOUR_MODE] = mode[r - 1]; + odts[r - 1][INCOME] = income[r - 1]; + odts[r - 1][ADULTS] = adults[r - 1]; + odts[r - 1][AUTOS] = autos[r - 1]; + odts[r - 1][AGE] = age[r - 1]; + odts[r - 1][HHSIZE] = hhsize[r - 1]; + odts[r - 1][FEMALE] = gender[r - 1] == 2 ? 1 : 0; + odts[r - 1][FIRST_TRIP] = firstTrip[r - 1]; + odts[r - 1][LAST_TRIP] = lastTrip[r - 1]; + odts[r - 1][OUT_STOPS] = outStops[r - 1]; + odts[r - 1][IN_STOPS] = inStops[r - 1]; + + odts[r - 1][TOUR_PURPOSE] = purpose[r - 1]; + odts[r - 1][JOINT] = jTourId[r - 1] > 0 ? 1 : 0; + odts[r - 1][PARTYSIZE] = jTourParticipants[r - 1]; + + } + + return odts; + } + + public static void main(String[] args) + { + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + StopLocationEstimationMcLogsumsAppender appender = new StopLocationEstimationMcLogsumsAppender( + rbMap); + + appender.startMatrixServer(rb); + appender.runLogsumAppender(rb); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StopLocationSampleCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StopLocationSampleCalculator.java new file mode 100644 index 0000000..b6ffadb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StopLocationSampleCalculator.java @@ -0,0 +1,502 @@ +package org.sandag.abm.accessibilities; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.application.SandagTripModeChoiceDMU; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.ResourceUtil; + +public final class StopLocationSampleCalculator + extends McLogsumsAppender +{ + + private static final int DEBUG_EST_RECORD = 5; + + /* + * for stop location choice estimation file + */ + private static final int PORTION_FIELD = 1; + private static final int SAMPNO_FIELD = 2; + private static final int PERNO_FIELD = 3; + private static final int TOUR_ID_FIELD = 4; + private static final int TRIPNO_FIELD = 5; + private static final int STOPID_FIELD = 6; + private static final int STOPNO_FIELD = 7; + + private static final int ORIG_MGRA_FIELD = 16; + private static final int DEST_MGRA_FIELD = 23; + private static final int CHOSEN_MGRA_FIELD = 17; + private static final int MGRA1_FIELD = 49; + + private static final int TOUR_DEPART_PERIOD_FIELD = 40; + private static final int TOUR_ARRIVE_PERIOD_FIELD = 41; + private static final int TRIP_START_PERIOD_FIELD = 29; + private static final int TOUR_MODE_FIELD = 30; + private static final int INCOME_FIELD = 24; + private static final int ADULTS_FIELD = 47; + private static final int AUTOS_FIELD = 28; + private static final int HHSIZE_FIELD = 27; + private static final int GENDER_FIELD = 26; + private static final int OUT_STOPS_FIELD = 45; + private static final int IN_STOPS_FIELD = 46; + private static final int FIRST_TRIP_FIELD = 43; + private static final int LAST_TRIP_FIELD = 44; + private static final int TOUR_PURPOSE_FIELD = 12; + private static final int STOP_PURPOSE_FIELD = 12; + private static final int AGE_FIELD = 25; + private static final int DIR_FIELD = 42; + private static final int J_TOUR_ID_FIELD = 10; + private static final int J_TOUR_PARTICIPANTS_FIELD = 11; + private static final int NUM_MGRA_FIELDS = 30; + + private static final String PROPERTIES_UEC_SLC_SOA_CHOICE = "slc.soa.uec.file"; + private static final String PROPERTIES_UEC_STOP_SOA_SIZE = "slc.soa.size.uec.file"; + private static final String PROPERTIES_UEC_STOP_SOA_SIZE_DATA = "slc.soa.size.uec.data.page"; + private static final String PROPERTIES_UEC_STOP_SOA_SIZE_MODEL = "slc.soa.size.uec.model.page"; + + private static final int WORK_STOP_PURPOSE_INDEX = 1; + private static final int UNIV_STOP_PURPOSE_INDEX = 2; + private static final int ESCORT_STOP_PURPOSE_INDEX = 4; + private static final int SHOP_STOP_PURPOSE_INDEX = 5; + private static final int MAINT_STOP_PURPOSE_INDEX = 6; + private static final int EAT_OUT_STOP_PURPOSE_INDEX = 7; + private static final int VISIT_STOP_PURPOSE_INDEX = 8; + private static final int DISCR_STOP_PURPOSE_INDEX = 9; + private static final int MAX_STOP_PURPOSE_INDEX = 9; + + private static final int WORK_STOP_PURPOSE_SOA_SIZE_INDEX = 0; + private static final int UNIV_STOP_PURPOSE_SOA_SIZE_INDEX = 1; + private static final int ESCORT_0_STOP_PURPOSE_SOA_SIZE_INDEX = 2; + private static final int ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX = 3; + private static final int ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX = 4; + private static final int ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX = 5; + private static final int SHOP_STOP_PURPOSE_SOA_SIZE_INDEX = 6; + private static final int MAINT_STOP_PURPOSE_SOA_SIZE_INDEX = 7; + private static final int EAT_OUT_STOP_PURPOSE_SOA_SIZE_INDEX = 8; + private static final int VISIT_STOP_PURPOSE_SOA_SIZE_INDEX = 9; + private static final int DISCR_STOP_PURPOSE_SOA_SIZE_INDEX = 10; + + private static final int AUTO_DIST_SKIM_INDEX = 2; + + private McLogsumsCalculator logsumHelper; + + private static final float defaultVOT = 15.0f; + + public StopLocationSampleCalculator(HashMap rbMap) + { + super(rbMap); + debugEstimationFileRecord1 = DEBUG_EST_RECORD; + + } + + private void runSampleProbabilitiesCalculator(ResourceBundle rb) + { + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + tazs = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + TableDataSet estTds = getEstimationDataTableDataSet(rbMap); + int[][] estDataOdts = getDcEstimationDataOrigDestTimes(estTds); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = rbMap.get(PROPERTIES_UEC_TRIP_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(rbMap); + + SandagTripModeChoiceDMU mcDmuObject = new SandagTripModeChoiceDMU(modelStructure, null); + + ChoiceModelApplication[] mcModel = new ChoiceModelApplication[5 + 1]; + mcModel[WORK_CATEGORY] = new ChoiceModelApplication(mcUecFile, WORK_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[UNIVERSITY_CATEGORY] = new ChoiceModelApplication(mcUecFile, UNIVERSITY_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[SCHOOL_CATEGORY] = new ChoiceModelApplication(mcUecFile, SCHOOL_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[MAINTENANCE_CATEGORY] = new ChoiceModelApplication(mcUecFile, MAINTENANCE_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[DISCRETIONARY_CATEGORY] = new ChoiceModelApplication(mcUecFile, + DISCRETIONARY_SHEET, 0, rbMap, (VariableTable) mcDmuObject); + mcModel[SUBTOUR_CATEGORY] = new ChoiceModelApplication(mcUecFile, SUBTOUR_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + + /* + * SandagStopDCSoaDMU slcSoaDmuObject = new + * SandagStopDCSoaDMU(modelStructure); + * + * String slcSoaUecFile = rbMap.get(PROPERTIES_UEC_SLC_SOA_CHOICE); + * slcSoaUecFile = uecPath + slcSoaUecFile; + * + * ChoiceModelApplication[] slcSoaModel = new + * ChoiceModelApplication[MAX_STOP_PURPOSE_INDEX+1]; + * slcSoaModel[WORK_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, WORK_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + * slcSoaModel[UNIV_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, UNIV_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + * slcSoaModel[ESCORT_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, ESCORT_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + * slcSoaModel[SHOP_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, SHOP_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + * slcSoaModel[EAT_OUT_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, EAT_OUT_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + * slcSoaModel[MAINT_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, MAINT_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + * slcSoaModel[VISIT_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, VISIT_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + * slcSoaModel[DISCR_STOP_PURPOSE_INDEX] = new + * ChoiceModelApplication(slcSoaUecFile, DISCR_STOP_PURPOSE_INDEX, 0, + * rbMap, (VariableTable) slcSoaDmuObject); + */ + + double absoulteDistanceDeviationCoefficient = -0.05; + + int i = DEBUG_EST_RECORD - 1; + + int[] odtSet = estDataOdts[i]; + + int mgra = mgras[i][24]; + + int category = PURPOSE_CATEGORIES[odtSet[TOUR_PURPOSE]]; + // int stopPurpose = odtSet[STOP_PURPOSE]; + int stopPurpose = 6; + + double[] logsums = null; + try + { + logsums = calculateTripModeChoiceLogsumForEstimationRecord(rbMap, mcModel[category], + mcDmuObject, odtSet, mgra); + } catch (Exception e) + { + logger.error("exception caught calculating trip mode choice logsum for survey record i = " + + (i + 1)); + throw new RuntimeException(); + } + + double[] slcSoaSizeTerms = null; + try + { + boolean preSchoolInHh = false; + boolean gradeSchoolInHh = false; + boolean highSchoolInHh = false; + double[][] sizeTerms = calculateSlcSoaSizeTerms(rbMap, mgra); + slcSoaSizeTerms = getSlcSoaSizeTermsForStopPurpose(stopPurpose, preSchoolInHh, + gradeSchoolInHh, highSchoolInHh, sizeTerms); + } catch (Exception e) + { + logger.error("exception caught calculating stop location choice size terms for survey record i = " + + (i + 1)); + throw new RuntimeException(); + } + + try + { + int origMgra = odtSet[ORIG_MGRA]; + int destMgra = odtSet[DEST_MGRA]; + int departPeriod = odtSet[TRIP_PERIOD]; // depart period + int skimPeriodIndex = modelStructure.getSkimPeriodIndex(departPeriod) + 1; // depart + // skim + + double odDist = logsumHelper.getAnmSkimCalculator().getAutoSkims(origMgra, destMgra, + skimPeriodIndex, defaultVOT, false, logger)[AUTO_DIST_SKIM_INDEX]; + double osDist = logsumHelper.getAnmSkimCalculator().getAutoSkims(origMgra, mgra, + skimPeriodIndex, defaultVOT, false, logger)[AUTO_DIST_SKIM_INDEX]; + double sdDist = logsumHelper.getAnmSkimCalculator().getAutoSkims(mgra, destMgra, + skimPeriodIndex, defaultVOT, false, logger)[AUTO_DIST_SKIM_INDEX]; + double distance = osDist + sdDist - odDist; + int availability = 1; + + boolean walkTransitIsAvailable = false; + if (mgraManager.getMgraWlkTapsDistArray()[mgra][0] != null) + walkTransitIsAvailable = true; + + double util = -999; + if (availability == 1) + util = Math.log(slcSoaSizeTerms[mgra]) + absoulteDistanceDeviationCoefficient + * distance; + + logUtilityCalculation(origMgra, mgra, destMgra, departPeriod, skimPeriodIndex, osDist, + sdDist, odDist, distance, slcSoaSizeTerms[mgra], util, logsums); + } catch (Exception e) + { + logger.error("exception caught calculating and logging utility calculation for survey record i = " + + (i + 1)); + throw new RuntimeException(); + } + + } + + private void logUtilityCalculation(int origMgra, int sampleMgra, int destMgra, + int departPeriodIndex, int skimPeriodIndex, double osDist, double sdDist, + double odDist, double distance, double size, double util, double[] logsums) + { + + // write UEC calculation results to logsum specific log file if + // its the chosen dest and its the chosen time combo + slcSoaLogger.info("Stop Location Sample Probabilities Calculation:"); + slcSoaLogger.info(""); + slcSoaLogger + .info("--------------------------------------------------------------------------------------------------------"); + slcSoaLogger.info("origin mgra = " + origMgra); + slcSoaLogger.info("sample destination mgra = " + sampleMgra); + slcSoaLogger.info("final destination mgra = " + destMgra); + slcSoaLogger.info("origin taz = " + mgraManager.getTaz(origMgra)); + slcSoaLogger.info("sample destination taz = " + mgraManager.getTaz(sampleMgra)); + slcSoaLogger.info("final destination taz = " + mgraManager.getTaz(destMgra)); + slcSoaLogger.info("depart period interval = " + departPeriodIndex); + slcSoaLogger.info("skim period index = " + skimPeriodIndex); + slcSoaLogger.info("orig to stop distance = " + osDist); + slcSoaLogger.info("stop to dest distance = " + sdDist); + slcSoaLogger.info("orig to dest distance = " + odDist); + slcSoaLogger.info("distance = " + distance); + slcSoaLogger.info("size = " + size); + slcSoaLogger.info(""); + slcSoaLogger.info("util = size * exp ( -0.05*distance )"); + slcSoaLogger.info("util = " + util); + slcSoaLogger.info("os logsum = " + logsums[0]); + slcSoaLogger.info("sd logsum = " + logsums[1]); + slcSoaLogger + .info("--------------------------------------------------------------------------------------------------------"); + slcSoaLogger.info(""); + + } + + private double[] getSlcSoaSizeTermsForStopPurpose(int stopPurpose, boolean preSchoolInHh, + boolean gradeSchoolInHh, boolean highSchoolInHh, double[][] sizeTerms) + { + + double[] slcSoaSizeTerms = null; + switch (stopPurpose) + { + + case WORK_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[WORK_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case UNIV_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[UNIV_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case ESCORT_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[ESCORT_0_STOP_PURPOSE_SOA_SIZE_INDEX]; + + // add preschool size term if the hh has a preschool child + if (preSchoolInHh) + { + for (int j = 0; j < sizeTerms[ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX].length; j++) + slcSoaSizeTerms[j] += sizeTerms[ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX][j]; + } + + // add grade school size term if the hh has a grade school child + if (gradeSchoolInHh) + { + for (int j = 0; j < sizeTerms[ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX].length; j++) + slcSoaSizeTerms[j] += sizeTerms[ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX][j]; + } + + // add high school size term if the hh has a high school child + if (highSchoolInHh) + { + for (int j = 0; j < sizeTerms[ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX].length; j++) + slcSoaSizeTerms[j] += sizeTerms[ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX][j]; + } + break; + case SHOP_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[SHOP_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case MAINT_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[MAINT_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case EAT_OUT_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[EAT_OUT_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case VISIT_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[VISIT_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case DISCR_STOP_PURPOSE_INDEX: + slcSoaSizeTerms = sizeTerms[DISCR_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + } + + return slcSoaSizeTerms; + + } + + private double[][] calculateSlcSoaSizeTerms(HashMap rbMap, int sampleMgra) + { + + logger.info(""); + logger.info(""); + logger.info("Calculating Stop Location SOA Size Terms"); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String slcSoaSizeUecFile = rbMap.get(PROPERTIES_UEC_STOP_SOA_SIZE); + slcSoaSizeUecFile = uecPath + slcSoaSizeUecFile; + int slcSoaSizeUecData = Integer.parseInt(rbMap.get(PROPERTIES_UEC_STOP_SOA_SIZE_DATA)); + int slcSoaSizeUecModel = Integer.parseInt(rbMap.get(PROPERTIES_UEC_STOP_SOA_SIZE_MODEL)); + + IndexValues iv = new IndexValues(); + UtilityExpressionCalculator slcSoaSizeUec = new UtilityExpressionCalculator(new File( + slcSoaSizeUecFile), slcSoaSizeUecModel, slcSoaSizeUecData, rbMap, null); + + ArrayList mgras = mgraManager.getMgras(); + int maxMgra = mgraManager.getMaxMgra(); + int alternatives = slcSoaSizeUec.getNumberOfAlternatives(); + double[][] slcSoaSize = new double[alternatives][maxMgra + 1]; + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + iv.setZoneIndex(mgra); + double[] utilities = slcSoaSizeUec.solve(iv, null, null); + + if (mgra == sampleMgra) + slcSoaSizeUec.logAnswersArray(slcSoaLogger, "Stop Location SOA Size Terms, MGRA = " + + mgra); + + // store the size terms + for (int i = 0; i < alternatives; i++) + slcSoaSize[i][mgra] = utilities[i]; + + } + + return slcSoaSize; + + } + + private int[][] getDcEstimationDataOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][NUM_FIELDS]; + mgras = new int[hisTds.getRowCount()][NUM_MGRA_FIELDS]; + int[][] mgraData = new int[NUM_MGRA_FIELDS][]; + + int[] tourDeparts = hisTds.getColumnAsInt(TOUR_DEPART_PERIOD_FIELD); + int[] tourArrives = hisTds.getColumnAsInt(TOUR_ARRIVE_PERIOD_FIELD); + int[] tripStarts = hisTds.getColumnAsInt(TRIP_START_PERIOD_FIELD); + + int[] direction = hisTds.getColumnAsInt(DIR_FIELD); + + int[] portion = hisTds.getColumnAsInt(PORTION_FIELD); + int[] sampno = hisTds.getColumnAsInt(SAMPNO_FIELD); + int[] perno = hisTds.getColumnAsInt(PERNO_FIELD); + int[] tour_id = hisTds.getColumnAsInt(TOUR_ID_FIELD); + int[] tripno = hisTds.getColumnAsInt(TRIPNO_FIELD); + int[] stopid = hisTds.getColumnAsInt(STOPID_FIELD); + int[] stopno = hisTds.getColumnAsInt(STOPNO_FIELD); + int[] tourPurpose = hisTds.getColumnAsInt(TOUR_PURPOSE_FIELD); + int[] stopPurpose = hisTds.getColumnAsInt(STOP_PURPOSE_FIELD); + int[] jTourId = hisTds.getColumnAsInt(J_TOUR_ID_FIELD); + int[] jTourParticipants = hisTds.getColumnAsInt(J_TOUR_PARTICIPANTS_FIELD); + int[] income = hisTds.getColumnAsInt(INCOME_FIELD); + int[] mode = hisTds.getColumnAsInt(TOUR_MODE_FIELD); + int[] origs = hisTds.getColumnAsInt(ORIG_MGRA_FIELD); + int[] dests = hisTds.getColumnAsInt(DEST_MGRA_FIELD); + int[] chosen = hisTds.getColumnAsInt(CHOSEN_MGRA_FIELD); + int[] adults = hisTds.getColumnAsInt(ADULTS_FIELD); + int[] age = hisTds.getColumnAsInt(AGE_FIELD); + int[] autos = hisTds.getColumnAsInt(AUTOS_FIELD); + int[] hhsize = hisTds.getColumnAsInt(HHSIZE_FIELD); + int[] gender = hisTds.getColumnAsInt(GENDER_FIELD); + int[] outStops = hisTds.getColumnAsInt(OUT_STOPS_FIELD); + int[] inStops = hisTds.getColumnAsInt(IN_STOPS_FIELD); + int[] firstTrip = hisTds.getColumnAsInt(FIRST_TRIP_FIELD); + int[] lastTrip = hisTds.getColumnAsInt(LAST_TRIP_FIELD); + + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgraData[i] = hisTds.getColumnAsInt(MGRA1_FIELD + i); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgras[r - 1][i] = mgraData[i][r - 1]; + + odts[r - 1][PORTION] = portion[r - 1]; + odts[r - 1][SAMPNO] = sampno[r - 1]; + odts[r - 1][PERNO] = perno[r - 1]; + odts[r - 1][TOUR_ID] = tour_id[r - 1]; + odts[r - 1][TRIPNO] = tripno[r - 1]; + odts[r - 1][STOPID] = stopid[r - 1]; + odts[r - 1][STOPNO] = stopno[r - 1]; + + odts[r - 1][DEPART_PERIOD] = tourDeparts[r - 1]; + odts[r - 1][ARRIVE_PERIOD] = tourArrives[r - 1]; + odts[r - 1][TRIP_PERIOD] = tripStarts[r - 1]; + + odts[r - 1][DIRECTION] = direction[r - 1]; + + odts[r - 1][ORIG_MGRA] = origs[r - 1]; + odts[r - 1][DEST_MGRA] = dests[r - 1]; + odts[r - 1][CHOSEN_MGRA] = chosen[r - 1]; + odts[r - 1][TOUR_MODE] = mode[r - 1]; + odts[r - 1][INCOME] = income[r - 1]; + odts[r - 1][ADULTS] = adults[r - 1]; + odts[r - 1][AUTOS] = autos[r - 1]; + odts[r - 1][AGE] = age[r - 1]; + odts[r - 1][HHSIZE] = hhsize[r - 1]; + odts[r - 1][FEMALE] = gender[r - 1] == 2 ? 1 : 0; + odts[r - 1][FIRST_TRIP] = firstTrip[r - 1]; + odts[r - 1][LAST_TRIP] = lastTrip[r - 1]; + odts[r - 1][OUT_STOPS] = outStops[r - 1]; + odts[r - 1][IN_STOPS] = inStops[r - 1]; + + odts[r - 1][TOUR_PURPOSE] = tourPurpose[r - 1]; + odts[r - 1][STOP_PURPOSE] = stopPurpose[r - 1]; + odts[r - 1][JOINT] = jTourId[r - 1] > 0 ? 1 : 0; + odts[r - 1][PARTYSIZE] = jTourParticipants[r - 1]; + + } + + return odts; + } + + public static void main(String[] args) + { + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + StopLocationSampleCalculator appender = new StopLocationSampleCalculator(rbMap); + + appender.startMatrixServer(rb); + appender.runSampleProbabilitiesCalculator(rb); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StoredTransitSkimData.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StoredTransitSkimData.java new file mode 100644 index 0000000..0f37752 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StoredTransitSkimData.java @@ -0,0 +1,51 @@ +package org.sandag.abm.accessibilities; + + +public class StoredTransitSkimData +{ + + private static StoredTransitSkimData objInstance = null; + private int numSets; + + // these arrays are shared by McLogsumsAppender objects and are used by wtw, wtd, and dtw calculators. + private double[][][][][] storedWtwDepartPeriodTapTapSkims; + private double[][][][][] storedWtdDepartPeriodTapTapSkims; + private double[][][][][] storedDtwDepartPeriodTapTapSkims; + + + private StoredTransitSkimData(){ + this.numSets = numSets; + } + + public static synchronized StoredTransitSkimData getInstance( int numSets, int numPeriods, int maxTap ) + { + if (objInstance == null) { + objInstance = new StoredTransitSkimData(); + objInstance.setupStoredDataArrays(numSets, numPeriods, maxTap ); + return objInstance; + } + else { + return objInstance; + } + } + + private void setupStoredDataArrays(int numSets, int numPeriods, int maxTap ){ + storedWtwDepartPeriodTapTapSkims = new double[numSets][numPeriods + 1][maxTap + 1][][]; + storedWtdDepartPeriodTapTapSkims = new double[numSets][numPeriods + 1][maxTap + 1][][]; + storedDtwDepartPeriodTapTapSkims = new double[numSets][numPeriods + 1][maxTap + 1][][]; + } + + public double[][][][][] getStoredWtwDepartPeriodTapTapSkims() { + return storedWtwDepartPeriodTapTapSkims; + } + + public double[][][][][] getStoredWtdDepartPeriodTapTapSkims() { + return storedWtdDepartPeriodTapTapSkims; + } + + public double[][][][][] getStoredDtwDepartPeriodTapTapSkims() { + return storedDtwDepartPeriodTapTapSkims; + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StoredUtilityData.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StoredUtilityData.java new file mode 100644 index 0000000..51644a5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/StoredUtilityData.java @@ -0,0 +1,133 @@ +package org.sandag.abm.accessibilities; + +import java.util.concurrent.ConcurrentHashMap; +import java.util.HashMap; + + +public class StoredUtilityData +{ + + private static StoredUtilityData objInstance = null; + public static final float default_utility = -999; + + // these arrays are shared by multiple BestTransitPathCalculator objects in a distributed computing environment + private float[][] storedWalkAccessUtils; // dim#1: MGRA id, dim#2: TAP id + private float[][] storedDriveAccessUtils; // dim#1: TAZ id, dim#2: TAP id + private float[][] storedWalkEgressUtils; // dim#1: TAP id, dim#2: MGRA id + private float[][] storedDriveEgressUtils; // dim#1: TAP id, dim#2: TAZ id + + // {0:WTW, 1:WTD, 2:DTW} -> TOD period number -> pTAP*100000+aTAP -> utility + private HashMap>> storedDepartPeriodTapTapUtils; + + + private StoredUtilityData(){ + } + + public static synchronized StoredUtilityData getInstance( int maxMgra, int maxTap, int maxTaz, int[] accEgrSegments, int[] periods) + { + if (objInstance == null) { + objInstance = new StoredUtilityData(); + objInstance.setupStoredDataArrays( maxMgra, maxTap, maxTaz, accEgrSegments, periods); + return objInstance; + } + else { + return objInstance; + } + } + + private void setupStoredDataArrays( int maxMgra, int maxTap, int maxTaz, int[] accEgrSegments, int[] periods){ + // dimension the arrays + storedWalkAccessUtils = new float[maxMgra + 1][maxTap + 1]; + storedDriveAccessUtils = new float[maxTaz + 1][maxTap + 1]; + storedWalkEgressUtils = new float[maxTap + 1][maxMgra + 1]; + storedDriveEgressUtils = new float[maxTap + 1][maxTaz + 1]; + // assign default values to array elements + for (int i=0; i<=maxMgra; i++) + for (int j=0; j<=maxTap; j++) { + storedWalkAccessUtils[i][j] = default_utility; + storedWalkEgressUtils[j][i] = default_utility; + } + // assign default values to array elements + for (int i=0; i<=maxTaz; i++) + for (int j=0; j<=maxTap; j++) { + storedDriveAccessUtils[i][j] = default_utility; + storedDriveEgressUtils[j][i] = default_utility; + } + + //put into concurrent hashmap + storedDepartPeriodTapTapUtils = new HashMap>>(); + for(int i=0; i>()); + for(int j=0; j> hm = storedDepartPeriodTapTapUtils.get(accEgrSegments[i]); + hm.put(periods[j], new ConcurrentHashMap()); //key method paTapKey below + } + } + } + + public float[][] getStoredWalkAccessUtils() { + return storedWalkAccessUtils; + } + + public float[][] getStoredDriveAccessUtils() { + return storedDriveAccessUtils; + } + + public float[][] getStoredWalkEgressUtils() { + return storedWalkEgressUtils; + } + + public float[][]getStoredDriveEgressUtils() { + return storedDriveEgressUtils; + } + + public HashMap>> getStoredDepartPeriodTapTapUtils() { + return storedDepartPeriodTapTapUtils; + } + + //create p to a hash key - up to 99,999 + public long paTapKey(int p, int a) { + return(p * 100000 + a); + } + + //convert double array to float array + public float[] d2f(double[] d) { + float[] f = new float[d.length]; + for(int i=0; i rbMap) + { + super(rbMap); + + debugEstimationFileRecord1 = DEBUG_EST_RECORD1; + debugEstimationFileRecord2 = DEBUG_EST_RECORD2; + + } + + private void runLogsumAppender(ResourceBundle rb) + { + + totalTime1 = 0; + totalTime2 = 0; + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + tazs = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + mgraSetForLogsums = new int[numMgraFields + 1]; + + // allocate the logsums array for the chosen destination alternative + modeChoiceLogsums = new double[1][]; + + departArriveLogsums = new double[1][departArriveCombinations.length]; + + String outputFileName = Util.getStringValueFromPropertyMap(rbMap, + "tod.est.skims.output.file"); + + PrintWriter outStream = null; + + if (outputFileName == null) + { + logger.info("no output file name was specified in the properties file. Nothing to do."); + return; + } + + try + { + outStream = new PrintWriter( + new BufferedWriter(new FileWriter(new File(outputFileName)))); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileName)); + throw new RuntimeException(e); + } + + writeTodFile(rbMap, outStream); + + logger.info("total part 1 runtime = " + (totalTime1 / 1000) + " seconds."); + logger.info("total part 2 runtime = " + (totalTime2 / 1000) + " seconds."); + + } + + private void writeTodFile(HashMap rbMap, PrintWriter outStream2) + { + + // print the chosen destMgra and the depart/arrive logsum field names to + // the + // file + outStream2.print("seq,hisseq,chosenMgra"); + for (String[] labels : departArriveCombinationLabels) + { + outStream2.print(",logsum" + labels[0] + labels[1]); + } + outStream2.print("\n"); + + TableDataSet estTds = getEstimationDataTableDataSet(rbMap); + int[][] estDataOdts = getTodEstimationDataOrigDestTimes(estTds); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = rbMap.get(PROPERTIES_UEC_TOUR_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + SandagAppendMcLogsumDMU mcDmuObject = new SandagAppendMcLogsumDMU(modelStructure, null); + + ChoiceModelApplication[] mcModel = new ChoiceModelApplication[5 + 1]; + mcModel[WORK_CATEGORY] = new ChoiceModelApplication(mcUecFile, WORK_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[UNIVERSITY_CATEGORY] = new ChoiceModelApplication(mcUecFile, UNIVERSITY_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[SCHOOL_CATEGORY] = new ChoiceModelApplication(mcUecFile, SCHOOL_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[MAINTENANCE_CATEGORY] = new ChoiceModelApplication(mcUecFile, MAINTENANCE_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[DISCRETIONARY_CATEGORY] = new ChoiceModelApplication(mcUecFile, + DISCRETIONARY_SHEET, 0, rbMap, (VariableTable) mcDmuObject); + mcModel[SUBTOUR_CATEGORY] = new ChoiceModelApplication(mcUecFile, SUBTOUR_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + + // write skims data for estimation data file records + int seq = 1; + for (int i = 0; i < estDataOdts.length; i++) + { + + int[] odtSet = estDataOdts[i]; + int[] mgraSet = mgras[i]; + + odtSet[0] = seq; + + outStream2.print(seq + "," + odtSet[SAMPNO]); + + int category = PURPOSE_CATEGORIES[odtSet[TOUR_PURPOSE]]; + + int[] departAvailable = {-1, 1, 1, 1, 1, 1}; + int[] arriveAvailable = {-1, 1, 1, 1, 1, 1}; + calculateModeChoiceLogsums(rbMap, category == -1 ? null : mcModel[category], + mcDmuObject, odtSet, mgraSet, departAvailable, arriveAvailable, false); + + // write chosen dest and logsums to both files + outStream2.print("," + odtSet[DEST_MGRA]); + for (double logsum : departArriveLogsums[0]) + { + outStream2.printf(",%.8f", logsum); + } + outStream2.print("\n"); + + if (seq % 1000 == 0) logger.info("wrote TOD Estimation file record: " + seq); + + seq++; + } + + outStream2.close(); + + } + + private int[][] getTodEstimationDataOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][NUM_FIELDS]; + mgras = new int[hisTds.getRowCount()][NUM_MGRA_FIELDS]; + int[][] mgraData = new int[NUM_MGRA_FIELDS][]; + + int[] departs = hisTds.getColumnAsInt(DEPART_PERIOD_FIELD); + int[] arrives = hisTds.getColumnAsInt(ARRIVE_PERIOD_FIELD); + + int[] hisseq = hisTds.getColumnAsInt(SEQ_FIELD); + int[] origs = hisTds.getColumnAsInt(ORIG_MGRA_FIELD); + int[] dests = hisTds.getColumnAsInt(DEST_MGRA_FIELD); + int[] autos = hisTds.getColumnAsInt(AUTOS_FIELD); + int[] age = hisTds.getColumnAsInt(AGE_FIELD); + int[] workTourMode = hisTds.getColumnAsInt(WORK_TOUR_MODE_FIELD); + + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgraData[i] = hisTds.getColumnAsInt(MGRA1_FIELD + i); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgras[r - 1][i] = mgraData[i][r - 1]; + + odts[r - 1][SAMPNO] = hisseq[r - 1]; + + odts[r - 1][TOUR_PURPOSE] = SUBTOUR_PURPOSE; + + odts[r - 1][DEPART_PERIOD] = departs[r - 1]; + odts[r - 1][ARRIVE_PERIOD] = arrives[r - 1]; + + odts[r - 1][ORIG_MGRA] = origs[r - 1]; + odts[r - 1][DEST_MGRA] = dests[r - 1]; + odts[r - 1][AUTOS] = autos[r - 1]; + odts[r - 1][AGE] = age[r - 1]; + odts[r - 1][WORK_TOUR_MODE] = workTourMode[r - 1]; + + } + + return odts; + } + + public static void main(String[] args) + { + + long startTime = System.currentTimeMillis(); + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + SubtourTodEstimationMcLogsumsAppender appender = new SubtourTodEstimationMcLogsumsAppender( + rbMap); + + appender.startMatrixServer(rb); + appender.runLogsumAppender(rb); + + /* + * used this to read/parse the UEC expressions - debugging the UEC + * sheet. + * + * HashMap rbMap = + * ResourceUtil.changeResourceBundleIntoHashMap(rb); + * + * String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + * String mcUecFile = rbMap.get(PROPERTIES_UEC_TOUR_MODE_CHOICE); + * mcUecFile = uecPath + mcUecFile; + * + * ModelStructure modelStructure = new SandagModelStructure(); + * SandagAppendMcLogsumDMU mcDmuObject = new + * SandagAppendMcLogsumDMU(modelStructure); ChoiceModelApplication + * mcModel = new ChoiceModelApplication(mcUecFile, SUBTOUR_SHEET, 0, + * rbMap, (VariableTable) mcDmuObject); + */ + + System.out.println("total runtime = " + ((System.currentTimeMillis() - startTime) / 1000) + + " seconds."); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/TransitPath.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/TransitPath.java new file mode 100644 index 0000000..c3985af --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/TransitPath.java @@ -0,0 +1,45 @@ +package org.sandag.abm.accessibilities; + +public class TransitPath implements Comparable{ + + public int oMaz; + public int dMaz; + public int pTap; + public int aTap; + public int set; + public int accEgr; + public float accUtil; + public float tapTapUtil; + public float egrUtil; + public static final int NA = -999; + + public TransitPath(int oMaz, int dMaz, int pTap, int aTap, int set, int accEgr, float accUtil, float tapTapUtil, float egrUtil) { + this.oMaz = oMaz; + this.dMaz = dMaz; + this.pTap = pTap; + this.aTap = aTap; + this.set = set; + this.accEgr = accEgr; + this.accUtil = accUtil; + this.tapTapUtil = tapTapUtil; + this.egrUtil = egrUtil; + } + + public float getTotalUtility() { + return(accUtil + tapTapUtil + egrUtil); + } + + @Override + public int compareTo(TransitPath o) { + + //return compareTo value + if ( getTotalUtility() < o.getTotalUtility() ) { + return -1; + } else if (getTotalUtility() == o.getTotalUtility()) { + return 0; + } else { + return 1; + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/TripSkimsAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/TripSkimsAppender.java new file mode 100644 index 0000000..dab1318 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/TripSkimsAppender.java @@ -0,0 +1,569 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +public final class TripSkimsAppender +{ + + protected transient Logger logger = Logger.getLogger(TripSkimsAppender.class); + + /* + * for trip mode choice estimation files + */ + private static final String HIS_DATA_RECORDS_FILE_KEY = "homeInterview.survey.file"; + + // private static final int HIS_SAMPNO = 2; + // private static final int HIS_ORIG_MGRA = 188; + // private static final int HIS_DEST_MGRA = 189; + // private static final int HIS_DEPART_PERIOD = 192; + + private static final int HIS_SAMPNO = 1; + private static final int HIS_ORIG_MGRA = 2; + private static final int HIS_DEST_MGRA = 3; + private static final int HIS_DEPART_PERIOD = 5; + + // private static final int HIS_SAMPNO = 2; + // private static final int HIS_ORIG_MGRA = 247; + // private static final int HIS_DEST_MGRA = 248; + // private static final int HIS_DEPART_PERIOD = 325; + + // survey periods are: + // 0=not used, + // 1=03:00-05:59, + // 2=06:00-08:59, + // 3=09:00-11:59, + // 4=12:00-15:29, + // 5=15:30-18:59, + // 6=19:00-02:59 + // skim periods are: 0=0(N/A), 1=3(OP), 2=1(AM), 3=3(OP), 4=3(OP), 5=2(PM), + // 6=3(OP) + + // define a conversion array to convert period values in the survey file to + // skim + // period indices used in this propgram: 1=am peak, 2=pm peak, 3=off-peak. + private static final String[] SKIM_PERIOD_LABELS = {"am", "pm", "op"}; + private static final int[] SURVEY_PERIOD_TO_SKIM_PERIOD = {0, 3, 1, 3, 3, 2, 3}; + + private static int debugOrigMgra = 0; + private static int debugDestMgra = 0; + private static int departModelPeriod = 0; + + private MatrixDataServerIf ms; + private BestTransitPathCalculator bestPathUEC; + + private static final float defaultVOT = 15.0f; + + private TripSkimsAppender() + { + } + + private void runSkimsAppender(ResourceBundle rb) + { + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + Logger autoLogger = Logger.getLogger("auto"); + Logger wtwLogger = Logger.getLogger("wtw"); + Logger wtdLogger = Logger.getLogger("wtd"); + Logger dtwLogger = Logger.getLogger("dtw"); + + String outputFileNameHis = Util.getStringValueFromPropertyMap(rbMap, + "his.trip.skims.output.file"); + + FileWriter writer; + PrintWriter outStreamHis = null; + + McLogsumsAppender logsumHelper = new McLogsumsAppender(rbMap); + bestPathUEC = logsumHelper.getBestTransitPathCalculator(); + + AutoAndNonMotorizedSkimsCalculator anm = logsumHelper.getAnmSkimCalculator(); + WalkTransitWalkSkimsCalculator wtw = new WalkTransitWalkSkimsCalculator(rbMap); + WalkTransitDriveSkimsCalculator wtd = new WalkTransitDriveSkimsCalculator(rbMap); + DriveTransitWalkSkimsCalculator dtw = new DriveTransitWalkSkimsCalculator(rbMap); + + String heading = "seq,sampno"; + + heading += ",origMgra,destMgra,departPeriod"; + heading += getAutoSkimsHeaderRecord("auto", anm.getAutoSkimNames()); + heading += getNonMotorizedSkimsHeaderRecord("nm", anm.getNmSkimNames()); + heading += getTransitSkimsHeaderRecord("wtw", wtw.getSkimNames()); + heading += getTransitSkimsHeaderRecord("wtd", wtd.getSkimNames()); + heading += getTransitSkimsHeaderRecord("dtw", dtw.getSkimNames()); + + try + { + writer = new FileWriter(new File(outputFileNameHis)); + outStreamHis = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileNameHis)); + throw new RuntimeException(e); + } + outStreamHis.println("his" + heading); + + Logger[] loggers = new Logger[4]; + loggers[0] = autoLogger; + loggers[1] = wtwLogger; + loggers[2] = wtdLogger; + loggers[3] = dtwLogger; + + int[] odt = new int[4]; + + TableDataSet hisTds = getHomeInterviewSurveyTableDataSet(rbMap); + int[][] hisOdts = getHomeInterviewSurveyOrigDestTimes(hisTds); + // 11100, pnrCoaster, mgra 4357 = taz 3641, mgra 26931 = taz 1140 + // int[][] hisOdts = { { 4357, 26931, 5, 0 } }; + // 25040, wlkCoaster, mgra 4989 = taz 3270, mgra 7796 = taz 1986 + // int[][] hisOdts = { { 7796, 4989, 2, 0 } }; + + // if ( debugOrigMgra <= 0 || debugDestMgra <= 0 || departModelPeriod <= + // 0 || departModelPeriod > 6 ) + // { + // logger.error("please set values for command line arguments: properties file, orig mgra, dest mgra, depart model period."); + // System.exit(-1); + // } + // int[][] hisOdts = { { debugOrigMgra, debugDestMgra, + // departModelPeriod, 0 } }; + + // write skims data for home interview survey records + int seq = 1; + for (int[] hisOdt : hisOdts) + { + // write outbound direction + odt[0] = hisOdt[0]; // orig + odt[1] = hisOdt[1]; // dest + odt[2] = SURVEY_PERIOD_TO_SKIM_PERIOD[hisOdt[2]]; // depart skim + // period + odt[3] = hisOdt[3]; + + try + { + + int dummy = 0; + if (seq == 3424) + { + dummy = 1; + } + + writeSkimsToFile(seq, outStreamHis, false, odt, anm, wtw, wtd, dtw, loggers); + } catch (Exception e) + { + logger.error("Exception caught processing record: " + seq + " of " + hisOdts.length + + "."); + break; + } + + if (seq % 1000 == 0) logger.info("wrote HIS record: " + seq); + + seq++; + } + + outStreamHis.close(); + + } + + private void writeSkimsToFile(int sequence, PrintWriter outStream, boolean loggingEnabled, + int[] odt, AutoAndNonMotorizedSkimsCalculator anm, WalkTransitWalkSkimsCalculator wtw, + WalkTransitDriveSkimsCalculator wtd, DriveTransitWalkSkimsCalculator dtw, + Logger[] loggers) + { + + Logger autoLogger = loggers[0]; + Logger wtwLogger = loggers[1]; + Logger wtdLogger = loggers[2]; + Logger dtwLogger = loggers[3]; + + int[][] bestTapPairs = null; + double[][] returnedSkims = null; + + outStream.print(String.format("%d,%d,%d,%d,%d", sequence, odt[3], odt[0], odt[1], odt[2])); + + double[] skims = anm.getAutoSkims(odt[0], odt[1], odt[2], defaultVOT, loggingEnabled, autoLogger); + if (loggingEnabled) + anm.logReturnedSkims(odt[0], odt[1], odt[2], skims, "auto", autoLogger); + + String autoRecord = getAutoSkimsRecord(skims); + outStream.print(autoRecord); + + skims = anm.getNonMotorizedSkims(odt[0], odt[1], odt[2], loggingEnabled, autoLogger); + if (loggingEnabled) + anm.logReturnedSkims(odt[0], odt[1], odt[2], skims, "non-motorized", autoLogger); + + String nmRecord = getAutoSkimsRecord(skims); + outStream.print(nmRecord); + + /* + * TODO: Fix this code + + bestTapPairs = wtw.getBestTapPairs(odt[0], odt[1], odt[2], loggingEnabled, wtwLogger); + returnedSkims = new double[bestTapPairs.length][]; + for (int i = 0; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] == null) returnedSkims[i] = wtw.getNullTransitSkims(i); + else + { + returnedSkims[i] = wtw.getWalkTransitWalkSkims(i, BestTransitPathCalculator + .findWalkTransitAccessTime(odt[0], bestTapPairs[i][0]), + BestTransitPathCalculator.findWalkTransitEgressTime(odt[1], + bestTapPairs[i][1]), bestTapPairs[i][0], bestTapPairs[i][1], + odt[2], loggingEnabled); + } + } + if (loggingEnabled) wtw.logReturnedSkims(odt, bestTapPairs, returnedSkims); + + String wtwRecord = getTransitSkimsRecord(odt, returnedSkims); + outStream.print(wtwRecord); + + bestTapPairs = wtd.getBestTapPairs(odt[0], odt[1], odt[2], loggingEnabled, wtdLogger); + returnedSkims = new double[bestTapPairs.length][]; + for (int i = 0; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] == null) returnedSkims[i] = wtd.getNullTransitSkims(i); + else + { + returnedSkims[i] = wtd.getWalkTransitDriveSkims(i, BestTransitPathCalculator + .findWalkTransitAccessTime(odt[0], bestTapPairs[i][0]), + BestTransitPathCalculator.findDriveTransitEgressTime(odt[1], + bestTapPairs[i][1]), bestTapPairs[i][0], bestTapPairs[i][1], + odt[2], loggingEnabled); + } + } + if (loggingEnabled) wtd.logReturnedSkims(odt, bestTapPairs, returnedSkims); + + String wtdRecord = getTransitSkimsRecord(odt, returnedSkims); + outStream.print(wtdRecord); + + bestTapPairs = dtw.getBestTapPairs(odt[0], odt[1], odt[2], loggingEnabled, dtwLogger); + returnedSkims = new double[bestTapPairs.length][]; + for (int i = 0; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] == null) returnedSkims[i] = dtw.getNullTransitSkims(i); + else + { + returnedSkims[i] = dtw.getDriveTransitWalkSkims(i, BestTransitPathCalculator + .findDriveTransitAccessTime(odt[0], bestTapPairs[i][0]), + BestTransitPathCalculator.findWalkTransitEgressTime(odt[1], + bestTapPairs[i][1]), bestTapPairs[i][0], bestTapPairs[i][1], + odt[2], loggingEnabled); + } + } + if (loggingEnabled) dtw.logReturnedSkims(odt, bestTapPairs, returnedSkims); + + String dtwRecord = getTransitSkimsRecord(odt, returnedSkims); + outStream.println(dtwRecord); + */ + } + + /** + * Start the matrix server + * + * @param rb + * is a ResourceBundle for the properties file for this + * application + */ + private void startMatrixServer(ResourceBundle rb) + { + + logger.info(""); + logger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + } + + /** + * create a String which can be written to an output file with all the skim + * values for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + * @param skims + * is a double[][] of skim values with the first dimesion the + * ride mode indices and second dimention the skim categories + */ + private String getTransitSkimsRecord(int[] odt, double[][] skims) + { + + int nrows = skims.length; + int ncols = 0; + for (int i = 0; i < nrows; i++) + if (skims[i].length > ncols) ncols = skims[i].length; + + String tableRecord = ""; + for (int i = 0; i < skims.length; i++) + { + for (int j = 0; j < skims[i].length; j++) + tableRecord += String.format(",%.5f", skims[i][j]); + } + + return tableRecord; + + } + + /** + * create a String which can be written to an output file with all the skim + * values for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + * @param skims + * is a double[] of skim values + */ + private String getAutoSkimsRecord(double[] skims) + { + + String tableRecord = ""; + for (int i = 0; i < skims.length; i++) + { + tableRecord += String.format(",%.5f", skims[i]); + } + + return tableRecord; + + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getTransitSkimsHeaderRecord(String transitServiveLabel, String[] skimNames) + { + + Modes.TransitMode[] mode = Modes.TransitMode.values(); + + String heading = ""; + + for (int i = 0; i < mode.length; i++) + { + for (int j = 0; j < skimNames.length; j++) + heading += String.format(",%s_%s_%s", transitServiveLabel, mode[i], + skimNames[j]); + + } + + return heading; + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getAutoSkimsHeaderRecord(String label, String[] names) + { + + String heading = ""; + + for (int i = 0; i < names.length; i++) + heading += String.format(",%s_%s", label, names[i]); + + return heading; + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getNonMotorizedSkimsHeaderRecord(String label, String[] names) + { + + String heading = ""; + + for (int i = 0; i < names.length; i++) + heading += String.format(",%s_%s", label, names[i]); + + return heading; + } + + private TableDataSet getHomeInterviewSurveyTableDataSet(HashMap rbMap) + { + + String hisFileName = Util.getStringValueFromPropertyMap(rbMap, HIS_DATA_RECORDS_FILE_KEY); + if (hisFileName == null) + { + logger.error("Error getting the filename from the properties file for the Sandag home interview survey data records file."); + logger.error("Properties file target: " + HIS_DATA_RECORDS_FILE_KEY + " not found."); + logger.error("Please specify a filename value for the " + HIS_DATA_RECORDS_FILE_KEY + + " property."); + throw new RuntimeException(); + } + + try + { + TableDataSet inTds = null; + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + inTds = reader.readFile(new File(hisFileName)); + return inTds; + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading Sandag home interview survey data records file: %s into TableDataSet object.", + hisFileName)); + throw new RuntimeException(e); + } + + } + + private int[][] getHomeInterviewSurveyOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure period(1-6), and his sampno. + int[][] odts = new int[hisTds.getRowCount()][4]; + + int[] sampnos = hisTds.getColumnAsInt(HIS_SAMPNO); + int[] origs = hisTds.getColumnAsInt(HIS_ORIG_MGRA); + int[] dests = hisTds.getColumnAsInt(HIS_DEST_MGRA); + int[] departs = hisTds.getColumnAsInt(HIS_DEPART_PERIOD); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + odts[r - 1][0] = origs[r - 1]; + odts[r - 1][1] = dests[r - 1]; + odts[r - 1][2] = departs[r - 1]; + odts[r - 1][3] = sampnos[r - 1]; + } + + return odts; + } + + public static void main(String[] args) + { + + ResourceBundle rb = null; + if (args.length == 0) + { + System.out + .println(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else if (args.length == 4) + { + rb = ResourceBundle.getBundle(args[0]); + + debugOrigMgra = Integer.parseInt(args[1]); + debugDestMgra = Integer.parseInt(args[2]); + departModelPeriod = Integer.parseInt(args[3]); + } else + { + System.out + .println("please set values for command line arguments: properties file, orig mgra, dest mgra, depart model period."); + System.exit(-1); + } + + try + { + + MatrixDataServerIf ms = null; + String serverAddress = null; + int serverPort = -1; + + HashMap propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + System.out.println(""); + System.out.println(""); + serverAddress = (String) propertyMap.get("RunModel.MatrixServerAddress"); + + String serverPortString = (String) propertyMap.get("RunModel.MatrixServerPort"); + if (serverPortString != null) serverPort = Integer.parseInt(serverPortString); + + if (serverAddress != null && serverPort > 0) + { + try + { + System.out.println("attempting connection to matrix server " + serverAddress + + ":" + serverPort); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + System.out.println("connected to matrix server " + serverAddress + ":" + + serverPort); + + } catch (Exception e) + { + System.out + .println("exception caught running ctramp model components -- exiting."); + e.printStackTrace(); + throw new RuntimeException(); + } + } + + TazDataManager tazs = TazDataManager.getInstance(propertyMap); + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + TapDataManager tapManager = TapDataManager.getInstance(propertyMap); + + // create an appender object and run it + TripSkimsAppender appender = new TripSkimsAppender(); + appender.runSkimsAppender(rb); + + } catch (RuntimeException e) + { + e.printStackTrace(); + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/VisitorTourLocationChoiceAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/VisitorTourLocationChoiceAppender.java new file mode 100644 index 0000000..dafb12e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/VisitorTourLocationChoiceAppender.java @@ -0,0 +1,367 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.sandag.abm.application.SandagAppendMcLogsumDMU; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; + +public final class VisitorTourLocationChoiceAppender + extends McLogsumsAppender +{ + + private static final int DEBUG_EST_RECORD1 = 1; + private static final int DEBUG_EST_RECORD2 = -1; + + /* + * for DC estimation file + */ + private static final int SEQ_FIELD = 2; + + // for Atwork subtour DC + // private static final int ORIG_MGRA_FIELD = 79; + // private static final int DEST_MGRA_FIELD = 220; + // private static final int MGRA1_FIELD = 221; + // private static final int PURPOSE_INDEX_OFFSET = 4; + + // for Escort DC + private static final int ORIG_MGRA_FIELD = 76; + private static final int DEST_MGRA_FIELD = 79; + private static final int MGRA1_FIELD = 217; + private static final int PURPOSE_INDEX_OFFSET = 0; + + // for NonMandatory DC + // private static final int ORIG_MGRA_FIELD = 76; + // private static final int DEST_MGRA_FIELD = 79; + // private static final int MGRA1_FIELD = 221; + // private static final int PURPOSE_INDEX_OFFSET = 0; + + private static final int DEPART_PERIOD_FIELD = 189; + private static final int ARRIVE_PERIOD_FIELD = 190; + private static final int INCOME_FIELD = 20; + private static final int ADULTS_FIELD = 32; + private static final int AUTOS_FIELD = 6; + private static final int HHSIZE_FIELD = 5; + private static final int GENDER_FIELD = 38; + private static final int AGE_FIELD = 39; + private static final int PURPOSE_FIELD = 80; + private static final int JOINT_ID_FIELD = 125; + private static final int JOINT_PURPOSE_FIELD = 126; + private static final int JOINT_P1_FIELD = 151; + private static final int JOINT_P2_FIELD = 152; + private static final int JOINT_P3_FIELD = 153; + private static final int JOINT_P4_FIELD = 154; + private static final int JOINT_P5_FIELD = 155; + private static final int NUM_MGRA_FIELDS = 30; + + private static final String OUTPUT_SAMPLE_DEST_LOGSUMS = "output.sample.dest.logsums"; + + public VisitorTourLocationChoiceAppender(HashMap rbMap) + { + super(rbMap); + + debugEstimationFileRecord1 = DEBUG_EST_RECORD1; + debugEstimationFileRecord2 = DEBUG_EST_RECORD2; + + numMgraFields = NUM_MGRA_FIELDS; + } + + private void runLogsumAppender(ResourceBundle rb) + { + + totalTime1 = 0; + totalTime2 = 0; + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + tazs = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + mgraSetForLogsums = new int[numMgraFields + 1]; + + // allocate the logsums array for the chosen destination alternative + modeChoiceLogsums = new double[NUM_MGRA_FIELDS + 1][]; + + departArriveLogsums = new double[NUM_MGRA_FIELDS + 1][departArriveCombinations.length]; + + String outputAllKey = Util.getStringValueFromPropertyMap(rbMap, OUTPUT_SAMPLE_DEST_LOGSUMS); + + String outputFileName = Util.getStringValueFromPropertyMap(rbMap, + "dc.est.skims.output.file"); + if (outputFileName == null) + { + logger.info("no output file name was specified in the properties file. Nothing to do."); + return; + } + + int dotIndex = outputFileName.indexOf("."); + String baseName = outputFileName.substring(0, dotIndex); + String extension = outputFileName.substring(dotIndex); + + // output1 is only written if "all" was set in propoerties file + String outputName1 = ""; + if (outputAllKey.equalsIgnoreCase("all")) outputName1 = baseName + "_" + "all" + extension; + + // output1 is written in any case + String outputName2 = baseName + "_" + "chosen" + extension; + + PrintWriter outStream1 = null; + PrintWriter outStream2 = null; + + try + { + if (outputAllKey.equalsIgnoreCase("all")) + outStream1 = new PrintWriter(new BufferedWriter(new FileWriter( + new File(outputName1)))); + outStream2 = new PrintWriter(new BufferedWriter(new FileWriter(new File(outputName2)))); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileName)); + throw new RuntimeException(e); + } + + writeDcFile(rbMap, outStream1, outStream2); + + logger.info("total part 1 runtime = " + (totalTime1 / 1000) + " seconds."); + logger.info("total part 2 runtime = " + (totalTime2 / 1000) + " seconds."); + + } + + private void writeDcFile(HashMap rbMap, PrintWriter outStream1, + PrintWriter outStream2) + { + + // print the chosen destMgra and the depart/arrive logsum field names to + // both + // files + if (outStream1 != null) outStream1.print("seq,sampno,chosenMgra"); + + // attach the OB and IB period labels to the logsum field names for each + // period + if (outStream1 != null) + { + for (String[] labels : departArriveCombinationLabels) + outStream1.print(",logsum" + labels[0] + labels[1]); + } + + outStream2.print("seq,sampno,chosenMgra,chosenTodLogsum"); + + // print each set of sample destMgra and the depart/arrive logsum + // fieldnames + // to file 1. + // print each set of sample destMgra and the chosen depart/arrive logsum + // fieldname to file 2. + for (int m = 1; m < departArriveLogsums.length; m++) + { + if (outStream1 != null) + { + outStream1.print(",sampleMgra" + m); + for (String[] labels : departArriveCombinationLabels) + outStream1.print(",logsum" + m + labels[0] + labels[1]); + } + + outStream2.print(",sampleMgra" + m); + outStream2.print(",sampleLogsum" + m); + } + if (outStream1 != null) outStream1.print("\n"); + outStream2.print("\n"); + + TableDataSet estTds = getEstimationDataTableDataSet(rbMap); + int[][] estDataOdts = getDcEstimationDataOrigDestTimes(estTds); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = rbMap.get(PROPERTIES_UEC_TOUR_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + SandagAppendMcLogsumDMU mcDmuObject = new SandagAppendMcLogsumDMU(modelStructure, null); + + ChoiceModelApplication[] mcModel = new ChoiceModelApplication[5 + 1]; + mcModel[WORK_CATEGORY] = new ChoiceModelApplication(mcUecFile, WORK_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[UNIVERSITY_CATEGORY] = new ChoiceModelApplication(mcUecFile, UNIVERSITY_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[SCHOOL_CATEGORY] = new ChoiceModelApplication(mcUecFile, SCHOOL_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + mcModel[MAINTENANCE_CATEGORY] = new ChoiceModelApplication(mcUecFile, MAINTENANCE_SHEET, 0, + rbMap, (VariableTable) mcDmuObject); + mcModel[DISCRETIONARY_CATEGORY] = new ChoiceModelApplication(mcUecFile, + DISCRETIONARY_SHEET, 0, rbMap, (VariableTable) mcDmuObject); + mcModel[SUBTOUR_CATEGORY] = new ChoiceModelApplication(mcUecFile, SUBTOUR_SHEET, 0, rbMap, + (VariableTable) mcDmuObject); + + // write skims data for estimation data file records + int seq = 1; + for (int i = 0; i < estDataOdts.length; i++) + { + + int[] odtSet = estDataOdts[i]; + int[] mgraSet = mgras[i]; + + odtSet[0] = seq; + + if (outStream1 != null) + { + outStream1.print(seq + "," + odtSet[SAMPNO]); + } + outStream2.print(seq + "," + odtSet[SAMPNO]); + + int category = PURPOSE_CATEGORIES[odtSet[TOUR_PURPOSE]]; + + int[] departAvailable = {-1, 1, 1, 1, 1, 1}; + int[] arriveAvailable = {-1, 1, 1, 1, 1, 1}; + calculateModeChoiceLogsums(rbMap, category == -1 ? null : mcModel[category], + mcDmuObject, odtSet, mgraSet, departAvailable, arriveAvailable, false); + + // write chosen dest and logsums to both files + if (outStream1 != null) + { + outStream1.print("," + odtSet[DEST_MGRA]); + for (double logsum : departArriveLogsums[0]) + outStream1.printf(",%.8f", logsum); + } + + outStream2.print("," + odtSet[DEST_MGRA]); + outStream2.printf(",%.8f", departArriveLogsums[0][chosenLogsumTodIndex]); + + // write logsum sets for each dest in the sample to file 1 + for (int m = 1; m < departArriveLogsums.length; m++) + { + if (outStream1 != null) + { + outStream1.print("," + mgraSet[m - 1]); + for (double logsum : departArriveLogsums[m]) + outStream1.printf(",%.8f", logsum); + } + + outStream2.print("," + mgraSet[m - 1]); + outStream2.printf(",%.8f", departArriveLogsums[m][chosenLogsumTodIndex]); + } + if (outStream1 != null) outStream1.print("\n"); + outStream2.print("\n"); + + if (seq % 1000 == 0) logger.info("wrote DC Estimation file record: " + seq); + + seq++; + } + + if (outStream1 != null) outStream1.close(); + outStream2.close(); + + } + + private int[][] getDcEstimationDataOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure + // period(1-6), and arrival period(1-6). + int[][] odts = new int[hisTds.getRowCount()][NUM_FIELDS]; + mgras = new int[hisTds.getRowCount()][NUM_MGRA_FIELDS]; + int[][] mgraData = new int[NUM_MGRA_FIELDS][]; + + int[] departs = hisTds.getColumnAsInt(DEPART_PERIOD_FIELD); + int[] arrives = hisTds.getColumnAsInt(ARRIVE_PERIOD_FIELD); + + int[] hisseq = hisTds.getColumnAsInt(SEQ_FIELD); + int[] purpose = hisTds.getColumnAsInt(PURPOSE_FIELD); + int[] jtPurpose = hisTds.getColumnAsInt(JOINT_PURPOSE_FIELD); + int[] income = hisTds.getColumnAsInt(INCOME_FIELD); + int[] origs = hisTds.getColumnAsInt(ORIG_MGRA_FIELD); + int[] dests = hisTds.getColumnAsInt(DEST_MGRA_FIELD); + int[] adults = hisTds.getColumnAsInt(ADULTS_FIELD); + int[] autos = hisTds.getColumnAsInt(AUTOS_FIELD); + int[] hhsize = hisTds.getColumnAsInt(HHSIZE_FIELD); + int[] gender = hisTds.getColumnAsInt(GENDER_FIELD); + int[] age = hisTds.getColumnAsInt(AGE_FIELD); + int[] jointId = hisTds.getColumnAsInt(JOINT_ID_FIELD); + int[] jointPerson1Participates = hisTds.getColumnAsInt(JOINT_P1_FIELD); + int[] jointPerson2Participates = hisTds.getColumnAsInt(JOINT_P2_FIELD); + int[] jointPerson3Participates = hisTds.getColumnAsInt(JOINT_P3_FIELD); + int[] jointPerson4Participates = hisTds.getColumnAsInt(JOINT_P4_FIELD); + int[] jointPerson5Participates = hisTds.getColumnAsInt(JOINT_P5_FIELD); + + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgraData[i] = hisTds.getColumnAsInt(MGRA1_FIELD + i); + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + for (int i = 0; i < NUM_MGRA_FIELDS; i++) + mgras[r - 1][i] = mgraData[i][r - 1]; + + odts[r - 1][SAMPNO] = hisseq[r - 1]; + + odts[r - 1][DEPART_PERIOD] = departs[r - 1]; + odts[r - 1][ARRIVE_PERIOD] = arrives[r - 1]; + + odts[r - 1][ORIG_MGRA] = origs[r - 1]; + odts[r - 1][DEST_MGRA] = dests[r - 1]; + odts[r - 1][INCOME] = income[r - 1]; + odts[r - 1][ADULTS] = adults[r - 1]; + odts[r - 1][AUTOS] = autos[r - 1]; + odts[r - 1][HHSIZE] = hhsize[r - 1]; + odts[r - 1][FEMALE] = gender[r - 1] == 2 ? 1 : 0; + odts[r - 1][AGE] = age[r - 1]; + odts[r - 1][JOINT] = jointId[r - 1] > 0 ? 1 : 0; + + // the offest constant is used because at-work subtours in + // estimation file are coded as work purpose index (=1), + // but the model index to use is 5. Nonmandatory and escort files + // have correct purpose codes, so offset is 0. + int purposeIndex = purpose[r - 1] + PURPOSE_INDEX_OFFSET; + + odts[r - 1][ESCORT] = purposeIndex == 4 ? 1 : 0; + + odts[r - 1][PARTYSIZE] = jointPerson1Participates[r - 1] + + jointPerson2Participates[r - 1] + jointPerson3Participates[r - 1] + + jointPerson4Participates[r - 1] + jointPerson5Participates[r - 1]; + + odts[r - 1][TOUR_PURPOSE] = odts[r - 1][JOINT] == 1 && purposeIndex > 4 ? jtPurpose[r - 1] + : purposeIndex; + + } + + return odts; + } + + public static void main(String[] args) + { + + ResourceBundle rb; + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + VisitorTourLocationChoiceAppender appender = new VisitorTourLocationChoiceAppender(rbMap); + + appender.startMatrixServer(rb); + appender.runLogsumAppender(rb); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/WalkTransitDriveSkimsCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/WalkTransitDriveSkimsCalculator.java new file mode 100644 index 0000000..d97d976 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/WalkTransitDriveSkimsCalculator.java @@ -0,0 +1,295 @@ +package org.sandag.abm.accessibilities; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.util.ResourceUtil; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +import java.io.File; +import java.io.Serializable; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; + +/** + * This class is used to return walk-transit-drive skim values for MGRA pairs + * associated with estimation data file records. + * + * @author Jim Hicks + * @version March, 2010 + */ +public class WalkTransitDriveSkimsCalculator + implements Serializable +{ + + private transient Logger logger; + + private static final int EA = ModelStructure.EA_SKIM_PERIOD_INDEX; + private static final int AM = ModelStructure.AM_SKIM_PERIOD_INDEX; + private static final int MD = ModelStructure.MD_SKIM_PERIOD_INDEX; + private static final int PM = ModelStructure.PM_SKIM_PERIOD_INDEX; + private static final int EV = ModelStructure.EV_SKIM_PERIOD_INDEX; + public static final int NUM_PERIODS = ModelStructure.SKIM_PERIOD_INDICES.length; + private static final String[] PERIODS = ModelStructure.SKIM_PERIOD_STRINGS; + + private static final int ACCESS_TIME_INDEX = 0; + private static final int EGRESS_TIME_INDEX = 1; + private static final int NA = -999; + + private int maxWTDSkimSets = 5; + private int[] NUM_SKIMS; + private double[] defaultSkims; + + // declare UEC object + private UtilityExpressionCalculator walkDriveSkimUEC; + private IndexValues iv; + + // The simple auto skims UEC does not use any DMU variables + private TransitDriveAccessDMU dmu = new TransitDriveAccessDMU(); // DMU + // for + // this + // UEC + + private BestTransitPathCalculator bestPathUEC; + + private MgraDataManager mgraManager; + private int maxTap; + + private String[] skimNames; + + // skim values for transit service type(local, premium), + // transit ride mode(lbs, ebs, brt, lrt, crl), + // depart skim period(am, pm, op), and Tap-Tap pair. + private double[][][][][] storedDepartPeriodTapTapSkims; + + private MatrixDataServerIf ms; + + public WalkTransitDriveSkimsCalculator(HashMap rbMap) + { + mgraManager = MgraDataManager.getInstance(); + maxTap = mgraManager.getMaxTap(); + } + + public void setup(HashMap rbMap, Logger aLogger, + BestTransitPathCalculator myBestPathUEC) + { + + logger = aLogger; + + // set the best transit path utility UECs + bestPathUEC = myBestPathUEC; + + // Create the skim UECs + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap,"skim.walk.transit.drive.data.page"); + int skimPage = Util.getIntegerValueFromPropertyMap(rbMap,"skim.walk.transit.drive.skim.page"); + int wtdNumSkims = Util.getIntegerValueFromPropertyMap(rbMap, "skim.walk.transit.drive.skims"); + String uecPath = Util.getStringValueFromPropertyMap(rbMap, CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = Paths.get(uecPath,Util.getStringValueFromPropertyMap(rbMap, "skim.walk.transit.drive.uec.file")).toString(); + File uecFile = new File(uecFileName); + walkDriveSkimUEC = new UtilityExpressionCalculator(uecFile, skimPage, dataPage, rbMap, dmu); + + skimNames = walkDriveSkimUEC.getAlternativeNames(); + + //setup index values + iv = new IndexValues(); + + //setup default skim values + defaultSkims = new double[wtdNumSkims]; + for (int j = 0; j < wtdNumSkims; j++) { + defaultSkims[j] = NA; + } + + // point the stored Array of skims: by Prem or Local, DepartPeriod, O tap, D tap, skim values[] to a shared data store + StoredTransitSkimData storedDataObject = StoredTransitSkimData.getInstance( maxWTDSkimSets, NUM_PERIODS, maxTap ); + storedDepartPeriodTapTapSkims = storedDataObject.getStoredWtdDepartPeriodTapTapSkims(); + } + + + + /** + * Return the array of walk-transit-drive skims for the ride mode, origin TAP, + * destination TAP, and departure time period. + * + * @param set for set source skims + * @param origTap best Origin TAP for the MGRA pair + * @param workTap best Destination TAP for the MGRA pair + * @param departPeriod Departure time period - 1 = AM period, 2 = PM period, 3 = + * OffPeak period + * @return Array of 55 skim values for the MGRA pair and departure period + */ + public double[] getWalkTransitDriveSkims(int set, double pWalkTime, double aDriveTime, int origTap, int destTap, int departPeriod, boolean debug) + { + + dmu.setMgraTapWalkTime(pWalkTime); + dmu.setDriveTimeFromTap(aDriveTime); + + iv.setOriginZone(origTap); + iv.setDestZone(destTap); + + // allocate space for the origin tap if it hasn't been allocated already + if (storedDepartPeriodTapTapSkims[set][departPeriod][origTap] == null) + { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap] = new double[maxTap + 1][]; + } + + // if the destTap skims are not already stored, calculate them and store + // them + if (storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap] == null) + { + dmu.setTOD(departPeriod); + dmu.setSet(set); + double[] results = walkDriveSkimUEC.solve(iv, dmu, null); + if (debug) + walkDriveSkimUEC.logAnswersArray(logger, "Walk-Drive Skims"); + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap] = results; + } + + try { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap][ACCESS_TIME_INDEX] = pWalkTime; + } + catch ( Exception e ) { + logger.error ("departPeriod=" + departPeriod + ", origTap=" + origTap + ", destTap=" + destTap + ", pWalkTime=" + pWalkTime); + logger.error ("exception setting walk-transit-drive walk access time in stored array.", e); + } + + try { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap][EGRESS_TIME_INDEX] = aDriveTime; + } + catch ( Exception e ) { + logger.error ("departPeriod=" + departPeriod + ", origTap=" + origTap + ", destTap=" + destTap + ", aDriveTime=" + aDriveTime); + logger.error ("exception setting walk-transit-drive drive egress time in stored array.", e); + } + return storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap]; + + + } + + public double[] getNullTransitSkims() + { + return defaultSkims; + } + + /** + * Start the matrix server + * + * @param rb is a ResourceBundle for the properties file for this application + */ + private void startMatrixServer(ResourceBundle rb) + { + + logger.info(""); + logger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + logger.error(String + .format("exception caught running ctramp model components -- exiting."), e); + throw new RuntimeException(); + + } + + } + + /** + * log a report of the final skim values for the MGRA odt + * + * @param odt is an int[] with the first element the origin mgra and the second + * element the dest mgra and third element the departure period index + * @param bestTapPairs is an int[][] of TAP values with the first dimesion the + * ride mode and second dimension a 2 element array with best orig and + * dest TAP + * @param returnedSkims is a double[][] of skim values with the first dimesion + * the ride mode indices and second dimention the skim categories + */ + public void logReturnedSkims(int[] odt, int[][] bestTapPairs, double[][] skims) + { + + Modes.TransitMode[] mode = Modes.TransitMode.values(); + + int nrows = skims.length; + int ncols = 0; + for (int i = 0; i < nrows; i++) + if (skims[i].length > ncols) ncols = skims[i].length; + + String separator = ""; + String header = ""; + + logger.info(""); + logger.info(""); + header = "Returned walk-transit-drive skim value tables for origMgra=" + odt[0] + + ", destMgra=" + odt[1] + ", period index=" + odt[2] + ", period label=" + + PERIODS[odt[2]]; + for (int i = 0; i < header.length(); i++) + separator += "^"; + + logger.info(separator); + logger.info(header); + logger.info(""); + + String modeHeading = String.format("%-12s %3s ", "RideMode:", mode[0]); + for (int i = 1; i < bestTapPairs.length; i++) + modeHeading += String.format(" %3s ", mode[i]); + logger.info(modeHeading); + + String tapHeading = String.format("%-12s %4s-%4s ", "TAP Pair:", + bestTapPairs[0] != null ? String.valueOf(bestTapPairs[0][0]) : "NA", + bestTapPairs[0] != null ? String.valueOf(bestTapPairs[0][1]) : "NA"); + for (int i = 1; i < bestTapPairs.length; i++) + tapHeading += String.format(" %4s-%4s ", bestTapPairs[i] != null ? String + .valueOf(bestTapPairs[i][0]) : "NA", bestTapPairs[i] != null ? String + .valueOf(bestTapPairs[i][1]) : "NA"); + logger.info(tapHeading); + + String underLine = String.format("%-12s %9s ", "---------", "---------"); + for (int i = 1; i < bestTapPairs.length; i++) + underLine += String.format(" %9s ", "---------"); + logger.info(underLine); + + for (int j = 0; j < ncols; j++) + { + String tableRecord = ""; + if (j < skims[0].length) tableRecord = String.format("%-12d %12.5f ", j + 1, + skims[0][j]); + else tableRecord = String.format("%-12d %12s ", j + 1, ""); + for (int i = 1; i < bestTapPairs.length; i++) + { + if (j < skims[i].length) tableRecord += String.format(" %12.5f ", skims[i][j]); + else tableRecord += String.format(" %12s ", ""); + } + logger.info(tableRecord); + } + + logger.info(""); + logger.info(separator); + } + + public String[] getSkimNames() { + return skimNames; + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/WalkTransitWalkSkimsCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/WalkTransitWalkSkimsCalculator.java new file mode 100644 index 0000000..3f90731 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/WalkTransitWalkSkimsCalculator.java @@ -0,0 +1,299 @@ +package org.sandag.abm.accessibilities; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.util.ResourceUtil; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +import java.io.File; +import java.io.Serializable; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; + +/** + * This class is used to return walk-transit-walk skim values for MGRA pairs + * associated with estimation data file records. + * + * @author Jim Hicks + * @version March, 2010 + */ +public class WalkTransitWalkSkimsCalculator + implements Serializable +{ + + private transient Logger logger; + + private static final int EA = ModelStructure.EA_SKIM_PERIOD_INDEX; + private static final int AM = ModelStructure.AM_SKIM_PERIOD_INDEX; + private static final int MD = ModelStructure.MD_SKIM_PERIOD_INDEX; + private static final int PM = ModelStructure.PM_SKIM_PERIOD_INDEX; + private static final int EV = ModelStructure.EV_SKIM_PERIOD_INDEX; + public static final int NUM_PERIODS = ModelStructure.SKIM_PERIOD_INDICES.length; + private static final String[] PERIODS = ModelStructure.SKIM_PERIOD_STRINGS; + + private static final int ACCESS_TIME_INDEX = 0; + private static final int EGRESS_TIME_INDEX = 1; + private static final int NA = -999; + + private int maxWTWSkimSets = 5; + private int[] NUM_SKIMS; + private double[] defaultSkims; + + // declare UEC object + private UtilityExpressionCalculator walkWalkSkimUEC; + private IndexValues iv; + + private String[] skimNames; + + // The simple auto skims UEC does not use any DMU variables + private TransitWalkAccessDMU dmu = new TransitWalkAccessDMU(); + // DMU + // for + // this + // UEC + + private MgraDataManager mgraManager; + private int maxTap; + + // skim values for transit skim set + // depart skim period(am, pm, op) + // and Tap-Tap pair. + private double[][][][][] storedDepartPeriodTapTapSkims; + + private BestTransitPathCalculator bestPathUEC; + + private MatrixDataServerIf ms; + + public WalkTransitWalkSkimsCalculator(HashMap rbMap) + { + mgraManager = MgraDataManager.getInstance(); + maxTap = mgraManager.getMaxTap(); + } + + public void setup(HashMap rbMap, Logger aLogger, BestTransitPathCalculator myBestPathUEC) + { + + logger = aLogger; + + // Create the utility UECs + bestPathUEC = myBestPathUEC; + + // Create the skim UECs + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap,"skim.walk.transit.walk.data.page"); + int skimPage = Util.getIntegerValueFromPropertyMap(rbMap,"skim.walk.transit.walk.skim.page"); + int wtwNumSkims = Util.getIntegerValueFromPropertyMap(rbMap, "skim.walk.transit.walk.skims"); + String uecPath = Util.getStringValueFromPropertyMap(rbMap, CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = Paths.get(uecPath,Util.getStringValueFromPropertyMap(rbMap, "skim.walk.transit.walk.uec.file")).toString(); + File uecFile = new File(uecFileName); + walkWalkSkimUEC = new UtilityExpressionCalculator(uecFile, skimPage, dataPage, rbMap, dmu); + + //setup index values + iv = new IndexValues(); + + //setup default skim values + defaultSkims = new double[wtwNumSkims]; + for (int j = 0; j < wtwNumSkims; j++) { + defaultSkims[j] = NA; + } + + skimNames = walkWalkSkimUEC.getAlternativeNames(); + + // point the stored Array of skims: skim set, period, O tap, D tap, skim values[] to a shared data store + StoredTransitSkimData storedDataObject = StoredTransitSkimData.getInstance( maxWTWSkimSets, NUM_PERIODS, maxTap ); + storedDepartPeriodTapTapSkims = storedDataObject.getStoredWtwDepartPeriodTapTapSkims(); + + } + + + + /** + * Return the array of walk-transit skims for the ride mode, origin TAP, + * destination TAP, and departure time period. + * + * @param set for set source skims + * @param origTap best Origin TAP for the MGRA pair + * @param destTap best Destination TAP for the MGRA pair + * @param departPeriod skim period index for the departure period - 0 = AM + * period, 1 = PM period, 2 = OffPeak period + * @return Array of skim values for the MGRA pair and departure period for the + * skim set + */ + public double[] getWalkTransitWalkSkims(int set, double pWalkTime, double aWalkTime, int origTap, int destTap, + int departPeriod, boolean debug) + { + + dmu.setMgraTapWalkTime(pWalkTime); + dmu.setTapMgraWalkTime(aWalkTime); + + iv.setOriginZone(origTap); + iv.setDestZone(destTap); + + // allocate space for the origin tap if it hasn't been allocated already + if (storedDepartPeriodTapTapSkims[set][departPeriod][origTap] == null) + { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap] = new double[maxTap + 1][]; + } + + // if the destTap skims are not already stored, calculate them and store + // them + if (storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap] == null) + { + dmu.setTOD(departPeriod); + dmu.setSet(set); + double[] results = walkWalkSkimUEC.solve(iv, dmu, null); + if (debug) + walkWalkSkimUEC.logAnswersArray(logger, "Walk-Walk Tap-Tap Skims"); + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap] = results; + } + + try { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap][ACCESS_TIME_INDEX] = pWalkTime; + } + catch ( Exception e ) { + logger.error ("departPeriod=" + departPeriod + ", origTap=" + origTap + ", destTap=" + destTap + ", pWalkTime=" + pWalkTime); + logger.error ("exception setting walk-transit-walk walk access time in stored array.", e); + } + + try { + storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap][EGRESS_TIME_INDEX] = aWalkTime; + } + catch ( Exception e ) { + logger.error ("departPeriod=" + departPeriod + ", origTap=" + origTap + ", destTap=" + destTap + ", aWalkTime=" + aWalkTime); + logger.error ("exception setting walk-transit-walk walk egress time in stored array.", e); + } + return storedDepartPeriodTapTapSkims[set][departPeriod][origTap][destTap]; + + + } + + public double[] getNullTransitSkims() + { + return defaultSkims; + } + + /** + * Start the matrix server + * + * @param rb is a ResourceBundle for the properties file for this application + */ + private void startMatrixServer(ResourceBundle rb) + { + + logger.info(""); + logger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + logger.error(String + .format("exception caught running ctramp model components -- exiting."), e); + throw new RuntimeException(); + + } + + } + + /** + * log a report of the final skim values for the MGRA odt + * + * @param odt is an int[] with the first element the origin mgra and the second + * element the dest mgra and third element the departure period index + * @param bestTapPairs is an int[][] of TAP values with the first dimesion the + * ride mode and second dimension a 2 element array with best orig and + * dest TAP + * @param returnedSkims is a double[][] of skim values with the first dimesion + * the ride mode indices and second dimention the skim categories + */ + public void logReturnedSkims(int[] odt, int[][] bestTapPairs, double[][] skims) + { + + int nrows = skims.length; + int ncols = 0; + for (int i = 0; i < nrows; i++) + if (skims[i].length > ncols) ncols = skims[i].length; + + String separator = ""; + String header = ""; + + logger.info(""); + logger.info(""); + header = "Returned walktransit skim value tables for origMgra=" + odt[0] + ", destMgra=" + + odt[1] + ", period index=" + odt[2] + ", period label=" + PERIODS[odt[2]]; + for (int i = 0; i < header.length(); i++) + separator += "^"; + + logger.info(separator); + logger.info(header); + logger.info(""); + + String modeHeading = String.format("%-12s %3s ", "Alt:"); + for (int i = 1; i < bestTapPairs.length; i++) + modeHeading += String.format(" %3s ", i); + logger.info(modeHeading); + + String tapHeading = String.format("%-12s %4s-%4s ", "TAP Pair:", + bestTapPairs[0] != null ? String.valueOf(bestTapPairs[0][0]) : "NA", + bestTapPairs[0] != null ? String.valueOf(bestTapPairs[0][1]) : "NA"); + for (int i = 1; i < bestTapPairs.length; i++) + tapHeading += String.format(" %4s-%4s ", bestTapPairs[i] != null ? String + .valueOf(bestTapPairs[i][0]) : "NA", bestTapPairs[i] != null ? String + .valueOf(bestTapPairs[i][1]) : "NA"); + logger.info(tapHeading); + + String underLine = String.format("%-12s %9s ", "---------", "---------"); + for (int i = 1; i < bestTapPairs.length; i++) + underLine += String.format(" %9s ", "---------"); + logger.info(underLine); + + for (int j = 0; j < ncols; j++) + { + String tableRecord = ""; + if (j < skims[0].length) tableRecord = String.format("%-12d %12.5f ", j + 1, + skims[0][j]); + else tableRecord = String.format("%-12d %12s ", j + 1, ""); + for (int i = 1; i < bestTapPairs.length; i++) + { + if (j < skims[i].length) tableRecord += String.format(" %12.5f ", skims[i][j]); + else tableRecord += String.format(" %12s ", ""); + } + logger.info(tableRecord); + } + + logger.info(""); + logger.info(separator); + } + + public String[] getSkimNames() { + return skimNames; + } + + public BestTransitPathCalculator getBestPathUEC() { + return bestPathUEC; + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/accessibilities/XBorderSkimsAppender.java b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/XBorderSkimsAppender.java new file mode 100644 index 0000000..1b29ea5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/accessibilities/XBorderSkimsAppender.java @@ -0,0 +1,518 @@ +package org.sandag.abm.accessibilities; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +public final class XBorderSkimsAppender +{ + + protected transient Logger logger = Logger.getLogger(XBorderSkimsAppender.class); + + /* + * for trip mode choice estimation files + */ + private static final String MGRA_O_D_RECORDS_FILE_KEY = "xborder.mgra.list.file"; + private static final String APPENDED_SKIMS_FILE_KEY = "xborder.appended.file"; + + private String[] inputFormats = {"NUMBER", "NUMBER", "NUMBER", + "STRING", "NUMBER", "NUMBER", "STRING" }; + private static final int INPUT_ORIG_MGRA = 5; + private static final int INPUT_DEST_MGRA = 6; + private static final int INPUT_DEPART_PERIOD = 7; + + // survey periods are: + // 0=not used, + // 1=03:00-05:59, + // 2=06:00-08:59, + // 3=09:00-11:59, + // 4=12:00-15:29, + // 5=15:30-18:59, + // 6=19:00-02:59 + // skim periods are: 0=0(N/A), 1=3(OP), 2=1(AM), 3=3(OP), 4=3(OP), 5=2(PM), + // 6=3(OP) + + // define a conversion array to convert period values in the survey file to + // skim + // period indices used in this propgram: 1=am peak, 2=pm peak, 3=off-peak. + private static final String[] SKIM_PERIOD_LABELS = {"am", "pm", "op"}; + private static final int[] SURVEY_PERIOD_TO_SKIM_PERIOD = {0, 3, 1, 3, 3, 2, 3}; + + private static int debugOrigMgra = 0; + private static int debugDestMgra = 0; + private static int departModelPeriod = 0; + + private MatrixDataServerIf ms; + private BestTransitPathCalculator bestPathUEC; + private static final float defaultVOT = 15.0f; + + private XBorderSkimsAppender() + { + } + + private void runSkimsAppender(ResourceBundle rb) + { + + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + Logger autoLogger = Logger.getLogger("auto"); + Logger wtwLogger = Logger.getLogger("wtw"); + + String outputFileNameHis = Util.getStringValueFromPropertyMap(rbMap, + APPENDED_SKIMS_FILE_KEY); + + FileWriter writer; + PrintWriter outStreamHis = null; + + AutoTazSkimsCalculator tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + + McLogsumsAppender logsumHelper = new McLogsumsAppender(rbMap); + bestPathUEC = logsumHelper.getBestTransitPathCalculator(); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + AutoAndNonMotorizedSkimsCalculator anm = logsumHelper.getAnmSkimCalculator(); + WalkTransitWalkSkimsCalculator wtw = new WalkTransitWalkSkimsCalculator(rbMap); + + String heading = "seq"; + + heading += ",origMgra,destMgra,departPeriod"; + heading += getAutoSkimsHeaderRecord("auto", anm.getAutoSkimNames()); + heading += getNonMotorizedSkimsHeaderRecord("nm", anm.getNmSkimNames()); + heading += getTransitSkimsHeaderRecord("wtw", wtw.getSkimNames()); + + try + { + writer = new FileWriter(new File(outputFileNameHis)); + outStreamHis = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening output skims file: %s.", + outputFileNameHis)); + throw new RuntimeException(e); + } + outStreamHis.println(heading); + + Logger[] loggers = new Logger[4]; + loggers[0] = autoLogger; + loggers[1] = wtwLogger; + + int[] odt = new int[3]; + + TableDataSet hisTds = getInputTableDataSet(rbMap); + int[][] hisOdts = getInputOrigDestTimes(hisTds); + // 11100, pnrCoaster, mgra 4357 = taz 3641, mgra 26931 = taz 1140 + // int[][] hisOdts = { { 4357, 26931, 5, 0 } }; + // 25040, wlkCoaster, mgra 4989 = taz 3270, mgra 7796 = taz 1986 + // int[][] hisOdts = { { 7796, 4989, 2, 0 } }; + + // if ( debugOrigMgra <= 0 || debugDestMgra <= 0 || departModelPeriod <= + // 0 || departModelPeriod > 6 ) + // { + // logger.error("please set values for command line arguments: properties file, orig mgra, dest mgra, depart model period."); + // System.exit(-1); + // } + // int[][] hisOdts = { { debugOrigMgra, debugDestMgra, + // departModelPeriod, 0 } }; + + // write skims data for home interview survey records + int seq = 1; + for (int[] hisOdt : hisOdts) + { + // write outbound direction + odt[0] = hisOdt[0]; // orig + odt[1] = hisOdt[1]; // dest + odt[2] = SURVEY_PERIOD_TO_SKIM_PERIOD[hisOdt[2]]; // depart skim + // period + + try + { + + writeSkimsToFile(seq, outStreamHis, false, odt, anm, wtw, loggers); + } catch (Exception e) + { + logger.error("Exception caught processing record: " + seq + " of " + hisOdts.length + + "."); + break; + } + + if (seq % 1000 == 0) logger.info("wrote HIS record: " + seq); + + seq++; + } + + outStreamHis.close(); + + } + + private void writeSkimsToFile(int sequence, PrintWriter outStream, boolean loggingEnabled, + int[] odt, AutoAndNonMotorizedSkimsCalculator anm, WalkTransitWalkSkimsCalculator wtw, + Logger[] loggers) + { + + Logger autoLogger = loggers[0]; + Logger wtwLogger = loggers[1]; + + int[][] bestTapPairs = null; + double[][] returnedSkims = null; + + outStream.print(String.format("%d,%d,%d,%s", sequence, odt[0], odt[1], + SKIM_PERIOD_LABELS[odt[2] - 1])); + + double[] skims = anm.getAutoSkims(odt[0], odt[1], odt[2], defaultVOT, loggingEnabled, autoLogger); + if (loggingEnabled) + anm.logReturnedSkims(odt[0], odt[1], odt[2], skims, "auto", autoLogger); + + String autoRecord = getAutoSkimsRecord(skims); + outStream.print(autoRecord); + + skims = anm.getNonMotorizedSkims(odt[0], odt[1], odt[2], loggingEnabled, autoLogger); + if (loggingEnabled) + anm.logReturnedSkims(odt[0], odt[1], odt[2], skims, "non-motorized", autoLogger); + + String nmRecord = getAutoSkimsRecord(skims); + outStream.print(nmRecord); + + /* + * TODO: Fix this code + + bestTapPairs = wtw.getBestTapPairs(odt[0], odt[1], odt[2], loggingEnabled, wtwLogger); + returnedSkims = new double[bestTapPairs.length][]; + for (int i = 0; i < bestTapPairs.length; i++) + { + if (bestTapPairs[i] == null) returnedSkims[i] = wtw.getNullTransitSkims(i); + else + { + returnedSkims[i] = wtw.getWalkTransitWalkSkims(i, BestTransitPathCalculator + .findWalkTransitAccessTime(odt[0], bestTapPairs[i][0]), + BestTransitPathCalculator.findWalkTransitEgressTime(odt[1], + bestTapPairs[i][1]), bestTapPairs[i][0], bestTapPairs[i][1], + odt[2], loggingEnabled); + } + } + if (loggingEnabled) wtw.logReturnedSkims(odt, bestTapPairs, returnedSkims); + + String wtwRecord = getTransitSkimsRecord(odt, returnedSkims); + outStream.println(wtwRecord); + */ + } + + /** + * Start the matrix server + * + * @param rb + * is a ResourceBundle for the properties file for this + * application + */ + private void startMatrixServer(ResourceBundle rb) + { + + logger.info(""); + logger.info(""); + String serverAddress = rb.getString("RunModel.MatrixServerAddress"); + int serverPort = new Integer(rb.getString("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try + { + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + } + + /** + * create a String which can be written to an output file with all the skim + * values for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + * @param skims + * is a double[][] of skim values with the first dimesion the + * ride mode indices and second dimention the skim categories + */ + private String getTransitSkimsRecord(int[] odt, double[][] skims) + { + + int nrows = skims.length; + int ncols = 0; + for (int i = 0; i < nrows; i++) + if (skims[i].length > ncols) ncols = skims[i].length; + + String tableRecord = ""; + for (int i = 0; i < skims.length; i++) + { + for (int j = 0; j < skims[i].length; j++) + tableRecord += String.format(",%.5f", skims[i][j]); + } + + return tableRecord; + + } + + /** + * create a String which can be written to an output file with all the skim + * values for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + * @param skims + * is a double[] of skim values + */ + private String getAutoSkimsRecord(double[] skims) + { + + String tableRecord = ""; + for (int i = 0; i < skims.length; i++) + { + tableRecord += String.format(",%.5f", skims[i]); + } + + return tableRecord; + + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getTransitSkimsHeaderRecord(String transitServiveLabel, String[] skimNames) + { + + Modes.TransitMode[] mode = Modes.TransitMode.values(); + + String heading = ""; + + for (int i = 0; i < mode.length; i++) + { + for (int j = 0; j < skimNames.length; j++) + heading += String.format(",%s_%s_%s", transitServiveLabel, mode[i], + skimNames[j]); + + } + + return heading; + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getAutoSkimsHeaderRecord(String label, String[] names) + { + + String heading = ""; + + for (int i = 0; i < names.length; i++) + heading += String.format(",%s_%s", label, names[i]); + + return heading; + } + + /** + * create a String for the output file header record which can be written to + * an output file with all the skim value namess for the orig/dest/period. + * + * @param odt + * is an int[] with the first element the origin mgra and the + * second element the dest mgra and third element the departure + * period index + */ + private String getNonMotorizedSkimsHeaderRecord(String label, String[] names) + { + + String heading = ""; + + for (int i = 0; i < names.length; i++) + heading += String.format(",%s_%s", label, names[i]); + + return heading; + } + + private TableDataSet getInputTableDataSet(HashMap rbMap) + { + + String hisFileName = Util.getStringValueFromPropertyMap(rbMap, MGRA_O_D_RECORDS_FILE_KEY); + if (hisFileName == null) + { + logger.error("Error getting the filename from the properties file for the XBorder MGRA List data records file."); + logger.error("Properties file target: " + MGRA_O_D_RECORDS_FILE_KEY + " not found."); + logger.error("Please specify a filename value for the " + MGRA_O_D_RECORDS_FILE_KEY + + " property."); + throw new RuntimeException(); + } + + try + { + TableDataSet inTds = null; + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + inTds = reader.readFileWithFormats(new File(hisFileName), inputFormats); + // inTds = reader.readFile(new File(hisFileName)); + return inTds; + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading Sandag XBorder MGRA List data records file: %s into TableDataSet object.", + hisFileName)); + throw new RuntimeException(e); + } + + } + + private int[][] getInputOrigDestTimes(TableDataSet hisTds) + { + + // odts are an array with elements: origin mgra, destination mgra, + // departure period(1-6), and his sampno. + int[][] odts = new int[hisTds.getRowCount()][4]; + + int[] origs = hisTds.getColumnAsInt(INPUT_ORIG_MGRA); + int[] dests = hisTds.getColumnAsInt(INPUT_DEST_MGRA); + String[] departStrings = hisTds.getColumnAsString(INPUT_DEPART_PERIOD); + int[] departs = new int[departStrings.length]; + + for (int r = 1; r <= hisTds.getRowCount(); r++) + { + if (departStrings[r - 1].equalsIgnoreCase("am")) departs[r - 1] = 2; + else if (departStrings[r - 1].equalsIgnoreCase("pm")) departs[r - 1] = 5; + else if (departStrings[r - 1].equalsIgnoreCase("op")) departs[r - 1] = 1; + else departs[r - 1] = -1; + + odts[r - 1][0] = origs[r - 1]; + odts[r - 1][1] = dests[r - 1]; + odts[r - 1][2] = departs[r - 1]; + } + + return odts; + } + + public static void main(String[] args) + { + + ResourceBundle rb = null; + if (args.length == 0) + { + System.out + .println(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else if (args.length == 4) + { + rb = ResourceBundle.getBundle(args[0]); + + debugOrigMgra = Integer.parseInt(args[1]); + debugDestMgra = Integer.parseInt(args[2]); + departModelPeriod = Integer.parseInt(args[3]); + } else + { + System.out + .println("please set values for command line arguments: properties file, orig mgra, dest mgra, depart model period."); + System.exit(-1); + } + + try + { + + MatrixDataServerIf ms = null; + String serverAddress = null; + int serverPort = -1; + + HashMap propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + System.out.println(""); + System.out.println(""); + serverAddress = (String) propertyMap.get("RunModel.MatrixServerAddress"); + + String serverPortString = (String) propertyMap.get("RunModel.MatrixServerPort"); + if (serverPortString != null) serverPort = Integer.parseInt(serverPortString); + + if (serverAddress != null && serverPort > 0) + { + try + { + System.out.println("attempting connection to matrix server " + serverAddress + + ":" + serverPort); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + System.out.println("connected to matrix server " + serverAddress + ":" + + serverPort); + + } catch (Exception e) + { + System.out + .println("exception caught running ctramp model components -- exiting."); + e.printStackTrace(); + throw new RuntimeException(); + } + } + + TazDataManager tazs = TazDataManager.getInstance(propertyMap); + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + TapDataManager tapManager = TapDataManager.getInstance(propertyMap); + + // create an appender object and run it + XBorderSkimsAppender appender = new XBorderSkimsAppender(); + appender.runSkimsAppender(rb); + + } catch (RuntimeException e) + { + + e.printStackTrace(); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/AbstractNetworkFactory.java b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractNetworkFactory.java new file mode 100644 index 0000000..b3fd57d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractNetworkFactory.java @@ -0,0 +1,51 @@ +package org.sandag.abm.active; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +public abstract class AbstractNetworkFactory, T extends Traversal> + extends NetworkFactory +{ + + @Override + public Network createNetwork() + { + Network network = new SimpleNetwork<>(getNodes(), getEdges(), getTraversals()); + calculateDerivedNodeAttributes(network); + calculateDerivedEdgeAttributes(network); + calculateDerivedTraversalAttributes(network); + return network; + } + + @Override + protected Collection getTraversals() + { + Collection edges = getEdges(); + Map> predecessors = new HashMap<>(); + for (N node : getNodes()) + predecessors.put(node, new LinkedList()); + for (E edge : edges) + predecessors.get(edge.getToNode()).add(edge); + Set traversals = new LinkedHashSet<>(); + for (E toEdge : getEdges()) + { + for (E fromEdge : predecessors.get(toEdge.getFromNode())) + if (!isReversal(fromEdge, toEdge)) traversals.add(getTraversal(fromEdge, toEdge)); + } + return Collections.unmodifiableCollection(traversals); + } + + private boolean isReversal(E edge1, E edge2) + { + return (edge1.getToNode().equals(edge2.getFromNode())) + && (edge1.getFromNode().equals(edge2.getToNode())); + } + + abstract protected T getTraversal(E fromEdge, E toEdge); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/AbstractPathChoiceEdgeAssignmentApplication.java b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractPathChoiceEdgeAssignmentApplication.java new file mode 100644 index 0000000..c94f312 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractPathChoiceEdgeAssignmentApplication.java @@ -0,0 +1,217 @@ +package org.sandag.abm.active; + +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.log4j.Logger; + +public abstract class AbstractPathChoiceEdgeAssignmentApplication, T extends Traversal> +{ + private static final Logger logger = Logger.getLogger(AbstractPathChoiceEdgeAssignmentApplication.class); + + protected PathAlternativeListGenerationConfiguration configuration; + private boolean randomCostSeeded; + private double maxCost; + private TraversalEvaluator traversalCostEvaluator; + private EdgeEvaluator edgeLengthEvaluator; + long startTime; + protected Network network; + String outputDir; + + double[] sampleDistanceBreaks; + double[] samplePathSizes; + double[] sampleMinCounts; + double[] sampleMaxCounts; + + private static final int TRIP_PROGRESS_REPORT_COUNT = 1000; + + public AbstractPathChoiceEdgeAssignmentApplication( + PathAlternativeListGenerationConfiguration configuration) + { + this.configuration = configuration; + configuration.getOriginZonalCentroidIdMap(); + this.randomCostSeeded = configuration.isRandomCostSeeded(); + this.maxCost = configuration.getMaxCost(); + this.traversalCostEvaluator = configuration.getTraversalCostEvaluator(); + this.edgeLengthEvaluator = configuration.getEdgeLengthEvaluator(); + this.sampleDistanceBreaks = configuration.getSampleDistanceBreaks(); + this.samplePathSizes = configuration.getSamplePathSizes(); + this.sampleMinCounts = configuration.getSampleMinCounts(); + this.sampleMaxCounts = configuration.getSampleMaxCounts(); + this.network = configuration.getNetwork(); + this.outputDir = configuration.getOutputDirectory(); + } + + protected abstract Map assignTrip(int tripNum, + PathAlternativeList alternativeList); + + public Map assignTrips(List tripNums) + { + logger.info("Assigning trips..."); + logger.info("Writing to " + outputDir); + ConcurrentHashMap volumes = new ConcurrentHashMap<>(); + int threadCount = Runtime.getRuntime().availableProcessors() -1; + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + final Queue tripQueue = new ConcurrentLinkedQueue<>(tripNums); + final CountDownLatch latch = new CountDownLatch(threadCount); + final AtomicInteger counter = new AtomicInteger(); + startTime = System.currentTimeMillis(); + for (int i = 0; i < threadCount; i++) + executor.execute(new CalculationTask(tripQueue, counter, latch, volumes)); + try + { + latch.await(); + } catch (InterruptedException e) + { + throw new RuntimeException(e); + } + executor.shutdown(); + + return volumes; + } + + private class CalculationTask + implements Runnable + { + private final Queue tripQueue; + private final AtomicInteger counter; + private final CountDownLatch latch; + private final ConcurrentHashMap volumes; + + private CalculationTask(Queue tripQueue, AtomicInteger counter, + CountDownLatch latch, ConcurrentHashMap volumes) + { + this.tripQueue = tripQueue; + this.counter = counter; + this.latch = latch; + this.volumes = volumes; + } + + private PathAlternativeList generateAlternatives(int tripId) + { + Set singleOriginNode = new HashSet<>(); + Set singleDestinationNode = new HashSet<>(); + + EdgeEvaluator randomizedEdgeCost; + ShortestPathStrategy shortestPathStrategy; + ShortestPathResultSet result; + + singleOriginNode.add(getOriginNode(tripId)); + singleDestinationNode.add(getDestinationNode(tripId)); + + NodePair odPair = new NodePair<>(getOriginNode(tripId), getDestinationNode(tripId)); + PathAlternativeList alternativeList = new PathAlternativeList<>(odPair, network, + edgeLengthEvaluator); + + TraversalEvaluator zeroTraversalEvaluator = new ZeroTraversalEvaluator(); + + shortestPathStrategy = new RepeatedSingleSourceDijkstra(network, + edgeLengthEvaluator, zeroTraversalEvaluator); + result = shortestPathStrategy.getShortestPaths(singleOriginNode, singleDestinationNode, + Double.MAX_VALUE); + if (result.getShortestPathResult(odPair) == null) + { + logger.error("no path found for trip with origin " + getOriginNode(tripId) + + " and destination " + getDestinationNode(tripId)); + return alternativeList; + } + double distance = result.getShortestPathResult(odPair).getCost(); + int distanceIndex = findFirstIndexGreaterThan(distance, sampleDistanceBreaks); + + for (int iterCount = 1; iterCount <= sampleMinCounts[distanceIndex]; iterCount++) + { + if (randomCostSeeded) + { + randomizedEdgeCost = configuration.getRandomizedEdgeCostEvaluator(iterCount, + Objects.hash(tripId, iterCount)); + } else + { + randomizedEdgeCost = configuration.getRandomizedEdgeCostEvaluator(iterCount, 0); + } + + shortestPathStrategy = new RepeatedSingleSourceDijkstra(network, + randomizedEdgeCost, traversalCostEvaluator); + result = shortestPathStrategy.getShortestPaths(singleOriginNode, + singleDestinationNode, Double.MAX_VALUE); + + alternativeList.add(result.getShortestPathResult(odPair).getPath()); + } + return alternativeList; + } + + public void run() + { + while (tripQueue.size() > 0) + { + int tripId = tripQueue.poll(); + PathAlternativeList alternativeList = generateAlternatives(tripId); + + if (alternativeList.getCount() > 0) + { + Map tripVolumes = assignTrip(tripId, alternativeList); + + for (E edge : tripVolumes.keySet()) + { + if (volumes.containsKey(edge)) + { + double[] values = volumes.get(edge); + for (int i = 0; i < values.length; i++) + values[i] += tripVolumes.get(edge)[i]; + volumes.put(edge, values); + } else + { + volumes.put(edge, tripVolumes.get(edge)); + } + } + } + + int c = counter.addAndGet(1); + if ((c % TRIP_PROGRESS_REPORT_COUNT) == 0) + { + System.out.println(" done with " + c + " trips, run time: " + + (System.currentTimeMillis() - startTime) / 1000 + " sec."); + } + } + + latch.countDown(); + } + } + + protected abstract N getOriginNode(int tripId); + + protected abstract N getDestinationNode(int tripId); + + private class ZeroTraversalEvaluator + implements TraversalEvaluator + { + private ZeroTraversalEvaluator() + { + } + + public double evaluate(T traversal) + { + return 0.0; + } + } + + protected int findFirstIndexGreaterThan(double value, double[] array) + { + for (int i = 0; i < array.length; i++) + { + if (array[i] >= value) + { + return i; + } + } + return array.length; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/AbstractPathChoiceLogsumMatrixApplication.java b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractPathChoiceLogsumMatrixApplication.java new file mode 100644 index 0000000..04c4abc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractPathChoiceLogsumMatrixApplication.java @@ -0,0 +1,422 @@ +package org.sandag.abm.active; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.Map; +import java.util.Objects; +import java.util.Queue; +import java.util.Random; +import java.util.Set; +import java.util.concurrent.ConcurrentHashMap; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import org.apache.log4j.Logger; + +public abstract class AbstractPathChoiceLogsumMatrixApplication, T extends Traversal> +{ + private static final Logger logger = Logger.getLogger(AbstractPathChoiceLogsumMatrixApplication.class); + + protected PathAlternativeListGenerationConfiguration configuration; + Network network; + Map> nearbyZonalDistanceMap; + Map originZonalCentroidIdMap; + Map destinationZonalCentroidIdMap; + double[] sampleDistanceBreaks; + double[] samplePathSizes; + double[] sampleMinCounts; + double[] sampleMaxCounts; + EdgeEvaluator edgeLengthEvaluator; + EdgeEvaluator edgeCostEvaluator; + TraversalEvaluator traversalCostEvaluator; + double maxCost; + long startTime; + String outputDir; + Set traceOrigins; + protected Map propertyMap; + boolean randomCostSeeded; + boolean intrazonalsNeeded; + + private static final int ORIGIN_PROGRESS_REPORT_COUNT = 50; + private static final double DOUBLE_PRECISION_TOLERANCE = 0.001; + + protected abstract double[] calculateMarketSegmentLogsums( + PathAlternativeList alternativeList); + + protected abstract List> getMarketSegmentIntrazonalCalculations(); + + public AbstractPathChoiceLogsumMatrixApplication( + PathAlternativeListGenerationConfiguration configuration) + { + this.configuration = configuration; + this.network = configuration.getNetwork(); + this.nearbyZonalDistanceMap = Collections.unmodifiableMap(configuration + .getNearbyZonalDistanceMap()); + this.originZonalCentroidIdMap = Collections.unmodifiableMap(configuration + .getOriginZonalCentroidIdMap()); + this.destinationZonalCentroidIdMap = Collections.unmodifiableMap(configuration + .getDestinationZonalCentroidIdMap()); + this.sampleDistanceBreaks = configuration.getSampleDistanceBreaks(); + this.samplePathSizes = configuration.getSamplePathSizes(); + this.sampleMinCounts = configuration.getSampleMinCounts(); + this.sampleMaxCounts = configuration.getSampleMaxCounts(); + this.edgeLengthEvaluator = configuration.getEdgeLengthEvaluator(); + this.edgeCostEvaluator = configuration.getEdgeCostEvaluator(); + this.traversalCostEvaluator = configuration.getTraversalCostEvaluator(); + this.maxCost = configuration.getMaxCost(); + this.outputDir = configuration.getOutputDirectory(); + this.traceOrigins = configuration.getTraceOrigins(); + this.propertyMap = configuration.getPropertyMap(); + this.randomCostSeeded = configuration.isRandomCostSeeded(); + this.intrazonalsNeeded = configuration.isIntrazonalsNeeded(); + } + + public Map, double[]> calculateMarketSegmentLogsums() + { + logger.info("Generating path alternative lists..."); + logger.info("Writing to " + outputDir); + Map> logsums = new ConcurrentHashMap<>(); + startTime = System.currentTimeMillis(); + int threadCount = Runtime.getRuntime().availableProcessors() -1; + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + final Queue originQueue = new ConcurrentLinkedQueue<>( + originZonalCentroidIdMap.keySet()); + + final ConcurrentHashMap> insufficientSamplePairs = new ConcurrentHashMap<>(); + final CountDownLatch latch = new CountDownLatch(threadCount); + final AtomicInteger counter = new AtomicInteger(); + for (int i = 0; i < threadCount; i++) + executor.execute(new CalculationTask(originQueue, counter, latch, logsums, + insufficientSamplePairs)); + try + { + latch.await(); + } catch (InterruptedException e) + { + throw new RuntimeException(e); + } + executor.shutdown(); + + /* + * for (int origin : insufficientSamplePairs.keySet() ) { String message + * = "Sample insufficient for origin zone " + origin + + * " and destination zones "; for (int destination : + * insufficientSamplePairs.get(origin) ) { message = message + + * destination + " "; } System.out.println(message); } + */ + + int totalPairs = 0; + for (int o : nearbyZonalDistanceMap.keySet()) + { + totalPairs += nearbyZonalDistanceMap.get(o).size(); + } + logger.info("Total OD pairs: " + totalPairs); + + int totalInsuffPairs = 0; + for (int o : insufficientSamplePairs.keySet()) + { + totalInsuffPairs += insufficientSamplePairs.get(o).size(); + } + + logger.info("Total insufficient sample pairs: " + totalInsuffPairs); + + if (intrazonalsNeeded) + { + logger.info("Calculating intrazonals"); + List> intrazonalCalculations = getMarketSegmentIntrazonalCalculations(); + int segments = intrazonalCalculations.size(); + for (int segment = 0; segment < segments; segment++) + { + for (N origin : logsums.keySet()) + { + Map originLogsums = logsums.get(origin); + if (segment == 0) originLogsums.put(origin, new double[segments]); + originLogsums.get(origin)[segment] = intrazonalCalculations.get(segment) + .getIntrazonalValue(origin, originLogsums, segment); + } + } + } + + Map, double[]> pairLogsums = new HashMap<>(); + for (N oNode : logsums.keySet()) + { + for (N dNode : logsums.get(oNode).keySet()) + { + pairLogsums.put(new NodePair(oNode, dNode), logsums.get(oNode).get(dNode)); + } + } + + return pairLogsums; + } + + private int findFirstIndexGreaterThan(double value, double[] array) + { + for (int i = 0; i < array.length; i++) + { + if (array[i] >= value) + { + return i; + } + } + return array.length; + } + + private class CalculationTask + implements Runnable + { + private final Queue originQueue; + private final AtomicInteger counter; + private final CountDownLatch latch; + + private final ConcurrentHashMap> insufficientSamplePairs; + private final Map> logsums; + + private CalculationTask(Queue originQueue, AtomicInteger counter, + CountDownLatch latch, Map> logsums, + ConcurrentHashMap> insufficientSamplePairs) + { + this.originQueue = originQueue; + this.counter = counter; + this.latch = latch; + this.insufficientSamplePairs = insufficientSamplePairs; + this.logsums = logsums; + } + + private Map, PathAlternativeList> generateAlternatives(int origin) + { + Set singleOriginNode = new HashSet<>(); + Set destinationNodes = new HashSet<>(); + Map destinationZoneMap = new HashMap<>(); + Map destinationDistanceMap = new HashMap<>(); + Map destinationPathSizeMap = new HashMap<>(); + Map destinationMinCountMap = new HashMap<>(); + Map destinationMaxCountMap = new HashMap<>(); + HashMap, PathAlternativeList> alternativeLists = new HashMap<>(); + EdgeEvaluator randomizedEdgeCost; + ShortestPathStrategy shortestPathStrategy; + ShortestPathResultSet result; + int distanceIndex; + + singleOriginNode.add(network.getNode(originZonalCentroidIdMap.get(origin))); + N destinationNode = null; + PathAlternativeList alternativeList; + + if (nearbyZonalDistanceMap.containsKey(origin)) + { + for (int destination : nearbyZonalDistanceMap.get(origin).keySet()) + { + try + { + destinationNode = network.getNode(destinationZonalCentroidIdMap + .get(destination)); + } catch (NullPointerException e) + { + logger.warn(destinationZonalCentroidIdMap.get(destination)); + } + destinationNodes.add(destinationNode); + destinationDistanceMap.put(destinationNode, nearbyZonalDistanceMap.get(origin) + .get(destination)); + destinationZoneMap.put(destinationNode, destination); + distanceIndex = findFirstIndexGreaterThan( + destinationDistanceMap.get(destinationNode), sampleDistanceBreaks); + destinationPathSizeMap.put(destinationNode, samplePathSizes[distanceIndex]); + destinationMinCountMap.put(destinationNode, sampleMinCounts[distanceIndex]); + destinationMaxCountMap.put(destinationNode, sampleMaxCounts[distanceIndex]); + } + } + + int iterCount = 1; + while (destinationNodes.size() > 0) + { + + if (randomCostSeeded) + { + randomizedEdgeCost = configuration.getRandomizedEdgeCostEvaluator(iterCount, + Objects.hash(origin, iterCount)); + } else + { + randomizedEdgeCost = configuration.getRandomizedEdgeCostEvaluator(iterCount, 0); + } + + shortestPathStrategy = new RepeatedSingleSourceDijkstra(network, + randomizedEdgeCost, traversalCostEvaluator); + result = shortestPathStrategy.getShortestPaths(singleOriginNode, destinationNodes, + maxCost); + + for (NodePair odPair : result) + { + if (!alternativeLists.containsKey(odPair)) + { + alternativeLists.put(odPair, new PathAlternativeList(odPair, network, + edgeLengthEvaluator)); + } + alternativeList = alternativeLists.get(odPair); + alternativeList.add(result.getShortestPathResult(odPair).getPath()); + destinationNode = odPair.getToNode(); + + if (alternativeList.getSizeMeasureTotal() >= destinationPathSizeMap + .get(destinationNode) - DOUBLE_PRECISION_TOLERANCE + && iterCount >= destinationMinCountMap.get(destinationNode)) + { + destinationNodes.remove(odPair.getToNode()); + alternativeList.clearPathSizeCalculator(); + } else if (iterCount >= destinationMaxCountMap.get(destinationNode)) + { + destinationNodes.remove(odPair.getToNode()); + alternativeList.clearPathSizeCalculator(); + if (!insufficientSamplePairs.containsKey(origin)) + insufficientSamplePairs.put(origin, new ArrayList()); + insufficientSamplePairs.get(origin).add( + destinationZoneMap.get(destinationNode)); + } + } + + iterCount++; + } + + if (traceOrigins.contains(origin)) + { + try + { + PathAlternativeListWriter writer = new PathAlternativeListWriter( + outputDir + "origpaths_" + origin + ".csv", outputDir + "origlinks_" + + origin + ".csv"); + writer.writeHeaders(); + for (PathAlternativeList list : alternativeLists.values()) + { + writer.write(list); + } + writer.close(); + } catch (IOException e) + { + throw new RuntimeException(e.getMessage()); + } + + } + + for (NodePair odPair : alternativeLists.keySet()) + alternativeLists.put( + odPair, + resampleAlternatives(alternativeLists.get(odPair), + destinationPathSizeMap.get(odPair.getToNode()))); + + return alternativeLists; + } + + private PathAlternativeList resampleAlternatives(PathAlternativeList alts, + double targetSize) + { + if (targetSize >= alts.getSizeMeasureTotal()) + { + return alts; + } + Random r; + if (randomCostSeeded) + { + r = new Random(alts.getODPair().hashCode()); + } else + { + r = new Random(); + } + PathAlternativeList newAlts = new PathAlternativeList<>(alts.getODPair(), + network, alts.getLengthEvaluator()); + double[] prob = new double[alts.getCount()]; + double[] cum = new double[alts.getCount()]; + double tot = 0.0; + for (int i = 0; i < prob.length; i++) + { + prob[i] = alts.getSizeMeasures().get(i) / alts.getSizeMeasureTotal(); + tot = tot + prob[i]; + cum[i] = tot; + } + cum[alts.getCount() - 1] = 1.0; + + while (newAlts.getSizeMeasureTotal() < targetSize + && newAlts.getCount() < alts.getCount()) + { + double p = r.nextDouble(); + int idx = BinarySearch.binarySearch(cum, p); + newAlts.add(alts.get(idx)); + double curProb = cum[idx]; + if (idx > 0) + { + curProb = curProb - cum[idx - 1]; + } + for (int i = 0; i < cum.length; i++) + { + if (i < idx) + { + cum[i] = cum[i] / (1 - curProb); + } else + { + cum[i] = (cum[i] - curProb) / (1 - curProb); + } + } + } + return newAlts; + } + + @Override + public void run() + { + while (originQueue.size() > 0) + { + int origin = originQueue.poll(); + + Map, PathAlternativeList> alternativeLists = generateAlternatives(origin); + + if (traceOrigins.contains(origin)) + { + try + { + PathAlternativeListWriter writer = new PathAlternativeListWriter( + outputDir + "resamplepaths_" + origin + ".csv", outputDir + + "resamplelinks_" + origin + ".csv"); + writer.writeHeaders(); + for (PathAlternativeList list : alternativeLists.values()) + { + writer.write(list); + } + writer.close(); + } catch (IOException e) + { + throw new RuntimeException(e.getMessage()); + } + } + + double[] logsumValues; + for (NodePair odPair : alternativeLists.keySet()) + { + + if (!odPair.getFromNode().equals(odPair.getToNode())) + { + + logsumValues = calculateMarketSegmentLogsums(alternativeLists.get(odPair)); + if (!logsums.containsKey(odPair.getFromNode())) + { + logsums.put(odPair.getFromNode(), new ConcurrentHashMap()); + } + logsums.get(odPair.getFromNode()).put(odPair.getToNode(), logsumValues); + } + + } + + int c = counter.addAndGet(1); + if ((c % ORIGIN_PROGRESS_REPORT_COUNT) == 0) + { + logger.info(" done with " + c + " origins, run time: " + + (System.currentTimeMillis() - startTime) / 1000 + " sec."); + } + } + + latch.countDown(); + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/AbstractShortestPathResultSet.java b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractShortestPathResultSet.java new file mode 100644 index 0000000..8921833 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/AbstractShortestPathResultSet.java @@ -0,0 +1,20 @@ +package org.sandag.abm.active; + +public abstract class AbstractShortestPathResultSet + implements ModifiableShortestPathResultSet +{ + + @Override + public void addResult(NodePair od, Path path, double cost) + { + addResult(new ShortestPathResult(od, path, cost)); + } + + @Override + public void addAll(ShortestPathResultSet results) + { + for (ShortestPathResult result : results.getResults()) + addResult(result); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/BasicShortestPathResultSet.java b/sandag_abm/src/main/java/org/sandag/abm/active/BasicShortestPathResultSet.java new file mode 100644 index 0000000..417a9e1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/BasicShortestPathResultSet.java @@ -0,0 +1,59 @@ +package org.sandag.abm.active; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +public class BasicShortestPathResultSet + extends AbstractShortestPathResultSet +{ + private final Map, ShortestPathResult> results; + + public BasicShortestPathResultSet() + { + results = new HashMap<>(); // iteration order may not matter, but just + // in case, this is cheap + } + + @Override + public void addResult(ShortestPathResult spResult) + { + ShortestPathResult spr = results.put(spResult.getOriginDestination(), spResult); + if (spr != null) + throw new IllegalArgumentException("Repeated shortest path results for node pair: (" + + spResult.getOriginDestination().getFromNode().getId() + "," + + spResult.getOriginDestination().getToNode().getId() + ")"); + } + + @Override + public void addResult(NodePair od, Path path, double cost) + { + addResult(new ShortestPathResult(od, path, cost)); + } + + @Override + public Iterator> iterator() + { + return results.keySet().iterator(); + } + + @Override + public ShortestPathResult getShortestPathResult(NodePair od) + { + return results.get(od); + } + + @Override + public int size() + { + return results.size(); + } + + @Override + public Collection> getResults() + { + return results.values(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/BinarySearch.java b/sandag_abm/src/main/java/org/sandag/abm/active/BinarySearch.java new file mode 100644 index 0000000..c76b467 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/BinarySearch.java @@ -0,0 +1,35 @@ +package org.sandag.abm.active; + +public class BinarySearch +{ + public static int binarySearch(double[] values, double target) + { + return binarySearch(values, target, 0, values.length - 1); + } + + public static int binarySearch(double[] values, double target, int lower, int upper) + { + if (lower <= upper) + { + int mid = (lower + upper) / 2; + + switch (Double.compare(values[mid], target)) + { + case 0: + return mid; + case 1: + return binarySearch(values, target, lower, upper - 1); + case -1: + return binarySearch(values, target, mid + 1, upper); + } + } + + if (values[lower] >= target) + { + return lower; + } else + { + return lower + 1; + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/CompositeShortestPathResultSet.java b/sandag_abm/src/main/java/org/sandag/abm/active/CompositeShortestPathResultSet.java new file mode 100644 index 0000000..eddfe63 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/CompositeShortestPathResultSet.java @@ -0,0 +1,57 @@ +package org.sandag.abm.active; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; + +public class CompositeShortestPathResultSet + implements ShortestPathResultSet +{ + private final Map, ShortestPathResultSet> spResultsLookup; + + public CompositeShortestPathResultSet() + { + spResultsLookup = new HashMap<>(); + } + + public void addShortestPathResults(ShortestPathResultSet spResults) + { + for (NodePair nodePair : spResults) + if (spResultsLookup.put(nodePair, spResults) != null) + throw new IllegalArgumentException( + "Repeated shortest path results for node pair: (" + + nodePair.getFromNode().getId() + "," + + nodePair.getToNode().getId() + ")"); + } + + @Override + public Iterator> iterator() + { + return spResultsLookup.keySet().iterator(); + } + + @Override + public ShortestPathResult getShortestPathResult(NodePair od) + { + return spResultsLookup.get(od).getShortestPathResult(od); + } + + @Override + public int size() + { + return spResultsLookup.size(); + } + + @Override + public Collection> getResults() + { + List> results = new LinkedList<>(); + for (ShortestPathResultSet spr : spResultsLookup.values()) + results.addAll(spr.getResults()); + return results; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/DestinationNotFoundException.java b/sandag_abm/src/main/java/org/sandag/abm/active/DestinationNotFoundException.java new file mode 100644 index 0000000..cee8240 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/DestinationNotFoundException.java @@ -0,0 +1,10 @@ +package org.sandag.abm.active; + +public class DestinationNotFoundException + extends Exception +{ + public DestinationNotFoundException(String message) + { + super(message); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/Edge.java b/sandag_abm/src/main/java/org/sandag/abm/active/Edge.java new file mode 100644 index 0000000..4d25097 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/Edge.java @@ -0,0 +1,9 @@ +package org.sandag.abm.active; + +public interface Edge + extends Comparable> +{ + N getFromNode(); + + N getToNode(); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/EdgeEvaluator.java b/sandag_abm/src/main/java/org/sandag/abm/active/EdgeEvaluator.java new file mode 100644 index 0000000..1ee55f4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/EdgeEvaluator.java @@ -0,0 +1,6 @@ +package org.sandag.abm.active; + +public interface EdgeEvaluator> +{ + double evaluate(E edge); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/IntrazonalCalculation.java b/sandag_abm/src/main/java/org/sandag/abm/active/IntrazonalCalculation.java new file mode 100644 index 0000000..16e757b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/IntrazonalCalculation.java @@ -0,0 +1,35 @@ +package org.sandag.abm.active; + +import java.util.Map; + +/** + * The {@code IntrazonalCalculation} class provides a framework for calculation + * intrazonals. + * + * @param + * The type of the zone nodes. + */ +public interface IntrazonalCalculation +{ + /** + * Get the intrazonal value given the origin node and the logsum values with + * that origin node. The logsum values may be stratified across markets, so + * the index of the market of interest is also provided. + * + * @param originNode + * The origin node. + * + * @param logsums + * The logsums with {@code originNode} as their origin. The + * logsums are stored as a map with the destination node as the + * key and an array of logsums as the value. The logsum array has + * a different logsum for each market. + * + * @param logsumIndex + * The index for the logsum of interest in the logsum arrays + * provided in {@code logsums}. + * + * @return the intrazonal logsum for {@code originNode}. + */ + double getIntrazonalValue(N originNode, Map logsums, int logsumIndex); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/IntrazonalCalculations.java b/sandag_abm/src/main/java/org/sandag/abm/active/IntrazonalCalculations.java new file mode 100644 index 0000000..be82cc1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/IntrazonalCalculations.java @@ -0,0 +1,365 @@ +package org.sandag.abm.active; + +import java.util.Map; +import org.apache.log4j.Logger; + +/** + * The {@code IntrazonalCalculations} class provides convenient default + * implementations of the {IntrazonalCalculation} interface. + * + */ +public class IntrazonalCalculations +{ + + private static final Logger logger = Logger.getLogger(IntrazonalCalculations.class); + + // this class is more of a static factory provider, so constructor is hidden + private IntrazonalCalculations() + { + } + + /** + * The {@code Factorizer} interface provides a framework for transforming an + * input value. It is essentially a function of one variable. + */ + public static interface Factorizer + { + /** + * Factor, or transform, an input value. + * + * @param inputValue + * The input value. + * + * @return the transformation of {@code inputValue}. + */ + double factor(double inputValue); + } + + /** + * Get a simple {@code Factorizer} implementation which applies a linear + * scale and offset. That is, for an input x, the function will + * return the following value: + *

+ * factor*x + offset + * + * @param factor + * The multiplicative factor. + * + * @param offset + * The addititive offset. + * + * @return the factorizer which will linearly scale and offset an input. + */ + public static Factorizer simpleFactorizer(final double factor, final double offset) + { + return new Factorizer() + { + @Override + public double factor(double inputValue) + { + return inputValue * factor + offset; + } + }; + } + + /** + * Get a {@code Factorizer} which applies a linear transformation, with + * different scale and offset for positive and negative input values. That + * is, for an input x, the factorizer function will return the + * following value + *

+ * factor*x + offset + *

+ * where factor and offset may differ according to + * whether x is positive or negative (if x is 0, + * it is considered positive). + * + * @param negativeFactor + * The multiplicative factor for negative input values. + * + * @param negativeOffset + * The additivie offset for negative input values. + * + * @param positiveFactor + * The multiplicative factor for positive input values. + * + * @param positiveOffset + * The additivie offset for positive input values. + * + * @return the factorizer which will linearly scale and offset an input, + * using different transoformations based on the input's sign. + */ + public static Factorizer positiveNegativeFactorizer(final double negativeFactor, + final double negativeOffset, final double positiveFactor, final double positiveOffset) + { + return new Factorizer() + { + @Override + public double factor(double inputValue) + { + if (inputValue < 0) return negativeFactor * inputValue + negativeOffset; + return positiveFactor * inputValue + positiveOffset; + } + }; + } + + /** + * Get an {@code IntrazonalCalculation} which will apply a function to the + * sum of the largest origin-based logsum values. That is, an intrazonal + * value is calculated by a function (defined by a {@code Factorizer}) which + * acts on the sum of the largest maxCount logsum values whose + * origin is the intrazonal's zone, where maxCount is set by + * the call to this function. + * + * @param + * The type of the zone nodes. + * + * @param factorizer + * The factorizer used to calculate the intrazonal value. + * + * @param maxCount + * The number of logsum values to be used in the intrazonal + * calculation. + * + * @return an intrazonal calculation which will apply {@code factorizer} to + * the sum of the largest {@code maxCount} logsum values. + */ + public static IntrazonalCalculation maxFactorIntrazonalCalculation( + final Factorizer factorizer, final int maxCount) + { + return new IntrazonalCalculation() + { + + @Override + public double getIntrazonalValue(N originNode, Map logsums, int logsumIndex) + { + MinHeap maxValues = new MinHeap(maxCount); + int initialCount = maxCount; + double minValue = 0; // will be filled in when needed + for (N node : logsums.keySet()) + { + if (!node.equals(originNode)) + { + double value = logsums.get(node)[logsumIndex]; + if (initialCount > 0) + { + maxValues.insert(value); + if (--initialCount == 0) minValue = maxValues.getMin(); + } else if (value > minValue) + { + maxValues.removeMin(); + maxValues.insert(value); + minValue = maxValues.getMin(); + } + } + } + return factorizer.factor(maxValues.getSum()); + } + }; + } + + /** + * Get an {@code IntrazonalCalculation} which will apply a function to the + * sum of the smallest origin-based logsum values. That is, an intrazonal + * value is calculated by a function (defined by a {@code Factorizer}) which + * acts on the sum of the smallest minCount logsum values whose + * origin is the intrazonal's zone, where minCount is set by + * the call to this function. + * + * @param + * The type of the zone nodes. + * + * @param factorizer + * The factorizer used to calculate the intrazonal value. + * + * @param minCount + * The number of logsum values to be used in the intrazonal + * calculation. + * + * @return an intrazonal calculation which will apply {@code factorizer} to + * the sum of the smallest {@code minCount} logsum values. + */ + public static IntrazonalCalculation minFactorIntrazonalCalculation( + final Factorizer factorizer, final int minCount) + { + return new IntrazonalCalculation() + { + + @Override + public double getIntrazonalValue(N originNode, Map logsums, int logsumIndex) + { + MaxHeap minValues = new MaxHeap(minCount); + int initialCount = minCount; + double maxValue = 0; // will be filled in when needed + for (N node : logsums.keySet()) + { + if (!node.equals(originNode)) + { + double value = logsums.get(node)[logsumIndex]; + if (initialCount > 0) + { + minValues.insert(value); + if (--initialCount == 0) maxValue = minValues.getMax(); + } else if (value < maxValue) + { + minValues.removeMax(); + minValues.insert(value); + maxValue = minValues.getMax(); + } + } + } + return factorizer.factor(minValues.getSum()); + } + }; + } + + private static class Heap + { + protected final double[] heap; + protected int end; + + private Heap(int size) + { + heap = new double[size]; + end = 0; + } + + public double getSum() + { + double sum = 0; + for (int i = 0; i < end; i++) + sum += heap[i]; + return sum; + } + } + + private static class MaxHeap + extends Heap + { + + private MaxHeap(int size) + { + super(size); + } + + public void insert(double value) + { + int point = end++; + if (point == 0) + { + heap[0] = value; + return; + } + while (point > 0) + { + int newPoint = (point - 1) / 2; + if (heap[newPoint] < value) + { + heap[point] = heap[newPoint]; + point = newPoint; + } else + { + heap[point] = value; + break; + } + if (point == 0) heap[0] = value; + } + } + + public double getMax() + { + return heap[0]; + } + + public double removeMax() + { + double max = heap[0]; + heap[0] = heap[--end]; + double value = heap[0]; + int point = 0; + while (true) + { + int left = 2 * point + 1; + int right = left + 1; + int largest = point; + if ((left < end) && (heap[left] > heap[largest])) largest = left; + if ((right < end) && (heap[right] > heap[largest])) largest = right; + if (largest != point) + { + heap[point] = heap[largest]; + point = largest; + } else + { + heap[point] = value; + break; + } + } + return max; + } + } + + private static class MinHeap + extends Heap + { + + private MinHeap(int size) + { + super(size); + } + + public void insert(double value) + { + int point = end++; + if (point == 0) + { + heap[0] = value; + return; + } + while (point > 0) + { + int newPoint = (point - 1) / 2; + if (heap[newPoint] > value) + { + heap[point] = heap[newPoint]; + point = newPoint; + } else + { + heap[point] = value; + break; + } + if (point == 0) heap[0] = value; + } + } + + public double getMin() + { + return heap[0]; + } + + public double removeMin() + { + double min = heap[0]; + heap[0] = heap[--end]; + double value = heap[0]; + int point = 0; + while (true) + { + int left = 2 * point + 1; + int right = left + 1; + int largest = point; + if ((left < end) && (heap[left] < heap[largest])) largest = left; + if ((right < end) && (heap[right] < heap[largest])) largest = right; + if (largest != point) + { + heap[point] = heap[largest]; + point = largest; + } else + { + heap[point] = value; + break; + } + } + return min; + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/ModifiableShortestPathResultSet.java b/sandag_abm/src/main/java/org/sandag/abm/active/ModifiableShortestPathResultSet.java new file mode 100644 index 0000000..5a52993 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/ModifiableShortestPathResultSet.java @@ -0,0 +1,11 @@ +package org.sandag.abm.active; + +public interface ModifiableShortestPathResultSet + extends ShortestPathResultSet +{ + void addResult(ShortestPathResult spResult); + + void addResult(NodePair od, Path path, double cost); + + void addAll(ShortestPathResultSet results); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/Network.java b/sandag_abm/src/main/java/org/sandag/abm/active/Network.java new file mode 100644 index 0000000..025035e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/Network.java @@ -0,0 +1,163 @@ +package org.sandag.abm.active; + +import java.util.Collection; +import java.util.Iterator; + +public interface Network, T extends Traversal> +{ + N getNode(int nodeId); + + E getEdge(N fromNode, N toNode); + + E getEdge(NodePair nodes); + + T getTraversal(E fromEdge, E toEdge); + + Collection getSuccessors(N node); + + Collection getPredecessors(N node); + + Iterator nodeIterator(); + + Iterator edgeIterator(); + + Iterator traversalIterator(); + + boolean containsNodeId(int id); + + boolean containsNode(N node); + + boolean containsEdge(N fromNode, N toNode); + + boolean containsTraversal(E fromEdge, E toEdge); + + // public void addNode(T node) + // { + // if ( nodeIndex.containsKey(node.getId()) ) { + // throw new RuntimeException("Network already contains Node with id " + + // node.getId()); + // } + // nodeIndex.put(node.getId(), nodes.size()); + // nodes.add(node); + // if (! successorIndex.containsKey(node.getId()) ) { + // successorIndex.put(node.getId(), new ArrayList()); } + // if (! predecessorIndex.containsKey(node.getId()) ) { + // predecessorIndex.put(node.getId(), new ArrayList()); } + // } + // + // public void addEdge(U edge) + // { + // int fromId = edge.getFromNode(); + // int toId = edge.getToNode(); + // EdgeKey edgeIndexKey = new EdgeKey(fromId, toId); + // + // if ( edgeIndex.containsKey(edgeIndexKey) ) { + // throw new RuntimeException("Network already contains Edge with fromId " + + // edge.getFromNode() + " and toId " + edge.getToNode()); + // } + // + // edgeIndex.put(edgeIndexKey, edges.size()); + // edges.add(edge); + // + // if ( ! successorIndex.containsKey(fromId) ) { successorIndex.put(fromId, + // new ArrayList()); } + // if ( ! predecessorIndex.containsKey(toId) ) { predecessorIndex.put(toId, + // new ArrayList()); } + // + // if ( ! successorIndex.get(fromId).contains(toId) ) { + // successorIndex.get(fromId).add(toId); } + // if ( ! predecessorIndex.get(toId).contains(fromId) ) { + // predecessorIndex.get(toId).add(fromId); } + // } + // + // public void addTraversal(V traversal) + // { + // int startId = traversal.getStartId(); + // int thruId = traversal.getThruId(); + // int endId = traversal.getEndId(); + // TraversalKey traversalIndexKey = new TraversalKey(startId, thruId, + // endId); + // + // traversalIndex.put(traversalIndexKey, traversals.size()); + // traversals.add(traversal); + // } + // + // public boolean containsNodeId(int id) { + // return nodeIndex.containsKey(id); + // } + // + // public boolean containsEdgeIds(int[] ids) { + // return edgeIndex.containsKey(new EdgeKey(ids[0],ids[1])); + // } + // + // public boolean containsTraversalIds(int[] ids) { + // return traversalIndex.containsKey(new + // TraversalKey(ids[0],ids[1],ids[2])); + // } + // + // private class EdgeKey { + // private int fromId, toId; + // + // EdgeKey(int fromId, int toId) { + // this.fromId = fromId; + // this.toId = toId; + // } + // + // @Override + // public int hashCode() + // { + // final int prime = 31; + // int result = 1; + // result = prime * result + fromId; + // result = prime * result + toId; + // return result; + // } + // + // @Override + // public boolean equals(Object obj) + // { + // if (this == obj) return true; + // if (obj == null) return false; + // if (getClass() != obj.getClass()) return false; + // EdgeKey other = (EdgeKey) obj; + // if (fromId != other.fromId) return false; + // if (toId != other.toId) return false; + // return true; + // } + // } + // + // private class TraversalKey { + // private int startId, thruId, endId; + // + // public TraversalKey(int startId, int thruId, int endId) + // { + // this.startId = startId; + // this.thruId = thruId; + // this.endId = endId; + // } + // + // @Override + // public int hashCode() + // { + // final int prime = 31; + // int result = 1; + // result = prime * result + endId; + // result = prime * result + startId; + // result = prime * result + thruId; + // return result; + // } + // + // @Override + // public boolean equals(Object obj) + // { + // if (this == obj) return true; + // if (obj == null) return false; + // if (getClass() != obj.getClass()) return false; + // TraversalKey other = (TraversalKey) obj; + // if (endId != other.endId) return false; + // if (startId != other.startId) return false; + // if (thruId != other.thruId) return false; + // return true; + // } + // } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/NetworkFactory.java b/sandag_abm/src/main/java/org/sandag/abm/active/NetworkFactory.java new file mode 100644 index 0000000..02d471b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/NetworkFactory.java @@ -0,0 +1,35 @@ +package org.sandag.abm.active; + +import java.util.Collection; + +public abstract class NetworkFactory, T extends Traversal> +{ + + public Network createNetwork() + { + Network network = new SimpleNetwork<>(getNodes(), getEdges(), getTraversals()); + calculateDerivedNodeAttributes(network); + calculateDerivedEdgeAttributes(network); + calculateDerivedTraversalAttributes(network); + return network; + } + + protected abstract Collection getNodes(); + + protected abstract Collection getEdges(); + + protected abstract Collection getTraversals(); + + protected void calculateDerivedNodeAttributes(Network network) + { + } + + protected void calculateDerivedEdgeAttributes(Network network) + { + } + + protected void calculateDerivedTraversalAttributes(Network network) + { + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/Node.java b/sandag_abm/src/main/java/org/sandag/abm/active/Node.java new file mode 100644 index 0000000..d0fcd45 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/Node.java @@ -0,0 +1,7 @@ +package org.sandag.abm.active; + +public interface Node + extends Comparable +{ + int getId(); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/NodePair.java b/sandag_abm/src/main/java/org/sandag/abm/active/NodePair.java new file mode 100644 index 0000000..c375a3d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/NodePair.java @@ -0,0 +1,50 @@ +package org.sandag.abm.active; + +import java.util.Objects; + +public class NodePair + implements Comparable> +{ + private final N fromNode; + private final N toNode; + + public NodePair(N fromNode, N toNode) + { + this.fromNode = fromNode; + this.toNode = toNode; + } + + public int compareTo(NodePair other) + { + int c = fromNode.compareTo(other.fromNode); + if (c == 0) c = toNode.compareTo(other.toNode); + return c; + } + + public N getFromNode() + { + return fromNode; + } + + public N getToNode() + { + return toNode; + } + + public boolean equals(Object other) + { + if ((other == null) || (!(other instanceof NodePair))) return false; + NodePair np = (NodePair) other; + return (fromNode.equals(np.fromNode)) && (toNode.equals(np.toNode)); + } + + public int hashCode() + { + return Objects.hash(fromNode, toNode); + } + + public String toString() + { + return ""; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/ParallelSingleSourceDijkstra.java b/sandag_abm/src/main/java/org/sandag/abm/active/ParallelSingleSourceDijkstra.java new file mode 100644 index 0000000..ca82302 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/ParallelSingleSourceDijkstra.java @@ -0,0 +1,230 @@ +package org.sandag.abm.active; + +import java.util.HashSet; +import java.util.Queue; +import java.util.Set; +import java.util.concurrent.ConcurrentLinkedQueue; +import java.util.concurrent.CountDownLatch; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicInteger; +import com.pb.sawdust.util.concurrent.DnCRecursiveTask; + +public class ParallelSingleSourceDijkstra + implements ShortestPathStrategy +{ + private final ShortestPathStrategy sp; + private final ParallelMethod method; + private final int SEGMENT_SIZE = 50; + + public ParallelSingleSourceDijkstra(ShortestPathStrategy sp, ParallelMethod method) + { + this.sp = sp; + this.method = method; + } + + public static enum ParallelMethod + { + FORK_JOIN, QUEUE + } + + @Override + public ShortestPathResultSet getShortestPaths(Set originNodes, Set destinationNodes, + double maxCost) + { + switch (method) + { + case FORK_JOIN: + { + ShortestPathRecursiveTask task = new ShortestPathRecursiveTask(sp, originNodes, + destinationNodes, maxCost); + new ForkJoinPool().execute(task); + ModifiableShortestPathResultSet sprc = task.getResult(); + return sprc; + } + case QUEUE: + { + int threadCount = Runtime.getRuntime().availableProcessors(); + ExecutorService executor = Executors.newFixedThreadPool(threadCount); + final Queue> sprcQueue = new ConcurrentLinkedQueue<>(); + final Queue originNodeQueue = new ConcurrentLinkedQueue<>(originNodes); + ThreadLocal> sprcThreadLocal = new ThreadLocal>() + { + @Override + public ModifiableShortestPathResultSet initialValue() + { + ModifiableShortestPathResultSet sprc = new BasicShortestPathResultSet<>(); + sprcQueue.add(sprc); + return sprc; + } + }; + final CountDownLatch latch = new CountDownLatch(threadCount); + final AtomicInteger counter = new AtomicInteger(); + for (int i = 0; i < threadCount; i++) + executor.execute(new QueueMethodTask(sp, originNodeQueue, destinationNodes, + maxCost, counter, sprcThreadLocal, latch)); + try + { + latch.await(); + } catch (InterruptedException e) + { + throw new RuntimeException(e); + } + executor.shutdown(); + + ModifiableShortestPathResultSet finalContainer = null; + for (ModifiableShortestPathResultSet sprc : sprcQueue) + if (finalContainer == null) finalContainer = sprc; + else finalContainer.addAll(sprc); + + return finalContainer; + } + default: + throw new IllegalStateException("Should not be here."); + } + } + + @Override + public ShortestPathResultSet getShortestPaths(Set originNodes, Set destinationNodes) + { + return getShortestPaths(originNodes, destinationNodes, Double.POSITIVE_INFINITY); + } + + private class QueueMethodTask + implements Runnable + { + private final ShortestPathStrategy sp; + private final Queue originNodes; + private final Set destinationNodes; + private final double maxCost; + private final AtomicInteger counter; + private final ThreadLocal> spr; + private final CountDownLatch latch; + + private QueueMethodTask(ShortestPathStrategy sp, Queue originNodes, + Set destinationNodes, double maxCost, AtomicInteger counter, + ThreadLocal> spr, CountDownLatch latch) + { + this.sp = sp; + this.destinationNodes = destinationNodes; + this.originNodes = originNodes; + this.maxCost = maxCost; + this.counter = counter; + this.spr = spr; + this.latch = latch; + } + + @Override + public void run() + { + int segmentSize = SEGMENT_SIZE; + final Set origins = new HashSet<>(); + while (originNodes.size() > 0) + { + while ((originNodes.size() > 0) && (origins.size() < segmentSize)) + { + N origin = originNodes.poll(); + if (origin != null) origins.add(origin); + } + if (origins.size() == 0) break; + ShortestPathResultSet result = sp.getShortestPaths(origins, destinationNodes, + maxCost); + ModifiableShortestPathResultSet sprc = spr.get(); + for (ShortestPathResult spResult : result.getResults()) + sprc.addResult(spResult); + int c = counter.addAndGet(origins.size()); + if (c % segmentSize < origins.size()) + System.out.println(" done with " + ((c / segmentSize) * segmentSize) + + " origins"); + origins.clear(); + } + latch.countDown(); + } + } + + private class ShortestPathRecursiveTask + extends DnCRecursiveTask> + { + AtomicInteger counter; + private final ShortestPathStrategy sp; + private final Set destinations; + private final Node[] origins; + private final double maxCost; + + protected ShortestPathRecursiveTask(ShortestPathStrategy sp, Set origins, + Set destinations, double maxCost) + { + super(0, origins.size()); + this.sp = sp; + this.origins = origins.toArray(new Node[origins.size()]); + this.destinations = destinations; + this.maxCost = maxCost; + counter = new AtomicInteger(0); + } + + protected ShortestPathRecursiveTask(long start, long length, + DnCRecursiveTask> next, + ShortestPathStrategy sp, Node[] origins, Set destinations, double maxCost, + AtomicInteger counter) + { + super(start, length, next); + this.sp = sp; + this.origins = origins; + this.destinations = destinations; + this.maxCost = maxCost; + this.counter = counter; + } + + @Override + @SuppressWarnings("unchecked") + // origins only hold N, we just can't declare as such because of + // generics + protected ModifiableShortestPathResultSet computeTask(long start, long length) + { + Set originNodes = new HashSet<>(); + int end = (int) (start + length); + for (int n = (int) start; n < end; n++) + originNodes.add((N) origins[n]); + ShortestPathResultSet result = sp.getShortestPaths(originNodes, destinations); + ModifiableShortestPathResultSet spr = new BasicShortestPathResultSet<>(); + for (ShortestPathResult spResult : result.getResults()) + spr.addResult(spResult); + + int c = counter.addAndGet((int) length); + if (c % 10 < length) + System.out.println(" done with " + ((c / 10) * 10) + " origins"); + return spr; + } + + @Override + protected boolean continueDividing(long newLength) + { + return (newLength > 5) && (getSurplusQueuedTaskCount() < 3); + } + + @Override + protected DnCRecursiveTask> getNextTask(long start, + long length, DnCRecursiveTask> next) + { + return new ShortestPathRecursiveTask(start, length, next, sp, origins, destinations, + maxCost, counter); + } + + @Override + protected ModifiableShortestPathResultSet joinResults( + ModifiableShortestPathResultSet spr1, ModifiableShortestPathResultSet spr2) + { + if (spr1.size() > spr2.size()) + { + spr1.addAll(spr2); + return spr1; + } else + { + spr2.addAll(spr1); + return spr2; + } + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/Path.java b/sandag_abm/src/main/java/org/sandag/abm/active/Path.java new file mode 100644 index 0000000..337db3b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/Path.java @@ -0,0 +1,82 @@ +package org.sandag.abm.active; + +import java.util.Iterator; +import java.util.NoSuchElementException; + +public class Path + implements Iterable +{ + private final Path predecessorPath; + private final N next; + private final int length; + + public Path(Path predecessorPath, N next) + { + this.predecessorPath = predecessorPath; + this.next = next; + this.length = predecessorPath == null ? 1 : predecessorPath.length + 1; + } + + public Path(N first) + { + this(null, first); + } + + public int getLength() + { + return length; + } + + public N getNode(int index) + { + if (index < 0 || index >= length) + throw new IllegalArgumentException("Invalid index " + index + " for path of length " + + length); + return getNodeNoChecks(index + 1); + } + + private N getNodeNoChecks(int index) + { // index here is 1-based, not zero based! + return index == length ? next : predecessorPath.getNodeNoChecks(index); + } + + public Path extendPath(N next) + { + return new Path(this, next); + } + + public String getPathString() + { + StringBuilder sb = new StringBuilder(); + for (N n : this) + sb.append(n.getId()).append(n == next ? "" : " "); + return sb.toString(); + } + + public Iterator iterator() + { + return new Iterator() + { + private int point = 0; + + @Override + public boolean hasNext() + { + return point < length; + } + + @Override + public N next() + { + if (point < length) return getNodeNoChecks(++point); + else throw new NoSuchElementException(); + } + + @Override + public void remove() + { + throw new UnsupportedOperationException(); + } + }; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeList.java b/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeList.java new file mode 100644 index 0000000..d8c4e25 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeList.java @@ -0,0 +1,177 @@ +package org.sandag.abm.active; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class PathAlternativeList> +{ + private List> paths; + private NodePair odPair; + private List sizeMeasures; + private PathSizeCalculator sizeCalculator; + private double sizeMeasureTotal; + private boolean sizeMeasuresUpdated; + Network network; + EdgeEvaluator lengthEvaluator; + + public PathAlternativeList(NodePair odPair, Network network, + EdgeEvaluator lengthEvaluator) + { + paths = new ArrayList>(); + sizeMeasures = new ArrayList(); + this.odPair = odPair; + sizeMeasuresUpdated = true; + this.network = network; + this.lengthEvaluator = lengthEvaluator; + this.sizeCalculator = new PathSizeCalculator(this); + this.sizeMeasureTotal = 0.0; + } + + public Network getNetwork() + { + return network; + } + + public void add(Path path) + { + if (!path.getNode(0).equals(odPair.getFromNode()) + || !path.getNode(path.getLength() - 1).equals(odPair.getToNode())) + { + throw new IllegalStateException( + "OD pair of path does not match that of path alternative list"); + } + for (Path otherPath : paths) + { + if (path.equals(otherPath)) + { + return; + } + } + paths.add(path); + sizeMeasures.add(0.0); + if (sizeCalculator == null) + { + sizeMeasuresUpdated = false; + } else + { + sizeCalculator.update(); + } + } + + public List getSizeMeasures() + { + return sizeMeasures; + } + + private void setSizeMeasure(int index, double value) + { + sizeMeasureTotal += value - sizeMeasures.get(index); + sizeMeasures.set(index, value); + } + + public double getSizeMeasureTotal() + { + return sizeMeasureTotal; + } + + public int getCount() + { + return paths.size(); + } + + public Path get(int index) + { + return paths.get(index); + } + + public boolean areSizeMeasuresUpdated() + { + return sizeMeasuresUpdated; + } + + public void clearPathSizeCalculator() + { + sizeCalculator = null; + } + + public void restartPathSizeCalculator() + { + if (sizeCalculator == null) + { + sizeCalculator = new PathSizeCalculator(this); + sizeMeasuresUpdated = true; + } + } + + private class PathSizeCalculator + { + Map> incidenceMap; + List lengths; + PathAlternativeList alternatives; + int nUsingEdge; + double edgeLength; + + private PathSizeCalculator(PathAlternativeList alternatives) + { + incidenceMap = new HashMap>(); + lengths = new ArrayList(); + this.alternatives = alternatives; + if (alternatives.getCount() > 0) + { + for (int i = 0; i < alternatives.getCount(); i++) + { + alternatives.setSizeMeasure(i, 0.0); + update(); + } + } + } + + private void update() + { + lengths.add(0.0); + N previous = null; + E edge; + int index = lengths.size() - 1; + double decrement; + for (N node : alternatives.get(index)) + { + if (previous != null) + { + edge = network.getEdge(previous, node); + if (!incidenceMap.containsKey(edge)) + { + incidenceMap.put(edge, new ArrayList()); + } + incidenceMap.get(edge).add(index); + edgeLength = lengthEvaluator.evaluate(edge); + lengths.set(index, lengths.get(index) + edgeLength); + nUsingEdge = incidenceMap.get(edge).size(); + alternatives.setSizeMeasure(index, alternatives.getSizeMeasures().get(index) + + edgeLength / nUsingEdge); + for (Integer i : incidenceMap.get(edge).subList(0, nUsingEdge - 1)) + { + decrement = edgeLength / lengths.get(i) / (nUsingEdge) / (nUsingEdge - 1); + alternatives.setSizeMeasure(i, alternatives.getSizeMeasures().get(i) + - decrement); + } + } + previous = node; + } + alternatives.setSizeMeasure(index, + alternatives.getSizeMeasures().get(index) / lengths.get(index)); + } + + } + + public NodePair getODPair() + { + return odPair; + } + + public EdgeEvaluator getLengthEvaluator() + { + return lengthEvaluator; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..756f2ad --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeListGenerationConfiguration.java @@ -0,0 +1,52 @@ +package org.sandag.abm.active; + +import java.util.Map; +import java.util.Set; + +public interface PathAlternativeListGenerationConfiguration, T extends Traversal> +{ + public Network getNetwork(); + + public EdgeEvaluator getEdgeLengthEvaluator(); + + public EdgeEvaluator getEdgeCostEvaluator(); + + public TraversalEvaluator getTraversalCostEvaluator(); + + public double getMaxCost(); + + public double[] getSampleDistanceBreaks(); + + public double[] getSamplePathSizes(); + + public double[] getSampleMinCounts(); + + public double[] getSampleMaxCounts(); + + public boolean isRandomCostSeeded(); + + public Map> getNearbyZonalDistanceMap(); + + public Map getOriginZonalCentroidIdMap(); + + public Map getDestinationZonalCentroidIdMap(); + + public String getOutputDirectory(); + + public Set getTraceOrigins(); + + public Map getPropertyMap(); + + public Map getInverseOriginZonalCentroidIdMap(); + + public Map getInverseDestinationZonalCentroidIdMap(); + + public boolean isTraceExclusive(); + + public EdgeEvaluator getRandomizedEdgeCostEvaluator(int iter, long seed); + + public boolean isIntrazonalsNeeded(); + + public double getDefaultMinutesPerMile(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeListWriter.java b/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeListWriter.java new file mode 100644 index 0000000..a446045 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/PathAlternativeListWriter.java @@ -0,0 +1,59 @@ +package org.sandag.abm.active; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; + +public class PathAlternativeListWriter> + implements AutoCloseable +{ + private FileWriter pathWriter; + private FileWriter linkWriter; + + public PathAlternativeListWriter(String pathFileName, String linkFileName) throws IOException + { + pathWriter = new FileWriter(new File(pathFileName)); + linkWriter = new FileWriter(new File(linkFileName)); + } + + public void writeHeaders() throws IOException + { + pathWriter.write("alt,origNode,destNode,length,size\n"); + linkWriter.write("alt,origNode,destNode,link,fromNode,toNode\n"); + } + + public void write(PathAlternativeList alternativeList) throws IOException + { + Path path; + int index = 1; + for (int i = 0; i < alternativeList.getCount(); i++) + { + path = alternativeList.get(i); + pathWriter.write(index + "," + path.getNode(0).getId() + "," + + path.getNode(path.getLength() - 1).getId() + "," + path.getLength() + "," + + alternativeList.getSizeMeasures().get(i) + "\n"); + N previous = null; + int j = 0; + for (N node : path) + { + if (previous != null) + { + linkWriter.write(index + "," + path.getNode(0).getId() + "," + + path.getNode(path.getLength() - 1).getId() + "," + j + "," + + previous.getId() + "," + node.getId() + "\n"); + } + previous = node; + j++; + } + index++; + } + } + + public void close() throws IOException + { + pathWriter.flush(); + pathWriter.close(); + linkWriter.flush(); + linkWriter.close(); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/RepeatedSingleSourceDijkstra.java b/sandag_abm/src/main/java/org/sandag/abm/active/RepeatedSingleSourceDijkstra.java new file mode 100644 index 0000000..bf2ba01 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/RepeatedSingleSourceDijkstra.java @@ -0,0 +1,156 @@ +package org.sandag.abm.active; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.PriorityQueue; +import java.util.Set; + +public class RepeatedSingleSourceDijkstra, T extends Traversal> + implements ShortestPathStrategy +{ + private final Network network; + private final EdgeEvaluator edgeEvaluator; + private final TraversalEvaluator traversalEvaluator; + + public RepeatedSingleSourceDijkstra(Network network, EdgeEvaluator edgeEvaluator, + TraversalEvaluator traversalEvaluator) + { + this.network = network; + this.edgeEvaluator = edgeEvaluator; + this.traversalEvaluator = traversalEvaluator; + } + + private class TraversedEdge + implements Comparable + { + private final E edge; + private final double cost; + private final Path path; + + private TraversedEdge(E edge, double cost, Path path) + { + this.edge = edge; + this.cost = cost; + this.path = path; + } + + public int compareTo(TraversedEdge other) + { + return Double.compare(cost, other.cost); + } + } + + @Override + public ShortestPathResultSet getShortestPaths(Set originNodes, Set destinationNodes) + { + return getShortestPaths(originNodes, destinationNodes, Double.POSITIVE_INFINITY); + } + + @Override + public ShortestPathResultSet getShortestPaths(Set originNodes, Set destinationNodes, + double maxCost) + { + ModifiableShortestPathResultSet spResults = new BasicShortestPathResultSet<>(); + for (N originNode : originNodes) + spResults.addAll(getShortestPaths(originNode, destinationNodes, maxCost)); + return spResults; + } + + protected ShortestPathResultSet getShortestPaths(N originNode, Set destinationNodes, + double maxCost) + { + + BasicShortestPathResultSet spResults = new BasicShortestPathResultSet<>(); + Map finalCosts = new HashMap<>(); // cost to (and including) + // edge + + PriorityQueue traversalQueue = new PriorityQueue<>(); + + Set targets = new HashSet<>(destinationNodes); + Path basePath = new Path<>(originNode); + + // Don't remove origin node, and then we can force a circle for + // intrazonal trips + // if (targets.contains(originNode)) { + // targets.remove(originNode); + // costs.put(originNode,0.0); + // paths.put(originNode,basePath); + // } + + // initialize traversalQueue and costs + for (N successor : network.getSuccessors(originNode)) + { + E edge = network.getEdge(originNode, successor); + double edgeCost = edgeEvaluator.evaluate(edge); + if (edgeCost < 0) + { + throw new RuntimeException("Negative weight found for edge with fromNode " + + edge.getFromNode().getId() + " and toNode " + edge.getToNode().getId()); + } + + if (edgeCost < maxCost) + { + TraversedEdge traversedEdge = new TraversedEdge(edge, edgeCost, + basePath.extendPath(successor)); + traversalQueue.add(traversedEdge); + } + } + + double traversalCost; + + // dijkstra + while (!traversalQueue.isEmpty() && !targets.isEmpty()) + { + TraversedEdge traversedEdge = traversalQueue.poll(); + E edge = traversedEdge.edge; + + if (finalCosts.containsKey(edge)) // already considered + continue; + Path path = traversedEdge.path; + double cost = traversedEdge.cost; + + finalCosts.put(edge, cost); + N fromNode = edge.getFromNode(); + N toNode = edge.getToNode(); + if (targets.remove(toNode)) + { + spResults.addResult(new NodePair(originNode, toNode), path, cost); + } + + for (N successor : network.getSuccessors(toNode)) + { + if (successor.equals(fromNode)) continue; // no u-turns will be + // allowed, so don't + // pollute heap + T traversal = network.getTraversal(traversedEdge.edge, + network.getEdge(toNode, successor)); + traversalCost = evaluateTraversalCost(traversal); + if (traversalCost < 0) + { + throw new RuntimeException( + "Negative weight found for traversal with start node " + + traversal.getFromEdge().getFromNode().getId() + + ", thru node " + traversal.getFromEdge().getToNode().getId() + + ", and end node " + traversal.getToEdge().getToNode().getId()); + } + traversalCost += cost; + if (traversalCost < maxCost) + traversalQueue.add(new TraversedEdge(traversal.getToEdge(), traversalCost, path + .extendPath(successor))); + } + } + + // Not returning null path references and infinite costs for nodes not + // found for possibility of insufficient memory + + return spResults; + } + + protected double evaluateTraversalCost(T traversal) + { + return edgeEvaluator.evaluate(traversal.getToEdge()) + + traversalEvaluator.evaluate(traversal); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathResult.java b/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathResult.java new file mode 100644 index 0000000..3804815 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathResult.java @@ -0,0 +1,31 @@ +package org.sandag.abm.active; + +public class ShortestPathResult +{ + private final NodePair od; + private final Path path; + private final double cost; + + public ShortestPathResult(NodePair od, Path path, double cost) + { + this.od = od; + this.path = path; + this.cost = cost; + } + + public NodePair getOriginDestination() + { + return od; + } + + public Path getPath() + { + return path; + } + + public double getCost() + { + return cost; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathResultSet.java b/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathResultSet.java new file mode 100644 index 0000000..cf2334d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathResultSet.java @@ -0,0 +1,13 @@ +package org.sandag.abm.active; + +import java.util.Collection; + +public interface ShortestPathResultSet + extends Iterable> +{ + int size(); + + ShortestPathResult getShortestPathResult(NodePair od); + + Collection> getResults(); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathStrategy.java b/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathStrategy.java new file mode 100644 index 0000000..9d47c64 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/ShortestPathStrategy.java @@ -0,0 +1,11 @@ +package org.sandag.abm.active; + +import java.util.Set; + +public interface ShortestPathStrategy +{ + ShortestPathResultSet getShortestPaths(Set originNodes, Set destinationNodes, + double maxCost); + + ShortestPathResultSet getShortestPaths(Set originNodes, Set destinationNodes); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/SimpleEdge.java b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleEdge.java new file mode 100644 index 0000000..0bdbe5b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleEdge.java @@ -0,0 +1,50 @@ +package org.sandag.abm.active; + +import java.util.Objects; + +public class SimpleEdge + implements Edge +{ + private final N fromNode; + private final N toNode; + + public SimpleEdge(N fromNode, N toNode) + { + this.fromNode = fromNode; + this.toNode = toNode; + } + + @Override + public N getFromNode() + { + return fromNode; + } + + @Override + public N getToNode() + { + return toNode; + } + + @Override + public int compareTo(Edge o) + { + int fromResult = this.fromNode.compareTo(o.getFromNode()); + int toResult = this.toNode.compareTo(o.getToNode()); + return fromResult + ((fromResult == 0) ? 1 : 0) * toResult; + } + + @Override + public int hashCode() + { + return Objects.hash(fromNode, toNode); + } + + @Override + public boolean equals(Object o) + { + if ((o == null) || !(o instanceof Edge)) return false; + Edge other = (Edge) o; + return fromNode.equals(other.getFromNode()) && toNode.equals(other.getToNode()); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/SimpleNetwork.java b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleNetwork.java new file mode 100644 index 0000000..d88553b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleNetwork.java @@ -0,0 +1,141 @@ +package org.sandag.abm.active; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.Map; + +public class SimpleNetwork, T extends Traversal> + implements Network +{ + private final Map nodes; + private final Map, E> edges; + private final Map traversals; + + private final Map> successors; + private final Map> predecessors; + + public SimpleNetwork(Collection nodes, Collection edges, Collection traversals) + { + this.nodes = new LinkedHashMap<>(); // use LinkedHashMap for fast + // iteration over keys + this.edges = new LinkedHashMap<>(); + this.traversals = new LinkedHashMap<>(); + + for (N node : nodes) + this.nodes.put(node.getId(), node); + for (E edge : edges) + this.edges.put(new NodePair(edge.getFromNode(), edge.getToNode()), edge); + for (T traversal : traversals) + this.traversals.put(new EdgePair(traversal.getFromEdge(), traversal.getToEdge()), + traversal); + + successors = new HashMap<>(); // save memory and insertion time over + // LinkedHashMap + predecessors = new HashMap<>(); + + for (N node : this.nodes.values()) + { + successors.put(node, new LinkedList()); + predecessors.put(node, new LinkedList()); + } + for (NodePair nodePair : this.edges.keySet()) + { + N from = nodePair.getFromNode(); + N to = nodePair.getToNode(); + successors.get(from).add(to); + predecessors.get(to).add(from); + } + } + + @Override + public N getNode(int nodeId) + { + return nodes.get(nodeId); + } + + @Override + public E getEdge(N fromNode, N toNode) + { + return getEdge(new NodePair(fromNode, toNode)); + } + + @Override + public E getEdge(NodePair nodes) + { + return edges.get(nodes); + } + + @Override + public T getTraversal(E fromEdge, E toEdge) + { + return traversals.get(new EdgePair(fromEdge, toEdge)); + } + + @Override + public Collection getSuccessors(Node node) + { + return Collections.unmodifiableCollection(successors.get(node)); + } + + @Override + public Collection getPredecessors(Node node) + { + return Collections.unmodifiableCollection(predecessors.get(node)); + } + + @Override + public Iterator nodeIterator() + { + return nodes.values().iterator(); + } + + @Override + public Iterator edgeIterator() + { + return edges.values().iterator(); + } + + @Override + public Iterator traversalIterator() + { + return traversals.values().iterator(); + } + + @Override + public boolean containsNodeId(int id) + { + return nodes.containsKey(id); + } + + @Override + public boolean containsNode(Node node) + { + return nodes.containsValue(node); + } + + @Override + public boolean containsEdge(N fromNode, N toNode) + { + return edges.containsKey(new NodePair(fromNode, toNode)); + } + + @Override + public boolean containsTraversal(E fromEdge, E toEdge) + { + return traversals.containsKey(new EdgePair(fromEdge, toEdge)); + } + + private class EdgePair + extends SimpleTraversal + { + public EdgePair(E fromEdge, E toEdge) + { + super(fromEdge, toEdge); + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/SimpleNode.java b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleNode.java new file mode 100644 index 0000000..f3b6bc9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleNode.java @@ -0,0 +1,45 @@ +package org.sandag.abm.active; + +import java.util.Objects; + +public class SimpleNode + implements Node +{ + private final int id; + + public SimpleNode(int id) + { + this.id = id; + } + + @Override + public int getId() + { + return id; + } + + @Override + public int compareTo(Node node) + { + return Integer.compare(id, node.getId()); + } + + @Override + public int hashCode() + { + return Objects.hash(id); + } + + @Override + public boolean equals(Object o) + { + if ((o == null) || !(o instanceof Node)) return false; + return id == ((Node) o).getId(); + } + + public String toString() + { + return ""; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/SimpleTraversal.java b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleTraversal.java new file mode 100644 index 0000000..02b7f49 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/SimpleTraversal.java @@ -0,0 +1,46 @@ +package org.sandag.abm.active; + +import java.util.Objects; + +public class SimpleTraversal> + implements Traversal +{ + private final E fromEdge; + private final E toEdge; + + public SimpleTraversal(E fromEdge, E toEdge) + { + this.fromEdge = fromEdge; + this.toEdge = toEdge; + } + + @Override + public E getFromEdge() + { + return fromEdge; + } + + @Override + public E getToEdge() + { + return toEdge; + } + + @Override + public int hashCode() + { + return Objects.hash(fromEdge, toEdge); + } + + @Override + public boolean equals(Object obj) + { + if ((obj == null) || (!(obj instanceof Traversal))) return false; + Traversal traversal = (Traversal) obj; + if (fromEdge == null) return (fromEdge == traversal.getFromEdge()) + && (toEdge.equals(traversal.getToEdge())); + else return (fromEdge.equals(traversal.getFromEdge())) + && (toEdge.equals(traversal.getToEdge())); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/Traversal.java b/sandag_abm/src/main/java/org/sandag/abm/active/Traversal.java new file mode 100644 index 0000000..6e508e1 Binary files /dev/null and b/sandag_abm/src/main/java/org/sandag/abm/active/Traversal.java differ diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/TraversalEvaluator.java b/sandag_abm/src/main/java/org/sandag/abm/active/TraversalEvaluator.java new file mode 100644 index 0000000..0e4c197 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/TraversalEvaluator.java @@ -0,0 +1,6 @@ +package org.sandag.abm.active; + +public interface TraversalEvaluator> +{ + double evaluate(T traversal); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/BikeAssignmentTripReader.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/BikeAssignmentTripReader.java new file mode 100644 index 0000000..2729f27 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/BikeAssignmentTripReader.java @@ -0,0 +1,216 @@ +package org.sandag.abm.active.sandag; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Stop; +import org.sandag.abm.ctramp.Tour; + +public class BikeAssignmentTripReader +{ + private String indivTripFileName, jointTripFileName, indivTourFileName, + jointTourFileName, personFileName, hhFileName; + private static final int DEFAULT_MANDATORY_PURPOSE_INDEX = 1; + private static final int DEFAULT_NONMANDATORY_PURPOSE_INDEX = 4; + private static final int BIKE_MODE_INDEX = 10; + + private static String PROPERTIES_HOUSEHOLD_FILENAME = "PopulationSynthesizer.InputToCTRAMP.HouseholdFile"; + private static String PROPERTIES_PERSON_FILENAME = "PopulationSynthesizer.InputToCTRAMP.PersonFile"; + private static String PROPERTIES_INDIV_TOUR_FILENAME = "Results.IndivTourDataFile"; + private static String PROPERTIES_JOINT_TOUR_FILENAME = "Results.JointTourDataFile"; + private static String PROPERTIES_INDIV_TRIP_FILENAME = "Results.IndivTripDataFile"; + private static String PROPERTIES_JOINT_TRIP_FILENAME = "Results.JointTripDataFile"; + private static String PROPERTIES_PROJECT_DIR = "Project.Directory"; + + public BikeAssignmentTripReader(Map propertyMap) + { + String dir = propertyMap.get(PROPERTIES_PROJECT_DIR); + this.indivTripFileName = dir + "/" + propertyMap.get(PROPERTIES_INDIV_TRIP_FILENAME); + this.jointTripFileName = dir + "/" + propertyMap.get(PROPERTIES_JOINT_TRIP_FILENAME); + this.indivTourFileName = dir + "/" + propertyMap.get(PROPERTIES_INDIV_TOUR_FILENAME); + this.jointTourFileName = dir + "/" + propertyMap.get(PROPERTIES_JOINT_TOUR_FILENAME); + this.personFileName = dir + "/" + propertyMap.get(PROPERTIES_PERSON_FILENAME); + this.hhFileName = dir + "/" + propertyMap.get(PROPERTIES_HOUSEHOLD_FILENAME); + } + + public BikeAssignmentTripReader(Map propertyMap, int iter) + { + String dir = propertyMap.get(PROPERTIES_PROJECT_DIR); + this.indivTripFileName = dir + + "/" + + propertyMap.get(PROPERTIES_INDIV_TRIP_FILENAME).substring(0, + PROPERTIES_INDIV_TRIP_FILENAME.length() - 5) + "_" + iter + ".csv"; + this.jointTripFileName = dir + + "/" + + propertyMap.get(PROPERTIES_JOINT_TRIP_FILENAME).substring(0, + PROPERTIES_JOINT_TRIP_FILENAME.length() - 5) + "_" + iter + ".csv"; + this.indivTourFileName = dir + + "/" + + propertyMap.get(PROPERTIES_INDIV_TOUR_FILENAME).substring(0, + PROPERTIES_INDIV_TOUR_FILENAME.length() - 5) + "_" + iter + ".csv"; + this.jointTourFileName = dir + + "/" + + propertyMap.get(PROPERTIES_JOINT_TOUR_FILENAME).substring(0, + PROPERTIES_JOINT_TOUR_FILENAME.length() - 5) + "_" + iter + ".csv"; + this.personFileName = dir + "/" + propertyMap.get(PROPERTIES_PERSON_FILENAME); + this.hhFileName = dir + "/" + propertyMap.get(PROPERTIES_HOUSEHOLD_FILENAME); + } + + public List createTripList() + { + + SandagModelStructure modelStructure = new SandagModelStructure(); + + Map indivTourMap = new HashMap<>(); + Map> jointTourMap = new HashMap<>(); + Map hhMap = new HashMap<>(); + List stops = new ArrayList<>(); + + try + { + + String line; + BufferedReader reader = new BufferedReader(new FileReader(hhFileName)); + reader.readLine(); + while ((line = reader.readLine()) != null) + { + String[] row = line.split(","); + Household h = new Household(modelStructure); + int hhSize = Integer.parseInt(row[8]); + h.setHhSize(hhSize); + int hhId = Integer.parseInt(row[0]); + hhMap.put(hhId, h); + } + reader.close(); + + reader = new BufferedReader(new FileReader(personFileName)); + reader.readLine(); + while ((line = reader.readLine()) != null) + { + String[] row = line.split(","); + int hhId = Integer.parseInt(row[0]); + int perId = Integer.parseInt(row[1]); + int perNo = Integer.parseInt(row[3]); + Household h = hhMap.get(hhId); + Person p = h.getPerson(perNo); + int gender = Integer.parseInt(row[5]); + p.setPersGender(gender); + p.setPersId(perId); + } + reader.close(); + + reader = new BufferedReader(new FileReader(indivTourFileName)); + reader.readLine(); + while ((line = reader.readLine()) != null) + { + String[] row = line.split(","); + int hhId = Integer.parseInt(row[0]); + int perId = Integer.parseInt(row[1]); + int perNo = Integer.parseInt(row[2]); + int tourId = Integer.parseInt(row[4]); + String tourCategory = row[5]; + int tourPurpose = DEFAULT_MANDATORY_PURPOSE_INDEX; + if (tourCategory != "MANDATORY") + { + tourPurpose = DEFAULT_NONMANDATORY_PURPOSE_INDEX; + } + Tour t = new Tour(hhMap.get(hhId).getPerson(perNo), tourId, tourPurpose); + if (!indivTourMap.containsKey(perId)) + { + indivTourMap.put(perId, new Tour[20]); + } + indivTourMap.get(perId)[tourId] = t; + } + reader.close(); + + reader = new BufferedReader(new FileReader(jointTourFileName)); + reader.readLine(); + while ((line = reader.readLine()) != null) + { + String[] row = line.split(","); + int hhId = Integer.parseInt(row[0]); + int tourId = Integer.parseInt(row[1]); + String[] tourParty = row[5].split(" "); + Household h = hhMap.get(hhId); + int[] participantArray = new int[tourParty.length]; + for (int i = 0; i < participantArray.length; i++) + { + participantArray[i] = Integer.parseInt(tourParty[i]); + } + Tour t = new Tour(h, "", modelStructure.JOINT_NON_MANDATORY_CATEGORY, + DEFAULT_NONMANDATORY_PURPOSE_INDEX); + t.setPersonObject(h.getPerson(participantArray[0])); + t.setPersonNumArray(participantArray); + t.setTourId(tourId); + if (!jointTourMap.containsKey(hhId)) + { + jointTourMap.put(hhId, new ArrayList()); + } + jointTourMap.get(hhId).add(t); + } + reader.close(); + + reader = new BufferedReader(new FileReader(indivTripFileName)); + reader.readLine(); + while ((line = reader.readLine()) != null) + { + String[] row = line.split(","); + int tripMode = Integer.parseInt(row[13]); + if (tripMode == BIKE_MODE_INDEX) + { + int perId = Integer.parseInt(row[1]); + int tourId = Integer.parseInt(row[3]); + boolean inbound = Boolean.parseBoolean(row[5]); + Tour t = indivTourMap.get(perId)[tourId]; + Stop s = new Stop(t, "", "", 0, inbound, 0); + int stopPeriod = Integer.parseInt(row[12]); + s.setStopPeriod(stopPeriod); + int oMgra = Integer.parseInt(row[9]); + int dMgra = Integer.parseInt(row[10]); + s.setOrig(oMgra); + s.setDest(dMgra); + stops.add(s); + } + } + reader.close(); + + reader = new BufferedReader(new FileReader(jointTripFileName)); + reader.readLine(); + while ((line = reader.readLine()) != null) + { + String[] row = line.split(","); + int tripMode = Integer.parseInt(row[11]); + if (tripMode == BIKE_MODE_INDEX) + { + int hhId = Integer.parseInt(row[0]); + int tourId = Integer.parseInt(row[1]); + boolean inbound = Boolean.parseBoolean(row[3]); + Tour t = jointTourMap.get(hhId).get(tourId); + Stop s = new Stop(t, "", "", 0, inbound, 0); + int stopPeriod = Integer.parseInt(row[10]); + s.setStopPeriod(stopPeriod); + int oMgra = Integer.parseInt(row[7]); + int dMgra = Integer.parseInt(row[8]); + s.setOrig(oMgra); + s.setDest(dMgra); + stops.add(s); + } + } + reader.close(); + + } catch (IOException e) + { + throw new RuntimeException(e); + } + + return stops; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/PropertyParser.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/PropertyParser.java new file mode 100644 index 0000000..1ffdbbb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/PropertyParser.java @@ -0,0 +1,99 @@ +package org.sandag.abm.active.sandag; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +public class PropertyParser +{ + public Map propertyMap; + + public PropertyParser(Map propertyMap) + { + this.propertyMap = propertyMap; + } + + public List parseStringPropertyList(String property) + { + return Arrays.asList(propertyMap.get(property.trim()).split("\\s*,\\s*")); + } + + public List parseFloatPropertyList(String property) + { + List stringList = Arrays.asList(propertyMap.get(property).split("\\s*,\\s*")); + List floatList = new ArrayList(); + for (String str : stringList) + { + floatList.add(Float.parseFloat(str)); + } + return floatList; + } + + public double[] parseDoublePropertyArray(String property) + { + List stringList = Arrays.asList(propertyMap.get(property).split("\\s*,\\s*")); + double[] array = new double[stringList.size()]; + for (int i = 0; i < stringList.size(); i++) + { + array[i] = Double.parseDouble(stringList.get(i)); + } + return array; + } + + public List parseIntPropertyList(String property) + { + List stringList = Arrays.asList(propertyMap.get(property).split("\\s*,\\s*")); + List intList = new ArrayList(); + for (String str : stringList) + { + intList.add(Integer.parseInt(str)); + } + return intList; + } + + public Map mapStringPropertyListToStrings(String keyProperty, + String stringValueProperty) + { + Map map = new HashMap(); + List keys = parseStringPropertyList(keyProperty); + List values = parseStringPropertyList(stringValueProperty); + for (int i = 0; i < keys.size(); i += 1) + { + map.put(keys.get(i), values.get(i)); + } + return map; + } + + public Map mapStringPropertyListToFloats(String keyProperty, + String stringValueProperty) + { + Map map = new HashMap(); + List keys = parseStringPropertyList(keyProperty); + List values = parseFloatPropertyList(stringValueProperty); + for (int i = 0; i < keys.size(); i += 1) + { + map.put(keys.get(i), values.get(i)); + } + return map; + } + + private boolean isIntValueIn(int value, List referenceValues) + { + for (int v : referenceValues) + { + if (v == value) + { + return true; + } + } + return false; + } + + public boolean isIntValueInPropertyList(int value, String property) + { + List referenceValues = parseIntPropertyList(property); + return isIntValueIn(value, referenceValues); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeEdge.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeEdge.java new file mode 100644 index 0000000..7b5a52f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeEdge.java @@ -0,0 +1,19 @@ +package org.sandag.abm.active.sandag; + +import org.sandag.abm.active.SimpleEdge; + +public class SandagBikeEdge + extends SimpleEdge +{ + public volatile byte bikeClass, lanes, functionalClass; + public volatile boolean centroidConnector, autosPermitted, cycleTrack, bikeBlvd; + public volatile float distance, scenicIndex; + public volatile short gain; + public volatile double bikeCost, walkCost; + public long roadsegid; + + public SandagBikeEdge(SandagBikeNode fromNode, SandagBikeNode toNode) + { + super(fromNode, toNode); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeMgraPathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeMgraPathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..8280f42 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeMgraPathAlternativeListGenerationConfiguration.java @@ -0,0 +1,36 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.sandag.abm.active.Network; + +public class SandagBikeMgraPathAlternativeListGenerationConfiguration + extends SandagBikePathAlternativeListGenerationConfiguration +{ + + public SandagBikeMgraPathAlternativeListGenerationConfiguration( + Map propertyMap, + Network network) + { + super(propertyMap, network); + this.PROPERTIES_MAXDIST_ZONE = Double.parseDouble(propertyMap.get("active.maxdist.bike.mgra")); + this.PROPERTIES_TRACE_ORIGINS = "active.trace.origins.mgra"; + } + + protected void createZonalCentroidIdMap() + { + System.out.println("Creating MGRA Zonal Centroid Id Map..."); + zonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.mgra > 0) + { + zonalCentroidIdMap.put((int) n.mgra, n.getId()); + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeNetworkFactory.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeNetworkFactory.java new file mode 100644 index 0000000..e5aebca --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeNetworkFactory.java @@ -0,0 +1,581 @@ +package org.sandag.abm.active.sandag; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.lang.reflect.Field; +import java.util.Collection; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedHashSet; +import java.util.Map; +import java.util.Set; +import org.apache.log4j.Logger; +import org.sandag.abm.active.AbstractNetworkFactory; +import org.sandag.abm.active.Network; +import com.linuxense.javadbf.DBFReader; + +public class SandagBikeNetworkFactory + extends AbstractNetworkFactory +{ + protected Logger logger = Logger.getLogger(SandagBikeNetworkFactory.class); + private Map propertyMap; + private PropertyParser propertyParser; + private Collection nodes = null; + private Collection edges = null; + private Collection traversals = null; + + private static final String PROPERTIES_NODE_FILE = "active.node.file"; + private static final String PROPERTIES_NODE_ID = "active.node.id"; + private static final String PROPERTIES_NODE_FIELDNAMES = "active.node.fieldnames"; + private static final String PROPERTIES_NODE_COLUMNS = "active.node.columns"; + private static final String PROPERTIES_EDGE_FILE = "active.edge.file"; + private static final String PROPERTIES_EDGE_ANODE = "active.edge.anode"; + private static final String PROPERTIES_EDGE_BNODE = "active.edge.bnode"; + private static final String PROPERTIES_EDGE_DIRECTIONAL = "active.edge.directional"; + private static final String PROPERTIES_EDGE_FIELDNAMES = "active.edge.fieldnames"; + private static final String PROPERTIES_EDGE_COLUMNS_AB = "active.edge.columns.ab"; + private static final String PROPERTIES_EDGE_COLUMNS_BA = "active.edge.columns.ba"; + private static final String PROPERTIES_EDGE_CENTROID_FIELD = "active.edge.centroid.field"; + private static final String PROPERTIES_EDGE_CENTROID_VALUE = "active.edge.centroid.value"; + private static final String PROPERTIES_EDGE_AUTOSPERMITTED_FIELD = "active.edge.autospermitted.field"; + private static final String PROPERTIES_EDGE_AUTOSPERMITTED_VALUES = "active.edge.autospermitted.values"; + + private static final double TURN_ANGLE_TOLERANCE = Math.PI / 6; + private static final double DISTANCE_CONVERSION_FACTOR = 0.000189; + private static final double INACCESSIBLE_COST_COEF = 999.0; + + private static final String PROPERTIES_COEF_DISTCLA0 = "active.coef.distcla0"; + private static final String PROPERTIES_COEF_DISTCLA1 = "active.coef.distcla1"; + private static final String PROPERTIES_COEF_DISTCLA2 = "active.coef.distcla2"; + private static final String PROPERTIES_COEF_DISTCLA3 = "active.coef.distcla3"; + private static final String PROPERTIES_COEF_DARTNE2 = "active.coef.dartne2"; + private static final String PROPERTIES_COEF_DWRONGWY = "active.coef.dwrongwy"; + private static final String PROPERTIES_COEF_GAIN = "active.coef.gain"; + private static final String PROPERTIES_COEF_TURN = "active.coef.turn"; + private static final String PROPERTIES_COEF_GAIN_WALK = "active.coef.gain.walk"; + private static final String PROPERTIES_COEF_DCYCTRAC = "active.coef.dcyctrac"; + private static final String PROPERTIES_COEF_DBIKBLVD = "active.coef.dbikblvd"; + private static final String PROPERTIES_COEF_SIGNALS = "active.coef.signals"; + private static final String PROPERTIES_COEF_UNLFRMA = "active.coef.unlfrma"; + private static final String PROPERTIES_COEF_UNLFRMI = "active.coef.unlfrmi"; + private static final String PROPERTIES_COEF_UNTOMA = "active.coef.untoma"; + private static final String PROPERTIES_COEF_UNTOMI = "active.coef.untomi"; + private static final String PROPERTIES_COEF_DISTANCE_WALK = "active.walk.minutes.per.mile"; + + + public SandagBikeNetworkFactory(Map propertyMap) + { + this.propertyMap = propertyMap; + propertyParser = new PropertyParser(propertyMap); + } + + protected Collection readNodes() + { + Set nodes = new LinkedHashSet<>(); + try + { + InputStream stream = new FileInputStream(propertyMap.get(PROPERTIES_NODE_FILE)); + DBFReader reader = new DBFReader(stream); + Map fieldMap = propertyParser.mapStringPropertyListToStrings( + PROPERTIES_NODE_FIELDNAMES, PROPERTIES_NODE_COLUMNS); + Field f; + int fieldCount = reader.getFieldCount(); + Map labels = new HashMap(); + for (int i = 0; i < fieldCount; i++) + { + labels.put(reader.getField(i).getName(), i); + } + Object[] rowObjects; + while ((rowObjects = reader.nextRecord()) != null) + { + int id = ((Number) rowObjects[labels.get(propertyMap.get(PROPERTIES_NODE_ID))]) + .intValue(); + SandagBikeNode node = new SandagBikeNode(id); + for (String fieldName : fieldMap.keySet()) + { + try + { + f = node.getClass().getField(fieldName); + setNumericFieldWithCast(node, f, + (Number) rowObjects[labels.get(fieldMap.get(fieldName))]); + } catch (NoSuchFieldException | SecurityException e) + { + logger.error("Exception caught getting class field " + fieldName + + " for object of class " + node.getClass().getName(), e); + throw new RuntimeException(); + } + } + nodes.add(node); + } + } catch (IOException e) + { + logger.error("Exception caught reading nodes from disk.", e); + throw new RuntimeException(); + } + return nodes; + } + + protected Collection readEdges(Collection nodes) + { + Set edges = new LinkedHashSet<>(); + Map idNodeMap = new HashMap<>(); + for (SandagBikeNode node : nodes) + idNodeMap.put(node.getId(), node); + + try + { + InputStream stream = new FileInputStream(propertyMap.get(PROPERTIES_EDGE_FILE)); + DBFReader reader = new DBFReader(stream); + Map abFieldMap = propertyParser.mapStringPropertyListToStrings( + PROPERTIES_EDGE_FIELDNAMES, PROPERTIES_EDGE_COLUMNS_AB); + Map baFieldMap = new HashMap(); + boolean directional = Boolean + .parseBoolean(propertyMap.get(PROPERTIES_EDGE_DIRECTIONAL)); + if (!directional) + { + baFieldMap = propertyParser.mapStringPropertyListToStrings( + PROPERTIES_EDGE_FIELDNAMES, PROPERTIES_EDGE_COLUMNS_BA); + } + int columnCount = reader.getFieldCount(); + Map labels = new HashMap(); + for (int i = 0; i < columnCount; i++) + { + labels.put(reader.getField(i).getName(), i); + } + Object[] rowObjects; + while ((rowObjects = reader.nextRecord()) != null) + { + SandagBikeNode a = idNodeMap.get(((Number) rowObjects[labels.get(propertyMap + .get(PROPERTIES_EDGE_ANODE))]).intValue()); + SandagBikeNode b = idNodeMap.get(((Number) rowObjects[labels.get(propertyMap + .get(PROPERTIES_EDGE_BNODE))]).intValue()); + + SandagBikeEdge edge = new SandagBikeEdge(a, b); + for (String fieldName : abFieldMap.keySet()) + { + try + { + Field f = edge.getClass().getField(fieldName); + setNumericFieldWithCast(edge, f, + (Number) rowObjects[labels.get(abFieldMap.get(fieldName))]); + } catch (NoSuchFieldException | SecurityException e) + { + logger.error("Exception caught getting class field " + fieldName + + " for object of class " + edge.getClass().getName(), e); + throw new RuntimeException(); + } + } + edges.add(edge); + + if (!directional) + { + edge = new SandagBikeEdge(b, a); + for (String fieldName : baFieldMap.keySet()) + { + try + { + Field f = edge.getClass().getField(fieldName); + setNumericFieldWithCast(edge, f, + (Number) rowObjects[labels.get(baFieldMap.get(fieldName))]); + } catch (NoSuchFieldException | SecurityException e) + { + logger.error("Exception caught getting class field " + fieldName + + " for object of class " + edge.getClass().getName(), e); + throw new RuntimeException(); + } + } + edges.add(edge); + } + } + } catch (IOException e) + { + logger.error("Exception caught reading edges from disk.", e); + throw new RuntimeException(); + } + return edges; + } + + @Override + protected void calculateDerivedNodeAttributes( + Network network) + { + Iterator nodeIterator = network.nodeIterator(); + while (nodeIterator.hasNext()) + { + SandagBikeNode n = nodeIterator.next(); + n.centroid = (n.mgra > 0) || (n.taz > 0); + if (n.mgra > 0) + { + n.taz = 0; + } + } + } + + @Override + protected void calculateDerivedEdgeAttributes( + Network network) + { + try + { + Iterator edgeIterator = network.edgeIterator(); + Field apf = SandagBikeEdge.class.getField(propertyMap + .get(PROPERTIES_EDGE_AUTOSPERMITTED_FIELD)); + Field cf = SandagBikeEdge.class.getField(propertyMap + .get(PROPERTIES_EDGE_CENTROID_FIELD)); + while (edgeIterator.hasNext()) + { + SandagBikeEdge edge = edgeIterator.next(); + edge.autosPermitted = propertyParser.isIntValueInPropertyList(apf.getInt(edge), + PROPERTIES_EDGE_AUTOSPERMITTED_VALUES); + edge.centroidConnector = propertyParser.isIntValueInPropertyList(cf.getInt(edge), + PROPERTIES_EDGE_CENTROID_VALUE); + edge.distance = edge.distance * (float) DISTANCE_CONVERSION_FACTOR; + edge.bikeCost = (double) edge.distance + * (Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA0)) + * ((edge.bikeClass < 1 ? 1 : 0) + (edge.bikeClass > 3 ? 1 : 0)) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA1)) + * (edge.bikeClass == 1 ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA2)) + * (edge.bikeClass == 2 ? 1 : 0) * (edge.cycleTrack ? 0 : 1) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA3)) + * (edge.bikeClass == 3 ? 1 : 0) * (edge.bikeBlvd ? 0 : 1) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DARTNE2)) + * (edge.bikeClass != 2 && edge.bikeClass != 1 ? 1 : 0) + * ((edge.functionalClass < 4 && edge.functionalClass > 0) ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DWRONGWY)) + * (edge.bikeClass != 1 ? 1 : 0) * (edge.lanes == 0 ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DCYCTRAC)) + * (edge.cycleTrack ? 1 : 0) + Double.parseDouble(propertyMap + .get(PROPERTIES_COEF_DBIKBLVD)) * (edge.bikeBlvd ? 1 : 0)) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_GAIN)) * edge.gain + + INACCESSIBLE_COST_COEF + * ((edge.functionalClass < 3 && edge.functionalClass > 0) ? 1 : 0); + edge.walkCost = (double) edge.distance + * Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTANCE_WALK)) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_GAIN_WALK)) + * edge.gain; + } + + } catch (NoSuchFieldException | IllegalAccessException e) + { + logger.error("Exception caught calculating derived edge attributes.", e); + throw new RuntimeException(); + } + } + + @Override + protected void calculateDerivedTraversalAttributes( + Network network) + { + Iterator traversalIterator = network.traversalIterator(); + while (traversalIterator.hasNext()) + { + SandagBikeTraversal t = traversalIterator.next(); + t.turnType = calculateTurnType(t, network); + t.thruCentroid = t.getFromEdge().centroidConnector && t.getToEdge().centroidConnector; + boolean signalized = t.getFromEdge().getToNode().signalized; + boolean fromMajorArt = t.getFromEdge().functionalClass <= 3 + && t.getFromEdge().functionalClass > 0 && t.getFromEdge().bikeClass != 1; + boolean fromMinorArt = t.getFromEdge().functionalClass == 4 + && t.getFromEdge().bikeClass != 1; + t.signalExclRightAndThruJunction = signalized && t.turnType != TurnType.RIGHT + && !isThruJunction(t, network); + t.unsigLeftFromMajorArt = !signalized && fromMajorArt && t.turnType == TurnType.LEFT; + t.unsigLeftFromMinorArt = !signalized && fromMinorArt && t.turnType == TurnType.LEFT; + t.unsigCrossMajorArt = !signalized && isCrossingOfMajorArterial(t, network); + t.unsigCrossMinorArt = !signalized && isCrossingOfMinorArterial(t, network); + t.cost = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_TURN)) + * ((t.turnType != TurnType.NONE) ? 1 : 0) + INACCESSIBLE_COST_COEF + * (t.thruCentroid ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_SIGNALS)) + * (t.signalExclRightAndThruJunction ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_UNLFRMA)) + * (t.unsigLeftFromMajorArt ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_UNLFRMI)) + * (t.unsigLeftFromMinorArt ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_UNTOMA)) + * (t.unsigCrossMajorArt ? 1 : 0) + + Double.parseDouble(propertyMap.get(PROPERTIES_COEF_UNTOMI)) + * (t.unsigCrossMinorArt ? 1 : 0); + } + } + + private boolean isCrossingOfMajorArterial(SandagBikeTraversal t, + Network network) + { + SandagBikeNode startNode = t.getFromEdge().getFromNode(); + SandagBikeNode thruNode = t.getFromEdge().getToNode(); + SandagBikeNode endNode = t.getToEdge().getToNode(); + + if (startNode.centroid || thruNode.centroid || endNode.centroid) + { + return false; + } + + SandagBikeEdge edge = t.getToEdge(); + if (t.turnType == TurnType.LEFT && edge.functionalClass <= 3 && edge.functionalClass > 0 + && edge.bikeClass != 1) + { + return true; + } + + if (t.turnType != TurnType.NONE) + { + return false; + } + + int majorArtCount = 0; + for (SandagBikeNode successor : network.getSuccessors(thruNode)) + { + edge = network.getEdge(thruNode, successor); + boolean majorArt = edge.functionalClass <= 3 && edge.functionalClass > 0 + && edge.bikeClass != 1; + if (majorArt && (!(successor.equals(startNode))) && (!(successor.equals(endNode)))) + { + majorArtCount += 1; + } + } + + return majorArtCount >= 2; + } + + private boolean isCrossingOfMinorArterial(SandagBikeTraversal t, + Network network) + { + if (isCrossingOfMajorArterial(t, network)) + { + return false; + } + + SandagBikeNode startNode = t.getFromEdge().getFromNode(); + SandagBikeNode thruNode = t.getFromEdge().getToNode(); + SandagBikeNode endNode = t.getToEdge().getToNode(); + + if (startNode.centroid || thruNode.centroid || endNode.centroid) + { + return false; + } + + SandagBikeEdge edge = t.getToEdge(); + if (t.turnType == TurnType.LEFT && edge.functionalClass == 4 && edge.bikeClass != 1) + { + return true; + } + + if (t.turnType != TurnType.NONE) + { + return false; + } + + int artCount = 0; + for (SandagBikeNode successor : network.getSuccessors(thruNode)) + { + edge = network.getEdge(thruNode, successor); + boolean art = edge.functionalClass <= 4 && edge.functionalClass > 0 + && edge.bikeClass != 1; + if (art && (!(successor.equals(startNode))) && (!(successor.equals(endNode)))) + { + artCount += 1; + } + } + + return artCount >= 2; + } + + private boolean isThruJunction(SandagBikeTraversal t, + Network network) + { + SandagBikeNode startNode = t.getFromEdge().getFromNode(); + SandagBikeNode thruNode = t.getFromEdge().getToNode(); + SandagBikeNode endNode = t.getToEdge().getToNode(); + + if (startNode.centroid || thruNode.centroid || endNode.centroid) + { + return false; + } + + if (t.turnType != TurnType.NONE) + { + return false; + } + + boolean rightTurnExists = false; + for (SandagBikeNode successor : network.getSuccessors(thruNode)) + { + SandagBikeTraversal traversal = network.getTraversal(t.getFromEdge(), + network.getEdge(thruNode, successor)); + if ((!(successor.equals(startNode))) && (!(successor.equals(endNode)))) + { + rightTurnExists = traversal.turnType == TurnType.NONE; + } + } + + return !rightTurnExists; + } + + private double calculateTraversalAngle(SandagBikeTraversal t) + { + float xDiff1 = t.getFromEdge().getToNode().x - t.getFromEdge().getFromNode().x; + float xDiff2 = t.getToEdge().getToNode().x - t.getToEdge().getFromNode().x; + float yDiff1 = t.getFromEdge().getToNode().y - t.getFromEdge().getFromNode().y; + float yDiff2 = t.getToEdge().getToNode().y - t.getToEdge().getFromNode().y; + + double angle = Math.atan2(yDiff2, xDiff2) - Math.atan2(yDiff1, xDiff1); + + if (angle > Math.PI) + { + angle = angle - 2 * Math.PI; + } + if (angle < -Math.PI) + { + angle = angle + 2 * Math.PI; + } + + return angle; + } + + private TurnType calculateTurnType(SandagBikeTraversal t, + Network network) + { + SandagBikeNode startNode = t.getFromEdge().getFromNode(); + SandagBikeNode thruNode = t.getFromEdge().getToNode(); + SandagBikeNode endNode = t.getToEdge().getToNode(); + + if (startNode.centroid || thruNode.centroid || endNode.centroid) + { + return TurnType.NONE; + } + + if (startNode.equals(endNode)) + { + return TurnType.REVERSAL; + } + + double thisAngle = calculateTraversalAngle(t); + + if (thisAngle < -Math.PI + TURN_ANGLE_TOLERANCE + || thisAngle > Math.PI - TURN_ANGLE_TOLERANCE) + { + return TurnType.REVERSAL; + } + + double minAngle = Math.PI; + double maxAngle = -Math.PI; + double minAbsAngle = Math.PI; + double currentAngle; + int legCount = 1; + + SandagBikeEdge startEdge = network.getEdge(startNode, thruNode); + for (SandagBikeNode successor : network.getSuccessors(thruNode)) + { + SandagBikeEdge edge = network.getEdge(thruNode, successor); + if (edge.autosPermitted && (!(successor.equals(startNode)))) + { + currentAngle = calculateTraversalAngle(network.getTraversal(startEdge, edge)); + minAngle = Math.min(minAngle, currentAngle); + maxAngle = Math.max(maxAngle, currentAngle); + minAbsAngle = Math.min(minAbsAngle, Math.abs(currentAngle)); + legCount += 1; + } + } + + if (legCount <= 2) + { + return TurnType.NONE; + } else if (legCount == 3) + { + if (thisAngle <= minAngle && Math.abs(thisAngle) > TURN_ANGLE_TOLERANCE) + { + return TurnType.RIGHT; + } else if (thisAngle >= maxAngle && Math.abs(thisAngle) > TURN_ANGLE_TOLERANCE) + { + return TurnType.LEFT; + } else + { + return TurnType.NONE; + } + } else + { + if (Math.abs(thisAngle) <= minAbsAngle + || (Math.abs(thisAngle) < TURN_ANGLE_TOLERANCE && thisAngle > minAngle && thisAngle < maxAngle)) + { + return TurnType.NONE; + } else if (thisAngle < 0) + { + return TurnType.RIGHT; + } else + { + return TurnType.LEFT; + } + } + } + + private void setNumericFieldWithCast(Object o, Field f, Number n) + { + Class c = f.getType(); + try + { + if (c.equals(Integer.class) || c.equals(Integer.TYPE)) + { + f.set(o, n.intValue()); + } else if (c.equals(Float.class) || c.equals(Float.TYPE)) + { + f.set(o, n.floatValue()); + } else if (c.equals(Double.class) || c.equals(Double.TYPE)) + { + f.set(o, n.doubleValue()); + } else if (c.equals(Boolean.class) || c.equals(Boolean.TYPE)) + { + f.set(o, n.intValue() == 1); + } else if (c.equals(Byte.class) || c.equals(Byte.TYPE)) + { + f.set(o, n.byteValue()); + } else if (c.equals(Short.class) || c.equals(Short.TYPE)) + { + f.set(o, n.shortValue()); + } else if (c.equals(Long.class) || c.equals(Long.TYPE)) + { + f.set(o, n.longValue()); + } else + { + throw new RuntimeException("Field " + f.getName() + " in class " + + o.getClass().getName() + " is not numeric"); + } + } catch (IllegalArgumentException | IllegalAccessException e) + { + logger.error("Exception caught setting class field " + f.getName() + + " for object of class " + o.getClass().getName(), e); + throw new RuntimeException(); + } + } + + private void loadNetworkData() + { + if (nodes == null) + { + nodes = readNodes(); + edges = readEdges(nodes); + } + } + + @Override + protected Collection getNodes() + { + loadNetworkData(); + return nodes; + } + + @Override + protected Collection getEdges() + { + loadNetworkData(); + return edges; + } + + @Override + protected SandagBikeTraversal getTraversal(SandagBikeEdge fromEdge, SandagBikeEdge toEdge) + { + return new SandagBikeTraversal(fromEdge, toEdge); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeNode.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeNode.java new file mode 100644 index 0000000..a25d42d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeNode.java @@ -0,0 +1,16 @@ +package org.sandag.abm.active.sandag; + +import org.sandag.abm.active.SimpleNode; + +public class SandagBikeNode + extends SimpleNode +{ + public volatile float x, y; + public volatile short mgra, taz, tap; + public volatile boolean signalized, centroid; + + public SandagBikeNode(int id) + { + super(id); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..d685c6b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathAlternativeListGenerationConfiguration.java @@ -0,0 +1,430 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Objects; +import java.util.Random; +import java.util.Set; +import org.sandag.abm.active.EdgeEvaluator; +import org.sandag.abm.active.Network; +import org.sandag.abm.active.NodePair; +import org.sandag.abm.active.ParallelSingleSourceDijkstra; +import org.sandag.abm.active.PathAlternativeListGenerationConfiguration; +import org.sandag.abm.active.RepeatedSingleSourceDijkstra; +import org.sandag.abm.active.ShortestPathResultSet; +import org.sandag.abm.active.ShortestPathStrategy; +import org.sandag.abm.active.TraversalEvaluator; + +public abstract class SandagBikePathAlternativeListGenerationConfiguration + implements + PathAlternativeListGenerationConfiguration +{ + + public static final String PROPERTIES_COEF_DISTCLA0 = "active.coef.distcla0"; + public static final String PROPERTIES_COEF_DISTCLA1 = "active.coef.distcla1"; + public static final String PROPERTIES_COEF_DISTCLA2 = "active.coef.distcla2"; + public static final String PROPERTIES_COEF_DISTCLA3 = "active.coef.distcla3"; + public static final String PROPERTIES_COEF_DARTNE2 = "active.coef.dartne2"; + public static final String PROPERTIES_COEF_DWRONGWY = "active.coef.dwrongwy"; + public static final String PROPERTIES_COEF_GAIN = "active.coef.gain"; + public static final String PROPERTIES_COEF_TURN = "active.coef.turn"; + public static final String PROPERTIES_COEF_GAIN_WALK = "active.coef.gain.walk"; + public static final String PROPERTIES_COEF_DCYCTRAC = "active.coef.dcyctrac"; + public static final String PROPERTIES_COEF_DBIKBLVD = "active.coef.dbikblvd"; + public static final String PROPERTIES_COEF_SIGNALS = "active.coef.signals"; + public static final String PROPERTIES_COEF_UNLFRMA = "active.coef.unlfrma"; + public static final String PROPERTIES_COEF_UNLFRMI = "active.coef.unlfrmi"; + public static final String PROPERTIES_COEF_UNTOMA = "active.coef.untoma"; + public static final String PROPERTIES_COEF_UNTOMI = "active.coef.untomi"; + public static final String PROPERTIES_COEF_NONSCENIC = "active.coef.nonscenic"; + public static final String PROPERTIES_BIKE_MINUTES_PER_MILE = "active.bike.minutes.per.mile"; + public static final String PROPERTIES_OUTPUT = "active.output.bike"; + private static final double INACCESSIBLE_COST_COEF = 999.0; + + protected Map propertyMap; + protected PropertyParser propertyParser; + protected final String PROPERTIES_SAMPLE_MAXCOST = "active.sample.maxcost"; + protected final String PROPERTIES_SAMPLE_RANDOM_SEEDED = "active.sample.random.seeded"; + protected final String PROPERTIES_SAMPLE_DISTANCE_BREAKS = "active.sample.distance.breaks"; + protected final String PROPERTIES_SAMPLE_PATHSIZES = "active.sample.pathsizes"; + protected final String PROPERTIES_SAMPLE_COUNT_MIN = "active.sample.count.min"; + protected final String PROPERTIES_SAMPLE_COUNT_MAX = "active.sample.count.max"; + protected final String PROPERTIES_TRACE_EXCLUSIVE = "active.trace.exclusive"; + protected final String PROPERTIES_RANDOM_SCALE_COEF = "active.sample.random.scale.coef"; + protected final String PROPERTIES_RANDOM_SCALE_LINK = "active.sample.random.scale.link"; + + protected final String PROPERTIES_TRACE_OUTPUTASSIGNMENTPATHS = "active.trace.outputassignmentpaths"; + + protected double PROPERTIES_MAXDIST_ZONE; + protected String PROPERTIES_TRACE_ORIGINS; + + protected Map> nearbyZonalDistanceMap; + protected Map zonalCentroidIdMap; + protected Network network; + private final double bikeMinutesPerMile; + + public SandagBikePathAlternativeListGenerationConfiguration(Map propertyMap, + Network network) + { + this.propertyMap = propertyMap; + this.propertyParser = new PropertyParser(propertyMap); + this.nearbyZonalDistanceMap = null; + this.zonalCentroidIdMap = null; + this.network = network; + bikeMinutesPerMile = Double.parseDouble(propertyMap.get(PROPERTIES_BIKE_MINUTES_PER_MILE)); + } + + public Set getTraceOrigins() + { + return propertyMap.containsKey(PROPERTIES_TRACE_ORIGINS) ? new HashSet<>( + propertyParser.parseIntPropertyList(PROPERTIES_TRACE_ORIGINS)) + : new HashSet(); + } + + @Override + public Network getNetwork() + { + return network; + } + + public String getOutputDirectory() + { + return propertyMap.get(PROPERTIES_OUTPUT); + } + + static class SandagBikeDistanceEvaluator + implements EdgeEvaluator + { + public double evaluate(SandagBikeEdge edge) + { + return edge.distance; + } + } + + static class SandagBikeAccessibleDistanceEvaluator + implements EdgeEvaluator + { + public double evaluate(SandagBikeEdge edge) + { + return edge.distance + (edge.bikeCost > 998 ? 999 : 0); + } + } + + static class ZeroTraversalEvaluator + implements TraversalEvaluator + { + public double evaluate(SandagBikeTraversal traversal) + { + return 999 * (traversal.thruCentroid ? 1 : 0); + } + } + + @Override + public EdgeEvaluator getEdgeLengthEvaluator() + { + return new SandagBikeDistanceEvaluator(); + } + + @Override + public EdgeEvaluator getEdgeCostEvaluator() + { + final class SandagBikeEdgeCostEvaluator + implements EdgeEvaluator + { + public double evaluate(SandagBikeEdge edge) + { + return edge.bikeCost; + } + } + + return new SandagBikeEdgeCostEvaluator(); + } + + @Override + public TraversalEvaluator getTraversalCostEvaluator() + { + final class SandagBikeTraversalCostEvaluator + implements TraversalEvaluator + { + public double evaluate(SandagBikeTraversal traversal) + { + return traversal.cost; + } + } + + return new SandagBikeTraversalCostEvaluator(); + } + + @Override + public double getMaxCost() + { + return Double.parseDouble(propertyMap.get(PROPERTIES_SAMPLE_MAXCOST)); + } + + @Override + public double getDefaultMinutesPerMile() + { + return bikeMinutesPerMile; + } + + @Override + public double[] getSampleDistanceBreaks() + { + return propertyParser.parseDoublePropertyArray(PROPERTIES_SAMPLE_DISTANCE_BREAKS); + } + + @Override + public double[] getSamplePathSizes() + { + return propertyParser.parseDoublePropertyArray(PROPERTIES_SAMPLE_PATHSIZES); + } + + @Override + public double[] getSampleMinCounts() + { + return propertyParser.parseDoublePropertyArray(PROPERTIES_SAMPLE_COUNT_MIN); + } + + @Override + public double[] getSampleMaxCounts() + { + return propertyParser.parseDoublePropertyArray(PROPERTIES_SAMPLE_COUNT_MAX); + } + + @Override + public boolean isRandomCostSeeded() + { + return Boolean.parseBoolean(propertyMap.get(PROPERTIES_SAMPLE_RANDOM_SEEDED)); + } + + @Override + public Map> getNearbyZonalDistanceMap() + { + if (nearbyZonalDistanceMap == null) + { + nearbyZonalDistanceMap = new HashMap<>(); + ShortestPathStrategy sps = new ParallelSingleSourceDijkstra( + new RepeatedSingleSourceDijkstra( + network, new SandagBikeAccessibleDistanceEvaluator(), + new ZeroTraversalEvaluator()), + ParallelSingleSourceDijkstra.ParallelMethod.QUEUE); + if (zonalCentroidIdMap == null) + { + createZonalCentroidIdMap(); + } + Set originNodes = new HashSet<>(); + Set destinationNodes = new HashSet<>(); + Map inverseOriginZonalCentroidMap = new HashMap<>(); + Map inverseDestinationZonalCentroidMap = new HashMap<>(); + SandagBikeNode n; + Map relevantOriginZonalCentroidIdMap = getOriginZonalCentroidIdMap(); + Map destinationZonalCentroidIdMap = getDestinationZonalCentroidIdMap(); + for (int zone : relevantOriginZonalCentroidIdMap.keySet()) + { + n = network.getNode(zonalCentroidIdMap.get(zone)); + originNodes.add(n); + inverseOriginZonalCentroidMap.put(n, zone); + } + for (int zone : destinationZonalCentroidIdMap.keySet()) + { + n = network.getNode(zonalCentroidIdMap.get(zone)); + destinationNodes.add(n); + inverseDestinationZonalCentroidMap.put(n, zone); + } + System.out.println("Calculating nearby Zonal Distance Map"); + ShortestPathResultSet resultSet = sps.getShortestPaths(originNodes, + destinationNodes, PROPERTIES_MAXDIST_ZONE); + int originZone, destinationZone; + for (NodePair odPair : resultSet) + { + originZone = inverseOriginZonalCentroidMap.get(odPair.getFromNode()); + destinationZone = inverseDestinationZonalCentroidMap.get(odPair.getToNode()); + if (!nearbyZonalDistanceMap.containsKey(originZone)) + { + nearbyZonalDistanceMap.put(originZone, new HashMap()); + } + nearbyZonalDistanceMap.get(originZone).put(destinationZone, + resultSet.getShortestPathResult(odPair).getCost()); + } + } + return nearbyZonalDistanceMap; + } + + @Override + public Map getOriginZonalCentroidIdMap() + { + if (zonalCentroidIdMap == null) + { + createZonalCentroidIdMap(); + } + + if (isTraceExclusive()) + { + Map m = new HashMap<>(); + for (int o : getTraceOrigins()) + { + m.put(o, zonalCentroidIdMap.get(o)); + } + return m; + } else return zonalCentroidIdMap; + } + + public Map getOriginZonalCentroidIdMapNonExclusiveOfTrace() + { + if (zonalCentroidIdMap == null) + { + createZonalCentroidIdMap(); + } + + return zonalCentroidIdMap; + } + + @Override + public Map getDestinationZonalCentroidIdMap() + { + return getOriginZonalCentroidIdMapNonExclusiveOfTrace(); + } + + @Override + public Map getPropertyMap() + { + return propertyMap; + } + + protected abstract void createZonalCentroidIdMap(); + + public Map getInverseOriginZonalCentroidIdMap() + { + HashMap newMap = new HashMap<>(); + Map origMap = getOriginZonalCentroidIdMap(); + for (Integer o : origMap.keySet()) + { + newMap.put(origMap.get(o), o); + } + return newMap; + } + + public Map getInverseDestinationZonalCentroidIdMap() + { + HashMap newMap = new HashMap<>(); + Map origMap = getDestinationZonalCentroidIdMap(); + for (Integer d : origMap.keySet()) + { + newMap.put(origMap.get(d), d); + } + return newMap; + } + + @Override + public boolean isTraceExclusive() + { + return Boolean.parseBoolean(propertyMap.get(PROPERTIES_TRACE_EXCLUSIVE)); + } + + private class RandomizedEdgeCostEvaluator + implements EdgeEvaluator + { + long seed; + Random random; + double cDistCla0, cDistCla1, cDistCla2, cDistCla3, cArtNe2, cWrongWay, cCycTrac, cBikeBlvd, + cGain, cNonScenic; + + public RandomizedEdgeCostEvaluator(long seed) + { + this.seed = seed; + + if (isRandomCostSeeded()) + { + random = new Random(seed); + } else + { + random = new Random(); + } + + cDistCla0 = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA0)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cDistCla1 = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA1)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cDistCla2 = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA2)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cDistCla3 = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DISTCLA3)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cArtNe2 = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DARTNE2)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cWrongWay = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DWRONGWY)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cCycTrac = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DCYCTRAC)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cBikeBlvd = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_DBIKBLVD)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cGain = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_GAIN)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + cNonScenic = Double.parseDouble(propertyMap.get(PROPERTIES_COEF_NONSCENIC)) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_COEF)) + * (2 * random.nextDouble() - 1)); + + } + + public double evaluate(SandagBikeEdge edge) + { + + if (isRandomCostSeeded()) + { + random = new Random(Objects.hash(seed, edge)); + } else + { + random = new Random(); + } + + return (edge.distance + * ((cDistCla0 * ((edge.bikeClass < 1 ? 1 : 0) + (edge.bikeClass > 3 ? 1 : 0)) + + cDistCla1 * (edge.bikeClass == 1 ? 1 : 0) + cDistCla2 + * (edge.bikeClass == 2 ? 1 : 0) * (edge.cycleTrack ? 0 : 1) + cDistCla3 + * (edge.bikeClass == 3 ? 1 : 0) * (edge.bikeBlvd ? 0 : 1) + cArtNe2 + * (edge.bikeClass != 2 && edge.bikeClass != 1 ? 1 : 0) + * ((edge.functionalClass < 5 && edge.functionalClass > 0) ? 1 : 0) + + cWrongWay * (edge.bikeClass != 1 ? 1 : 0) * (edge.lanes == 0 ? 1 : 0) + + cCycTrac * (edge.cycleTrack ? 1 : 0) + cBikeBlvd + * (edge.bikeBlvd ? 1 : 0)) + cNonScenic * (1-edge.scenicIndex) + ) + + cGain * edge.gain + ) + * (1 + Double.parseDouble(propertyMap.get(PROPERTIES_RANDOM_SCALE_LINK)) + * (random.nextBoolean() ? 1 : -1)) + INACCESSIBLE_COST_COEF + * ((edge.functionalClass < 3 && edge.functionalClass > 0) ? 1 : 0); + } + } + + public EdgeEvaluator getRandomizedEdgeCostEvaluator(int iter, long seed) + { + + if (iter == 1) + { + return getEdgeCostEvaluator(); + } else + { + return new RandomizedEdgeCostEvaluator(seed); + } + + } + + public boolean isIntrazonalsNeeded() + { + return true; + } + + public boolean isAssignmentPathOutputNeeded() + { + return Boolean.parseBoolean(propertyMap.get(PROPERTIES_TRACE_OUTPUTASSIGNMENTPATHS)); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathAlternatives.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathAlternatives.java new file mode 100644 index 0000000..d2d0923 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathAlternatives.java @@ -0,0 +1,207 @@ +package org.sandag.abm.active.sandag; + +import java.util.ArrayList; +import java.util.List; +import org.sandag.abm.active.Network; +import org.sandag.abm.active.PathAlternativeList; + +public class SandagBikePathAlternatives +{ + private final PathAlternativeList pathAlternativeList; + private List distance, distClass1, + distClass2, distClass3, distArtNoLane, distWrongWay, distCycTrack, distBikeBlvd, distScenic, gain, + turns, signals, unlfrma, unlfrmi, untoma, untomi, netCost; + private Network network; + + @SuppressWarnings("unchecked") + public SandagBikePathAlternatives( + PathAlternativeList pathAlternativeList) + { + this.pathAlternativeList = pathAlternativeList; + this.network = (Network) pathAlternativeList + .getNetwork(); + calcAndStoreAttributes(); + } + + private void calcAndStoreAttributes() + { + distance = new ArrayList<>(); + distClass1 = new ArrayList<>(); + distClass2 = new ArrayList<>(); + distClass3 = new ArrayList<>(); + distArtNoLane = new ArrayList<>(); + distWrongWay = new ArrayList<>(); + distCycTrack = new ArrayList<>(); + distBikeBlvd = new ArrayList<>(); + distScenic = new ArrayList<>(); + gain = new ArrayList<>(); + turns = new ArrayList<>(); + signals = new ArrayList<>(); + unlfrma = new ArrayList<>(); + unlfrmi = new ArrayList<>(); + untoma = new ArrayList<>(); + untomi = new ArrayList<>(); + netCost = new ArrayList<>(); + + for (int i = 0; i < getPathCount(); i++) + { + distance.add(0.0); + distClass1.add(0.0); + distClass2.add(0.0); + distClass3.add(0.0); + distArtNoLane.add(0.0); + distWrongWay.add(0.0); + distCycTrack.add(0.0); + distBikeBlvd.add(0.0); + distScenic.add(0.0); + gain.add(0.0); + turns.add(0.0); + signals.add(0.0); + unlfrma.add(0.0); + unlfrmi.add(0.0); + untoma.add(0.0); + untomi.add(0.0); + netCost.add(0.0); + SandagBikeNode parent = null, grandparent = null; + for (SandagBikeNode current : pathAlternativeList.get(i)) + { + if (parent != null) + { + SandagBikeEdge edge = network.getEdge(parent, current); + distance.set(i, distance.get(i) + edge.distance); + distClass1.set(i, distClass1.get(i) + edge.distance + * (edge.bikeClass == 1 ? 1 : 0)); + distClass2.set(i, distClass2.get(i) + edge.distance + * (edge.bikeClass == 2 ? 1 : 0)); + distClass3.set(i, distClass3.get(i) + edge.distance + * (edge.bikeClass == 3 ? 1 : 0)); + distArtNoLane.set(i, distArtNoLane.get(i) + edge.distance + * (edge.bikeClass != 2 && edge.bikeClass != 1 ? 1 : 0) + * ((edge.functionalClass < 4 && edge.functionalClass > 0) ? 1 : 0)); + distWrongWay.set(i, distWrongWay.get(i) + edge.distance + * (edge.bikeClass != 1 ? 1 : 0) * (edge.lanes == 0 ? 1 : 0)); + distCycTrack.set(i, distCycTrack.get(i) + edge.distance + * (edge.cycleTrack ? 1 : 0)); + distBikeBlvd.set(i, distBikeBlvd.get(i) + edge.distance + * (edge.bikeBlvd ? 1 : 0)); + distScenic.set(i, distScenic.get(i) + edge.distance + * edge.scenicIndex); + gain.set(i, gain.get(i) + edge.gain); + netCost.set(i, netCost.get(i) + edge.bikeCost); + if (grandparent != null) + { + SandagBikeEdge fromEdge = network.getEdge(grandparent, parent); + SandagBikeTraversal traversal = network.getTraversal(fromEdge, edge); + turns.set(i, turns.get(i) + (traversal.turnType != TurnType.NONE ? 1 : 0)); + signals.set(i, signals.get(i) + + (traversal.signalExclRightAndThruJunction ? 1 : 0)); + unlfrma.set(i, unlfrma.get(i) + (traversal.unsigLeftFromMajorArt ? 1 : 0)); + unlfrmi.set(i, unlfrmi.get(i) + (traversal.unsigLeftFromMinorArt ? 1 : 0)); + untoma.set(i, untoma.get(i) + (traversal.unsigCrossMajorArt ? 1 : 0)); + untomi.set(i, untomi.get(i) + (traversal.unsigCrossMinorArt ? 1 : 0)); + netCost.set(i, netCost.get(i) + traversal.cost); + } + } + grandparent = parent; + parent = current; + } + } + } + + public double getSizeAlt(int path) + { + return pathAlternativeList.getSizeMeasures().get(path) + / pathAlternativeList.getSizeMeasureTotal(); + } + + public double getDistanceAlt(int path) + { + return distance.get(path); + } + + public double getDistanceClass1Alt(int path) + { + return distClass1.get(path); + } + + public double getDistanceClass2Alt(int path) + { + return distClass2.get(path); + } + + public double getDistanceClass3Alt(int path) + { + return distClass3.get(path); + } + + public double getDistanceArtNoLaneAlt(int path) + { + return distArtNoLane.get(path); + } + + public double getDistanceCycleTrackAlt(int path) + { + return distCycTrack.get(path); + } + + public double getDistanceBikeBlvdAlt(int path) + { + return distBikeBlvd.get(path); + } + + public double getDistanceWrongWayAlt(int path) + { + return distWrongWay.get(path); + } + + public double getDistanceScenicAlt(int path) + { + return distScenic.get(path); + } + + public double getGainAlt(int path) + { + return gain.get(path); + } + + public double getTurnsAlt(int path) + { + return turns.get(path); + } + + public double getSignalsAlt(int path) + { + return signals.get(path); + } + + public double getUnsigLeftFromMajorArtAlt(int path) + { + return unlfrma.get(path); + } + + public double getUnsigLeftFromMinorArtAlt(int path) + { + return unlfrmi.get(path); + } + + public double getUnsigCrossMajorArtAlt(int path) + { + return untoma.get(path); + } + + public double getUnsigCrossMinorArtAlt(int path) + { + return untomi.get(path); + } + + public int getPathCount() + { + return pathAlternativeList.getCount(); + } + + public double getNetworkCostAlt(int path) + { + return netCost.get(path); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceDmu.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceDmu.java new file mode 100644 index 0000000..ce01a7d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceDmu.java @@ -0,0 +1,300 @@ +package org.sandag.abm.active.sandag; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class SandagBikePathChoiceDmu + implements VariableTable, Serializable +{ + + private final transient Logger logger = Logger.getLogger(SandagBikePathChoiceDmu.class); + + protected final Map methodIndexMap; + private final IndexValues dmuIndex; + + private int personIsFemale; + private int isInboundTrip; + private int tourPurpose; + private SandagBikePathAlternatives paths; + private int pathCount = 0; + + public SandagBikePathChoiceDmu() + { + methodIndexMap = new HashMap<>(); + dmuIndex = new IndexValues(); + setupMethodIndexMap(); + } + + // not needed right now + // public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, + // int destIndex, boolean debug) { + // dmuIndex.setHHIndex(hhIndex); + // dmuIndex.setZoneIndex(zoneIndex); + // dmuIndex.setOriginZone(origIndex); + // dmuIndex.setDestZone(destIndex); + // + // dmuIndex.setDebug(false); + // dmuIndex.setDebugLabel(""); + // if (debug) { + // dmuIndex.setDebug(true); + // dmuIndex.setDebugLabel("Debug Path Choice UEC"); + // } + // + // } + + public void setPersonIsFemale(boolean isFemale) + { + personIsFemale = isFemale ? 1 : 0; + } + + public void setIsInboundTrip(boolean isInboundTrip) + { + this.isInboundTrip = isInboundTrip ? 1 : 0; + } + + public void setTourPurpose(int tourPurpose) + { + this.tourPurpose = tourPurpose; + } + + public void setPathAlternatives(SandagBikePathAlternatives paths) + { + this.paths = paths; + pathCount = paths.getPathCount(); + } + + public SandagBikePathAlternatives getPathAlternatives() + { + return paths; + } + + public int getFemale() + { + return personIsFemale; + } + + public int getInbound() + { + return isInboundTrip; + } + + public int getTourPurpose() + { + return tourPurpose; + } + + public double getSizeAlt(int path) + { + return paths.getSizeAlt(path - 1); + } + + public double getDistanceAlt(int path) + { + return paths.getDistanceAlt(path - 1); + } + + public double getDistanceClass1Alt(int path) + { + return paths.getDistanceClass1Alt(path - 1); + } + + public double getDistanceClass2Alt(int path) + { + return paths.getDistanceClass2Alt(path - 1); + } + + public double getDistanceClass3Alt(int path) + { + return paths.getDistanceClass3Alt(path - 1); + } + + public double getDistanceArtNoLaneAlt(int path) + { + return paths.getDistanceArtNoLaneAlt(path - 1); + } + + public double getDistanceCycleTrackAlt(int path) + { + return paths.getDistanceCycleTrackAlt(path - 1); + } + + public double getDistanceBikeBlvdAlt(int path) + { + return paths.getDistanceBikeBlvdAlt(path - 1); + } + + public double getDistanceWrongWayAlt(int path) + { + return paths.getDistanceWrongWayAlt(path - 1); + } + + public double getDistanceScenicAlt(int path) + { + return paths.getDistanceScenicAlt(path - 1); + } + + public double getGainAlt(int path) + { + return paths.getGainAlt(path - 1); + } + + public double getTurnsAlt(int path) + { + return paths.getTurnsAlt(path - 1); + } + + public double getSignalsAlt(int path) + { + return paths.getSignalsAlt(path - 1); + } + + public double getUnsigLeftFromMajorArtAlt(int path) + { + return paths.getUnsigLeftFromMajorArtAlt(path - 1); + } + + public double getUnsigLeftFromMinorArtAlt(int path) + { + return paths.getUnsigLeftFromMinorArtAlt(path - 1); + } + + public double getUnsigCrossMajorArtAlt(int path) + { + return paths.getUnsigCrossMajorArtAlt(path - 1); + } + + public double getUnsigCrossMinorArtAlt(int path) + { + return paths.getUnsigCrossMinorArtAlt(path - 1); + } + + public double getNetworkCostAlt(int path) + { + return paths.getNetworkCostAlt(path - 1); + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + @Override + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + @Override + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + @Override + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + @Override + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + @Override + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + + private void setupMethodIndexMap() + { + methodIndexMap.clear(); + + methodIndexMap.put("getSizeAlt", 0); + methodIndexMap.put("getDistanceAlt", 1); + methodIndexMap.put("getDistanceClass1Alt", 2); + methodIndexMap.put("getDistanceClass2Alt", 3); + methodIndexMap.put("getDistanceClass3Alt", 4); + methodIndexMap.put("getDistanceArtNoLaneAlt", 5); + methodIndexMap.put("getDistanceCycleTrackAlt", 6); + methodIndexMap.put("getDistanceBikeBlvdAlt", 7); + methodIndexMap.put("getDistanceWrongWayAlt", 8); + methodIndexMap.put("getGainAlt", 9); + methodIndexMap.put("getTurnsAlt", 10); + + methodIndexMap.put("getFemale", 11); + methodIndexMap.put("getInbound", 12); + methodIndexMap.put("getTourPurpose", 13); + + methodIndexMap.put("getSignalsAlt", 14); + methodIndexMap.put("getUnsigLeftFromMajorArtAlt", 15); + methodIndexMap.put("getUnsigLeftFromMinorArtAlt", 16); + methodIndexMap.put("getUnsigCrossMajorArtAlt", 17); + methodIndexMap.put("getUnsigCrossMinorArtAlt", 18); + methodIndexMap.put("getNetworkCostAlt", 19); + methodIndexMap.put("getDistanceScenicAlt", 20); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + switch (variableIndex) + { + case 0: + return getSizeAlt(arrayIndex); + case 1: + return getDistanceAlt(arrayIndex); + case 2: + return getDistanceClass1Alt(arrayIndex); + case 3: + return getDistanceClass2Alt(arrayIndex); + case 4: + return getDistanceClass3Alt(arrayIndex); + case 5: + return getDistanceArtNoLaneAlt(arrayIndex); + case 6: + return getDistanceCycleTrackAlt(arrayIndex); + case 7: + return getDistanceBikeBlvdAlt(arrayIndex); + case 8: + return getDistanceWrongWayAlt(arrayIndex); + case 9: + return getGainAlt(arrayIndex); + case 10: + return getTurnsAlt(arrayIndex); + case 11: + return getFemale(); + case 12: + return getInbound(); + case 13: + return getTourPurpose(); + case 14: + return getSignalsAlt(arrayIndex); + case 15: + return getUnsigLeftFromMajorArtAlt(arrayIndex); + case 16: + return getUnsigLeftFromMinorArtAlt(arrayIndex); + case 17: + return getUnsigCrossMajorArtAlt(arrayIndex); + case 18: + return getUnsigCrossMinorArtAlt(arrayIndex); + case 19: + return getNetworkCostAlt(arrayIndex); + case 20: + return getDistanceScenicAlt(arrayIndex); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceEdgeAssignmentApplication.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceEdgeAssignmentApplication.java new file mode 100644 index 0000000..0e41082 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceEdgeAssignmentApplication.java @@ -0,0 +1,281 @@ +package org.sandag.abm.active.sandag; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.concurrent.ConcurrentHashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.active.AbstractPathChoiceEdgeAssignmentApplication; +import org.sandag.abm.active.Network; +import org.sandag.abm.active.PathAlternativeList; +import org.sandag.abm.ctramp.Stop; +import org.sandag.abm.ctramp.Tour; +import com.pb.common.util.ResourceUtil; + +public class SandagBikePathChoiceEdgeAssignmentApplication + extends + AbstractPathChoiceEdgeAssignmentApplication +{ + private static final Logger logger = Logger.getLogger(SandagBikePathChoiceEdgeAssignmentApplication.class); + private static final String BIKE_ASSIGNMENT_FILE_PROPERTY = "active.assignment.file.bike"; + + List stops; + final static String[] TIME_PERIOD_LABELS = {"EA", "AM", + "MD", "PM", "EV" }; + final static double[] TIME_PERIOD_BREAKS = {3, 9, 22, 29, + 99 }; + + private ThreadLocal model; + private Map storedPathData; + + private class PathData { + PathAlternativeList pal; + int tripNum; + int householdId; + int tourId; + int stopId; + int inbound; + double[] probs; + + public PathData(PathAlternativeList pal, int tripNum, + int householdId, int tourId, int stopId, int inbound, double[] probs) + { + this.pal = pal; + this.tripNum = tripNum; + this.householdId = householdId; + this.tourId = tourId; + this.stopId = stopId; + this.inbound = inbound; + this.probs = probs; + } + } + + SandagBikePathAlternativeListGenerationConfiguration configuration; + + public SandagBikePathChoiceEdgeAssignmentApplication( + SandagBikePathAlternativeListGenerationConfiguration configuration, + List stops, final Map propertyMap) + { + super(configuration); + this.stops = stops; + model = new ThreadLocal() + { + @Override + protected SandagBikePathChoiceModel initialValue() + { + return new SandagBikePathChoiceModel((HashMap) propertyMap); + } + }; + storedPathData = new ConcurrentHashMap<>(); + this.configuration = configuration; + } + + @Override + protected Map assignTrip(int tripNum, + PathAlternativeList alternativeList) + { + Stop stop = stops.get(tripNum); + Tour tour = stop.getTour(); + SandagBikePathAlternatives paths = new SandagBikePathAlternatives(alternativeList); + double[] probs = model.get().getPathProbabilities(tour.getPersonObject(), paths, + stop.isInboundStop(), tour, false); + double numPersons = 1; + if (tour.getPersonNumArray() != null && tour.getPersonNumArray().length > 1) + { + numPersons = tour.getPersonNumArray().length; + } + int periodIdx = findFirstIndexGreaterThan((double) stop.getStopPeriod(), TIME_PERIOD_BREAKS); + + Map volumes = new HashMap<>(); + for (int pathIdx = 0; pathIdx < probs.length; pathIdx++) + { + SandagBikeNode parent = null; + for (SandagBikeNode node : alternativeList.get(pathIdx)) + { + if (parent != null) + { + SandagBikeEdge edge = network.getEdge(parent, node); + double[] values; + if (volumes.containsKey(edge)) + { + values = volumes.get(edge); + } else + { + values = new double[TIME_PERIOD_BREAKS.length]; + Arrays.fill(values, 0.0); + } + values[periodIdx] += probs[pathIdx] * numPersons; + volumes.put(edge, values); + } + parent = node; + } + } + + if ( this.configuration.isAssignmentPathOutputNeeded() ) { + PathData pd = new PathData(alternativeList,tripNum,tour.getHhId(),tour.getTourId(),stop.isInboundStop() ? 1 : 0,stop.getStopId(),probs); + storedPathData.put(tripNum, pd); + } + + return volumes; + } + + @Override + protected SandagBikeNode getOriginNode(int tripId) + { + return network.getNode(configuration.getOriginZonalCentroidIdMap().get( + stops.get(tripId).getOrig())); + } + + @Override + protected SandagBikeNode getDestinationNode(int tripId) + { + return network.getNode(configuration.getDestinationZonalCentroidIdMap().get( + stops.get(tripId).getDest())); + } + + public static void main(String... args) + { + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } + logger.info("loading property file: " + + ClassLoader.getSystemClassLoader().getResource(args[0] + ".properties").getFile() + .toString()); + + if (args.length < 2) + { + logger.error(String.format("no sample rate was specified as an argument.")); + return; + } + double sampleRate = Double.parseDouble(args[1]); + + // String RESOURCE_BUNDLE_NAME = "sandag_abm_active_test"; + @SuppressWarnings("unchecked") + // this is ok - the map will be String->String + Map propertyMap = (Map) ResourceUtil + .getResourceBundleAsHashMap(args[0]); + DecimalFormat formatter = new DecimalFormat("#.###"); + + SandagBikeNetworkFactory factory = new SandagBikeNetworkFactory(propertyMap); + Network network = factory + .createNetwork(); + + SandagBikePathAlternativeListGenerationConfiguration configuration = new SandagBikeMgraPathAlternativeListGenerationConfiguration( + propertyMap, network); + + BikeAssignmentTripReader reader; + if (args.length >= 3) + { + reader = new BikeAssignmentTripReader(propertyMap, Integer.parseInt(args[2])); + } else + { + reader = new BikeAssignmentTripReader(propertyMap); + } + + List stops = reader.createTripList(); + + Path outputDirectory = Paths.get(configuration.getOutputDirectory()); + Path outputFile = outputDirectory.resolve(propertyMap.get(BIKE_ASSIGNMENT_FILE_PROPERTY)); + SandagBikePathChoiceEdgeAssignmentApplication application = new SandagBikePathChoiceEdgeAssignmentApplication( + configuration, stops, propertyMap); + + List relevantTripNums = new ArrayList<>(); + for (int i = 0; i < stops.size(); i++) + relevantTripNums.add(i); + + Map volumes = application.assignTrips(relevantTripNums); + + try + { + Files.createDirectories(outputDirectory); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + try (PrintWriter writer = new PrintWriter(outputFile.toFile())) + { + StringBuilder sb = new StringBuilder("roadsegid,from,to"); + for (String segment : TIME_PERIOD_LABELS) + sb.append(",").append(segment); + writer.println(sb.toString()); + Iterator edgeIterator = network.edgeIterator(); + while (edgeIterator.hasNext()) + { + SandagBikeEdge edge = edgeIterator.next(); + sb = new StringBuilder(); + sb.append(edge.roadsegid).append(",").append(edge.getFromNode().getId()).append(",").append(edge.getToNode().getId()); + if (volumes.containsKey(edge)) + { + for (double value : volumes.get(edge)) + sb.append(",").append(formatter.format(value / sampleRate)); + } else + { + for (int i = 0; i < TIME_PERIOD_BREAKS.length; i++) + sb.append(",").append(formatter.format(0.0)); + } + writer.println(sb.toString()); + } + } catch (IOException e) + { + logger.fatal(e); + throw new RuntimeException(e); + } + + if ( configuration.isAssignmentPathOutputNeeded() ) { + + Path probFile = outputDirectory.resolve("bikeAssignmentDisaggregatePathProbabilities.csv"); + + try (PrintWriter writer = new PrintWriter(probFile.toFile())) + { + writer.println("tripid,hhid,tourid,stopid,inbound,pathid,prob"); + for (PathData pd : application.storedPathData.values()) { + for (int i=0;i +{ + private static final Logger logger = Logger.getLogger(SandagBikePathChoiceLogsumMatrixApplication.class); + + public static final String PROPERTIES_DEBUG_ORIGIN = "active.debug.origin"; + public static final String PROPERTIES_DEBUG_DESTINATION = "active.debug.destination"; + public static final String PROPERTIES_WRITE_DERIVED_BIKE_NETWORK = "active.bike.write.derived.network"; + public static final String PROPERTIES_DERIVED_NETWORK_EDGES_FILE = "active.bike.derived.network.edges"; + public static final String PROPERTIES_DERIVED_NETWORK_NODES_FILE = "active.bike.derived.network.nodes"; + public static final String PROPERTIES_DERIVED_NETWORK_TRAVERSALS_FILE = "active.bike.derived.network.traversals"; + + private static final String[] MARKET_SEGMENT_NAMES = {"logsum"}; + private static final int[] MARKET_SEGMENT_GENDER_VALUES = {1}; + private static final int[] MARKET_SEGMENT_TOUR_PURPOSE_INDICES = {1}; + private static final boolean[] MARKET_SEGMENT_INBOUND_TRIP_VALUES = {false}; + + private ThreadLocal model; + private Person[] persons; + private Tour[] tours; + private final boolean runDebug; + private final int debugOrigin; + private final int debugDestination; + + public SandagBikePathChoiceLogsumMatrixApplication( + PathAlternativeListGenerationConfiguration configuration, + final Map propertyMap) + { + super(configuration); + model = new ThreadLocal() + { + @Override + protected SandagBikePathChoiceModel initialValue() + { + return new SandagBikePathChoiceModel((HashMap) propertyMap); + } + }; + persons = new Person[MARKET_SEGMENT_NAMES.length]; + tours = new Tour[MARKET_SEGMENT_NAMES.length]; + + // for dummy person + SandagModelStructure modelStructure = new SandagModelStructure(); + for (int i = 0; i < MARKET_SEGMENT_NAMES.length; i++) + { + persons[i] = new Person(null, 1, modelStructure); + persons[i].setPersGender(MARKET_SEGMENT_GENDER_VALUES[i]); + tours[i] = new Tour(persons[i], 1, MARKET_SEGMENT_TOUR_PURPOSE_INDICES[i]); + } + + debugOrigin = propertyMap.containsKey(PROPERTIES_DEBUG_ORIGIN) ? Integer + .parseInt(this.propertyMap.get(PROPERTIES_DEBUG_ORIGIN)) : -1; + debugDestination = propertyMap.containsKey(PROPERTIES_DEBUG_DESTINATION) ? Integer + .parseInt(this.propertyMap.get(PROPERTIES_DEBUG_DESTINATION)) : -1; + runDebug = (debugOrigin > 0) && (debugDestination > 0); + } + + @Override + protected double[] calculateMarketSegmentLogsums( + PathAlternativeList alternativeList) + { + SandagBikePathAlternatives alts = new SandagBikePathAlternatives(alternativeList); + double[] logsums = new double[MARKET_SEGMENT_NAMES.length + 1]; + + boolean debug = runDebug + && (alternativeList.getODPair().getFromNode().getId() == debugOrigin) + && (alternativeList.getODPair().getToNode().getId() == debugDestination); + + for (int i = 0; i < MARKET_SEGMENT_NAMES.length; i++) + logsums[i] = model.get().getPathLogsums(persons[i], alts, + MARKET_SEGMENT_INBOUND_TRIP_VALUES[i], tours[i], debug); + + double[] probs = model.get().getPathProbabilities(persons[0], alts, false, tours[0], debug); + double avgDist = 0; + for (int i = 0; i < alts.getPathCount(); i++) + avgDist += probs[i] * alts.getDistanceAlt(i); + logsums[logsums.length - 1] = avgDist * configuration.getDefaultMinutesPerMile(); + + return logsums; + } + + @Override + protected List> getMarketSegmentIntrazonalCalculations() + { + List> intrazonalCalculations = new ArrayList<>(); + IntrazonalCalculation logsumIntrazonalCalculation = IntrazonalCalculations + .maxFactorIntrazonalCalculation( + IntrazonalCalculations.positiveNegativeFactorizer(0.5, 0, 2, 0), 1); + // IntrazonalCalculations.maxFactorIntrazonalCalculation(IntrazonalCalculations.simpleFactorizer(1,Math.log(2)),1); + for (int i = 0; i < MARKET_SEGMENT_NAMES.length; i++) + intrazonalCalculations.add(logsumIntrazonalCalculation); + // do distance + intrazonalCalculations.add(IntrazonalCalculations + .minFactorIntrazonalCalculation( + IntrazonalCalculations.simpleFactorizer(0.5, 0), 1)); + return intrazonalCalculations; + } + + // these methods might be moved to the network classes... + public static void writeDerivedNetworkEdges( + Network network, Path outputFile) + { + try (PrintWriter writer = new PrintWriter(outputFile.toFile())) + { + logger.info("Writing edges with derived attributes to " + outputFile.toString()); + StringBuilder sb = new StringBuilder(); + sb.append("fromNode").append(",").append("toNode").append(",").append("bikeClass") + .append(",").append("lanes").append(",").append("functionalClass").append(",") + .append("centroidConnector").append(",").append("autosPermitted").append(",") + .append("cycleTrack").append(",").append("bikeBlvd").append(",") + .append("distance").append(",").append("gain").append(",").append("bikeCost") + .append(",").append("walkCost"); + writer.println(sb.toString()); + Iterator it = network.edgeIterator(); + while (it.hasNext()) + { + SandagBikeEdge edge = it.next(); + sb = new StringBuilder(); + sb.append(edge.getFromNode().getId()).append(",").append(edge.getToNode().getId()) + .append(",").append(edge.bikeClass).append(",").append(edge.lanes) + .append(",").append(edge.functionalClass).append(",") + .append(edge.centroidConnector).append(",").append(edge.autosPermitted) + .append(",").append(edge.cycleTrack).append(",").append(edge.bikeBlvd) + .append(",").append(edge.distance).append(",").append(edge.gain) + .append(",").append(edge.bikeCost).append(",").append(edge.walkCost); + writer.println(sb.toString()); + } + } catch (IOException e) + { + logger.fatal(e); + throw new RuntimeException(e); + } + } + + public static void writeDerivedNetworkNodes( + Network network, Path outputFile) + { + try (PrintWriter writer = new PrintWriter(outputFile.toFile())) + { + logger.info("Writing nodes with derived attributes to " + outputFile.toString()); + StringBuilder sb = new StringBuilder(); + sb.append("id").append(",").append("x").append(",").append("y").append(",") + .append("mgra").append(",").append("taz").append(",").append("tap").append(",") + .append("signalized").append(",").append("centroid"); + writer.println(sb.toString()); + Iterator it = network.nodeIterator(); + while (it.hasNext()) + { + SandagBikeNode node = it.next(); + sb = new StringBuilder(); + sb.append(node.getId()).append(",").append(node.x).append(",").append(node.y) + .append(",").append(node.mgra).append(",").append(node.taz).append(",") + .append(node.tap).append(",").append(node.signalized).append(",") + .append(node.centroid); + writer.println(sb.toString()); + } + } catch (IOException e) + { + logger.fatal(e); + throw new RuntimeException(e); + } + } + + public static void writeDerivedNetworkTraversals( + Network network, Path outputFile) + { + try (PrintWriter writer = new PrintWriter(outputFile.toFile())) + { + logger.info("Writing traversals with derived attributes to " + outputFile.toString()); + StringBuilder sb = new StringBuilder(); + sb.append("start").append(",").append("thru").append(",").append("end").append(",") + .append("turnType").append(",").append("bikecost").append(",") + .append("thruCentroid").append(",").append("signalExclRight").append(",") + .append("unlfrma").append(",").append("unlfrmi").append(",").append("unxma") + .append(",").append("unxmi"); + writer.println(sb.toString()); + Iterator it = network.traversalIterator(); + while (it.hasNext()) + { + SandagBikeTraversal traversal = it.next(); + sb = new StringBuilder(); + sb.append(traversal.getFromEdge().getFromNode().getId()).append(",") + .append(traversal.getFromEdge().getToNode().getId()).append(",") + .append(traversal.getToEdge().getToNode().getId()).append(",") + .append(traversal.turnType.getKey()).append(",").append(traversal.cost) + .append(",").append(traversal.thruCentroid).append(",") + .append(traversal.signalExclRightAndThruJunction).append(",") + .append(traversal.unsigLeftFromMajorArt).append(",") + .append(traversal.unsigLeftFromMinorArt).append(",") + .append(traversal.unsigCrossMajorArt).append(",") + .append(traversal.unsigCrossMinorArt); + writer.println(sb.toString()); + } + } catch (IOException e) + { + logger.fatal(e); + throw new RuntimeException(e); + } + } + + public static void main(String... args) + { + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } + logger.info("loading property file: " + + ClassLoader.getSystemClassLoader().getResource(args[0] + ".properties").getFile() + .toString()); + + // String RESOURCE_BUNDLE_NAME = "sandag_abm_active_test"; + @SuppressWarnings("unchecked") + // this is ok - the map will be String->String + Map propertyMap = (Map) ResourceUtil + .getResourceBundleAsHashMap(args[0]); + DecimalFormat formatter = new DecimalFormat("#.###"); + + SandagBikeNetworkFactory factory = new SandagBikeNetworkFactory(propertyMap); + Network network = factory + .createNetwork(); + + // order matters, taz first, then mgra, so use linked hash map + Map, String> configurationOutputMap = new LinkedHashMap<>(); + configurationOutputMap.put(new SandagBikeTazPathAlternativeListGenerationConfiguration( + propertyMap, network), propertyMap.get(BikeLogsum.BIKE_LOGSUM_TAZ_FILE_PROPERTY)); + configurationOutputMap.put(new SandagBikeMgraPathAlternativeListGenerationConfiguration( + propertyMap, network), propertyMap.get(BikeLogsum.BIKE_LOGSUM_MGRA_FILE_PROPERTY)); + + for (PathAlternativeListGenerationConfiguration configuration : configurationOutputMap + .keySet()) + { + Path outputDirectory = Paths.get(configuration.getOutputDirectory()); + Path outputFile = outputDirectory.resolve(configurationOutputMap.get(configuration)); + SandagBikePathChoiceLogsumMatrixApplication application = new SandagBikePathChoiceLogsumMatrixApplication( + configuration, propertyMap); + + Map origins = configuration.getInverseOriginZonalCentroidIdMap(); + Map dests = configuration.getInverseDestinationZonalCentroidIdMap(); + + try + { + Files.createDirectories(outputDirectory); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + Map, double[]> logsums = application + .calculateMarketSegmentLogsums(); + + try (PrintWriter writer = new PrintWriter(outputFile.toFile())) + { + StringBuilder sb = new StringBuilder("i,j"); + for (String segment : MARKET_SEGMENT_NAMES) + sb.append(",").append(segment); + sb.append(",time"); + writer.println(sb.toString()); + for (NodePair od : logsums.keySet()) + { + sb = new StringBuilder(); + sb.append(origins.get(od.getFromNode().getId())).append(",") + .append(dests.get(od.getToNode().getId())); + for (double value : logsums.get(od)) + sb.append(",").append(formatter.format(value)); + writer.println(sb.toString()); + } + } catch (IOException e) + { + logger.fatal(e); + throw new RuntimeException(e); + } + } + + if (Boolean.parseBoolean(propertyMap.get(PROPERTIES_WRITE_DERIVED_BIKE_NETWORK))) + { + Path outputDirectory = Paths.get(propertyMap + .get(SandagBikePathAlternativeListGenerationConfiguration.PROPERTIES_OUTPUT)); + writeDerivedNetworkEdges(network, + outputDirectory.resolve(propertyMap.get(PROPERTIES_DERIVED_NETWORK_EDGES_FILE))); + writeDerivedNetworkNodes(network, + outputDirectory.resolve(propertyMap.get(PROPERTIES_DERIVED_NETWORK_NODES_FILE))); + writeDerivedNetworkTraversals(network, outputDirectory.resolve(propertyMap + .get(PROPERTIES_DERIVED_NETWORK_TRAVERSALS_FILE))); + } + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceModel.java new file mode 100644 index 0000000..77932da --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikePathChoiceModel.java @@ -0,0 +1,134 @@ +package org.sandag.abm.active.sandag; + +import java.util.Arrays; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Tour; +import com.pb.common.newmodel.ChoiceModelApplication; + +// note this class is not thread safe! - use a ThreadLocal or something to +// isolate it amongst threads +public class SandagBikePathChoiceModel +{ + public static final String PATH_CHOICE_MODEL_UEC_SPREADSHEET_PROPERTY = "path.choice.uec.spreadsheet"; + public static final String PATH_CHOICE_MODEL_UEC_MODEL_SHEET_PROPERTY = "path.choice.uec.model.sheet"; + public static final String PATH_CHOICE_MODEL_UEC_DATA_SHEET_PROPERTY = "path.choice.uec.data.sheet"; + public static final String PATH_CHOICE_MODEL_MAX_PATH_COUNT_PROPERTY = "path.choice.max.path.count"; + + public static final String PATH_CHOICE_ALTS_ID_TOKEN_PROPERTY = "path.alts.id.token"; + public static final String PATH_CHOICE_ALTS_FILE_PROPERTY = "path.alts.file"; + public static final String PATH_CHOICE_ALTS_LINK_FILE_PROPERTY = "path.alts.link.file"; + + private static final Logger logger = Logger.getLogger(SandagBikePathChoiceModel.class); + + private final ThreadLocal model; + private final ThreadLocal dmu; + private final int maxPathCount; + private final ThreadLocal pathAltsAvailable; + private final ThreadLocal pathAltsSample; + + public SandagBikePathChoiceModel(final HashMap propertyMap) + { + final String uecSpreadsheet = propertyMap.get(PATH_CHOICE_MODEL_UEC_SPREADSHEET_PROPERTY); + final int modelSheet = Integer.parseInt(propertyMap + .get(PATH_CHOICE_MODEL_UEC_MODEL_SHEET_PROPERTY)); + final int dataSheet = Integer.parseInt(propertyMap + .get(PATH_CHOICE_MODEL_UEC_DATA_SHEET_PROPERTY)); + + dmu = new ThreadLocal() + { + @Override + protected SandagBikePathChoiceDmu initialValue() + { + return new SandagBikePathChoiceDmu(); + } + }; + model = new ThreadLocal() + { + @Override + protected ChoiceModelApplication initialValue() + { + return new ChoiceModelApplication(uecSpreadsheet, modelSheet, dataSheet, + propertyMap, dmu.get()); + } + }; + + maxPathCount = Integer.parseInt(propertyMap.get(PATH_CHOICE_MODEL_MAX_PATH_COUNT_PROPERTY)); + pathAltsAvailable = new ThreadLocal() + { + @Override + protected boolean[] initialValue() + { + return new boolean[maxPathCount + 1]; + } + }; + pathAltsSample = new ThreadLocal() + { + @Override + protected int[] initialValue() + { + return new int[maxPathCount + 1]; + } + }; + } + + public double[] getPathProbabilities(Person person, SandagBikePathAlternatives paths, + boolean inboundTrip, Tour tour, boolean debug) + { + applyPathChoiceModel(person, paths, inboundTrip, tour); + double[] probabilities = Arrays + .copyOf(model.get().getProbabilities(), paths.getPathCount()); + if (debug) debugPathChoiceModel(person, paths, inboundTrip, tour, probabilities); + return probabilities; + + } + + public double getPathLogsums(Person person, SandagBikePathAlternatives paths, + boolean inboundTrip, Tour tour, boolean debug) + { + applyPathChoiceModel(person, paths, inboundTrip, tour); + if (debug) + { + model.get().logUECResults(logger); + logger.info("logsum: " + model.get().getLogsum()); + } + return model.get().getLogsum(); + } + + private void applyPathChoiceModel(Person person, SandagBikePathAlternatives paths, + boolean inboundTrip, Tour tour) + { + SandagBikePathChoiceDmu dmu = this.dmu.get(); + dmu.setPersonIsFemale(person.getPersonIsFemale() == 1); + dmu.setTourPurpose(tour.getTourPrimaryPurposeIndex()); + dmu.setIsInboundTrip(inboundTrip); + dmu.setPathAlternatives(paths); + + boolean[] pathAltsAvailable = this.pathAltsAvailable.get(); + int[] pathAltsSample = this.pathAltsSample.get(); + Arrays.fill(pathAltsAvailable, false); + Arrays.fill(pathAltsSample, 0); + + for (int i = 1; i <= paths.getPathCount(); i++) + { + pathAltsAvailable[i] = true; + pathAltsSample[i] = 1; + } + + model.get().computeUtilities(dmu, dmu.getDmuIndexValues(), pathAltsAvailable, + pathAltsSample); + } + + private void debugPathChoiceModel(Person person, SandagBikePathAlternatives paths, + boolean inboundTrip, Tour tour, double[] probabilities) + { + // want: person id, tour id, inbound trip, path count, path + // probabilities + logger.info(String + .format("debug of path choice model for person id %s, tour id %s, inbound trip: %s, path alternative count: %s", + person.getPersonId(), tour.getTourId(), inboundTrip, paths.getPathCount())); + logger.info(" path probabilities: " + Arrays.toString(probabilities)); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeTazPathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeTazPathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..0eaef70 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeTazPathAlternativeListGenerationConfiguration.java @@ -0,0 +1,35 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.sandag.abm.active.Network; + +public class SandagBikeTazPathAlternativeListGenerationConfiguration + extends SandagBikePathAlternativeListGenerationConfiguration +{ + + public SandagBikeTazPathAlternativeListGenerationConfiguration(Map propertyMap, + Network network) + { + super(propertyMap, network); + this.PROPERTIES_MAXDIST_ZONE = Double.parseDouble(propertyMap.get("active.maxdist.bike.taz")); + this.PROPERTIES_TRACE_ORIGINS = "active.trace.origins.taz"; + } + + protected void createZonalCentroidIdMap() + { + zonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.taz > 0) + { + zonalCentroidIdMap.put((int) n.taz, n.getId()); + } + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeTraversal.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeTraversal.java new file mode 100644 index 0000000..d29c38b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagBikeTraversal.java @@ -0,0 +1,22 @@ +package org.sandag.abm.active.sandag; + +import org.sandag.abm.active.SimpleTraversal; + +public class SandagBikeTraversal + extends SimpleTraversal +{ + public volatile TurnType turnType; + public volatile double cost; + public volatile boolean thruCentroid, signalExclRightAndThruJunction, unsigLeftFromMajorArt, + unsigLeftFromMinorArt, unsigCrossMajorArt, unsigCrossMinorArt; + + public SandagBikeTraversal(SandagBikeEdge fromEdge, SandagBikeEdge toEdge) + { + super(fromEdge, toEdge); + } + + public SandagBikeTraversal(SandagBikeEdge edge) + { + super(null, edge); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkMgraMgraPathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkMgraMgraPathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..a9c7992 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkMgraMgraPathAlternativeListGenerationConfiguration.java @@ -0,0 +1,62 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.sandag.abm.active.Network; + +public class SandagWalkMgraMgraPathAlternativeListGenerationConfiguration + extends SandagWalkPathAlternativeListGenerationConfiguration +{ + + public SandagWalkMgraMgraPathAlternativeListGenerationConfiguration( + Map propertyMap, + Network network) + { + super(propertyMap, network); + this.PROPERTIES_MAXDIST_ZONE = Math.max( + Math.max( + Double.parseDouble(propertyMap.get("active.maxdist.walk.mgra")), + Double.parseDouble(propertyMap.get("active.maxdist.micromobility.mgra"))), + Double.parseDouble(propertyMap.get("active.maxdist.microtransit.mgra"))); + this.PROPERTIES_TRACE_ORIGINS = "active.trace.origins.mgra"; + } + + protected void createOriginZonalCentroidIdMap() + { + System.out.println("Creating MGRA Origin Zonal Centroid Id Map..."); + originZonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.mgra > 0) + { + originZonalCentroidIdMap.put((int) n.mgra, n.getId()); + } + } + } + + protected void createDestinationZonalCentroidIdMap() + { + System.out.println("Creating MGRA Destination Zonal Centroid Id Map..."); + destinationZonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.mgra > 0) + { + destinationZonalCentroidIdMap.put((int) n.mgra, n.getId()); + } + } + } + + public boolean isIntrazonalsNeeded() + { + return true; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkMgraTapPathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkMgraTapPathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..ee27177 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkMgraTapPathAlternativeListGenerationConfiguration.java @@ -0,0 +1,62 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.sandag.abm.active.Network; + +public class SandagWalkMgraTapPathAlternativeListGenerationConfiguration + extends SandagWalkPathAlternativeListGenerationConfiguration +{ + + public SandagWalkMgraTapPathAlternativeListGenerationConfiguration( + Map propertyMap, + Network network) + { + super(propertyMap, network); + this.PROPERTIES_MAXDIST_ZONE = Math.max( + Math.max( + Double.parseDouble(propertyMap.get("active.maxdist.walk.tap")), + Double.parseDouble(propertyMap.get("active.maxdist.micromobility.tap"))), + Double.parseDouble(propertyMap.get("active.maxdist.microtransit.tap"))); + this.PROPERTIES_TRACE_ORIGINS = "active.trace.origins.mgra"; + } + + protected void createOriginZonalCentroidIdMap() + { + System.out.println("Creating MGRA Origin Zonal Centroid Id Map..."); + originZonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.mgra > 0) + { + originZonalCentroidIdMap.put((int) n.mgra, n.getId()); + } + } + } + + protected void createDestinationZonalCentroidIdMap() + { + System.out.println("Creating TAP Destination Zonal Centroid Id Map..."); + destinationZonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.tap > 0) + { + destinationZonalCentroidIdMap.put((int) n.tap, n.getId()); + } + } + } + + public boolean isIntrazonalsNeeded() + { + return false; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkPathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkPathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..14fa304 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkPathAlternativeListGenerationConfiguration.java @@ -0,0 +1,310 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.sandag.abm.active.EdgeEvaluator; +import org.sandag.abm.active.Network; +import org.sandag.abm.active.NodePair; +import org.sandag.abm.active.ParallelSingleSourceDijkstra; +import org.sandag.abm.active.PathAlternativeListGenerationConfiguration; +import org.sandag.abm.active.RepeatedSingleSourceDijkstra; +import org.sandag.abm.active.ShortestPathResultSet; +import org.sandag.abm.active.ShortestPathStrategy; +import org.sandag.abm.active.TraversalEvaluator; + +public abstract class SandagWalkPathAlternativeListGenerationConfiguration + implements + PathAlternativeListGenerationConfiguration +{ + public static final String PROPERTIES_SAMPLE_MAXCOST = "active.sample.maxcost"; + public static final String PROPERTIES_OUTPUT = "active.output.walk"; + public static final String PROPERTIES_TRACE_EXCLUSIVE = "active.trace.exclusive"; + public static final String PROPERTIES_WALK_MINUTES_PER_MILE = "active.walk.minutes.per.mile"; + + protected Map propertyMap; + protected PropertyParser propertyParser; + + protected double PROPERTIES_MAXDIST_ZONE; + protected String PROPERTIES_TRACE_ORIGINS; + + protected Map> nearbyZonalDistanceMap; + protected Map originZonalCentroidIdMap; + protected Map destinationZonalCentroidIdMap; + protected Network network; + private final double walkMinutesPerMile; + + public SandagWalkPathAlternativeListGenerationConfiguration(Map propertyMap, + Network network) + { + this.propertyMap = propertyMap; + this.propertyParser = new PropertyParser(propertyMap); + this.nearbyZonalDistanceMap = null; + this.originZonalCentroidIdMap = null; + this.destinationZonalCentroidIdMap = null; + this.network = network; + walkMinutesPerMile = Double.parseDouble(propertyMap.get(PROPERTIES_WALK_MINUTES_PER_MILE)); + } + + public Set getTraceOrigins() + { + return propertyMap.containsKey(PROPERTIES_TRACE_ORIGINS) ? new HashSet<>( + propertyParser.parseIntPropertyList(PROPERTIES_TRACE_ORIGINS)) + : new HashSet(); + } + + @Override + public Network getNetwork() + { + return network; + } + + public String getOutputDirectory() + { + return propertyMap.get(PROPERTIES_OUTPUT); + } + + static class SandagBikeDistanceEvaluator + implements EdgeEvaluator + { + public double evaluate(SandagBikeEdge edge) + { + return edge.distance; + } + } + + static class SandagWalkAccessibleDistanceEvaluator + implements EdgeEvaluator + { + public double evaluate(SandagBikeEdge edge) + { + return edge.distance + (edge.walkCost > 998 ? 999 : 0); + } + } + + static class ZeroTraversalEvaluator + implements TraversalEvaluator + { + public double evaluate(SandagBikeTraversal traversal) + { + return 999 * (traversal.thruCentroid ? 1 : 0); + } + } + + @Override + public EdgeEvaluator getEdgeLengthEvaluator() + { + return new SandagBikeDistanceEvaluator(); + } + + @Override + public EdgeEvaluator getEdgeCostEvaluator() + { + final class SandagWalkEdgeCostEvaluator + implements EdgeEvaluator + { + public double evaluate(SandagBikeEdge edge) + { + return edge.walkCost; + } + } + + return new SandagWalkEdgeCostEvaluator(); + } + + @Override + public TraversalEvaluator getTraversalCostEvaluator() + { + return new ZeroTraversalEvaluator(); + } + + @Override + public double getMaxCost() + { + return Double.parseDouble(propertyMap.get(PROPERTIES_SAMPLE_MAXCOST)); + } + + @Override + public double getDefaultMinutesPerMile() + { + return walkMinutesPerMile; + } + + @Override + public double[] getSampleDistanceBreaks() + { + return new double[] {99.0}; + } + + @Override + public double[] getSamplePathSizes() + { + return new double[] {1.0}; + } + + @Override + public double[] getSampleMinCounts() + { + return new double[] {1.0}; + } + + @Override + public double[] getSampleMaxCounts() + { + return new double[] {1.0}; + } + + @Override + public boolean isRandomCostSeeded() + { + return false; + } + + @Override + public Map> getNearbyZonalDistanceMap() + { + if (nearbyZonalDistanceMap == null) + { + nearbyZonalDistanceMap = new HashMap<>(); + ShortestPathStrategy sps = new ParallelSingleSourceDijkstra( + new RepeatedSingleSourceDijkstra( + network, new SandagWalkAccessibleDistanceEvaluator(), + new ZeroTraversalEvaluator()), + ParallelSingleSourceDijkstra.ParallelMethod.QUEUE); + if (originZonalCentroidIdMap == null) + { + createOriginZonalCentroidIdMap(); + } + if (destinationZonalCentroidIdMap == null) + { + createDestinationZonalCentroidIdMap(); + } + Set originNodes = new HashSet<>(); + Set destinationNodes = new HashSet<>(); + Map inverseOriginZonalCentroidIdMap = new HashMap<>(); + Map inverseDestinationZonalCentroidIdMap = new HashMap<>(); + SandagBikeNode n; + Map relevantOriginZonalCentroidIdMap = getOriginZonalCentroidIdMap(); + for (int zone : relevantOriginZonalCentroidIdMap.keySet()) + { + n = network.getNode(originZonalCentroidIdMap.get(zone)); + originNodes.add(n); + inverseOriginZonalCentroidIdMap.put(n, zone); + } + for (int zone : destinationZonalCentroidIdMap.keySet()) + { + n = network.getNode(destinationZonalCentroidIdMap.get(zone)); + destinationNodes.add(n); + inverseDestinationZonalCentroidIdMap.put(n, zone); + } + System.out.println("Calculating nearby Zonal Distance Map"); + ShortestPathResultSet resultSet = sps.getShortestPaths(originNodes, + destinationNodes, PROPERTIES_MAXDIST_ZONE); + int originZone, destinationZone; + for (NodePair odPair : resultSet) + { + originZone = inverseOriginZonalCentroidIdMap.get(odPair.getFromNode()); + destinationZone = inverseDestinationZonalCentroidIdMap.get(odPair.getToNode()); + if (!nearbyZonalDistanceMap.containsKey(originZone)) + { + nearbyZonalDistanceMap.put(originZone, new HashMap()); + } + nearbyZonalDistanceMap.get(originZone).put(destinationZone, + resultSet.getShortestPathResult(odPair).getCost()); + } + } + return nearbyZonalDistanceMap; + } + + @Override + public Map getOriginZonalCentroidIdMap() + { + if (originZonalCentroidIdMap == null) + { + createOriginZonalCentroidIdMap(); + } + + if (isTraceExclusive()) + { + Map m = new HashMap<>(); + for (int o : getTraceOrigins()) + { + m.put(o, originZonalCentroidIdMap.get(o)); + } + return m; + } else return originZonalCentroidIdMap; + } + + public Map getOriginZonalCentroidIdMapNonExclusiveOfTrace() + { + if (originZonalCentroidIdMap == null) + { + createOriginZonalCentroidIdMap(); + } + + return originZonalCentroidIdMap; + } + + @Override + public Map getDestinationZonalCentroidIdMap() + { + if (destinationZonalCentroidIdMap == null) + { + createDestinationZonalCentroidIdMap(); + } + + return destinationZonalCentroidIdMap; + } + + @Override + public Map getPropertyMap() + { + return propertyMap; + } + + protected abstract void createOriginZonalCentroidIdMap(); + + protected abstract void createDestinationZonalCentroidIdMap(); + + public Map getInverseOriginZonalCentroidIdMap() + { + HashMap newMap = new HashMap<>(); + Map origMap = getOriginZonalCentroidIdMap(); + for (Integer o : origMap.keySet()) + { + newMap.put(origMap.get(o), o); + } + return newMap; + } + + public Map getInverseDestinationZonalCentroidIdMap() + { + HashMap newMap = new HashMap<>(); + Map origMap = getDestinationZonalCentroidIdMap(); + for (Integer o : origMap.keySet()) + { + newMap.put(origMap.get(o), o); + } + return newMap; + } + + @Override + public boolean isTraceExclusive() + { + return Boolean.parseBoolean(propertyMap.get(PROPERTIES_TRACE_EXCLUSIVE)); + } + + public EdgeEvaluator getRandomizedEdgeCostEvaluator(int iter, long seed) + { + return getEdgeCostEvaluator(); + } + + @Override + public abstract boolean isIntrazonalsNeeded(); + + public boolean isAssignmentPathOutputNeeded() + { + return false; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkPathChoiceLogsumMatrixApplication.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkPathChoiceLogsumMatrixApplication.java new file mode 100644 index 0000000..442c736 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkPathChoiceLogsumMatrixApplication.java @@ -0,0 +1,232 @@ +package org.sandag.abm.active.sandag; + +import java.io.IOException; +import java.io.PrintWriter; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.TreeSet; +import org.apache.log4j.Logger; +import org.sandag.abm.active.AbstractPathChoiceLogsumMatrixApplication; +import org.sandag.abm.active.IntrazonalCalculation; +import org.sandag.abm.active.IntrazonalCalculations; +import org.sandag.abm.active.Network; +import org.sandag.abm.active.NodePair; +import org.sandag.abm.active.PathAlternativeList; +import org.sandag.abm.active.PathAlternativeListGenerationConfiguration; +import com.pb.common.util.ResourceUtil; + +public class SandagWalkPathChoiceLogsumMatrixApplication + extends + AbstractPathChoiceLogsumMatrixApplication +{ + private static final Logger logger = Logger.getLogger(SandagWalkPathChoiceLogsumMatrixApplication.class); + + public static final String WALK_LOGSUM_SKIM_MGRA_MGRA_FILE_PROPERTY = "active.logsum.matrix.file.walk.mgra"; + public static final String WALK_LOGSUM_SKIM_MGRA_TAP_FILE_PROPERTY = "active.logsum.matrix.file.walk.mgratap"; + + private final PathAlternativeListGenerationConfiguration configuration; + + public SandagWalkPathChoiceLogsumMatrixApplication( + PathAlternativeListGenerationConfiguration configuration) + { + super(configuration); + this.configuration = configuration; + } + + @Override + protected double[] calculateMarketSegmentLogsums( + PathAlternativeList alternativeList) + { + if (alternativeList.getCount() > 1) + { + throw new UnsupportedOperationException( + "Walk logsums cannot be calculated for alternative lists containing multiple paths"); + } + + double utility = 0; + double distance = 0; + double gain = 0; + SandagBikeNode parent = null; + for (SandagBikeNode n : alternativeList.get(0)) + { + if (parent != null) + { + utility += configuration.getNetwork().getEdge(parent, n).walkCost; + distance += configuration.getNetwork().getEdge(parent, n).distance; + gain += configuration.getNetwork().getEdge(parent,n).gain; + } + parent = n; + } + + return new double[] {utility, distance * configuration.getDefaultMinutesPerMile(),gain}; + } + + @Override + protected List> getMarketSegmentIntrazonalCalculations() + { + IntrazonalCalculation intrazonalCalculation = IntrazonalCalculations + .minFactorIntrazonalCalculation( + IntrazonalCalculations.simpleFactorizer(0.5, 0), 1); + // do time then distance then gain + return Arrays.asList(intrazonalCalculation, intrazonalCalculation, intrazonalCalculation); + } + + public static void main(String... args) + { + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } + logger.info("loading property file: " + + ClassLoader.getSystemClassLoader().getResource(args[0] + ".properties").getFile() + .toString()); + + logger.info("Building walk skims"); + // String RESOURCE_BUNDLE_NAME = "sandag_abm_active_test"; + @SuppressWarnings("unchecked") + // this is ok - the map will be String->String + Map propertyMap = (Map) ResourceUtil + .getResourceBundleAsHashMap(args[0]); + + SandagBikeNetworkFactory factory = new SandagBikeNetworkFactory(propertyMap); + Network network = factory + .createNetwork(); + + DecimalFormat formatter = new DecimalFormat("#.###"); + + logger.info("Generating mgra->mgra walk skims"); + // mgra->mgra + PathAlternativeListGenerationConfiguration configuration = new SandagWalkMgraMgraPathAlternativeListGenerationConfiguration( + propertyMap, network); + SandagWalkPathChoiceLogsumMatrixApplication application = new SandagWalkPathChoiceLogsumMatrixApplication( + configuration); + Map, double[]> logsums = application + .calculateMarketSegmentLogsums(); + + Path outputDirectory = Paths.get(configuration.getOutputDirectory()); + Path outputFile = outputDirectory.resolve(propertyMap + .get(WALK_LOGSUM_SKIM_MGRA_MGRA_FILE_PROPERTY)); + + try + { + Files.createDirectories(outputDirectory); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + Map originCentroids = configuration.getInverseOriginZonalCentroidIdMap(); + Map destinationCentroids = configuration + .getInverseDestinationZonalCentroidIdMap(); + + try (PrintWriter writer = new PrintWriter(outputFile.toFile())) + { + writer.println("i,j,percieved,actual,gain"); + StringBuilder sb; + for (NodePair od : new TreeSet<>(logsums.keySet())) + { // sort them so the output "looks nice" + sb = new StringBuilder(); + sb.append(originCentroids.get(od.getFromNode().getId())).append(","); + sb.append(destinationCentroids.get(od.getToNode().getId())).append(","); + double[] values = logsums.get(od); + sb.append(formatter.format(values[0])).append(","); // percieved + // time + sb.append(formatter.format(values[1])).append(","); // actual time + sb.append(formatter.format(values[2])); //gain + writer.println(sb.toString()); + } + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("Generating mgra->tap walk skims"); + // mgra->tap + configuration = new SandagWalkMgraTapPathAlternativeListGenerationConfiguration( + propertyMap, network); + application = new SandagWalkPathChoiceLogsumMatrixApplication(configuration); + Map, double[]> mgraTapLogsums = application + .calculateMarketSegmentLogsums(); + + // for later - get from the first configuration + outputDirectory = Paths.get(configuration.getOutputDirectory()); + outputFile = outputDirectory.resolve(propertyMap + .get(WALK_LOGSUM_SKIM_MGRA_TAP_FILE_PROPERTY)); + originCentroids = configuration.getInverseOriginZonalCentroidIdMap(); + destinationCentroids = configuration.getInverseDestinationZonalCentroidIdMap(); + + // tap->mgra + configuration = new SandagWalkTapMgraPathAlternativeListGenerationConfiguration( + propertyMap, network); + application = new SandagWalkPathChoiceLogsumMatrixApplication(configuration); + Map, double[]> tapMgraLogsums = application + .calculateMarketSegmentLogsums(); + + // resolve if not a pair + int initialSize = mgraTapLogsums.size() + tapMgraLogsums.size(); + + for (NodePair mgraTapPair : mgraTapLogsums.keySet()) + { + NodePair tapMgraPair = new NodePair( + mgraTapPair.getToNode(), mgraTapPair.getFromNode()); + if (!tapMgraLogsums.containsKey(tapMgraPair)) + tapMgraLogsums.put(tapMgraPair, mgraTapLogsums.get(mgraTapPair)); + } + + for (NodePair tapMgraPair : tapMgraLogsums.keySet()) + { + NodePair mgraTapPair = new NodePair( + tapMgraPair.getToNode(), tapMgraPair.getFromNode()); + if (!mgraTapLogsums.containsKey(mgraTapPair)) + mgraTapLogsums.put(mgraTapPair, tapMgraLogsums.get(tapMgraPair)); + } + int asymmPairCount = initialSize - (mgraTapLogsums.size() + tapMgraLogsums.size()); + if (asymmPairCount > 0) + logger.info("Boarding or alighting times defaulted to transpose for " + asymmPairCount + + " mgra tap pairs with missing asymmetrical information"); + + try + { + Files.createDirectories(outputDirectory); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + try (PrintWriter writer = new PrintWriter(outputFile.toFile())) + { + writer.println("mgra,tap,boardingPerceived,boardingActual,alightingPerceived,alightingActual,boardingGain,alightingGain"); + StringBuilder sb; + for (NodePair od : new TreeSet<>(mgraTapLogsums.keySet())) + { // sort them so the output "looks nice" + sb = new StringBuilder(); + sb.append(originCentroids.get(od.getFromNode().getId())).append(","); + sb.append(destinationCentroids.get(od.getToNode().getId())).append(","); + double[] boardingValues = mgraTapLogsums.get(od); + sb.append(formatter.format(boardingValues[0])).append(","); // boarding + // percieved + sb.append(formatter.format(boardingValues[1])).append(","); // boarding + // actual + double[] alightingValues = tapMgraLogsums.get(new NodePair<>(od.getToNode(), od + .getFromNode())); + sb.append(formatter.format(alightingValues[0])).append(","); // alighting + // percieved + sb.append(formatter.format(alightingValues[1])).append(","); // alighting + // actual + sb.append(formatter.format(boardingValues[2])).append(","); // boarding gain + sb.append(formatter.format(alightingValues[2])); // alighting gain + writer.println(sb.toString()); + } + } catch (IOException e) + { + throw new RuntimeException(e); + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkTapMgraPathAlternativeListGenerationConfiguration.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkTapMgraPathAlternativeListGenerationConfiguration.java new file mode 100644 index 0000000..ead9201 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/SandagWalkTapMgraPathAlternativeListGenerationConfiguration.java @@ -0,0 +1,62 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import org.sandag.abm.active.Network; + +public class SandagWalkTapMgraPathAlternativeListGenerationConfiguration + extends SandagWalkPathAlternativeListGenerationConfiguration +{ + + public SandagWalkTapMgraPathAlternativeListGenerationConfiguration( + Map propertyMap, + Network network) + { + super(propertyMap, network); + this.PROPERTIES_MAXDIST_ZONE = Math.max( + Math.max( + Double.parseDouble(propertyMap.get("active.maxdist.walk.tap")), + Double.parseDouble(propertyMap.get("active.maxdist.micromobility.tap"))), + Double.parseDouble(propertyMap.get("active.maxdist.microtransit.tap"))); + this.PROPERTIES_TRACE_ORIGINS = "active.trace.origins.tap"; + } + + protected void createOriginZonalCentroidIdMap() + { + System.out.println("Creating TAP Zonal Centroid Id Map..."); + originZonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.tap > 0) + { + originZonalCentroidIdMap.put((int) n.tap, n.getId()); + } + } + } + + protected void createDestinationZonalCentroidIdMap() + { + System.out.println("Creating MGRA Zonal Centroid Id Map..."); + destinationZonalCentroidIdMap = new HashMap(); + Iterator nodeIterator = network.nodeIterator(); + SandagBikeNode n; + while (nodeIterator.hasNext()) + { + n = nodeIterator.next(); + if (n.mgra > 0) + { + destinationZonalCentroidIdMap.put((int) n.mgra, n.getId()); + } + } + } + + public boolean isIntrazonalsNeeded() + { + return false; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/active/sandag/TurnType.java b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/TurnType.java new file mode 100644 index 0000000..4a63681 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/active/sandag/TurnType.java @@ -0,0 +1,35 @@ +package org.sandag.abm.active.sandag; + +import java.util.HashMap; +import java.util.Map; + +public enum TurnType +{ + NONE(0), LEFT(1), RIGHT(2), REVERSAL(3); + + private int key; + private static Map map = new HashMap(); + + static + { + for (TurnType t : TurnType.values()) + { + map.put(t.key, t); + } + } + + private TurnType(final int key) + { + this.key = key; + } + + public static TurnType valueOf(int key) + { + return map.get(key); + } + + public int getKey() + { + return key; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDestChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDestChoiceModel.java new file mode 100644 index 0000000..ed1b4f1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDestChoiceModel.java @@ -0,0 +1,581 @@ +package org.sandag.abm.airport; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + +public class AirportDestChoiceModel +{ + + private double[][] sizeTerms; // by + // segment, + // tazNumber + private double[][][] mgraProbabilities; // by + // segment, + // tazNumber, + // mgra + // index + // (sequential, + // 0-based) + private double[][] tazProbabilities; // by + // segment, + // origin + // taz + // 0-based + // (note + // since + // airport + // model, + // only + // 1 + // taz + // dimension + // is + // needed) + private int[] zipCodes; // by + // taz + + private TableDataSet alternativeData; // the + // alternatives, + // with + // a + // dest + // field + // indicating + // tazNumber + + private transient Logger logger = Logger.getLogger("airportModel"); + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private ChoiceModelApplication[] destModel; + private UtilityExpressionCalculator sizeTermUEC; + private Tracer tracer; + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + private boolean seek; + private HashMap rbMap; + private TableDataSet externalDataSet; + private int externalAirportColumn; + private int tazColumn; + private int mazOutColumn; + private int mazInbColumn; + + + private int airportMgra; + private int airportTaz; + + /** + * Constructor + * + * @param propertyMap + * Resource properties file map. + * @param dmuFactory + * Factory object for creation of airport model DMUs + */ + public AirportDestChoiceModel(HashMap rbMap, AirportDmuFactoryIf dmuFactory, String airportCode) + { + + this.rbMap = rbMap; + + tazManager = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String airportDistUecFileName = Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".dc.uec.file"); + airportDistUecFileName = uecFileDirectory + airportDistUecFileName; + + int dataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".dc.data.page")); + int sizePage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".dc.size.page")); + + // read the model pages from the property file, create one choice model + // for each + destModel = new ChoiceModelApplication[AirportModelStructure.INTERNAL_PURPOSES]; + for (int i = 0; i < AirportModelStructure.INTERNAL_PURPOSES; ++i) + { + + // get page from property file + String purposeName = "airport."+airportCode+".dc.segment" + (i + 1) + ".page"; + String purposeString = Util.getStringValueFromPropertyMap(rbMap, purposeName); + purposeString.replaceAll(" ", ""); + int destModelPage = Integer.parseInt(purposeString); + + // initiate a DMU for each segment + AirportModelDMU dcDmu = dmuFactory.getAirportModelDMU(); + + // create a ChoiceModelApplication object for the filename, model + // page and data page. + destModel[i] = new ChoiceModelApplication(airportDistUecFileName, destModelPage, + dataPage, rbMap, (VariableTable) dcDmu); + } + + // get the alternative data from the first segment + UtilityExpressionCalculator uec = destModel[0].getUEC(); + alternativeData = uec.getAlternativeData(); + + // create a UEC to solve size terms for each MGRA + sizeTermUEC = new UtilityExpressionCalculator(new File(airportDistUecFileName), sizePage, + dataPage, rbMap, dmuFactory.getAirportModelDMU()); + + // set up the tracer object + trace = Util.getBooleanValueFromPropertyMap(rbMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.dtaz"); + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + seek = Util.getBooleanValueFromPropertyMap(rbMap, "Seek"); + + airportMgra = Util.getIntegerValueFromPropertyMap(rbMap, "airport."+airportCode+".airportMgra"); + airportTaz = mgraManager.getTaz(airportMgra); + + // calculate the zip code array + calculateZipCodes(); + + //read the external station dataset into memory + String externalStationFile = Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".externalStationFile"); + readExternalPercentages(externalStationFile,airportCode); + } + + /** + * Iterate through the segments, calculating the mgra probabilities for each + */ + public void calculateMgraProbabilities(AirportDmuFactoryIf dmuFactory) + { + + logger.info("Calculating Airport Model Size Terms"); + + ArrayList mgras = mgraManager.getMgras(); + int[] mgraTaz = mgraManager.getMgraTaz(); + int maxMgra = mgraManager.getMaxMgra(); + int alternatives = sizeTermUEC.getNumberOfAlternatives(); + + double[][] mgraSizeTerms = new double[alternatives][maxMgra + 1]; + IndexValues iv = new IndexValues(); + AirportModelDMU aDmu = dmuFactory.getAirportModelDMU(); + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + int taz = mgraTaz[mgra]; + iv.setZoneIndex(mgra); + double[] utilities = sizeTermUEC.solve(iv, aDmu, null); + + // store the size terms + for (int segment = 0; segment < alternatives; ++segment) + { + mgraSizeTerms[segment][mgra] = utilities[segment]; + } + + // log + if (tracer.isTraceOn() && tracer.isTraceZone(taz)) + { + + logger.info("Size Term calculations for mgra " + mgra); + sizeTermUEC.logResultsArray(logger, 0, mgra); + + } + } + + // now iterate through tazs, calculate probabilities + int[] tazs = tazManager.getTazs(); + int maxTaz = tazManager.getMaxTaz(); + + // initialize arrays + mgraProbabilities = new double[alternatives][maxTaz + 1][]; + sizeTerms = new double[alternatives][maxTaz + 1]; + + // calculate arrays + for (int segment = 0; segment < alternatives; ++segment) + { + for (int taz = 0; taz < tazs.length; ++taz) + { + int tazNumber = tazs[taz]; + int[] mgraArray = tazManager.getMgraArray(tazNumber); + + // initialize the vector of mgras for this purpose-taz + mgraProbabilities[segment][tazNumber] = new double[mgraArray.length]; + + // first calculate the sum of size for all the mgras in the taz + double sum = 0; + for (int mgra = 0; mgra < mgraArray.length; ++mgra) + { + + int mgraNumber = mgraArray[mgra]; + + sum += mgraSizeTerms[segment][mgraNumber]; + } + // store the logsum in the size term array by taz + if (sum > 0.0) sizeTerms[segment][tazNumber] = Math.log(sum + 1.0); + + // now calculate the cumulative probability distribution + double lastProb = 0.0; + for (int mgra = 0; mgra < mgraArray.length; ++mgra) + { + + int mgraNumber = mgraArray[mgra]; + if (sum > 0.0) + mgraProbabilities[segment][tazNumber][mgra] = lastProb + + mgraSizeTerms[segment][mgraNumber] / sum; + lastProb = mgraProbabilities[segment][tazNumber][mgra]; + } + if (sum > 0.0 && Math.abs(lastProb - 1.0) > 0.000001) + logger.info("Error: segment " + segment + " taz " + tazNumber + + " cum prob adds up to " + lastProb); + } + + } + logger.info("Finished Calculating Airport Model Size Terms"); + } + + /** + * Calculate the zip codes at a taz level from the mgra data file. This + * requires the mgra data to be specified as mgra.socec.file in the + * properties file. The mgra file must have four fields: zone, taz, pop, and + * zip The taz zip is coded based upon the highest population mgra within + * the taz. + * + * @return a zip code array dimensioned by taz numbers + */ + public void calculateZipCodes() + { + + logger.info("Calculating Airport Model TAZ Zip Code Array"); + + zipCodes = new int[tazManager.maxTaz + 1]; + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String fileName = directory + Util.getStringValueFromPropertyMap(rbMap, "mgra.socec.file"); + + logger.info("Begin reading the data in file " + fileName); + TableDataSet mgraTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + mgraTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + // iterate through TAZs and store zip codes in zipCodes array + int[] tazs = tazManager.getTazs(); + for (int i = 0; i < tazs.length; ++i) + { + + int tazNumber = tazs[i]; + int maxPop = 0; + int zip = 0; + for (int row = 1; row <= mgraTable.getRowCount(); ++row) + { + + if (mgraTable.getValueAt(row, "taz") == tazNumber) + { + int pop = (int) mgraTable.getValueAt(row, "pop"); + if (pop > maxPop) + { + maxPop = pop; + zip = (int) mgraTable.getValueAt(row, "ZIP09"); + } + } + } + // if iterate through mgra data, and no mgras with pop found, then + // choose zip of first mgra in taz + if (zip == 0) + { + for (int row = 1; row <= mgraTable.getRowCount(); ++row) + { + + if (mgraTable.getValueAt(row, "taz") == tazNumber) + { + zip = (int) mgraTable.getValueAt(row, "ZIP09"); + break; + } + } + } + // store zip in array + zipCodes[tazNumber] = zip; + } + logger.info("Finished Calculating Airport Model TAZ Zip Code Array"); + } + + /** + * Calculate taz probabilities. This method initializes and calculates the + * tazProbabilities array. + */ + public void calculateTazProbabilities(AirportDmuFactoryIf dmuFactory) + { + + if (sizeTerms == null) + { + logger.error("Error: attemping to execute airportmodel.calculateTazProbabilities() before calling calculateMgraProbabilities()"); + throw new RuntimeException(); + } + + logger.info("Calculating Airport Model TAZ Probabilities Arrays"); + + // initialize taz probabilities array + int segments = sizeTerms.length; + int maxTaz = tazManager.getMaxTaz(); + tazProbabilities = new double[segments][maxTaz + 1]; + + // Note: this is an aggregate model to calculate utilities, but we need + // income so we need a party object + AirportParty airportParty = new AirportParty(1001); + + AirportModelDMU dmu = dmuFactory.getAirportModelDMU(); + dmu.setZips(zipCodes); + dmu.setSizeTerms(sizeTerms); + dmu.setAirportParty(airportParty); + + int airportTaz = mgraManager.getTaz(airportMgra); + + // segments are combinations of 4 purposes and 8 income groups, which + // apply only to resident purposes + for (int segment = 0; segment < segments; ++segment) + { + + int purpose = AirportModelStructure.getPurposeFromDCSizeSegment(segment); + int income = AirportModelStructure.getIncomeFromDCSizeSegment(segment); + + airportParty.setPurpose((byte) purpose); + airportParty.setIncome((byte) income); + + // set airport taz as origin. Destination tazs controlled by + // alternative file. + IndexValues dmuIndex = dmu.getDmuIndex(); + dmuIndex.setOriginZone(airportTaz); + + // Calculate utilities & probabilities + destModel[purpose].computeUtilities(dmu, dmuIndex); + + // Store probabilities (by segment) + tazProbabilities[segment] = Arrays.copyOf( + destModel[purpose].getCumulativeProbabilities(), + destModel[purpose].getCumulativeProbabilities().length); + } + logger.info("Finished Calculating Airport Model TAZ Probabilities Arrays"); + } + + /** + * Choose an MGRA + * + * @param purpose + * Purpose + * @param income + * Income + * @param randomNumber + * Random number + * @return The chosen MGRA number + */ + public int chooseMGRA(int purpose, int income, double randomNumber) + { + + // first find a TAZ + int segment = AirportModelStructure.getDCSizeSegment(purpose, income); + int alt = 0; + double[] tazCumProb = tazProbabilities[segment]; + double altProb = 0; + double cumProb = 0; + for (int i = 0; i < tazCumProb.length; ++i) + { + if (tazCumProb[i] > randomNumber) + { + alt = i; + if (i != 0) + { + cumProb = tazCumProb[i - 1]; + altProb = tazCumProb[i] - tazCumProb[i - 1]; + } else + { + altProb = tazCumProb[i]; + } + break; + } + } + + // get the taz number of the alternative, and an array of mgras in that + // taz + int tazNumber = (int) alternativeData.getValueAt(alt + 1, "dest"); + int[] mgraArray = tazManager.getMgraArray(tazNumber); + + // now find an MGRA in the taz corresponding to the random number drawn: + // note that the indexing needs to be offset by the cumulative + // probability of the chosen taz and the + // mgra probabilities need to be scaled by the alternatives probability + int mgraNumber = 0; + double[] mgraCumProb = mgraProbabilities[segment][tazNumber]; + for (int i = 0; i < mgraCumProb.length; ++i) + { + cumProb += mgraCumProb[i] * altProb; + if (cumProb > randomNumber) + { + mgraNumber = mgraArray[i]; + } + } + // return the chosen MGRA number + return mgraNumber; + } + + /** + * Iterate through an array of AirportParty objects, choosing origin MGRAs + * for each and setting the result back in the objects. + * + * @param airportParties + * An array of AirportParty objects + */ + public void chooseOrigins(AirportParty[] airportParties) + { + + // iterate through the array, choosing mgras and setting them + for (AirportParty party : airportParties) + { + + int income = party.getIncome(); + int purpose = party.getPurpose(); + double random = party.getRandom(); + int mgra = -99; + if (purpose < AirportModelStructure.INTERNAL_PURPOSES){ + mgra = chooseMGRA(purpose, income, random); + + // if this is a departing travel party, the origin is the chosen + // mgra, and the destination is the airport terminal + if (party.getDirection() == AirportModelStructure.DEPARTURE) + { + party.setOriginMGRA(mgra); + party.setOriginTAZ(mgraManager.getTaz(mgra)); + party.setDestinationMGRA(airportMgra); + party.setDestinationTAZ(airportTaz); + } else + { + party.setOriginMGRA(airportMgra); + party.setOriginTAZ(airportTaz); + party.setDestinationMGRA(mgra); + party.setDestinationTAZ(mgraManager.getTaz(mgra)); + } + + }else{ + chooseExternalStation(party, random); + } + } + } + /** + * Read a csv file with probabilities by external station. Required fields in the file: + * + * taz The TAZ number of the external station + * mgraOut The MGRA number for trips leaving the region (closest MGRA to outbound external TAZ) + * mgraRet The MGRA number for trips returning to the region (closest MGRA to inbound external TAZ) + * AIRPORTNAME.pct The share of trips entering\exiting at the external station for the airport + * + * + * @param fileName The name of the external station file + */ + private void readExternalPercentages(String fileName, String airportCode){ + + logger.info("Begin reading the data in file " + fileName); + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + externalDataSet = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + externalAirportColumn = externalDataSet.getColumnPosition(airportCode+".pct"); + tazColumn = externalDataSet.getColumnPosition("taz"); + mazOutColumn = externalDataSet.getColumnPosition("mgraOut"); + mazInbColumn = externalDataSet.getColumnPosition("mgraRet"); + + if(externalAirportColumn<=0|| tazColumn<=0 || mazOutColumn<=0 || mazInbColumn<=0){ + logger.error("Check fields in external station file "+fileName); + logger.error("File should have fields taz, mgraOut, mgraReg and "+airportCode+".pct"); + throw new RuntimeException(); + } + + logger.info("End reading the data in file " + fileName); + + } + + /** + * Choose an external TAZ and associated MAZ for the tour if it is external. The + * probabilities are in the external station file. + * + * @param airportParty The airport party + * @param randomNumber A uniform random number + */ + private void chooseExternalStation(AirportParty airportParty, double randomNumber){ + + double cumProb=0; + int taz = -1; + int maz = -1; + for(int row = 1; row <= externalDataSet.getRowCount();++row){ + + cumProb += externalDataSet.getValueAt(row,externalAirportColumn); + if(cumProb > randomNumber){ + taz = (int) externalDataSet.getValueAt(row, tazColumn); + + if(airportParty.getDirection() == AirportModelStructure.DEPARTURE){ + maz = (int) externalDataSet.getValueAt(row,mazInbColumn); + airportParty.setOriginTAZ(taz); + airportParty.setOriginMGRA(maz); + airportParty.setDestinationMGRA(airportMgra); + airportParty.setDestinationTAZ(airportTaz); + }else{ + maz = (int) externalDataSet.getValueAt(row,mazOutColumn); + airportParty.setDestinationTAZ(taz); + airportParty.setDestinationMGRA(maz); + airportParty.setOriginMGRA(airportMgra); + airportParty.setOriginTAZ(airportTaz); + + } + + } + + } + if(taz==-1||maz==-1){ + logger.fatal("Error: could not find external destination for airport tour"); + logger.fatal("Make sure probabilities add up to 1.0 in external station file"); + throw new RuntimeException(); + } + + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDmuFactory.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDmuFactory.java new file mode 100644 index 0000000..9a79e69 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDmuFactory.java @@ -0,0 +1,35 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.airport; + +import java.io.Serializable; + +/** + * ArcCtrampDmuFactory is a class that creates Airport Model DMU objects + * + * @author Joel Freedman + */ +public class AirportDmuFactory + implements AirportDmuFactoryIf, Serializable +{ + + //private AirportModelStructure airportModelStructure; + + public AirportDmuFactory()//AirportModelStructure modelStructure) + { + //this.airportModelStructure = modelStructure; + } + + public AirportModelDMU getAirportModelDMU() + { + return new AirportModelDMU(null); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDmuFactoryIf.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDmuFactoryIf.java new file mode 100644 index 0000000..8f233cb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportDmuFactoryIf.java @@ -0,0 +1,11 @@ +package org.sandag.abm.airport; + +/** + * A DMU factory interface + */ +public interface AirportDmuFactoryIf +{ + + AirportModelDMU getAirportModelDMU(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModeChoiceModel.java new file mode 100644 index 0000000..b988d14 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModeChoiceModel.java @@ -0,0 +1,378 @@ +package org.sandag.abm.airport; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.accessibilities.BestTransitPathCalculator; +import org.sandag.abm.accessibilities.DriveTransitWalkSkimsCalculator; +import org.sandag.abm.accessibilities.McLogsumsAppender; +import org.sandag.abm.accessibilities.WalkTransitDriveSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitWalkSkimsCalculator; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.TripModeChoiceDMU; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + +public class AirportModeChoiceModel +{ + private transient Logger logger = Logger.getLogger("airportModel"); + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private ChoiceModelApplication driveAloneModel; + private ChoiceModelApplication shared2Model; + private ChoiceModelApplication shared3Model; + private ChoiceModelApplication transitModel; + private ChoiceModelApplication accessModel; + + private Tracer tracer; + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + private boolean seek; + private HashMap rbMap; + + private McLogsumsCalculator logsumHelper; + private TripModeChoiceDMU mcDmuObject; + private AutoTazSkimsCalculator tazDistanceCalculator; + + /** + * Constructor + * + * @param propertyMap + * Resource properties file map. + * @param dmuFactory + * Factory object for creation of airport model DMUs + */ + public AirportModeChoiceModel(HashMap rbMap, AirportDmuFactoryIf dmuFactory, String airportCode) + { + + this.rbMap = rbMap; + + tazManager = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String airportModeUecFileName = Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".mc.uec.file"); + airportModeUecFileName = uecFileDirectory + airportModeUecFileName; + + int dataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".mc.data.page")); + int daPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".mc.da.page")); + int s2Page = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".mc.s2.page")); + int s3Page = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".mc.s3.page")); + int transitPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".mc.transit.page")); + int accessPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".mc.accessMode.page")); + + logger.info("Creating Airport Model Mode Choice Application UECs"); + + // create a DMU + AirportModelDMU dmu = dmuFactory.getAirportModelDMU(); + + // create a ChoiceModelApplication object for drive-alone mode choice + driveAloneModel = new ChoiceModelApplication(airportModeUecFileName, daPage, dataPage, + rbMap, (VariableTable) dmu); + + // create a ChoiceModelApplication object for shared 2 mode choice + shared2Model = new ChoiceModelApplication(airportModeUecFileName, s2Page, dataPage, rbMap, + (VariableTable) dmu); + + // create a ChoiceModelApplication object for shared 3+ mode choice + shared3Model = new ChoiceModelApplication(airportModeUecFileName, s3Page, dataPage, rbMap, + (VariableTable) dmu); + + // create a ChoiceModelApplication object for transit mode choice + transitModel = new ChoiceModelApplication(airportModeUecFileName, transitPage, dataPage, + rbMap, (VariableTable) dmu); + + // create a ChoiceModelApplication object for access mode choice + accessModel = new ChoiceModelApplication(airportModeUecFileName, accessPage, dataPage, + rbMap, (VariableTable) dmu); + + logger.info("Finished Creating Airport Model Mode Choice Application UECs"); + + // set up the tracer object + trace = Util.getBooleanValueFromPropertyMap(rbMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.dtaz"); + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + seek = Util.getBooleanValueFromPropertyMap(rbMap, "Seek"); + + tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(rbMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + SandagModelStructure modelStructure = new SandagModelStructure(); + mcDmuObject = new TripModeChoiceDMU(modelStructure, logger); + + } + + + /** + * Choose airport arrival mode and trip mode for this party. Store results + * in the party object passed as argument. + * + * @param party + * The travel party + * @param dmu + * An airport model DMU + */ + public void chooseMode(AirportParty party, AirportModelDMU dmu) + { + + int origMgra = party.getOriginMGRA(); + int destMgra = party.getDestinationMGRA(); + int origTaz = mgraManager.getTaz(origMgra); + int destTaz = mgraManager.getTaz(destMgra); + int period = party.getDepartTime(); + + boolean inbound = false; + if (party.getDirection() == AirportModelStructure.ARRIVAL) inbound = true; + + dmu.setAirportParty(party); + dmu.setDmuIndexValues(party.getID(), origTaz, destTaz); + + // set trip mc dmu values for transit logsum (gets replaced below by uec values) + double c_ivt = -0.03; + double c_cost = - 0.0003; + + // Solve trip mode level utilities + mcDmuObject.setIvtCoeff(c_ivt); + mcDmuObject.setCostCoeff(c_cost); + double walkTransitLogsum = -999.0; + double driveTransitLogsum = -999.0; + + // if 1-person party, solve for the drive-alone and 2-person logsums + if (party.getSize() == 1) + { + driveAloneModel.computeUtilities(dmu, dmu.getDmuIndex()); + double driveAloneLogsum = driveAloneModel.getLogsum(); + dmu.setDriveAloneLogsum(driveAloneLogsum); + + c_ivt = driveAloneModel.getUEC().lookupVariableIndex("c_ivt"); + c_cost = driveAloneModel.getUEC().lookupVariableIndex("c_cost"); + + shared2Model.computeUtilities(dmu, dmu.getDmuIndex()); + double shared2Logsum = shared2Model.getLogsum(); + dmu.setShared2Logsum(shared2Logsum); + + } else if (party.getSize() == 2) + { // if 2-person party solve for the + // shared 2 and shared 3+ logsums + shared2Model.computeUtilities(dmu, dmu.getDmuIndex()); + double shared2Logsum = shared2Model.getLogsum(); + dmu.setShared2Logsum(shared2Logsum); + + shared3Model.computeUtilities(dmu, dmu.getDmuIndex()); + double shared3Logsum = shared3Model.getLogsum(); + dmu.setShared3Logsum(shared3Logsum); + + c_ivt = shared2Model.getUEC().lookupVariableIndex("c_ivt"); + c_cost = shared2Model.getUEC().lookupVariableIndex("c_cost"); + + } else + { // if 3+ person party, solve the shared 3+ logsums + shared3Model.computeUtilities(dmu, dmu.getDmuIndex()); + double shared3Logsum = shared3Model.getLogsum(); + dmu.setShared3Logsum(shared3Logsum); + + c_ivt = shared3Model.getUEC().lookupVariableIndex("c_ivt"); + c_cost = shared3Model.getUEC().lookupVariableIndex("c_cost"); + } + + logsumHelper.setWtwTripMcDmuAttributes( mcDmuObject, origMgra, destMgra, period, party.getDebugChoiceModels()); + walkTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTW); + if (party.getDirection() == AirportModelStructure.DEPARTURE) + { + logsumHelper.setDtwTripMcDmuAttributes( mcDmuObject, origMgra, destMgra, period, party.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.DTW); + } else + { + logsumHelper.setWtdTripMcDmuAttributes( mcDmuObject, origMgra, destMgra, period, party.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTD); + } + + dmu.setWalkTransitLogsum(walkTransitLogsum); + dmu.setDriveTransitLogsum(driveTransitLogsum); + + transitModel.computeUtilities(dmu, dmu.getDmuIndex()); + double transitLogsum = transitModel.getLogsum(); + dmu.setTransitLogsum(transitLogsum); + + // calculate access mode utility and choose access mode + accessModel.computeUtilities(dmu, dmu.getDmuIndex()); + int accessMode = accessModel.getChoiceResult(party.getRandom()); + party.setArrivalMode((byte) accessMode); + + // choose trip mode + int tripMode = 0; + int occupancy = AirportModelStructure.getOccupancy(accessMode, party.getSize()); + double randomNumber = party.getRandom(); + + float valueOfTime = 0; + + if ((accessMode != AirportModelStructure.TRANSIT) && (! AirportModelStructure.taxiTncMode(accessMode))) + { + if (occupancy == 1) + { + tripMode = occupancy; + + //following gets vot from UEC + UtilityExpressionCalculator uec = driveAloneModel.getUEC(); + int votIndex = uec.lookupVariableIndex("vot"); + valueOfTime = (float) uec.getValueForIndex(votIndex); + + } else if (occupancy == 2) + { + tripMode = occupancy; + + //following gets vot from UEC + UtilityExpressionCalculator uec = shared2Model.getUEC(); + int votIndex = uec.lookupVariableIndex("vot"); + valueOfTime = (float) uec.getValueForIndex(votIndex); + + } else if (occupancy > 2) + { + tripMode = 3; + + //following gets vot from UEC + UtilityExpressionCalculator uec = shared3Model.getUEC(); + int votIndex = uec.lookupVariableIndex("vot"); + valueOfTime = (float) uec.getValueForIndex(votIndex); + + } + } else if (accessMode == AirportModelStructure.TRANSIT) + { + int choice = transitModel.getChoiceResult(randomNumber); + double[][] bestTapPairs; + if (choice == 1){ + tripMode = AirportModelStructure.REALLOCATE_WLKTRN; //walk-transit + bestTapPairs = logsumHelper.getBestWtwTripTaps(); + } + else if (choice == 2){ + tripMode = AirportModelStructure.REALLOCATE_KNRPERTRN; //knr-personal tNCVehicle + if (party.getDirection() == AirportModelStructure.DEPARTURE) + bestTapPairs = logsumHelper.getBestDtwTripTaps(); + else + bestTapPairs = logsumHelper.getBestWtdTripTaps(); + } + else { + tripMode = AirportModelStructure.REALLOCATE_KNRTNCTRN; //knr-TNC + if (party.getDirection() == AirportModelStructure.DEPARTURE) + bestTapPairs = logsumHelper.getBestDtwTripTaps(); + else + bestTapPairs = logsumHelper.getBestWtdTripTaps(); + } + + //pick transit path from N-paths + double rn = party.getRandom(); + int pathIndex = logsumHelper.chooseTripPath(rn, bestTapPairs, party.getDebugChoiceModels(), logger); + int boardTap = (int) bestTapPairs[pathIndex][0]; + int alightTap = (int) bestTapPairs[pathIndex][1]; + int set = (int) bestTapPairs[pathIndex][2]; + party.setBoardTap(boardTap); + party.setAlightTap(alightTap); + party.setSet(set); + + //following gets vot from UEC + UtilityExpressionCalculator uec = transitModel.getUEC(); + int votIndex = uec.lookupVariableIndex("vot"); + valueOfTime = (float) uec.getValueForIndex(votIndex); + + }else if(accessMode == AirportModelStructure.TAXI){ + + tripMode=AirportModelStructure.REALLOCATE_TAXI; + } + else if(accessMode == AirportModelStructure.TNC_SINGLE){ + + tripMode=AirportModelStructure.REALLOCATE_TNCSINGLE; + + } + else if(accessMode == AirportModelStructure.TNC_SHARED){ + + tripMode=AirportModelStructure.REALLOCATE_TNCSHARED; + + } + + //set the VOT + if(AirportModelStructure.taxiTncMode(accessMode) ) { + UtilityExpressionCalculator uec = null; + + //following gets vot from UEC + if(occupancy==1) + uec = driveAloneModel.getUEC(); + else if (occupancy==2) + uec = shared2Model.getUEC(); + else + uec = shared3Model.getUEC(); + + int votIndex = uec.lookupVariableIndex("vot"); + valueOfTime = (float) uec.getValueForIndex(votIndex); + + } + party.setMode((byte) tripMode); + party.setValueOfTime(valueOfTime); + } + + /** + * Choose modes for internal trips. + * + * @param airportParties + * An array of travel parties, with destinations already chosen. + * @param dmuFactory + * A DMU Factory. + */ + public void chooseModes(AirportParty[] airportParties, AirportDmuFactoryIf dmuFactory) + { + + AirportModelDMU dmu = dmuFactory.getAirportModelDMU(); + // iterate through the array, choosing mgras and setting them + for (AirportParty party : airportParties) + { + + int ID = party.getID(); + + if ((ID <= 5) || (ID % 100) == 0) + logger.info("Choosing mode for party " + party.getID()); + + chooseMode(party, dmu); + + } + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModel.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModel.java new file mode 100644 index 0000000..f9c3159 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModel.java @@ -0,0 +1,233 @@ +package org.sandag.abm.airport; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +public class AirportModel +{ + + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + + private MatrixDataServerRmi ms; + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + private HashMap rbMap; + private static float sampleRate; + private static int iteration; + private static String airportCode; + + /** + * Constructor + * + * @param rbMap + */ + public AirportModel(HashMap rbMap, float aSampleRate) + { + this.rbMap = rbMap; + this.sampleRate=aSampleRate; + } + + /** + * Run airport model. + */ + public void runModel() + { + Runtime gfg = Runtime.getRuntime(); + long memory1; + // checking the total memeory + System.out.println("Total memory is: "+ gfg.totalMemory()); + // checking free memory + memory1 = gfg.freeMemory(); + System.out.println("Initial free memory at Airport model: "+ memory1); + // calling the garbage collector on demand + gfg.gc(); + memory1 = gfg.freeMemory(); + System.out.println("Free memory after garbage "+ "collection: " + memory1); + + AirportDmuFactory dmuFactory = new AirportDmuFactory(); + + AirportPartyManager apm = new AirportPartyManager(rbMap, sampleRate, airportCode); + + apm.generateAirportParties(); + AirportParty[] parties = apm.getParties(); + + AirportDestChoiceModel destChoiceModel = new AirportDestChoiceModel(rbMap, dmuFactory,airportCode); + destChoiceModel.calculateMgraProbabilities(dmuFactory); + destChoiceModel.calculateTazProbabilities(dmuFactory); + destChoiceModel.chooseOrigins(parties); + + AirportModeChoiceModel modeChoiceModel = new AirportModeChoiceModel(rbMap, dmuFactory,airportCode); + modeChoiceModel.chooseModes(parties, dmuFactory); + + apm.writeOutputFile(rbMap); + + logger.info("Airport Model successfully completed!"); + + } + + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * @param args + */ + public static void main(String[] args) + { + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running Airport Model")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else { + propertiesFile = args[0]; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + if(args[i].equalsIgnoreCase("-airport")){ + airportCode = args[i+1]; + } + } + } + + logger.info("Airport Model:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + AirportModel airportModel = new AirportModel(pMap, sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = airportModel.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + airportModel.ms = matrixServer; + } else + { + airportModel.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + airportModel.ms.testRemote("AirportModel"); + + // these methods need to be called to set the matrix data + // manager in the matrix data server + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(airportModel.ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + airportModel.runModel(); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModelDMU.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModelDMU.java new file mode 100644 index 0000000..b564cd4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModelDMU.java @@ -0,0 +1,478 @@ +package org.sandag.abm.airport; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class AirportModelDMU + implements Serializable, VariableTable +{ + protected IndexValues dmuIndex; + + private AirportParty airportParty; + private double[][] sizeTerms; // dimensioned + // by + // segment, + // taz + private int[] zips; // dimensioned + // by + // taz + public static final int OUT = 0; + public static final int IN = 1; + protected static final int NUM_DIR = 2; + + // estimation file defines time periods as: + // 1 | Early AM: 3:00 AM - 5:59 AM | + // 2 | AM Peak: 6:00 AM - 8:59 AM | + // 3 | Early MD: 9:00 AM - 11:59 PM | + // 4 | Late MD: 12:00 PM - 3:29 PM | + // 5 | PM Peak: 3:30 PM - 6:59 PM | + // 6 | Evening: 7:00 PM - 2:59 AM | + + protected static final int LAST_EA_INDEX = 3; + protected static final int LAST_AM_INDEX = 9; + protected static final int LAST_MD_INDEX = 22; + protected static final int LAST_PM_INDEX = 29; + + protected static final int EA = 1; + protected static final int AM = 2; + protected static final int MD = 3; + protected static final int PM = 4; + protected static final int EV = 5; + + protected static final int EA_D = 1; // 5am + protected static final int AM_D = 5; // 7am + protected static final int MD_D = 15; // 12pm + protected static final int PM_D = 27; // 6pm + protected static final int EV_D = 35; // 10pm + protected static final int[] DEFAULT_DEPART_INDICES = {-1, EA_D, AM_D, + MD_D, PM_D, EV_D }; + + protected static final int EA_A = 2; // 5:30am + protected static final int AM_A = 6; // 7:30am + protected static final int MD_A = 16; // 12:30pm + protected static final int PM_A = 28; // 6:30pm + protected static final int EV_A = 36; // 10:30pm + protected static final int[] DEFAULT_ARRIVE_INDICES = {-1, EA_A, AM_A, + MD_A, PM_A, EV_A }; + + protected String[][] departArriveCombinationLabels = { {"EA", "EA"}, + {"EA", "AM"}, {"EA", "MD"}, {"EA", "PM"}, {"EA", "EV"}, {"AM", "AM"}, {"AM", "MD"}, + {"AM", "PM"}, {"AM", "EV"}, {"MD", "MD"}, {"MD", "PM"}, {"MD", "EV"}, {"PM", "PM"}, + {"PM", "EV"}, {"EV", "EV"} }; + + protected int[][] departArriveCombinations = { {EA, EA}, {EA, AM}, + {EA, MD}, {EA, PM}, {EA, EV}, {AM, AM}, {AM, MD}, {AM, PM}, {AM, EV}, {MD, MD}, + {MD, PM}, {MD, EV}, {PM, PM}, {PM, EV}, {EV, EV} }; + + private double driveAloneLogsum; + private double shared2Logsum; + private double shared3Logsum; + private double transitLogsum; + + protected double walkTransitLogsum; + protected double driveTransitLogsum; + + protected Logger _logger = null; + + protected HashMap methodIndexMap; + + + public AirportModelDMU(Logger logger) + { + dmuIndex = new IndexValues(); + setupMethodIndexMap(); + if (logger == null) + { + _logger = Logger.getLogger(AirportModelDMU.class); + } else _logger = logger; + } + + /** + * Set up the method index hashmap, where the key is the getter method for a + * data item and the value is the index. + */ + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + methodIndexMap.put("getDirection", 0); + methodIndexMap.put("getPurpose", 1); + methodIndexMap.put("getSize", 2); + methodIndexMap.put("getIncome", 3); + methodIndexMap.put("getDepartTime", 4); + methodIndexMap.put("getNights", 5); + methodIndexMap.put("getOriginMGRA", 6); + methodIndexMap.put("getLnDestChoiceSizeTazAlt", 7); + methodIndexMap.put("getDestZipAlt", 8); + + methodIndexMap.put("getWalkTransitLogsum", 10); + methodIndexMap.put("getDriveTransitLogsum", 11); + + methodIndexMap.put("getAvAvailable", 70); + + methodIndexMap.put("getDriveAloneLogsum", 90); + methodIndexMap.put("getShared2Logsum", 91); + methodIndexMap.put("getShared3Logsum", 92); + methodIndexMap.put("getTransitLogsum", 93); + + } + + /** + * Look up and return the value for the variable according to the index. + * + */ + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getDirection(); + break; + case 1: + returnValue = getPurpose(); + break; + case 2: + returnValue = getSize(); + break; + case 3: + returnValue = getIncome(); + break; + case 4: + returnValue = getDepartTime(); + break; + case 5: + returnValue = getNights(); + break; + case 6: + returnValue = getOriginMGRA(); + break; + case 7: + returnValue = getLnDestChoiceSizeTazAlt(arrayIndex); + break; + case 8: + returnValue = getDestZipAlt(arrayIndex); + break; + case 10: + returnValue = getWalkTransitLogsum(); + break; + case 11: + returnValue = getDriveTransitLogsum(); + break; + case 70: + returnValue = getAvAvailable(); + break; + case 90: + returnValue = getDriveAloneLogsum(); + break; + case 91: + returnValue = getShared2Logsum(); + break; + case 92: + returnValue = getShared3Logsum(); + break; + case 93: + returnValue = getTransitLogsum(); + break; + default: + _logger.error( "method number = " + variableIndex + " not found" ); + throw new RuntimeException( "method number = " + variableIndex + " not found" ); + } + return returnValue; + + } + + + /** + * Get travel party direction. + * + * @return Travel party direction. + */ + public int getDirection() + { + return airportParty.getDirection(); + } + + /** + * Get travel party purpose. + * + * @return Travel party direction. + */ + public int getPurpose() + { + return airportParty.getPurpose(); + } + + /** + * Get travel party size. + * + * @return Travel party size. + */ + public int getSize() + { + return airportParty.getSize(); + } + + /** + * Get travel party income. + * + * @return Travel party income. + */ + public int getIncome() + { + return airportParty.getIncome(); + } + + /** + * Get the departure time for the trip + * + * @return Trip departure time. + */ + public int getDepartTime() + { + return airportParty.getDepartTime(); + } + + /** + * Get the number of nights + * + * @return Travel party number of nights. + */ + public int getNights() + { + return airportParty.getNights(); + } + + /** + * Get the origin(non-airport) MGRA + * + * @return Travel party origin MGRA + */ + public int getOriginMGRA() + { + return airportParty.getOriginMGRA(); + } + + public int getAvAvailable() { + + if(airportParty.getAvAvailable()) + return 1; + + return 0; + } + + + /** + * Set the index values for this DMU. + * + * @param id + * @param origTaz + * @param destTaz + */ + public void setDmuIndexValues(int id, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(id); + dmuIndex.setZoneIndex(origTaz); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (airportParty.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug Airport Model"); + } + + } + + /** + * Get the appropriate size term for this purpose and income market. + * + * @param tazNumber + * the number of the taz + * @return the size term + */ + public double getLnDestChoiceSizeTazAlt(int alt) + { + + int purpose = getPurpose(); + int income = getIncome(); + + int segment = AirportModelStructure.getDCSizeSegment(purpose, income); + + return sizeTerms[segment][alt]; + } + + /** + * Get the destination district for this alternative. + * + * @param tazNumber + * @return number of destination district. + */ + public int getDestZipAlt(int alt) + { + + return zips[alt]; + } + + /** + * Set size terms + * + * @param sizeTerms + * A double[][] array dimensioned by segments (purp\income + * groups) and taz numbers + */ + public void setSizeTerms(double[][] sizeTerms) + { + this.sizeTerms = sizeTerms; + } + + /** + * set the zip codes + * + * @param zips + * int[] dimensioned by taz number + */ + public void setZips(int[] zips) + { + this.zips = zips; + } + + /** + * Set the airport party object. + * + * @param party + * The airport party. + */ + public void setAirportParty(AirportParty party) + { + + airportParty = party; + } + + /** + * @return the dmuIndex + */ + public IndexValues getDmuIndex() + { + return dmuIndex; + } + + /** + * @return the driveAloneLogsum + */ + public double getDriveAloneLogsum() + { + return driveAloneLogsum; + } + + /** + * @param driveAloneLogsum + * the driveAloneLogsum to set + */ + public void setDriveAloneLogsum(double driveAloneLogsum) + { + this.driveAloneLogsum = driveAloneLogsum; + } + + /** + * @return the shared2Logsum + */ + public double getShared2Logsum() + { + return shared2Logsum; + } + + /** + * @param shared2Logsum + * the shared2Logsum to set + */ + public void setShared2Logsum(double shared2Logsum) + { + this.shared2Logsum = shared2Logsum; + } + + /** + * @return the shared3Logsum + */ + public double getShared3Logsum() + { + return shared3Logsum; + } + + /** + * @param shared3Logsum + * the shared3Logsum to set + */ + public void setShared3Logsum(double shared3Logsum) + { + this.shared3Logsum = shared3Logsum; + } + + /** + * @return the transitLogsum + */ + public double getTransitLogsum() + { + return transitLogsum; + } + + /** + * @param transitLogsum + * the transitLogsum to set + */ + public void setTransitLogsum(double transitLogsum) + { + this.transitLogsum = transitLogsum; + } + + public double getWalkTransitLogsum() { + return walkTransitLogsum; + } + + public void setWalkTransitLogsum(double walkTransitLogsum) { + this.walkTransitLogsum = walkTransitLogsum; + } + + public double getDriveTransitLogsum() { + return driveTransitLogsum; + } + + public void setDriveTransitLogsum(double driveTransitLogsum) { + this.driveTransitLogsum = driveTransitLogsum; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModelStructure.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModelStructure.java new file mode 100644 index 0000000..4b664ca --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportModelStructure.java @@ -0,0 +1,239 @@ +package org.sandag.abm.airport; + +public final class AirportModelStructure +{ + + public static final byte PURPOSES = 5; + public static final byte RESIDENT_BUSINESS = 0; + public static final byte RESIDENT_PERSONAL = 1; + public static final byte VISITOR_BUSINESS = 2; + public static final byte VISITOR_PERSONAL = 3; + public static final byte EXTERNAL = 4; + + public static final byte INTERNAL_PURPOSES = 4; + + public static final byte DEPARTURE = 0; + public static final byte ARRIVAL = 1; + + public static final byte INCOME_SEGMENTS = 8; + public static final byte DC_SIZE_SEGMENTS = INCOME_SEGMENTS * 2 + 2; + + public static final int AM = 0; + public static final int PM = 1; + public static final int OP = 2; + public static final int[] SKIM_PERIODS = {AM, PM, OP}; + public static final String[] SKIM_PERIOD_STRINGS = {"AM", "PM", "OP"}; + public static final int UPPER_EA = 3; + public static final int UPPER_AM = 9; + public static final int UPPER_MD = 22; + public static final int UPPER_PM = 29; + public static final String[] MODEL_PERIOD_LABELS = {"EA", "AM", "MD", "PM", "EV"}; + + public static final byte ACCESS_MODES = 11; + + public static final byte PARK_TMNL = 1; + public static final byte PARK_SANOFF = 2; + public static final byte PARK_PVTOFF = 3; + public static final byte PUDO_ESC = 4; + public static final byte PUDO_CURB = 5; + public static final byte RENTAL = 6; + public static final byte TAXI = 7; + public static final byte TNC_SINGLE = 8; + public static final byte TNC_SHARED = 9; + public static final byte SHUTTLE_VAN = 10; + public static final byte TRANSIT = 11; + + //reallocate the trip modes from the access choice model to ones that the trip table and other code can read, consistent with + //resident models. + public static final byte REALLOCATE_WLKTRN = 6; //walk access + public static final byte REALLOCATE_KNRPERTRN = 8; //knr-personal tNCVehicle + public static final byte REALLOCATE_KNRTNCTRN = 9; //knr-TNC + public static final byte REALLOCATE_TAXI = 10; + public static final byte REALLOCATE_TNCSINGLE = 11; + public static final byte REALLOCATE_TNCSHARED = 12; + + private AirportModelStructure() + { + } + + /** + * Calculate and return the destination choice size term segment + * + * @param purpose + * @param income + * @return The dc size term segment, currently 0-17, where: 0-7 are 8 income + * groups for RES_BUS 8-15 are 8 income groups for RES_PER 16 is + * VIS_BUS 17 is VIS_PER + */ + public static int getDCSizeSegment(int purpose, int income) + { + + int segment = -1; + + // size terms for resident trips are dimensioned by income + if (purpose < 2) + { + segment = purpose * INCOME_SEGMENTS + income; + } else + { + segment = 2 * INCOME_SEGMENTS + purpose - 2; + } + return segment; + + } + + /** + * Calculate the purpose from the dc size segment. + * + * @param segment + * The dc size segment (0-17) + * @return The purpose + */ + public static int getPurposeFromDCSizeSegment(int segment) + { + + int purpose = -1; + + if (segment < INCOME_SEGMENTS) + { + purpose = 0; + } else if (segment < (AirportModelStructure.INCOME_SEGMENTS * 2)) + { + purpose = 1; + } else if (segment == (AirportModelStructure.INCOME_SEGMENTS * 2)) purpose = 2; + else purpose = 3; + + return purpose; + } + + /** + * Calculate the income from the dc size segment. + * + * @param segment + * The dc size segment (0-17) + * @return The income (defaults to 3 if not a resident purpose) + */ + public static int getIncomeFromDCSizeSegment(int segment) + { + + int income = 3; + + if (segment < AirportModelStructure.INCOME_SEGMENTS) + { + income = (byte) segment; + } else if (segment < (AirportModelStructure.INCOME_SEGMENTS * 2)) + income = ((byte) (segment - AirportModelStructure.INCOME_SEGMENTS)); + + return income; + } + + /** + * return the Skim period index 0=am, 1=pm, 2=off-peak + */ + public static int getSkimPeriodIndex(int departPeriod) + { + + int skimPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_AM) skimPeriodIndex = AM; + else if (departPeriod <= UPPER_MD) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_PM) skimPeriodIndex = PM; + else skimPeriodIndex = OP; + + return skimPeriodIndex; + + } + + /** + * return the Model period index 0=EA, 1=AM, 2=MD, 3=PM, 4=EV + */ + public static int getModelPeriodIndex(int departPeriod) + { + + int modelPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) modelPeriodIndex = 0; + else if (departPeriod <= UPPER_AM) modelPeriodIndex = 1; + else if (departPeriod <= UPPER_MD) modelPeriodIndex = 2; + else if (departPeriod <= UPPER_PM) modelPeriodIndex = 3; + else modelPeriodIndex = 4; + + return modelPeriodIndex; + + } + + public static String getModelPeriodLabel(int period) + { + return MODEL_PERIOD_LABELS[period]; + } + + public static int getNumberModelPeriods() + { + return MODEL_PERIOD_LABELS.length; + } + + public static String getSkimMatrixPeriodString(int period) + { + int index = getSkimPeriodIndex(period); + return SKIM_PERIOD_STRINGS[index]; + } + + /** + * Get the tNCVehicle occupancy based upon the access mode and the party size. + * + * @param accessMode + * Access mode, 1-based, consistent with definitions above. + * @param partySize + * Number of passengers in travel party + * @return The (minimum) occupancy of the tNCVehicle trip to/from the airport. + */ + public static int getOccupancy(int accessMode, int partySize) + { + + switch (accessMode) + { + case PARK_TMNL: + return partySize; + case PARK_SANOFF: + return partySize; + case PARK_PVTOFF: + return partySize; + case PUDO_ESC: + return partySize + 1; + case PUDO_CURB: + return partySize + 1; + case RENTAL: + return partySize; + case TAXI: + return partySize + 1; + case TNC_SINGLE: + return partySize + 1; + case TNC_SHARED: + return partySize + 1; + case SHUTTLE_VAN: + return partySize + 1; + case TRANSIT: + return partySize; + + default: + throw new RuntimeException( + "Error: AccessMode not found in AirportModel.AirportModelStructure"); + + } + } + + public static boolean taxiTncMode(int accessMode) { + + switch (accessMode) { + case TAXI: + return true; + case TNC_SINGLE: + return true; + case TNC_SHARED: + return true; + } + + return false; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportParty.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportParty.java new file mode 100644 index 0000000..4f96be2 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportParty.java @@ -0,0 +1,321 @@ +package org.sandag.abm.airport; + +import java.io.Serializable; +import com.pb.common.math.MersenneTwister; + +public class AirportParty + implements Serializable +{ + + private MersenneTwister random; + private int ID; + + // following variables determined via simulation + private byte direction; + private byte purpose; + private byte size; + private byte income; + private int departTime; + private byte nights; + + private boolean debugChoiceModels; + + // following variables chosen via choice models + private int originMGRA; + private int destinationMGRA; + private int originTAZ; + private int destinationTAZ; + private byte mode; + private byte arrivalMode; + + private float valueOfTime; + + private int boardTap; + private int alightTap; + private int set = -1; + + private boolean avAvailable; + /** + * Public constructor. + * + * @param seed + * A seed for the random number generator. + */ + public AirportParty(long seed) + { + + random = new MersenneTwister(seed); + } + + /** + * @return the iD + */ + public int getID() + { + return ID; + } + + /** + * @param iD + * the iD to set + */ + public void setID(int iD) + { + ID = iD; + } + + /** + * @return the purpose + */ + public byte getPurpose() + { + return purpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(byte purpose) + { + this.purpose = purpose; + } + + /** + * @return the size + */ + public byte getSize() + { + return size; + } + + /** + * @param size + * the size to set + */ + public void setSize(byte size) + { + this.size = size; + } + + /** + * @return the income + */ + public byte getIncome() + { + return income; + } + + /** + * @param income + * the income to set + */ + public void setIncome(byte income) + { + this.income = income; + } + + /** + * @return the departTime + */ + public int getDepartTime() + { + return departTime; + } + + /** + * @param departTime + * the departTime to set + */ + public void setDepartTime(int departTime) + { + this.departTime = departTime; + } + + /** + * @return the direction + */ + public byte getDirection() + { + return direction; + } + + /** + * @param direction + * the direction to set + */ + public void setDirection(byte direction) + { + this.direction = direction; + } + + /** + * @return the originMGRA + */ + public int getOriginMGRA() + { + return originMGRA; + } + + /** + * @param originMGRA + * the originMGRA to set + */ + public void setOriginMGRA(int originMGRA) + { + this.originMGRA = originMGRA; + } + + /** + * @return the trip mode + */ + public byte getMode() + { + return mode; + } + + /** + * @param mode + * the trip mode to set + */ + public void setMode(byte mode) + { + this.mode = mode; + } + + /** + * @return the arrivalMode + */ + public byte getArrivalMode() + { + return arrivalMode; + } + + /** + * @param arrivalMode + * the arrivalMode to set + */ + public void setArrivalMode(byte arrivalMode) + { + this.arrivalMode = arrivalMode; + } + + /** + * @return the nights + */ + public byte getNights() + { + return nights; + } + + /** + * @param nights + * the nights to set + */ + public void setNights(byte nights) + { + this.nights = nights; + } + + /** + * Get a random number from the parties random class. + * + * @return A random number. + */ + public double getRandom() + { + return random.nextDouble(); + } + + /** + * @return the debugChoiceModels + */ + public boolean getDebugChoiceModels() + { + return debugChoiceModels; + } + + /** + * @param debugChoiceModels + * the debugChoiceModels to set + */ + public void setDebugChoiceModels(boolean debugChoiceModels) + { + this.debugChoiceModels = debugChoiceModels; + } + + + /** + * @return the destinationMGRA + */ + public int getDestinationMGRA() + { + return destinationMGRA; + } + + /** + * @param destinationMGRA + * the destinationMGRA to set + */ + public void setDestinationMGRA(int destinationMGRA) + { + this.destinationMGRA = destinationMGRA; + } + + public float getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(float valueOfTime) { + this.valueOfTime = valueOfTime; + } + + public int getBoardTap() { + return boardTap; + } + + public void setBoardTap(int boardTap) { + this.boardTap = boardTap; + } + + public int getAlightTap() { + return alightTap; + } + + public void setAlightTap(int alightTap) { + this.alightTap = alightTap; + } + + public int getSet() { + return set; + } + + public void setSet(int set) { + this.set = set; + } + + public int getOriginTAZ() { + return originTAZ; + } + + public void setOriginTAZ(int originTAZ) { + this.originTAZ = originTAZ; + } + + public int getDestinationTAZ() { + return destinationTAZ; + } + + public void setDestinationTAZ(int destinationTAZ) { + this.destinationTAZ = destinationTAZ; + } + + public boolean getAvAvailable() { + return avAvailable; + } + + public void setAvAvailable(boolean avAvailable) { + this.avAvailable = avAvailable; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportPartyManager.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportPartyManager.java new file mode 100644 index 0000000..75d7794 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportPartyManager.java @@ -0,0 +1,410 @@ +package org.sandag.abm.airport; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +public class AirportPartyManager +{ + + private static Logger logger = Logger.getLogger("SandagTourBasedModel.class"); + + private AirportParty[] parties; + + private double[] purposeDistribution; + private double[][] sizeDistribution; + private double[][] durationDistribution; + private double[][] incomeDistribution; + private double[][] departureDistribution; + private double[][] arrivalDistribution; + + + SandagModelStructure sandagStructure; + private String airportCode; + + private float avShare; + + + /** + * Constructor. Reads properties file and opens/stores all probability + * distributions for sampling. Estimates number of airport travel parties + * and initializes parties[]. + * + * @param resourceFile + * Property file. + */ + public AirportPartyManager(HashMap rbMap, float sampleRate, String airportCode) + { + sandagStructure = new SandagModelStructure(); + this.airportCode = airportCode; + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String purposeFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".purpose.file"); + String sizeFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".size.file"); + String durationFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".duration.file"); + String incomeFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".income.file"); + String departFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".departureTime.file"); + String arriveFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".arrivalTime.file"); + + // Read the distributions + setPurposeDistribution(purposeFile); + sizeDistribution = setDistribution(sizeDistribution, sizeFile); + durationDistribution = setDistribution(durationDistribution, durationFile); + incomeDistribution = setDistribution(incomeDistribution, incomeFile); + departureDistribution = setDistribution(departureDistribution, departFile); + arrivalDistribution = setDistribution(arrivalDistribution, arriveFile); + + // calculate total number of parties + float enplanements = new Float(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".enplanements").replace(",", "")); + float connectingPassengers = new Float(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".connecting").replace(",", "")); + float annualFactor = new Float(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".annualizationFactor")); + float averageSize = new Float(Util.getStringValueFromPropertyMap(rbMap, + "airport."+airportCode+".averageSize")); + + + avShare = Util.getFloatValueFromPropertyMap(rbMap, "Mobility.AV.Share"); + + float directPassengers = (enplanements - connectingPassengers) / annualFactor; + int totalParties = (int) (directPassengers / averageSize) * 2; + parties = new AirportParty[(int)(totalParties*sampleRate)]; + + logger.info("Total airport parties: " + totalParties); + } + + /** + * Create parties based upon total parties (calculated in constructor). Fill + * parties[] with travel parties, assuming one-half are arriving and + * one-half are departing. Simulate party characteristics (income, size, + * duration, time departing from origin or arriving at airport) from + * distributions, also read in during constructor. + * + */ + public void generateAirportParties() + { + + int departures = parties.length / 2; + int arrivals = parties.length - departures; + int totalParties = 0; + int totalPassengers = 0; + for (int i = 0; i < departures; ++i) + { + + AirportParty party = new AirportParty(i * 101 + 1000); + + // simulate from distributions + party.setDirection(AirportModelStructure.DEPARTURE); + byte purpose = (byte) choosePurpose(party.getRandom()); + byte size = (byte) chooseFromDistribution(purpose, sizeDistribution, party.getRandom()); + byte nights = (byte) chooseFromDistribution(purpose, durationDistribution, + party.getRandom()); + byte income = (byte) chooseFromDistribution(purpose, incomeDistribution, + party.getRandom()); + byte period = (byte) chooseFromDistribution(purpose, departureDistribution, + party.getRandom()); + + if(party.getRandom() random) return alt; + } + return -99; + } + + /** + * Choose a purpose. + * + * @param random + * A uniform random number. + * @return the purpose. + */ + protected int choosePurpose(double random) + { + // iterate through the probability array and choose + for (int alt = 0; alt < purposeDistribution.length; ++alt) + { + if (purposeDistribution[alt] > random) return alt; + } + return -99; + } + + /** + * Create a text file and write all records to the file. + * + */ + public void writeOutputFile(HashMap rbMap) + { + + // Open file and print header + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String fileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".output.file"); + + PrintWriter writer = null; + try + { + writer = new PrintWriter(new BufferedWriter(new FileWriter(fileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + fileName + " for writing\n"); + throw new RuntimeException(); + } + String headerString = new String( + "id,direction,purpose,size,income,nights,departTime,originMGRA,destinationMGRA,originTAZ," + + "destinationTAZ,tripMode,av_avail,arrivalMode,boardingTAP,alightingTAP,set,valueOfTime\n"); + writer.print(headerString); + + // Iterate through the array, printing records to the file + for (int i = 0; i < parties.length; ++i) + { + + String record = new String(parties[i].getID() + "," + parties[i].getDirection() + "," + + parties[i].getPurpose() + "," + parties[i].getSize() + "," + + parties[i].getIncome() + "," + parties[i].getNights() + "," + + parties[i].getDepartTime() + "," + parties[i].getOriginMGRA() + "," + + parties[i].getDestinationMGRA() + "," + + parties[i].getOriginTAZ() + "," + parties[i].getDestinationTAZ() + "," + + parties[i].getMode() + "," + + (parties[i].getAvAvailable() ? 1 : 0) + "," + + parties[i].getArrivalMode() + "," + parties[i].getBoardTap() + "," + + + parties[i].getAlightTap() + "," + parties[i].getSet() + "," + + String.format("%9.2f", parties[i].getValueOfTime()) + "\n"); + writer.print(record); + } + writer.close(); + + } + + /** + * @return the parties + */ + public AirportParty[] getParties() + { + return parties; + } + + + /* + public static void main(String[] args) + { + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running Airport Model Party Manager")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + AirportPartyManager apm = new AirportPartyManager(pMap); + + apm.generateAirportParties(); + + apm.writeOutputFile(pMap); + + logger.info("Airport Model successfully completed!"); + + } +*/ +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/airport/AirportTripTables.java b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportTripTables.java new file mode 100644 index 0000000..b6fbab1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/airport/AirportTripTables.java @@ -0,0 +1,707 @@ +package org.sandag.abm.airport; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.crossborder.CrossBorderTripTables; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.util.ResourceUtil; + +public class AirportTripTables +{ + + private static Logger logger = Logger.getLogger("tripTables"); + public static final int MATRIX_DATA_SERVER_PORT = 1171; + + private TableDataSet tripData; + + // Some parameters + private int[] modeIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // total + // modes, + // returns + // 0=auto + // modes, + // 1=non-motor, + // 2=transit, + // 3= + // other + private int[] matrixIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // modes, + // returns + // the + // element + // of + // the + // matrix + // array + // to + // store + // value + + // array modes: AUTO, NON-MOTORIZED, TRANSIT, OTHER + private int autoModes = 0; + private int tranModes = 0; + private int nmotModes = 0; + private int othrModes = 0; + + // one file per time period + private int numberOfPeriods; + + private String[] purposeName = {"RES_BUS", "RES_PER", "VIS_BUS", + "VIS_PER" }; + private HashMap rbMap; + + // matrices are indexed by modes, vot bins, submodes + private Matrix[][][] matrix; + + private ResourceBundle rb; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private TapDataManager tapManager; + private SandagModelStructure modelStructure; + private String airportCode; + + private MatrixDataServerRmi ms; + private float sampleRate = 1; + private static final String VOT_THRESHOLD_LOW = "valueOfTime.threshold.low"; + private static final String VOT_THRESHOLD_MED = "valueOfTime.threshold.med"; + private float valueOfTimeThresholdLow = 0; + private float valueOfTimeThresholdMed = 0; + //value of time bins by mode group + int[] votBins = {3,1,1,1}; + + public int numSkimSets; + + + public float getSampleRate() { + return sampleRate; + } + + public void setSampleRate(float sampleRate) { + this.sampleRate = sampleRate; + } + + public AirportTripTables(HashMap rbMap, String airportCode) + { + + this.rbMap = rbMap; + tazManager = TazDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + modelStructure = new SandagModelStructure(); + + // Time period limits + numberOfPeriods = modelStructure.getNumberModelPeriods(); + + // number of modes + modeIndex = new int[modelStructure.MAXIMUM_TOUR_MODE_ALT_INDEX + 1]; + matrixIndex = new int[modeIndex.length]; + numSkimSets = Util.getIntegerValueFromPropertyMap(rbMap,"utility.bestTransitPath.skim.sets"); + + // set the mode arrays + for (int i = 1; i < modeIndex.length; ++i) + { + if (modelStructure.getTourModeIsSovOrHov(i)) + { + modeIndex[i] = 0; + matrixIndex[i] = autoModes; + ++autoModes; + } else if (modelStructure.getTourModeIsNonMotorized(i)) + { + modeIndex[i] = 1; + matrixIndex[i] = nmotModes; + ++nmotModes; + } else if (modelStructure.getTourModeIsWalkTransit(i) + || modelStructure.getTourModeIsDriveTransit(i)) + { + modeIndex[i] = 2; + matrixIndex[i] = tranModes; + ++tranModes; + } else + { + modeIndex[i] = 3; + matrixIndex[i] = othrModes; + ++othrModes; + } + } + //value of time thresholds + valueOfTimeThresholdLow = new Float(rbMap.get(VOT_THRESHOLD_LOW)); + valueOfTimeThresholdMed = new Float(rbMap.get(VOT_THRESHOLD_MED)); + this.airportCode = airportCode; + } + + /** + * Initialize all the matrices for the given time period. + * + * @param periodName + * The name of the time period. + */ + public void initializeMatrices(String periodName) + { + + /* + * This won't work because external stations aren't listed in the MGRA + * file int[] tazIndex = tazManager.getTazsOneBased(); int tazs = + * tazIndex.length-1; + */ + // Instead, use maximum taz number + int maxTaz = tazManager.getMaxTaz(); + int[] tazIndex = new int[maxTaz + 1]; + + // assume zone numbers are sequential + for (int i = 1; i < tazIndex.length; ++i) + tazIndex[i] = i; + + // get the tap index + int[] tapIndex = tapManager.getTaps(); + int taps = tapIndex.length - 1; + + // Initialize matrices; one for each mode group (auto, non-mot, tran, + // other) + // All matrices will be dimensioned by TAZs except for transit, which is + // dimensioned by TAPs + int numberOfModes = 4; + matrix = new Matrix[numberOfModes][][]; + for (int i = 0; i < numberOfModes; ++i) + { + + String modeName; + matrix[i] = new Matrix[votBins[i]][]; + + for(int j = 0; j< votBins[i];++j){ + if (i == 0) + { + matrix[i][j] = new Matrix[autoModes]; + for (int k = 0; k < autoModes; ++k) + { + modeName = modelStructure.getModeName(k + 1); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 1) + { + matrix[i][j] = new Matrix[nmotModes]; + for (int k = 0; k < nmotModes; ++k) + { + modeName = modelStructure.getModeName(k + 1 + autoModes); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 2) + { + matrix[i][j] = new Matrix[tranModes*numSkimSets]; + for (int k = 0; k < tranModes; ++k) + { + for(int l=0;l1) + votBin = getValueOfTimeBin(valueOfTime); + + if (mode == 0) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + vehicleTrips)); + } else if (mode == 1) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } else if (mode == 2) + { + + if (boardTap == 0 || alightTap == 0) continue; + + //store transit trips in matrices + mat = (matrixIndex[tripMode]*numSkimSets)+set; + float value = matrix[mode][votBin][mat].getValueAt(boardTap, alightTap); + matrix[mode][votBin][mat].setValueAt(boardTap, alightTap, (value + personTrips)); + + // Store PNR transit trips in SOV free mode skim (mode 0 mat 0) + if (modelStructure.getTourModeIsDriveTransit(tripMode)) + { + + // add the tNCVehicle trip portion to the trip table + if (inbound == 0) + { // from origin to lot (boarding tap) + int PNRTAZ = tapManager.getTazForTap(boardTap); + value = matrix[0][votBin][0].getValueAt(originTAZ, PNRTAZ); + matrix[0][votBin][0].setValueAt(originTAZ, PNRTAZ, (value + vehicleTrips)); + + } else + { // from lot (alighting tap) to destination + int PNRTAZ = tapManager.getTazForTap(alightTap); + value = matrix[0][votBin][0].getValueAt(PNRTAZ, destinationTAZ); + matrix[0][votBin][0].setValueAt(PNRTAZ, destinationTAZ, (value + vehicleTrips)); + } + + } + } else + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } + + // generate another drive-alone trip in the opposite direction for + // pickup/dropoff + if (accMode == AirportModelStructure.PUDO_CURB + || accMode == AirportModelStructure.PUDO_CURB) + { + mode = 0; // auto mode + if (SandagModelStructure.getTripModeIsPay(tripMode)) // if the + // passenger + // chose + // pay, + // assume + // the + // driver + // will + // also + // pay + mat = 1; + else mat = 0; + float value = matrix[mode][votBin][mat].getValueAt(destinationTAZ, originTAZ); + matrix[mode][votBin][mat].setValueAt(destinationTAZ, originTAZ, (value + vehicleTrips)); + } + //logger.info("End creating trip tables for period " + timePeriod); + } + } + + /** + * Get the output trip table file names from the properties file, and write + * trip tables for all modes for the given time period. + * + * @param period + * Time period, which will be used to find the period time string + * to append to each trip table matrix file + */ + public void writeTrips(int period, MatrixType mt) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "scenario.path"); + String per = modelStructure.getModelPeriodLabel(period); + String[][] end = new String[4][]; + String[] fileName = new String[4]; + + fileName[0] = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".results.autoTripMatrix"); + fileName[1] = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".results.nMotTripMatrix"); + fileName[2] = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".results.tranTripMatrix"); + fileName[3] = directory + + Util.getStringValueFromPropertyMap(rbMap, "airport."+airportCode+".results.othrTripMatrix"); + + //the end of the name depends on whether there are multiple vot bins or not + String[] votBinName = {"low","med","high"}; + + for(int i = 0; i<4;++i){ + end[i] = new String[votBins[i]]; + for(int j = 0; j < votBins[i];++j){ + if(votBins[i]>1) + end[i][j] = "_" + per + "_"+ votBinName[j]+ ".omx"; + else + end[i][j] = "_" + per + ".omx"; + } + } + for (int i = 0; i < 4; ++i){ + for(int j = 0; j < votBins[i];++j){ + try + { + //Delete the file if it exists + File f = new File(fileName[i]+end[i][j]); + if(f.exists()){ + logger.info("Deleting existing trip file: "+fileName[i]+end[i][j]); + f.delete(); + } + + if (ms != null) ms.writeMatrixFile(fileName[i]+end[i][j], matrix[i][j], mt); + else writeMatrixFile(fileName[i]+end[i][j], matrix[i][j]); + } catch (Exception e) + { + logger.error("exception caught writing " + mt.toString() + " matrix file = " + + fileName[i] +end[i][j] + ", for mode index = " + i, e); + throw new RuntimeException(); + } + } + } + + + } + + /** + * Return the value of time bin 0 through 2 based on the thresholds provided in the property map + * @param valueOfTime + * @return value of time bin 0 through 2 + */ + public int getValueOfTimeBin(float valueOfTime){ + + if(valueOfTime pMap; + String propertiesFile = null; + String airportCode = null; + + logger.info(String.format( + "SANDAG Airport Model Trip Table Generation Program using CT-RAMP version %s", + CtrampApplication.VERSION)); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + + float sampleRate = 1.0f; + int iteration = 1; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-airport")) + { + airportCode = args[i + 1]; + } + } + + AirportTripTables tripTables = new AirportTripTables(pMap, airportCode); + logger.info("Airport Model Trip Table:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration+" -airport "+airportCode); + + tripTables.setSampleRate(sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = tripTables.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + tripTables.ms = matrixServer; + } else + { + tripTables.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + tripTables.ms.testRemote("AirportTripTables"); + + // mdm = MatrixDataManager.getInstance(); + // mdm.setMatrixDataServerObject(ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + tripTables.createTripTables(mt); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagAppendMcLogsumDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagAppendMcLogsumDMU.java new file mode 100644 index 0000000..74dff9b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagAppendMcLogsumDMU.java @@ -0,0 +1,615 @@ +package org.sandag.abm.application; + +import java.lang.reflect.InvocationTargetException; +import java.lang.reflect.Method; +import java.util.HashMap; +import java.util.Iterator; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.TourModeChoiceDMU; + +import com.pb.common.calculator.IndexValues; + +public class SandagAppendMcLogsumDMU + extends TourModeChoiceDMU +{ + + private int departPeriod; + private int arrivePeriod; + + private int incomeInDollars; + private int adults; + private int autos; + private int hhSize; + private int personIsFemale; + private int age; + private int tourCategoryJoint; + private int tourCategoryEscort; + private int numberOfParticipantsInJointTour; + private int workTourModeIsHOV; + private int workTourModeIsSOV; + private int workTourModeIsBike; + private int tourCategorySubtour; + + public SandagAppendMcLogsumDMU(ModelStructure modelStructure, Logger aLogger) + { + super(modelStructure, aLogger); + setupMethodIndexMap(); + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + + public void setNonMotorizedWalkTimeOut(double walkTime) + { + nmWalkTimeOut = walkTime; + } + + public void setNonMotorizedWalkTimeIn(double walkTime) + { + nmWalkTimeIn = walkTime; + } + + public void setNonMotorizedBikeTimeOut(double bikeTime) + { + nmBikeTimeOut = bikeTime; + } + + public void setNonMotorizedBikeTimeIn(double bikeTime) + { + nmBikeTimeIn = bikeTime; + } + + public float getTimeOutbound() + { + return departPeriod; + } + + public float getTimeInbound() + { + return arrivePeriod; + } + + public void setDepartPeriod(int period) + { + departPeriod = period; + } + + public void setArrivePeriod(int period) + { + arrivePeriod = period; + } + + public void setHhSize(int arg) + { + hhSize = arg; + } + + public void setAge(int arg) + { + age = arg; + } + + public void setTourCategoryJoint(int arg) + { + tourCategoryJoint = arg; + } + + public void setTourCategoryEscort(int arg) + { + tourCategoryEscort = arg; + } + + public void setNumberOfParticipantsInJointTour(int arg) + { + numberOfParticipantsInJointTour = arg; + } + + public void setWorkTourModeIsSOV(int arg) + { + workTourModeIsSOV = arg; + } + + public void setWorkTourModeIsHOV(int arg) + { + workTourModeIsHOV = arg; + } + + public void setWorkTourModeIsBike(int arg) + { + workTourModeIsBike = arg; + } + + public void setPTazTerminalTime(float arg) + { + pTazTerminalTime = arg; + } + + public void setATazTerminalTime(float arg) + { + aTazTerminalTime = arg; + } + + public void setIncomeInDollars(int arg) + { + incomeInDollars = arg; + } + + public int getIncome() + { + return incomeInDollars; + } + + public void setAdults(int arg) + { + adults = arg; + } + + public int getAdults() + { + return adults; + } + + public void setAutos(int arg) + { + autos = arg; + } + + public int getAutos() + { + return autos; + } + + public int getAge() + { + return age; + } + + public int getHhSize() + { + return hhSize; + } + + public int getTourCategoryJoint() + { + return tourCategoryJoint; + } + + public int getTourCategoryEscort() + { + return tourCategoryEscort; + } + + public int getNumberOfParticipantsInJointTour() + { + return numberOfParticipantsInJointTour; + } + + public int getWorkTourModeIsSov() + { + return workTourModeIsSOV; + } + + public int getWorkTourModeIsHov() + { + return workTourModeIsHOV; + } + + public int getWorkTourModeIsBike() + { + return workTourModeIsBike; + } + + public void setPersonIsFemale(int arg) + { + personIsFemale = arg; + } + + public int getFemale() + { + return personIsFemale; + } + + public void setOrigDuDen(double arg) + { + origDuDen = arg; + } + + public void setOrigEmpDen(double arg) + { + origEmpDen = arg; + } + + public void setOrigTotInt(double arg) + { + origTotInt = arg; + } + + public void setDestDuDen(double arg) + { + destDuDen = arg; + } + + public void setDestEmpDen(double arg) + { + destEmpDen = arg; + } + + public void setDestTotInt(double arg) + { + destTotInt = arg; + } + + public double getODUDen() + { + return origDuDen; + } + + public double getOEmpDen() + { + return origEmpDen; + } + + public double getOTotInt() + { + return origTotInt; + } + + public double getDDUDen() + { + return destDuDen; + } + + public double getDEmpDen() + { + return destEmpDen; + } + + public double getDTotInt() + { + return destTotInt; + } + + public double getNm_walkTime_out() + { + return nmWalkTimeOut; + } + + public double getNm_walkTime_in() + { + return nmWalkTimeIn; + } + + public double getNm_bikeTime_out() + { + return nmBikeTimeOut; + } + + public double getNm_bikeTime_in() + { + return nmBikeTimeIn; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTimeOutbound", 0); + methodIndexMap.put("getTimeInbound", 1); + methodIndexMap.put("getIncome", 2); + methodIndexMap.put("getAdults", 3); + methodIndexMap.put("getFemale", 4); + methodIndexMap.put("getHhSize", 5); + methodIndexMap.put("getAutos", 6); + methodIndexMap.put("getAge", 7); + methodIndexMap.put("getTourCategoryJoint", 8); + methodIndexMap.put("getNumberOfParticipantsInJointTour", 9); + methodIndexMap.put("getWorkTourModeIsSov", 10); + methodIndexMap.put("getWorkTourModeIsBike", 11); + methodIndexMap.put("getWorkTourModeIsHov", 12); + methodIndexMap.put("getPTazTerminalTime", 14); + methodIndexMap.put("getATazTerminalTime", 15); + methodIndexMap.put("getODUDen", 16); + methodIndexMap.put("getOEmpDen", 17); + methodIndexMap.put("getOTotInt", 18); + methodIndexMap.put("getDDUDen", 19); + methodIndexMap.put("getDEmpDen", 20); + methodIndexMap.put("getDTotInt", 21); + methodIndexMap.put("getTourCategoryEscort", 22); + + methodIndexMap.put("getNm_walkTime_out", 90); + methodIndexMap.put("getNm_walkTime_in", 91); + methodIndexMap.put("getNm_bikeTime_out", 92); + methodIndexMap.put("getNm_bikeTime_in", 93); + methodIndexMap.put("getWtw_LB_ivt_out", 176); + methodIndexMap.put("getWtw_LB_ivt_in", 177); + methodIndexMap.put("getWtw_EB_ivt_out", 178); + methodIndexMap.put("getWtw_EB_ivt_in", 179); + methodIndexMap.put("getWtw_BRT_ivt_out", 180); + methodIndexMap.put("getWtw_BRT_ivt_in", 181); + methodIndexMap.put("getWtw_LRT_ivt_out", 182); + methodIndexMap.put("getWtw_LRT_ivt_in", 183); + methodIndexMap.put("getWtw_CR_ivt_out", 184); + methodIndexMap.put("getWtw_CR_ivt_in", 185); + methodIndexMap.put("getWtw_fwait_out", 186); + methodIndexMap.put("getWtw_fwait_in", 187); + methodIndexMap.put("getWtw_xwait_out", 188); + methodIndexMap.put("getWtw_xwait_in", 189); + methodIndexMap.put("getWtw_AccTime_out", 190); + methodIndexMap.put("getWtw_AccTime_in", 191); + methodIndexMap.put("getWtw_EgrTime_out", 192); + methodIndexMap.put("getWtw_EgrTime_in", 193); + methodIndexMap.put("getWtw_WalkAuxTime_out", 194); + methodIndexMap.put("getWtw_WalkAuxTime_in", 195); + methodIndexMap.put("getWtw_fare_out", 196); + methodIndexMap.put("getWtw_fare_in", 197); + methodIndexMap.put("getWtw_xfers_out", 198); + methodIndexMap.put("getWtw_xfers_in", 199); + + methodIndexMap.put("getWtd_LB_ivt_out", 276); + methodIndexMap.put("getWtd_LB_ivt_in", 277); + methodIndexMap.put("getWtd_EB_ivt_out", 278); + methodIndexMap.put("getWtd_EB_ivt_in", 279); + methodIndexMap.put("getWtd_BRT_ivt_out", 280); + methodIndexMap.put("getWtd_BRT_ivt_in", 281); + methodIndexMap.put("getWtd_LRT_ivt_out", 282); + methodIndexMap.put("getWtd_LRT_ivt_in", 283); + methodIndexMap.put("getWtd_CR_ivt_out", 284); + methodIndexMap.put("getWtd_CR_ivt_in", 285); + methodIndexMap.put("getWtd_fwait_out", 286); + methodIndexMap.put("getWtd_fwait_in", 287); + methodIndexMap.put("getWtd_xwait_out", 288); + methodIndexMap.put("getWtd_xwait_in", 289); + methodIndexMap.put("getWtd_AccTime_out", 290); + methodIndexMap.put("getWtd_AccTime_in", 291); + methodIndexMap.put("getWtd_EgrTime_out", 292); + methodIndexMap.put("getWtd_EgrTime_in", 293); + methodIndexMap.put("getWtd_WalkAuxTime_out", 294); + methodIndexMap.put("getWtd_WalkAuxTime_in", 295); + methodIndexMap.put("getWtd_fare_out", 296); + methodIndexMap.put("getWtd_fare_in", 297); + methodIndexMap.put("getWtd_xfers_out", 298); + methodIndexMap.put("getWtd_xfers_in", 299); + methodIndexMap.put("getDtw_LB_ivt_out", 376); + methodIndexMap.put("getDtw_LB_ivt_in", 377); + methodIndexMap.put("getDtw_EB_ivt_out", 378); + methodIndexMap.put("getDtw_EB_ivt_in", 379); + methodIndexMap.put("getDtw_BRT_ivt_out", 380); + methodIndexMap.put("getDtw_BRT_ivt_in", 381); + methodIndexMap.put("getDtw_LRT_ivt_out", 382); + methodIndexMap.put("getDtw_LRT_ivt_in", 383); + methodIndexMap.put("getDtw_CR_ivt_out", 384); + methodIndexMap.put("getDtw_CR_ivt_in", 385); + methodIndexMap.put("getDtw_fwait_out", 386); + methodIndexMap.put("getDtw_fwait_in", 387); + methodIndexMap.put("getDtw_xwait_out", 388); + methodIndexMap.put("getDtw_xwait_in", 389); + methodIndexMap.put("getDtw_AccTime_out", 390); + methodIndexMap.put("getDtw_AccTime_in", 391); + methodIndexMap.put("getDtw_EgrTime_out", 392); + methodIndexMap.put("getDtw_EgrTime_in", 393); + methodIndexMap.put("getDtw_WalkAuxTime_out", 394); + methodIndexMap.put("getDtw_WalkAuxTime_in", 395); + methodIndexMap.put("getDtw_fare_out", 396); + methodIndexMap.put("getDtw_fare_in", 397); + methodIndexMap.put("getDtw_xfers_out", 398); + methodIndexMap.put("getDtw_xfers_in", 399); + + + } + + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + case 0: + returnValue = getTimeOutbound(); + break; + case 1: + returnValue = getTimeInbound(); + break; + case 2: + returnValue = getIncome(); + break; + case 3: + returnValue = getAdults(); + break; + case 4: + returnValue = getFemale(); + break; + case 5: + returnValue = getHhSize(); + break; + case 6: + returnValue = getAutos(); + break; + case 7: + returnValue = getAge(); + break; + case 8: + returnValue = getTourCategoryJoint(); + break; + case 9: + returnValue = getNumberOfParticipantsInJointTour(); + break; + case 10: + returnValue = getWorkTourModeIsSov(); + break; + case 11: + returnValue = getWorkTourModeIsBike(); + break; + case 12: + returnValue = getWorkTourModeIsHov(); + break; + case 14: + returnValue = getPTazTerminalTime(); + break; + case 15: + returnValue = getATazTerminalTime(); + break; + case 16: + returnValue = getODUDen(); + break; + case 17: + returnValue = getOEmpDen(); + break; + case 18: + returnValue = getOTotInt(); + break; + case 19: + returnValue = getDDUDen(); + break; + case 20: + returnValue = getDEmpDen(); + break; + case 21: + returnValue = getDTotInt(); + break; + case 22: + returnValue = getTourCategoryEscort(); + break; + case 90: + returnValue = getNm_walkTime_out(); + break; + case 91: + returnValue = getNm_walkTime_in(); + break; + case 92: + returnValue = getNm_bikeTime_out(); + break; + case 93: + returnValue = getNm_bikeTime_in(); + break; + /* TODO + case 176: + methodIndexMap.put("getWtw_LB_ivt_out", 176); + case 177: + methodIndexMap.put("getWtw_LB_ivt_in", 177); + case 178: + methodIndexMap.put("getWtw_EB_ivt_out", 178); + case 179: + methodIndexMap.put("getWtw_EB_ivt_in", 179); + case 180: + methodIndexMap.put("getWtw_BRT_ivt_out", 180); + case 181: + methodIndexMap.put("getWtw_BRT_ivt_in", 181); + case 182: + methodIndexMap.put("getWtw_LRT_ivt_out", 182); + case 183: + methodIndexMap.put("getWtw_LRT_ivt_in", 183); + methodIndexMap.put("getWtw_CR_ivt_out", 184); + methodIndexMap.put("getWtw_CR_ivt_in", 185); + methodIndexMap.put("getWtw_fwait_out", 186); + methodIndexMap.put("getWtw_fwait_in", 187); + methodIndexMap.put("getWtw_xwait_out", 188); + methodIndexMap.put("getWtw_xwait_in", 189); + methodIndexMap.put("getWtw_AccTime_out", 190); + methodIndexMap.put("getWtw_AccTime_in", 191); + methodIndexMap.put("getWtw_EgrTime_out", 192); + methodIndexMap.put("getWtw_EgrTime_in", 193); + methodIndexMap.put("getWtw_WalkAuxTime_out", 194); + methodIndexMap.put("getWtw_WalkAuxTime_in", 195); + methodIndexMap.put("getWtw_fare_out", 196); + methodIndexMap.put("getWtw_fare_in", 197); + methodIndexMap.put("getWtw_xfers_out", 198); + methodIndexMap.put("getWtw_xfers_in", 199); + + methodIndexMap.put("getWtd_LB_ivt_out", 276); + methodIndexMap.put("getWtd_LB_ivt_in", 277); + methodIndexMap.put("getWtd_EB_ivt_out", 278); + methodIndexMap.put("getWtd_EB_ivt_in", 279); + methodIndexMap.put("getWtd_BRT_ivt_out", 280); + methodIndexMap.put("getWtd_BRT_ivt_in", 281); + methodIndexMap.put("getWtd_LRT_ivt_out", 282); + methodIndexMap.put("getWtd_LRT_ivt_in", 283); + methodIndexMap.put("getWtd_CR_ivt_out", 284); + methodIndexMap.put("getWtd_CR_ivt_in", 285); + methodIndexMap.put("getWtd_fwait_out", 286); + methodIndexMap.put("getWtd_fwait_in", 287); + methodIndexMap.put("getWtd_xwait_out", 288); + methodIndexMap.put("getWtd_xwait_in", 289); + methodIndexMap.put("getWtd_AccTime_out", 290); + methodIndexMap.put("getWtd_AccTime_in", 291); + methodIndexMap.put("getWtd_EgrTime_out", 292); + methodIndexMap.put("getWtd_EgrTime_in", 293); + methodIndexMap.put("getWtd_WalkAuxTime_out", 294); + methodIndexMap.put("getWtd_WalkAuxTime_in", 295); + methodIndexMap.put("getWtd_fare_out", 296); + methodIndexMap.put("getWtd_fare_in", 297); + methodIndexMap.put("getWtd_xfers_out", 298); + methodIndexMap.put("getWtd_xfers_in", 299); + methodIndexMap.put("getDtw_LB_ivt_out", 376); + methodIndexMap.put("getDtw_LB_ivt_in", 377); + methodIndexMap.put("getDtw_EB_ivt_out", 378); + methodIndexMap.put("getDtw_EB_ivt_in", 379); + methodIndexMap.put("getDtw_BRT_ivt_out", 380); + methodIndexMap.put("getDtw_BRT_ivt_in", 381); + methodIndexMap.put("getDtw_LRT_ivt_out", 382); + methodIndexMap.put("getDtw_LRT_ivt_in", 383); + methodIndexMap.put("getDtw_CR_ivt_out", 384); + methodIndexMap.put("getDtw_CR_ivt_in", 385); + methodIndexMap.put("getDtw_fwait_out", 386); + methodIndexMap.put("getDtw_fwait_in", 387); + methodIndexMap.put("getDtw_xwait_out", 388); + methodIndexMap.put("getDtw_xwait_in", 389); + methodIndexMap.put("getDtw_AccTime_out", 390); + methodIndexMap.put("getDtw_AccTime_in", 391); + methodIndexMap.put("getDtw_EgrTime_out", 392); + methodIndexMap.put("getDtw_EgrTime_in", 393); + methodIndexMap.put("getDtw_WalkAuxTime_out", 394); + methodIndexMap.put("getDtw_WalkAuxTime_in", 395); + methodIndexMap.put("getDtw_fare_out", 396); + methodIndexMap.put("getDtw_fare_in", 397); + methodIndexMap.put("getDtw_xfers_out", 398); + methodIndexMap.put("getDtw_xfers_in", 399); + */ + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + return returnValue; + + } + + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagAtWorkSubtourFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagAtWorkSubtourFrequencyDMU.java new file mode 100644 index 0000000..82ae86d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagAtWorkSubtourFrequencyDMU.java @@ -0,0 +1,64 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.AtWorkSubtourFrequencyDMU; +import org.sandag.abm.ctramp.ModelStructure; +import com.pb.common.calculator.VariableTable; + +public class SandagAtWorkSubtourFrequencyDMU + extends AtWorkSubtourFrequencyDMU + implements VariableTable +{ + + public SandagAtWorkSubtourFrequencyDMU(ModelStructure modelStructure) + { + super(modelStructure); + this.modelStructure = modelStructure; + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getIncomeInDollars", 0); + methodIndexMap.put("getPersonType", 1); + methodIndexMap.put("getFemale", 2); + methodIndexMap.put("getDrivers", 3); + methodIndexMap.put("getNumPreschoolChildren", 4); + methodIndexMap.put("getNumIndivEatOutTours", 5); + methodIndexMap.put("getNumTotalTours", 6); + methodIndexMap.put("getNmEatOutAccessibilityWorkplace", 7); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getIncomeInDollars(); + case 1: + return getPersonType(); + case 2: + return getFemale(); + case 3: + return getDrivers(); + case 4: + return getNumPreschoolChildren(); + case 5: + return getNumIndivEatOutTours(); + case 6: + return getNumTotalTours(); + case 7: + return getNmEatOutAccessibilityWorkplace(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagAutoOwnershipChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagAutoOwnershipChoiceDMU.java new file mode 100644 index 0000000..3c25f8d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagAutoOwnershipChoiceDMU.java @@ -0,0 +1,104 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.AutoOwnershipChoiceDMU; + +public class SandagAutoOwnershipChoiceDMU + extends AutoOwnershipChoiceDMU +{ + + public SandagAutoOwnershipChoiceDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getDrivers", 1); + methodIndexMap.put("getNumFtWorkers", 2); + methodIndexMap.put("getNumPtWorkers", 3); + methodIndexMap.put("getNumPersons18to24", 4); + methodIndexMap.put("getNumPersons6to15", 5); + methodIndexMap.put("getNumPersons80plus", 6); + methodIndexMap.put("getNumPersons65to79", 7); + methodIndexMap.put("getHhIncomeInDollars", 8); + methodIndexMap.put("getNumHighSchoolGraduates", 9); + methodIndexMap.put("getDetachedDwellingType", 10); + methodIndexMap.put("getUseAccessibilities", 11); + methodIndexMap.put("getHomeTazNonMotorizedAccessibility", 12); + methodIndexMap.put("getHomeTazAutoAccessibility", 13); + methodIndexMap.put("getHomeTazTransitAccessibility", 14); + methodIndexMap.put("getWorkAutoDependency", 15); + methodIndexMap.put("getSchoolAutoDependency", 16); + methodIndexMap.put("getWorkersRailProportion", 17); + methodIndexMap.put("getStudentsRailProportion", 18); + methodIndexMap.put("getGq", 19); + methodIndexMap.put("getNumPersons18to35", 25); + methodIndexMap.put("getNumPersons65plus", 26); + methodIndexMap.put("getWorkAutoTime", 27); + methodIndexMap.put("getHomeTazMaasAccessibility", 28); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 1: + return getDrivers(); + case 2: + return getNumFtWorkers(); + case 3: + return getNumPtWorkers(); + case 4: + return getNumPersons18to24(); + case 5: + return getNumPersons6to15(); + case 6: + return getNumPersons80plus(); + case 7: + return getNumPersons65to79(); + case 8: + return getHhIncomeInDollars(); + case 9: + return getNumHighSchoolGraduates(); + case 10: + return getDetachedDwellingType(); + case 11: + return getUseAccessibilities(); + case 12: + return getHomeTazNonMotorizedAccessibility(); + case 13: + return getHomeTazAutoAccessibility(); + case 14: + return getHomeTazTransitAccessibility(); + case 15: + return getWorkAutoDependency(); + case 16: + return getSchoolAutoDependency(); + case 17: + return getWorkersRailProportion(); + case 18: + return getStudentsRailProportion(); + case 19: + return getGq(); + case 25: + return getNumPersons18to35(); + case 26: + return getNumPersons65Plus(); + case 27: + return getWorkAutoTime(); + case 28: + return getHomeTazMaasAccessibility(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagCoordinatedDailyActivityPatternDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCoordinatedDailyActivityPatternDMU.java new file mode 100644 index 0000000..f69cfdc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCoordinatedDailyActivityPatternDMU.java @@ -0,0 +1,176 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.CoordinatedDailyActivityPatternDMU; + +public class SandagCoordinatedDailyActivityPatternDMU + extends CoordinatedDailyActivityPatternDMU +{ + + public SandagCoordinatedDailyActivityPatternDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getFullTimeWorkerA", 0); + methodIndexMap.put("getFullTimeWorkerB", 1); + methodIndexMap.put("getFullTimeWorkerC", 2); + methodIndexMap.put("getPartTimeWorkerA", 3); + methodIndexMap.put("getPartTimeWorkerB", 4); + methodIndexMap.put("getPartTimeWorkerC", 5); + methodIndexMap.put("getUniversityStudentA", 6); + methodIndexMap.put("getUniversityStudentB", 7); + methodIndexMap.put("getUniversityStudentC", 8); + methodIndexMap.put("getNonWorkingAdultA", 9); + methodIndexMap.put("getNonWorkingAdultB", 10); + methodIndexMap.put("getNonWorkingAdultC", 11); + methodIndexMap.put("getRetiredA", 12); + methodIndexMap.put("getRetiredB", 13); + methodIndexMap.put("getRetiredC", 14); + methodIndexMap.put("getDrivingAgeSchoolChildA", 15); + methodIndexMap.put("getDrivingAgeSchoolChildB", 16); + methodIndexMap.put("getDrivingAgeSchoolChildC", 17); + methodIndexMap.put("getPreDrivingAgeSchoolChildA", 18); + methodIndexMap.put("getPreDrivingAgeSchoolChildB", 19); + methodIndexMap.put("getPreDrivingAgeSchoolChildC", 20); + methodIndexMap.put("getPreSchoolChildA", 21); + methodIndexMap.put("getPreSchoolChildB", 22); + methodIndexMap.put("getPreSchoolChildC", 23); + methodIndexMap.put("getAgeA", 24); + methodIndexMap.put("getFemaleA", 25); + methodIndexMap.put("getMoreCarsThanWorkers", 26); + methodIndexMap.put("getFewerCarsThanWorkers", 27); + methodIndexMap.put("getZeroCars", 28); + methodIndexMap.put("getHHIncomeInDollars", 29); + methodIndexMap.put("getHhDetach", 30); + methodIndexMap.put("getUsualWorkLocationIsHomeA", 31); + methodIndexMap.put("getNoUsualWorkLocationA", 32); + methodIndexMap.put("getNoUsualSchoolLocationA", 33); + methodIndexMap.put("getHhSize", 34); + methodIndexMap.put("getWorkLocationModeChoiceLogsumA", 35); + methodIndexMap.put("getSchoolLocationModeChoiceLogsumA", 36); + methodIndexMap.put("getRetailAccessibility", 37); + methodIndexMap.put("getNumAdultsWithNonMandatoryDap", 38); + methodIndexMap.put("getNumAdultsWithMandatoryDap", 39); + methodIndexMap.put("getNumKidsWithNonMandatoryDap", 40); + methodIndexMap.put("getNumKidsWithMandatoryDap", 41); + methodIndexMap.put("getAllAdultsAtHome", 42); + methodIndexMap.put("getWorkAccessForMandatoryDap", 43); + methodIndexMap.put("getTelecommuteFrequencyA", 44); + methodIndexMap.put("getTelecommuteFrequencyB", 45); + methodIndexMap.put("getTelecommuteFrequencyC", 46); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getFullTimeWorkerA(); + case 1: + return getFullTimeWorkerB(); + case 2: + return getFullTimeWorkerC(); + case 3: + return getPartTimeWorkerA(); + case 4: + return getPartTimeWorkerB(); + case 5: + return getPartTimeWorkerC(); + case 6: + return getUniversityStudentA(); + case 7: + return getUniversityStudentB(); + case 8: + return getUniversityStudentC(); + case 9: + return getNonWorkingAdultA(); + case 10: + return getNonWorkingAdultB(); + case 11: + return getNonWorkingAdultC(); + case 12: + return getRetiredA(); + case 13: + return getRetiredB(); + case 14: + return getRetiredC(); + case 15: + return getDrivingAgeSchoolChildA(); + case 16: + return getDrivingAgeSchoolChildB(); + case 17: + return getDrivingAgeSchoolChildC(); + case 18: + return getPreDrivingAgeSchoolChildA(); + case 19: + return getPreDrivingAgeSchoolChildB(); + case 20: + return getPreDrivingAgeSchoolChildC(); + case 21: + return getPreSchoolChildA(); + case 22: + return getPreSchoolChildB(); + case 23: + return getPreSchoolChildC(); + case 24: + return getAgeA(); + case 25: + return getFemaleA(); + case 26: + return getMoreCarsThanWorkers(); + case 27: + return getFewerCarsThanWorkers(); + case 28: + return getZeroCars(); + case 29: + return getHHIncomeInDollars(); + case 30: + return getHhDetach(); + case 31: + return getUsualWorkLocationIsHomeA(); + case 32: + return getNoUsualWorkLocationA(); + case 33: + return getNoUsualSchoolLocationA(); + case 34: + return getHhSize(); + case 35: + return getWorkLocationModeChoiceLogsumA(); + case 36: + return getSchoolLocationModeChoiceLogsumA(); + case 37: + return getRetailAccessibility(); + case 38: + return getNumAdultsWithNonMandatoryDap(); + case 39: + return getNumAdultsWithMandatoryDap(); + case 40: + return getNumKidsWithNonMandatoryDap(); + case 41: + return getNumKidsWithMandatoryDap(); + case 42: + return getAllAdultsAtHome(); + case 43: + return getWorkAccessForMandatoryDap(); + case 44: + return getTelecommuteFrequencyA(); + case 45: + return getTelecommuteFrequencyB(); + case 46: + return getTelecommuteFrequencyC(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagCreateTripGenerationFiles.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCreateTripGenerationFiles.java new file mode 100644 index 0000000..f329b78 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCreateTripGenerationFiles.java @@ -0,0 +1,1055 @@ +package org.sandag.abm.application; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.IOException; +import java.util.HashMap; +import java.util.ResourceBundle; +import java.util.StringTokenizer; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.datafile.CSVFileWriter; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +public class SandagCreateTripGenerationFiles +{ + + private static Logger logger = Logger.getLogger(SandagCreateTripGenerationFiles.class); + + private static final String SANDAG_TRIP_GEN_FILE_KEY = "trip.model.trips.file"; + private static final String ABM_TRIP_GEN_FILE_KEY = "output.trips.file"; + private static final String ABM_INDIV_TRIP_FILE_KEY = "abm.individual.trip.file"; + private static final String TAZ_TDZ_CORRESP_KEY = "taz.tdz.corresp.file"; + private static final String SCALE_NHB_KEY = "scale.nhb"; + + private static final String TAZ_COLUMN_HEADING = "taz"; + private static final String TDZ_COLUMN_HEADING = "tdz"; + + private static final String TRIP_ORIG_PURPOSE_FIELD_NAME = "orig_purpose"; + private static final String TRIP_DEST_PURPOSE_FIELD_NAME = "dest_purpose"; + private static final String TRIP_ORIG_MGRA_FIELD_NAME = "orig_maz"; + private static final String TRIP_DEST_MGRA_FIELD_NAME = "dest_maz"; + private static final String[] HH_HEADINGS = { + TRIP_ORIG_PURPOSE_FIELD_NAME, TRIP_DEST_PURPOSE_FIELD_NAME, TRIP_ORIG_MGRA_FIELD_NAME, + TRIP_DEST_MGRA_FIELD_NAME }; + + private static final int MAX_PURPOSE_INDEX = 10; + + private static final int MIN_EXTERNAL_TDZ = 1; + private static final int MAX_EXTERNAL_TDZ = 12; + + private static final String TAZ_FIELD_HEADING = "zone"; + + private static final String[] TRIP_MODEL_HOME_BASED_ATTRACTION_HEADINGS = {"a1", "a2", + "a3", "a4", "a5", "a8" }; + private static final String[] TRIP_MODEL_HOME_BASED_PRODUCTION_HEADINGS = {"p1", "p2", + "p3", "p4", "p5", "p8" }; + private static final String[] TRIP_MODEL_NON_HOME_BASED_ATTRACTION_HEADINGS = {"a6", "a7"}; + private static final String[] TRIP_MODEL_NON_HOME_BASED_PRODUCTION_HEADINGS = {"p6", "p7"}; + private static final String[] TRIP_MODEL_OTHER_BASED_PRODUCTION_HEADINGS = {"p9", "p10"}; + private static final String[] TRIP_MODEL_OTHER_BASED_ATTRACTION_HEADINGS = {"a9", "a10"}; + + private static final int[] AB_MODEL_HOME_BASED_PRODUCTION_INDICES = {1, 2, 3, 4, 5, 8}; + private static final int[] AB_MODEL_NON_HOME_BASED_PRODUCTION_INDICES = {6, 7}; + private static final int[] AB_MODEL_OTHER_PRODUCTION_INDICES = {9, 10}; + + private float[][] ieTrips; + + private static final String[] TABLE_HEADINGS = {"zone", "p1", + "p2", "p3", "p4", "p5", "p6", "p7", "p8", "p9", "p10", "a1", "a2", "a3", "a4", "a5", + "a6", "a7", "a8", "a9", "a10" }; + private static final String[] TABLE_HEADING_DESCRIPTIONS = {"zone", + "home based work", "home based university", "home based school", "home based shop", + "home based other", "non home based work related", "non home based other", + "home based escort", "home based visitor", "home based airport", "home based work", + "home based university", "home based school", "home based shop", "home based other", + "non home based work related", "non home based other", "home based escort", + "home based visitor", "home based airport" }; + + private MgraDataManager mgraManager; + private int maxTdz; + + public SandagCreateTripGenerationFiles(HashMap rbMap) + { + + mgraManager = MgraDataManager.getInstance(rbMap); + + } + + public void createTripGenFile(HashMap rbMap) + { + + String tgInputFile = rbMap.get(SANDAG_TRIP_GEN_FILE_KEY); + if (tgInputFile == null) + { + logger.error("Error getting the filename from the properties file for the input Sandag Trip Prods/Attrs by MDZ file."); + logger.error("Properties file target: " + SANDAG_TRIP_GEN_FILE_KEY + " not found."); + logger.error("Please specify a filename value for the " + SANDAG_TRIP_GEN_FILE_KEY + + " property."); + throw new RuntimeException(); + } + + String tgOutputFile = rbMap.get(ABM_TRIP_GEN_FILE_KEY); + if (tgOutputFile == null) + { + logger.error("Error getting the filename from the properties file to use for the new Trip Prods/Attrs by MDZ file created."); + logger.error("Properties file target: " + ABM_TRIP_GEN_FILE_KEY + " not found."); + logger.error("Please specify a filename value for the " + ABM_TRIP_GEN_FILE_KEY + + " property."); + throw new RuntimeException(); + } + + String abmTripFile = rbMap.get(ABM_INDIV_TRIP_FILE_KEY); + if (abmTripFile == null) + { + logger.error("Error getting the filename from the properties file to use for the ABM Model individual trips file."); + logger.error("Properties file target: " + ABM_INDIV_TRIP_FILE_KEY + " not found."); + logger.error("Please specify a filename value for the " + ABM_INDIV_TRIP_FILE_KEY + + " property."); + throw new RuntimeException(); + } + + String correspFile = rbMap.get(TAZ_TDZ_CORRESP_KEY); + if (correspFile == null) + { + logger.error("Error getting the filename from the properties file to use for the TAZ / TDZ correspondence file."); + logger.error("Properties file target: " + TAZ_TDZ_CORRESP_KEY + " not found."); + logger.error("Please specify a filename value for the " + TAZ_TDZ_CORRESP_KEY + + " property."); + throw new RuntimeException(); + } + + // default is false + boolean scaleNhbToAbm = false; + String scaleNhbToAbmString = rbMap.get(SCALE_NHB_KEY); + if (scaleNhbToAbmString != null && scaleNhbToAbmString.equalsIgnoreCase("true")) + scaleNhbToAbm = true; + logger.info("parameter to enable scaling NHB prods/attrs has a value of: " + scaleNhbToAbm); + + HashMap tazTdzMap = createTazTdzMap(correspFile); + + TableDataSet inTgTds = readInputTripGenFile(tgInputFile); + + int[][] tdzTrips = readInputAbmIndivTripFile(abmTripFile, tazTdzMap); + + TableDataSet outAbmTds = produceAbmTripTableDataSet(inTgTds, tdzTrips, scaleNhbToAbm); + + writeAbmTripGenFile(tgOutputFile, outAbmTds); + + logger.info(""); + logger.info(""); + logger.info("finished producing new trip generation files from the ABM trip data."); + } + + private TableDataSet readInputTripGenFile(String fileName) + { + + TableDataSet inTgTds = null; + + try + { + logger.info(""); + logger.info(""); + logger.info("reading input trip generation file."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + inTgTds = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading input trip generation data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + // create TDZ by purpose arrays for IE Prods and IE attrs from the trip + // model + // these will be added into the home-based AB model prods and attrs + // use the first dimension 0 element to accumulate totals by purpose for + // logging + ieTrips = new float[maxTdz + 1][2 * MAX_PURPOSE_INDEX + 1]; + for (int i = 0; i < inTgTds.getRowCount(); i++) + { + int tdz = (int) inTgTds.getValueAt(i + 1, TAZ_FIELD_HEADING); + for (int j = 1; j < inTgTds.getColumnCount(); j++) + { + if (tdz >= MIN_EXTERNAL_TDZ && tdz <= MAX_EXTERNAL_TDZ) + { + ieTrips[i + 1][j] = inTgTds.getValueAt(i + 1, j + 1); + ieTrips[0][j] += inTgTds.getValueAt(i + 1, j + 1); + } + } + } + + // log column totals + logger.info(""); + logger.info(""); + logger.info("\t" + inTgTds.getRowCount() + " rows in input file."); + logger.info("\t" + inTgTds.getColumnCount() + " columns in input file."); + logger.info(""); + logger.info(String.format("\t%-15s %-30s %15s %15s", "Column Name", "Column Purpose", + "Column Total", "Int-Ext")); + + String[] headings = inTgTds.getColumnLabels(); + logger.info(String.format("\t%-15s %-30s %15s %15s", headings[0], "N/A", "N/A", "N/A")); + float totProd = 0; + float totAttr = 0; + float totalIeProds = 0; + float totalIeAttrs = 0; + float columnSum = 0; + for (int i = 1; i < inTgTds.getColumnCount(); i++) + { + + columnSum = inTgTds.getColumnTotal(i + 1); + + // 1st 10 fields after zone are production fields, next 10 are + // attraction + // fields + if (i <= 10) + { + totProd += columnSum; + totalIeProds += ieTrips[0][i]; + } else + { + totAttr += columnSum; + totalIeAttrs += ieTrips[0][i]; + } + + logger.info(String.format("\t%-15s %-30s %15.1f %15.1f", headings[i], + TABLE_HEADING_DESCRIPTIONS[i], columnSum, ieTrips[0][i])); + + } + + logger.info(""); + logger.info(""); + logger.info(String.format("\ttotal productions = %15.1f", totProd)); + logger.info(String.format("\ttotal attractions = %15.1f", totAttr)); + logger.info(String.format("\ttotal IE productions = %12.1f", totalIeProds)); + logger.info(String.format("\ttotal IE attractions = %12.1f", totalIeAttrs)); + logger.info(""); + + return inTgTds; + } + + private HashMap createTazTdzMap(String correspFile) + { + + TableDataSet tazTdzTds = null; + + try + { + logger.info(""); + logger.info(""); + logger.info("reading input taz-tdz correspondence file."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + tazTdzTds = reader.readFile(new File(correspFile)); + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading input taz-tdz correspondence file: %s into TableDataSet object.", + correspFile)); + throw new RuntimeException(e); + } + + maxTdz = 0; + HashMap tazTdzMap = new HashMap(); + for (int r = 1; r <= tazTdzTds.getRowCount(); r++) + { + int taz = (int) tazTdzTds.getValueAt(r, TAZ_COLUMN_HEADING); + int tdz = (int) tazTdzTds.getValueAt(r, TDZ_COLUMN_HEADING); + tazTdzMap.put(taz, tdz); + + if (tdz > maxTdz) maxTdz = tdz; + } + + // a trip record with origin or destination mgra=0 or mgra=-1 (location + // not + // determined) should map to tdz=0 + // if a trip record mgra is not greater than 0, its taz will be 0 - then + // the + // following entry will map it to tdz=0. + tazTdzMap.put(0, 0); + + return tazTdzMap; + + } + + private int[][] readInputAbmIndivTripFile(String fileName, HashMap tazTdzMap) + { + + String origPurpose = ""; + String destPurpose = ""; + int origMgra = 0; + int destMgra = 0; + int homeTdz = 0; + int tripPurposeIndex = 0; + + // open the file for reading + String delimSet = ",\t\n\r\f\""; + BufferedReader inputStream = null; + try + { + inputStream = new BufferedReader(new FileReader(new File(fileName))); + } catch (FileNotFoundException e) + { + logger.fatal(String.format("Exception occurred reading input abm indiv trip file: %s.", + fileName)); + throw new RuntimeException(e); + } + + // first parse the trip file field names from the first record and + // associate + // column position with fields specified to be read + HashMap columnIndexHeadingMap = new HashMap(); + String line = ""; + try + { + line = inputStream.readLine(); + } catch (IOException e) + { + logger.fatal(String.format( + "Exception occurred reading header record of input abm indiv trip file: %s.", + fileName)); + logger.fatal(String.format("line = %s.", line)); + throw new RuntimeException(e); + } + StringTokenizer st = new StringTokenizer(line, delimSet); + int col = 0; + while (st.hasMoreTokens()) + { + String label = st.nextToken(); + for (String heading : HH_HEADINGS) + { + if (heading.equalsIgnoreCase(label)) + { + columnIndexHeadingMap.put(col, heading); + break; + } + } + col++; + } + + // dimension the array to hold trips summarized by tdz and trip model + // purpose + int[][] abmTdzTrips = new int[maxTdz + 1][MAX_PURPOSE_INDEX + 1]; + int[] abmTdzTotalTrips = new int[MAX_PURPOSE_INDEX + 1]; + + // read the trip records from the file + int lineCount = 0; + try + { + + while ((line = inputStream.readLine()) != null) + { + + lineCount++; + + // get the values for the fields specified. + col = 0; + st = new StringTokenizer(line, delimSet); + while (st.hasMoreTokens()) + { + String fieldValue = st.nextToken(); + if (columnIndexHeadingMap.containsKey(col)) + { + String fieldName = columnIndexHeadingMap.get(col++); + + if (fieldName.equalsIgnoreCase(TRIP_ORIG_PURPOSE_FIELD_NAME)) + { + origPurpose = fieldValue; + } else if (fieldName.equalsIgnoreCase(TRIP_DEST_PURPOSE_FIELD_NAME)) + { + destPurpose = fieldValue; + } else if (fieldName.equalsIgnoreCase(TRIP_ORIG_MGRA_FIELD_NAME)) + { + origMgra = Integer.parseInt(fieldValue); + } else if (fieldName.equalsIgnoreCase(TRIP_DEST_MGRA_FIELD_NAME)) + { + destMgra = Integer.parseInt(fieldValue); + + // don't need to process any more fields + break; + + } + + } else + { + col++; + } + + } + + int homeTaz = 0; + try + { + if (origPurpose.equalsIgnoreCase("Home") && origMgra > 0) homeTaz = mgraManager + .getTaz(origMgra); + else if (destPurpose.equalsIgnoreCase("Home") && destMgra > 0) + homeTaz = mgraManager.getTaz(destMgra); + } catch (Exception e) + { + logger.error("error getting home taz from mgraManager for origPurpose = " + + origPurpose + ", origMgra = " + origMgra + ", destPurpose = " + + destPurpose + ", destMgra = " + destMgra + ", lineCount = " + + lineCount); + throw new RuntimeException(e); + } + + try + { + homeTdz = tazTdzMap.get(homeTaz); + } catch (Exception e) + { + logger.error("error getting home tdz from tazTdzMap for homeTaz = " + homeTaz + + ", lineCount = " + lineCount); + throw new RuntimeException(e); + } + + try + { + // get the trip based model purpose index for this abm model + // trip + tripPurposeIndex = getTripModelPurposeForAbmTrip(origPurpose, destPurpose); + } catch (Exception e) + { + logger.error("error getting tripPurposeIndex for origPurpose = " + origPurpose + + ", destPurpose = " + destPurpose + ", lineCount = " + lineCount); + throw new RuntimeException(e); + } + + // accumulate trips in table + if (tripPurposeIndex >= 1 && tripPurposeIndex <= 5 || tripPurposeIndex == 8) + { + if (homeTdz > 0) abmTdzTrips[homeTdz][tripPurposeIndex]++; + else + { + logger.error("home tdz is le 0 for home-based trip."); + throw new RuntimeException(); + } + } else + { + if (homeTdz > 0) + { + logger.error("home tdz is gt 0 for non-home-based trip."); + throw new RuntimeException(); + } + abmTdzTrips[homeTdz][tripPurposeIndex]++; + } + abmTdzTotalTrips[tripPurposeIndex]++; + + } + + } catch (NumberFormatException e) + { + logger.fatal(String + .format("NumberFormatException occurred reading record of input abm indiv trip file: %s.", + fileName)); + logger.fatal(String.format("last record number read = %d.", lineCount)); + } catch (IOException e) + { + logger.fatal(String.format( + "IOException occurred reading record of input abm indiv trip file: %s.", + fileName)); + logger.fatal(String.format("last record number read = %d.", lineCount)); + } + + logger.info(lineCount + " trip records read from " + fileName); + + // log a summary report of trips by trip model purpose + logger.info(""); + logger.info(""); + logger.info("ABM Trip file trips by TM purpose"); + logger.info(String.format("\t%-15s %-30s %15s", "Column Name", "Column Purpose", + "Column Total")); + String[] headings = {"", "hbw", "hbu", "hbc", "hbs", "hbo", "nhw", "nho", "hbp"}; + int total = 0; + for (int i = 1; i < headings.length; i++) + { + logger.info(String.format("\t%-15s %-30s %15d", headings[i], + TABLE_HEADING_DESCRIPTIONS[i], abmTdzTotalTrips[i])); + total += abmTdzTotalTrips[i]; + } + logger.info(String.format("\t%-15s %-30s %15d", "Total", "", total)); + + return abmTdzTrips; + + } + + private int getTripModelPurposeForAbmTrip(String origPurpose, String destPurpose) + { + + /* + * assignment rules: replace tpurp4s = 1 if orig_purpose=="Home" & + * dest_purpose=="Work"; replace tpurp4s = 1 if orig_purpose=="Work" & + * dest_purpose=="Home"; replace tpurp4s = 2 if orig_purpose=="Home" & + * dest_purpose=="University"; replace tpurp4s = 2 if + * orig_purpose=="University" & dest_purpose=="Home"; replace tpurp4s = + * 3 if orig_purpose=="Home" & dest_purpose=="School"; replace tpurp4s = + * 3 if orig_purpose=="School" & dest_purpose=="Home"; replace tpurp4s = + * 4 if orig_purpose=="Home" & dest_purpose=="Shop"; replace tpurp4s = 4 + * if orig_purpose=="Shop" & dest_purpose=="Home"; replace tpurp4s = 5 + * if orig_purpose=="Home" & (dest_purpose=="Maintenance" | + * dest_purpose=="Eating Out" | dest_purpose=="Visiting" | + * dest_purpose=="Discretionary"); replace tpurp4s = 5 if + * dest_purpose=="Home" & (orig_purpose=="Maintenance" | + * orig_purpose=="Eating Out" | orig_purpose=="Visiting" | + * orig_purpose=="Discretionary"); replace tpurp4s = 8 if + * orig_purpose=="Home" & dest_purpose=="Escort"; replace tpurp4s = 8 if + * orig_purpose=="Escort" & dest_purpose=="Home"; replace tpurp4s = 6 if + * orig_purpose=="Work" & dest_purpose!="Home"; replace tpurp4s = 6 if + * orig_purpose!="Home" & dest_purpose=="Work"; replace tpurp4s = 6 if + * orig_purpose=="Work-Based" | dest_purpose=="Work-Based"; replace + * tpurp4s = 7 if tpurp4s==0; + */ + + int tripPurposeIndex = 0; + if (origPurpose.equalsIgnoreCase("Home") && destPurpose.equalsIgnoreCase("Work")) tripPurposeIndex = 1; + else if (origPurpose.equalsIgnoreCase("Work") && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 1; + else if (origPurpose.equalsIgnoreCase("Home") && destPurpose.equalsIgnoreCase("University")) tripPurposeIndex = 2; + else if (origPurpose.equalsIgnoreCase("University") && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 2; + else if (origPurpose.equalsIgnoreCase("Home") && destPurpose.equalsIgnoreCase("School")) tripPurposeIndex = 3; + else if (origPurpose.equalsIgnoreCase("School") && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 3; + else if (origPurpose.equalsIgnoreCase("Home") && destPurpose.equalsIgnoreCase("Shop")) tripPurposeIndex = 4; + else if (origPurpose.equalsIgnoreCase("Shop") && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 4; + else if (origPurpose.equalsIgnoreCase("Home") + && destPurpose.equalsIgnoreCase("Maintenance")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Maintenance") + && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Home") && destPurpose.equalsIgnoreCase("Eating Out")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Eating Out") && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Home") && destPurpose.equalsIgnoreCase("Visiting")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Visiting") && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Home") + && destPurpose.equalsIgnoreCase("Discretionary")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Discretionary") + && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Home") + && destPurpose.equalsIgnoreCase("Work Related")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Work Related") + && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 5; + else if (origPurpose.equalsIgnoreCase("Home") && destPurpose.equalsIgnoreCase("Escort")) tripPurposeIndex = 8; + else if (origPurpose.equalsIgnoreCase("Escort") && destPurpose.equalsIgnoreCase("Home")) tripPurposeIndex = 8; + else if (origPurpose.equalsIgnoreCase("Work") && (!destPurpose.equalsIgnoreCase("Home"))) tripPurposeIndex = 6; + else if ((!destPurpose.equalsIgnoreCase("Home")) && destPurpose.equalsIgnoreCase("Work")) tripPurposeIndex = 6; + else if (origPurpose.equalsIgnoreCase("Work-Based") + || destPurpose.equalsIgnoreCase("Work-Based")) tripPurposeIndex = 6; + else tripPurposeIndex = 7; + + return tripPurposeIndex; + + } + + private TableDataSet produceAbmTripTableDataSet(TableDataSet inTgTds, int[][] tdzTrips, + boolean scaleNhbToAbm) + { + + float[][] newTrips = new float[maxTdz][2 * MAX_PURPOSE_INDEX + 1]; + + saveAbmHbProdsAndScaleTmAttrs(inTgTds, tdzTrips, newTrips); + + saveTmNhbProdsAsAbmProds(inTgTds, tdzTrips, scaleNhbToAbm, newTrips); + + saveTmNhbAttrsAsAbmProds(inTgTds, tdzTrips, scaleNhbToAbm, newTrips); + + addTmIeAttrsToAbmHbProds(inTgTds, tdzTrips, newTrips); + + addTmIeProdsToAbmHbAttrs(inTgTds, tdzTrips, newTrips); + + addTmAirportAndVisitorProdsToAbmProds(inTgTds, tdzTrips, newTrips); + + addTmAirportAndVisitorAttrsToAbmAttrs(inTgTds, tdzTrips, newTrips); + + saveZoneField(inTgTds, newTrips); + + TableDataSet abmTds = createFinalTableDataset(newTrips); + + return abmTds; + } + + private void saveAbmHbProdsAndScaleTmAttrs(TableDataSet inTgTds, int[][] tdzTrips, + float[][] newTrips) + { + logger.info(""); + logger.info(""); + logger.info("transferring ABM home-based productions and scaling TM attractions:"); + logger.info(String.format("%10s %-30s %15s %15s %15s %15s %15s", "TM Heading", + "TM Purpose", "TM Attrs", "ABM Attrs", "Scale Factor", "New ABM Prods", + "New ABM Attrs")); + int index = 0; + for (String heading : TRIP_MODEL_HOME_BASED_ATTRACTION_HEADINGS) + { + + // get the trip model attractions, the TableDataSet returns a 0s + // based + // array + float[] values = inTgTds.getColumnAsFloat(heading); + + // add up the total TM attractions for this purpose + float total = 0; + for (int i = 0; i < values.length; i++) + total += values[i]; + + // add up the total ABM productions for this purpose + int abTotal = 0; + int abProdIndex = AB_MODEL_HOME_BASED_PRODUCTION_INDICES[index]; + for (int i = 1; i < tdzTrips.length; i++) + abTotal += tdzTrips[i][abProdIndex]; + + // get the scale factor to scale trip model atractions to ABM + // productions + // by purpose + double scaleFactor = 0.0; + if (total > 0) + { + scaleFactor = abTotal / total; + } else + { + logger.error("attempting to scale an array which sums to 0.0."); + throw new RuntimeException(); + } + + // get the scaled attractions for the purpose + double[] scaledAttrs = getScaledValues(values, scaleFactor); + + // determine the final array column index into which to store the + // scaled + // attractions + int abAttrIndex = abProdIndex + MAX_PURPOSE_INDEX; + + // save the scaled attractions in the final array + float abmAttrs = 0; + for (int i = 0; i < newTrips.length; i++) + { + newTrips[i][abAttrIndex] = (float) scaledAttrs[i]; + abmAttrs += newTrips[i][abAttrIndex]; + } + + // save the ABM productions in the final array + float abmProds = 0; + for (int i = 0; i < newTrips.length; i++) + { + newTrips[i][abProdIndex] = tdzTrips[i + 1][abProdIndex]; + abmProds += newTrips[i][abProdIndex]; + } + + logger.info(String.format("%10s %-30s %15.1f %15d %15.6f %15.1f %15.1f", + heading, TABLE_HEADING_DESCRIPTIONS[abAttrIndex], total, abTotal, scaleFactor, + abmProds, abmAttrs)); + + index++; + + } + } + + private void saveTmNhbProdsAsAbmProds(TableDataSet inTgTds, int[][] tdzTrips, + boolean scaleNhbToAbm, float[][] newTrips) + { + logger.info(""); + logger.info(""); + logger.info("non-home-based TM productions to total ABM productions:"); + logger.info(String.format("%10s %-30s %15s %15s %15s %15s", "TM Heading", + "TM Purpose", "TM Prods", "ABM Prods", "Scale Factor", "New ABM Prods")); + int index = 0; + for (String heading : TRIP_MODEL_NON_HOME_BASED_PRODUCTION_HEADINGS) + { + + // get the trip model nhb productions, the TableDataSet returns a 0s + // based array + float[] values = inTgTds.getColumnAsFloat(heading); + + // add up total TM productions by purpose + float total = 0; + for (int i = 0; i < values.length; i++) + total += values[i]; + + // get the total ab model productions for this purpose + int abProdIndex = AB_MODEL_NON_HOME_BASED_PRODUCTION_INDICES[index]; + int abTotal = tdzTrips[0][abProdIndex]; + + // get the scale factor to scale trip model productions to ABM + // productions by purpose + double scaleFactor = 0.0; + if (scaleNhbToAbm) + { + if (total > 0) + { + scaleFactor = abTotal / total; + } else + { + logger.error("attempting to scale an array which sums to 0.0."); + throw new RuntimeException(); + } + } else + { + scaleFactor = 1.0; + } + + // get the scaled productions for the purpose + double[] scaledProds = getScaledValues(values, scaleFactor); + + // save the scaled attractions in the final array + float abmProds = 0; + for (int i = 0; i < newTrips.length; i++) + { + newTrips[i][abProdIndex] = (float) scaledProds[i]; + abmProds += newTrips[i][abProdIndex]; + } + + logger.info(String.format("%10s %-30s %15.1f %15d %15.6f %15.1f", heading, + TABLE_HEADING_DESCRIPTIONS[abProdIndex], total, abTotal, scaleFactor, abmProds)); + + index++; + + } + } + + private void saveTmNhbAttrsAsAbmProds(TableDataSet inTgTds, int[][] tdzTrips, + boolean scaleNhbToAbm, float[][] newTrips) + { + logger.info(""); + logger.info(""); + logger.info("non-home-based TM attractions to total ABM productions:"); + logger.info(String.format("%10s %-30s %15s %15s %15s %15s", "TM Heading", + "TM Purpose", "TM Attrs", "ABM Prods", "Scale Factor", "New ABM Attrs")); + int index = 0; + for (String heading : TRIP_MODEL_NON_HOME_BASED_ATTRACTION_HEADINGS) + { + + // get the trip model nhb attractions, the TableDataSet returns a 0s + // based array + float[] values = inTgTds.getColumnAsFloat(heading); + + // add up total TM attracctions by purpose + float total = 0; + for (int i = 0; i < values.length; i++) + total += values[i]; + + // get the total ab model productions for this purpose + int abProdIndex = AB_MODEL_NON_HOME_BASED_PRODUCTION_INDICES[index]; + int abTotal = tdzTrips[0][abProdIndex]; + + // get the scale factor to scale trip model atractions to ABM + // productions + // by purpose + double scaleFactor = 0.0; + if (scaleNhbToAbm) + { + if (total > 0) + { + scaleFactor = abTotal / total; + } else + { + logger.error("attempting to scale an array which sums to 0.0."); + throw new RuntimeException(); + } + } else + { + scaleFactor = 1.0; + } + + // get the scaled attractions for the purpose + double[] scaledAttrs = getScaledValues(values, scaleFactor); + + // determine the final array column index into which to store the + // scaled + // attractions + int abAttrIndex = abProdIndex + MAX_PURPOSE_INDEX; + + // save the scaled attractions in the final array + float abmAttrs = 0; + for (int i = 0; i < newTrips.length; i++) + { + newTrips[i][abAttrIndex] = (float) scaledAttrs[i]; + abmAttrs += newTrips[i][abAttrIndex]; + } + + index++; + + logger.info(String.format("%10s %-30s %15.1f %15d %15.6f %15.1f", heading, + TABLE_HEADING_DESCRIPTIONS[abAttrIndex], total, abTotal, scaleFactor, abmAttrs)); + + } + } + + private void addTmIeAttrsToAbmHbProds(TableDataSet inTgTds, int[][] tdzTrips, float[][] newTrips) + { + logger.info(""); + logger.info(""); + logger.info("adding IE attrs from trip model to home-based ABM prods:"); + logger.info(String.format("%10s %-30s %15s %15s %15s", "TM Heading", "TM Purpose", + "ABM Prods", "IE attrs", "new ABM Prods")); + int index = 0; + for (String heading : TRIP_MODEL_HOME_BASED_PRODUCTION_HEADINGS) + { + + int abProdIndex = AB_MODEL_HOME_BASED_PRODUCTION_INDICES[index]; + int abAttrIndex = abProdIndex + MAX_PURPOSE_INDEX; + + // save the new ABM productions in the final array + float abTotal = 0; + float newTotal = 0; + for (int i = 0; i < newTrips.length; i++) + { + abTotal += newTrips[i][abProdIndex]; + newTrips[i][abProdIndex] += ieTrips[i + 1][abAttrIndex]; + newTotal += newTrips[i][abProdIndex]; + } + + logger.info(String.format("%10s %-30s %15.1f %15.1f %15.1f", heading, + TABLE_HEADING_DESCRIPTIONS[abProdIndex], abTotal, ieTrips[0][abAttrIndex], + newTotal)); + + index++; + + } + } + + private void addTmIeProdsToAbmHbAttrs(TableDataSet inTgTds, int[][] tdzTrips, float[][] newTrips) + { + logger.info(""); + logger.info(""); + logger.info("adding IE prods from trip model to home-based ABM attrs:"); + logger.info(String.format("%10s %-30s %15s %15s %15s", "TM Heading", "TM Purpose", + "ABM Attrs", "IE prods", "new ABM Attrs")); + int index = 0; + for (String heading : TRIP_MODEL_HOME_BASED_ATTRACTION_HEADINGS) + { + + int abProdIndex = AB_MODEL_HOME_BASED_PRODUCTION_INDICES[index]; + int abAttrIndex = AB_MODEL_HOME_BASED_PRODUCTION_INDICES[index] + MAX_PURPOSE_INDEX; + + // save the new ABM attractions in the final array + float abTotal = 0; + float newTotal = 0; + for (int i = 0; i < newTrips.length; i++) + { + abTotal += newTrips[i][abAttrIndex]; + newTrips[i][abAttrIndex] += ieTrips[i + 1][abProdIndex]; + newTotal += newTrips[i][abAttrIndex]; + } + + logger.info(String.format("%10s %-30s %15.1f %15.1f %15.1f", heading, + TABLE_HEADING_DESCRIPTIONS[abAttrIndex], abTotal, ieTrips[0][abProdIndex], + newTotal)); + + index++; + + } + } + + private void addTmAirportAndVisitorProdsToAbmProds(TableDataSet inTgTds, int[][] tdzTrips, + float[][] newTrips) + { + logger.info(""); + logger.info(""); + logger.info("airport and visitor TM to ABM productions:"); + logger.info(String.format("%10s %-30s %15s %15s %15s", "TM Heading", "TM Purpose", + "TM Prods", "Scale Factor", "New ABM Prods")); + int index = 0; + for (String heading : TRIP_MODEL_OTHER_BASED_PRODUCTION_HEADINGS) + { + + // get the trip model productions + float[] pValues = inTgTds.getColumnAsFloat(heading); + + // determine the final array column index into which to store the + // scaled + // attractions + int prodIndex = AB_MODEL_OTHER_PRODUCTION_INDICES[index]; + + // save the productions in the final array + // add up the original values + float pTotal = 0; + for (int i = 0; i < newTrips.length; i++) + { + newTrips[i][prodIndex] = pValues[i]; + pTotal += newTrips[i][prodIndex]; + } + + logger.info(String.format("%10s %-30s %15.1f %15.6f %15.1f", heading, + TABLE_HEADING_DESCRIPTIONS[prodIndex], pTotal, 1.0, pTotal)); + + index++; + + } + } + + private void addTmAirportAndVisitorAttrsToAbmAttrs(TableDataSet inTgTds, int[][] tdzTrips, + float[][] newTrips) + { + logger.info(""); + logger.info(""); + logger.info("airport and visitor TM to ABM attractions:"); + logger.info(String.format("%10s %-30s %15s %15s %15s", "TM Heading", "TM Purpose", + "TM Attrs", "Scale Factor", "New ABM Attrs")); + int index = 0; + for (String heading : TRIP_MODEL_OTHER_BASED_ATTRACTION_HEADINGS) + { + + // get the trip model attractions + float[] aValues = inTgTds.getColumnAsFloat(heading); + + // determine the final array column index into which to store the + // scaled + // attractions + int attrIndex = AB_MODEL_OTHER_PRODUCTION_INDICES[index] + MAX_PURPOSE_INDEX; + + // save the attractions in the final array + float aTotal = 0; + for (int i = 0; i < newTrips.length; i++) + { + newTrips[i][attrIndex] = aValues[i]; + aTotal += newTrips[i][attrIndex]; + } + + logger.info(String.format("%10s %-30s %15.1f %15.6f %15.1f", heading, + TABLE_HEADING_DESCRIPTIONS[attrIndex], aTotal, 1.0, aTotal)); + + index++; + + } + } + + private void saveZoneField(TableDataSet inTgTds, float[][] newTrips) + { + // save the zone field in final table + float[] values = inTgTds.getColumnAsFloat(TAZ_FIELD_HEADING); + int tazFieldIndex = inTgTds.getColumnPosition(TAZ_FIELD_HEADING) - 1; + for (int i = 0; i < newTrips.length; i++) + newTrips[i][tazFieldIndex] = values[i]; + } + + private TableDataSet createFinalTableDataset(float[][] newTrips) + { + TableDataSet abmTds = TableDataSet.create(newTrips, TABLE_HEADINGS); + + float[] newIeTrips = new float[2 * MAX_PURPOSE_INDEX + 1]; + for (int i = 0; i < abmTds.getRowCount(); i++) + { + int tdz = (int) abmTds.getValueAt(i + 1, TAZ_FIELD_HEADING); + for (int j = 1; j < abmTds.getColumnCount(); j++) + { + if (tdz >= MIN_EXTERNAL_TDZ && tdz <= MAX_EXTERNAL_TDZ) + { + newIeTrips[j] += abmTds.getValueAt(i + 1, j + 1); + } + } + } + + logger.info(""); + logger.info(""); + logger.info("summary of newly created trip generation file."); + logger.info("\t" + abmTds.getRowCount() + " rows in output file."); + logger.info("\t" + abmTds.getColumnCount() + " columns in output file."); + logger.info(""); + logger.info(String.format("\t%-15s %-30s %15s %15s", "Column Name", "Column Purpose", + "Column Total", "Int-Ext")); + + String[] headings = abmTds.getColumnLabels(); + logger.info(String.format("\t%-15s %-30s %15s %15s", headings[0], "N/A", "N/A", "N/A")); + float totProd = 0; + float totAttr = 0; + float totalIeProds = 0; + float totalIeAttrs = 0; + float columnSum = 0; + for (int i = 1; i < abmTds.getColumnCount(); i++) + { + + columnSum = abmTds.getColumnTotal(i + 1); + + // 1st 10 fields after zone are production fields, next 10 are + // attraction + // fields + if (i <= 10) + { + totProd += columnSum; + totalIeProds += newIeTrips[i]; + } else + { + totAttr += columnSum; + totalIeAttrs += newIeTrips[i]; + } + + logger.info(String.format("\t%-15s %-30s %15.1f %15.1f", headings[i], + TABLE_HEADING_DESCRIPTIONS[i], columnSum, newIeTrips[i])); + + } + + logger.info(""); + logger.info(""); + logger.info(String.format("\ttotal productions = %15.1f", totProd)); + logger.info(String.format("\ttotal attractions = %15.1f", totAttr)); + logger.info(String.format("\ttotal IE productions = %12.1f", totalIeProds)); + logger.info(String.format("\ttotal IE attractions = %12.1f", totalIeAttrs)); + logger.info(""); + + return abmTds; + } + + private void writeAbmTripGenFile(String tgOutputFile, TableDataSet outAbmTds) + { + + CSVFileWriter writer = new CSVFileWriter(); + try + { + writer.writeFile(outAbmTds, new File(tgOutputFile)); + } catch (IOException e) + { + logger.fatal(String + .format("Exception occurred writing new trip generation data file = %s from TableDataSet object.", + tgOutputFile)); + throw new RuntimeException(e); + } + } + + private double[] getScaledValues(float[] values, double scaleFactor) + { + + double[] scaledValues = new double[values.length]; + for (int i = 0; i < values.length; i++) + scaledValues[i] = values[i] * scaleFactor; + + return scaledValues; + } + + public static void main(String[] args) throws Exception + { + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else + { + + String baseName; + if (args[0].endsWith(".properties")) + { + int index = args[0].indexOf(".properties"); + baseName = args[0].substring(0, index); + } else + { + baseName = args[0]; + } + + ResourceBundle rb = ResourceBundle.getBundle(baseName); + HashMap rbMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + SandagCreateTripGenerationFiles mainObject = new SandagCreateTripGenerationFiles(rbMap); + + // pass true as an argument if NHB trips from the trip model are to + // be + // scaled to the number from the activity-based model + mainObject.createTripGenFile(rbMap); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagCtrampApplication.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCtrampApplication.java new file mode 100644 index 0000000..8dad984 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCtrampApplication.java @@ -0,0 +1,23 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import java.util.ResourceBundle; +import org.sandag.abm.ctramp.CtrampApplication; + +public class SandagCtrampApplication + extends CtrampApplication +{ + + public static final String PROGRAM_VERSION = "09June2008"; + public static final String PROPERTIES_PROJECT_DIRECTORY = "Project.Directory"; + + public SandagCtrampApplication(ResourceBundle rb, HashMap rbMap, + boolean calculateLandUseAccessibilities) + { + super(rb, rbMap, calculateLandUseAccessibilities); + + projectDirectory = rbMap.get(PROPERTIES_PROJECT_DIRECTORY); + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagCtrampDmuFactory.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCtrampDmuFactory.java new file mode 100644 index 0000000..c473901 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagCtrampDmuFactory.java @@ -0,0 +1,170 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.application; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Map; + +import org.sandag.abm.ctramp.AtWorkSubtourFrequencyDMU; +import org.sandag.abm.ctramp.AutoOwnershipChoiceDMU; +import org.sandag.abm.ctramp.BikeLogsum; +import org.sandag.abm.ctramp.CoordinatedDailyActivityPatternDMU; +import org.sandag.abm.ctramp.CtrampDmuFactoryIf; +import org.sandag.abm.ctramp.DcSoaDMU; +import org.sandag.abm.ctramp.DestChoiceDMU; +import org.sandag.abm.ctramp.DestChoiceTwoStageModelDMU; +import org.sandag.abm.ctramp.DestChoiceTwoStageSoaTazDistanceUtilityDMU; +import org.sandag.abm.ctramp.IndividualMandatoryTourFrequencyDMU; +import org.sandag.abm.ctramp.IndividualNonMandatoryTourFrequencyDMU; +import org.sandag.abm.ctramp.InternalExternalTripChoiceDMU; +import org.sandag.abm.ctramp.JointTourModelsDMU; +import org.sandag.abm.ctramp.MicromobilityChoiceDMU; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.ParkingChoiceDMU; +import org.sandag.abm.ctramp.ParkingProvisionChoiceDMU; +import org.sandag.abm.ctramp.StopFrequencyDMU; +import org.sandag.abm.ctramp.StopLocationDMU; +import org.sandag.abm.ctramp.TelecommuteDMU; +import org.sandag.abm.ctramp.TourDepartureTimeAndDurationDMU; +import org.sandag.abm.ctramp.TourModeChoiceDMU; +import org.sandag.abm.ctramp.TransponderChoiceDMU; +import org.sandag.abm.ctramp.TripModeChoiceDMU; + +/** + * ArcCtrampDmuFactory is a class that ... + * + * @author Kimberly Grommes + * @version 1.0, Jul 17, 2008 Created by IntelliJ IDEA. + */ +public class SandagCtrampDmuFactory + implements CtrampDmuFactoryIf, Serializable +{ + + private ModelStructure modelStructure; + private Map propertyMap; + + public SandagCtrampDmuFactory(ModelStructure modelStructure, Map propertyMap) + { + this.modelStructure = modelStructure; + this.propertyMap = propertyMap; + } + + public AutoOwnershipChoiceDMU getAutoOwnershipDMU() + { + return new SandagAutoOwnershipChoiceDMU(); + } + + public TransponderChoiceDMU getTransponderChoiceDMU() + { + return new SandagTransponderChoiceDMU(); + } + + public TelecommuteDMU getTelecommuteDMU() + { + return new SandagTelecommuteDMU(); + } + + public InternalExternalTripChoiceDMU getInternalExternalTripChoiceDMU() + { + return new SandagInternalExternalTripChoiceDMU(); + } + + public ParkingProvisionChoiceDMU getFreeParkingChoiceDMU() + { + return new SandagParkingProvisionChoiceDMU(); + } + + public CoordinatedDailyActivityPatternDMU getCoordinatedDailyActivityPatternDMU() + { + return new SandagCoordinatedDailyActivityPatternDMU(); + } + + public DcSoaDMU getDcSoaDMU() + { + return new SandagDcSoaDMU(); + } + + public DestChoiceDMU getDestChoiceDMU() + { + return new SandagDestChoiceDMU(modelStructure); + } + + public DestChoiceTwoStageModelDMU getDestChoiceSoaTwoStageDMU() + { + return new SandagDestChoiceSoaTwoStageModelDMU(modelStructure); + } + + public DestChoiceTwoStageSoaTazDistanceUtilityDMU getDestChoiceSoaTwoStageTazDistUtilityDMU() + { + return new SandagDestChoiceSoaTwoStageTazDistUtilityDMU(); + } + + public TourModeChoiceDMU getModeChoiceDMU() + { + SandagTourModeChoiceDMU dmu = new SandagTourModeChoiceDMU(modelStructure,null); + dmu.setBikeLogsum(BikeLogsum.getBikeLogsum(propertyMap)); + return dmu; + } + + public IndividualMandatoryTourFrequencyDMU getIndividualMandatoryTourFrequencyDMU() + { + return new SandagIndividualMandatoryTourFrequencyDMU(); + } + + public TourDepartureTimeAndDurationDMU getTourDepartureTimeAndDurationDMU() + { + return new SandagTourDepartureTimeAndDurationDMU(modelStructure); + } + + public AtWorkSubtourFrequencyDMU getAtWorkSubtourFrequencyDMU() + { + return new SandagAtWorkSubtourFrequencyDMU(modelStructure); + } + + public JointTourModelsDMU getJointTourModelsDMU() + { + return new SandagJointTourModelsDMU(modelStructure); + } + + public IndividualNonMandatoryTourFrequencyDMU getIndividualNonMandatoryTourFrequencyDMU() + { + return new SandagIndividualNonMandatoryTourFrequencyDMU(); + } + + public StopFrequencyDMU getStopFrequencyDMU() + { + return new SandagStopFrequencyDMU(modelStructure); + } + + public StopLocationDMU getStopLocationDMU() + { + return new SandagStopLocationDMU(modelStructure,propertyMap); + } + + public TripModeChoiceDMU getTripModeChoiceDMU() + { + SandagTripModeChoiceDMU dmu = new SandagTripModeChoiceDMU(modelStructure,null); + dmu.setBikeLogsum(BikeLogsum.getBikeLogsum(propertyMap)); + return dmu; + } + + public ParkingChoiceDMU getParkingChoiceDMU() + { + return new SandagParkingChoiceDMU(); + } + + public MicromobilityChoiceDMU getMicromobilityChoiceDMU() + { + return new SandagMicromobilityChoiceDMU(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagDcSoaDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDcSoaDMU.java new file mode 100644 index 0000000..8e17074 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDcSoaDMU.java @@ -0,0 +1,89 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.DcSoaDMU; + +public class SandagDcSoaDMU + extends DcSoaDMU +{ + + public SandagDcSoaDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getLnDcSizeAlt", 0); + methodIndexMap.put("getOriginToMgraDistanceAlt", 1); + methodIndexMap.put("getTourPurposeIsEscort", 2); + methodIndexMap.put("getNumPreschool", 3); + methodIndexMap.put("getNumGradeSchoolStudents", 4); + methodIndexMap.put("getNumHighSchoolStudents", 5); + methodIndexMap.put("getDcSizeAlt", 6); + methodIndexMap.put("getHouseholdsDestAlt", 8); + methodIndexMap.put("getGradeSchoolEnrollmentDestAlt", 9); + methodIndexMap.put("getHighSchoolEnrollmentDestAlt", 10); + methodIndexMap.put("getGradeSchoolDistrictDestAlt", 11); + methodIndexMap.put("getHomeMgraGradeSchoolDistrict", 12); + methodIndexMap.put("getHighSchoolDistrictDestAlt", 14); + methodIndexMap.put("getHomeMgraHighSchoolDistrict", 15); + methodIndexMap.put("getUniversityEnrollmentDestAlt", 16); + //methodIndexMap.put("getHomeMgra", 17); + + } + + // DMU methods - define one of these for every @var in the mode choice + // control + // file. + public double getLnDcSizeAlt(int alt) + { + return getLnDcSize(alt); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getLnDcSizeAlt(arrayIndex); + case 1: + return getOriginToMgraDistanceAlt(arrayIndex); + case 2: + return getTourPurposeIsEscort(); + case 3: + return getNumPreschool(); + case 4: + return getNumGradeSchoolStudents(); + case 5: + return getNumHighSchoolStudents(); + case 6: + return getDcSizeAlt(arrayIndex); + case 8: + return getHouseholdsDestAlt(arrayIndex); + case 9: + return getGradeSchoolEnrollmentDestAlt(arrayIndex); + case 10: + return getHighSchoolEnrollmentDestAlt(arrayIndex); + case 11: + return getGradeSchoolDistrictDestAlt(arrayIndex); + case 12: + return getHomeMgraGradeSchoolDistrict(); + case 14: + return getHighSchoolDistrictDestAlt(arrayIndex); + case 15: + return getHomeMgraHighSchoolDistrict(); + case 16: + return getUniversityEnrollmentDestAlt(arrayIndex); + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceDMU.java new file mode 100644 index 0000000..163c6b6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceDMU.java @@ -0,0 +1,161 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.DestChoiceDMU; +import org.sandag.abm.ctramp.ModelStructure; + +public class SandagDestChoiceDMU + extends DestChoiceDMU +{ + + public SandagDestChoiceDMU(ModelStructure modelStructure) + { + super(modelStructure); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getMcLogsumDestAlt", 3); + methodIndexMap.put("getNumGradeSchoolStudents", 4); + methodIndexMap.put("getNumHighSchoolStudents", 5); + methodIndexMap.put("getHouseholdsDestAlt", 8); + methodIndexMap.put("getPopulationDestAlt", 9); + methodIndexMap.put("getGradeSchoolEnrollmentDestAlt", 10); + methodIndexMap.put("getHighSchoolEnrollmentDestAlt", 11); + methodIndexMap.put("getUniversityEnrollmentDestAlt", 16); + methodIndexMap.put("getPersonIsWorker", 20); + methodIndexMap.put("getPersonHasBachelors", 21); + methodIndexMap.put("getPersonType", 22); + methodIndexMap.put("getSubtourType", 23); + methodIndexMap.put("getDcSoaCorrectionsAlt", 24); + methodIndexMap.put("getNumberOfNonWorkingAdults", 25); + methodIndexMap.put("getNumPreschool", 26); + methodIndexMap.put("getFemale", 27); + methodIndexMap.put("getIncome", 28); + methodIndexMap.put("getFemaleWorker", 29); + methodIndexMap.put("getIncomeInDollars", 30); + methodIndexMap.put("getAutos", 31); + methodIndexMap.put("getWorkers", 32); + methodIndexMap.put("getNumChildrenUnder16", 33); + methodIndexMap.put("getNumChildrenUnder19", 34); + methodIndexMap.put("getAge", 35); + methodIndexMap.put("getFullTimeWorker", 36); + methodIndexMap.put("getWorkTaz", 37); + methodIndexMap.put("getWorkTourModeIsSOV", 38); + methodIndexMap.put("getTourIsJoint", 39); + methodIndexMap.put("getOpSovDistanceAlt", 42); + methodIndexMap.put("getLnDcSizeAlt", 43); + methodIndexMap.put("getWorkAccessibility", 44); + methodIndexMap.put("getNonMandatoryAccessibilityAlt", 45); + methodIndexMap.put("getToursLeft", 46); + methodIndexMap.put("getMaxWindow", 47); + methodIndexMap.put("getDcSizeAlt", 48); + } + + public void setMcLogsum(int mgra, double logsum) + { + modeChoiceLogsums[mgra] = logsum; + } + + public double getLogsumDestAlt(int alt) + { + return getMcLogsumDestAlt(alt); + } + + public int getPersonIsFullTimeWorker() + { + return person.getPersonIsFullTimeWorker(); + } + + /* + * public int getSubtourType() { if ( + * tour.getTourCategory().equalsIgnoreCase( ModelStructure.AT_WORK_CATEGORY + * ) ) return tour.getTourPurposeIndex(); else return 0; } + */ + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 3: + return getMcLogsumDestAlt(arrayIndex); + case 4: + return getNumGradeSchoolStudents(); + case 5: + return getNumHighSchoolStudents(); + case 8: + return getHouseholdsDestAlt(arrayIndex); + case 9: + return getPopulationDestAlt(arrayIndex); + case 10: + return getGradeSchoolEnrollmentDestAlt(arrayIndex); + case 11: + return getHighSchoolEnrollmentDestAlt(arrayIndex); + case 16: + return getUniversityEnrollmentDestAlt(arrayIndex); + case 20: + return getPersonIsWorker(); + case 21: + return getPersonHasBachelors(); + case 22: + return getPersonType(); + case 24: + return getDcSoaCorrectionsAlt(arrayIndex); + case 25: + return getNumberOfNonWorkingAdults(); + case 26: + return getNumPreschool(); + case 27: + return getFemale(); + case 28: + return getIncome(); + case 29: + return getFemaleWorker(); + case 30: + return getIncomeInDollars(); + case 31: + return getAutos(); + case 32: + return getWorkers(); + case 33: + return getNumChildrenUnder16(); + case 34: + return getNumChildrenUnder19(); + case 35: + return getAge(); + case 36: + return getFullTimeWorker(); + case 37: + return getWorkTaz(); + case 38: + return getWorkTourModeIsSOV(); + case 39: + return getTourIsJoint(); + case 42: + return getOpSovDistanceAlt(arrayIndex); + case 43: + return getLnDcSizeAlt(arrayIndex); + case 44: + return getWorkAccessibility(); + case 45: + return getNonMandatoryAccessibilityAlt(arrayIndex); + case 46: + return getToursLeftCount(); + case 47: + return getMaxContinuousAvailableWindow(); + case 48: + return getDcSizeAlt(arrayIndex); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceSoaTwoStageModelDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceSoaTwoStageModelDMU.java new file mode 100644 index 0000000..aae0533 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceSoaTwoStageModelDMU.java @@ -0,0 +1,158 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.DestChoiceTwoStageModelDMU; +import org.sandag.abm.ctramp.ModelStructure; + +public class SandagDestChoiceSoaTwoStageModelDMU + extends DestChoiceTwoStageModelDMU +{ + + public SandagDestChoiceSoaTwoStageModelDMU(ModelStructure modelStructure) + { + super(modelStructure); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getMcLogsumDestAlt", 3); + methodIndexMap.put("getNumGradeSchoolStudents", 4); + methodIndexMap.put("getNumHighSchoolStudents", 5); + methodIndexMap.put("getHouseholdsDestAlt", 8); + methodIndexMap.put("getPopulationDestAlt", 9); + methodIndexMap.put("getGradeSchoolEnrollmentDestAlt", 10); + methodIndexMap.put("getHighSchoolEnrollmentDestAlt", 11); + methodIndexMap.put("getUniversityEnrollmentDestAlt", 16); + methodIndexMap.put("getPersonIsWorker", 20); + methodIndexMap.put("getPersonHasBachelors", 21); + methodIndexMap.put("getPersonType", 22); + methodIndexMap.put("getSubtourType", 23); + methodIndexMap.put("getDcSoaCorrectionsAlt", 24); + methodIndexMap.put("getNumberOfNonWorkingAdults", 25); + methodIndexMap.put("getNumPreschool", 26); + methodIndexMap.put("getFemale", 27); + methodIndexMap.put("getIncome", 28); + methodIndexMap.put("getFemaleWorker", 29); + methodIndexMap.put("getIncomeInDollars", 30); + methodIndexMap.put("getAutos", 31); + methodIndexMap.put("getWorkers", 32); + methodIndexMap.put("getNumChildrenUnder16", 33); + methodIndexMap.put("getNumChildrenUnder19", 34); + methodIndexMap.put("getAge", 35); + methodIndexMap.put("getFullTimeWorker", 36); + methodIndexMap.put("getWorkTaz", 37); + methodIndexMap.put("getWorkTourModeIsSOV", 38); + methodIndexMap.put("getTourIsJoint", 39); + methodIndexMap.put("getOpSovDistanceAlt", 42); + methodIndexMap.put("getLnDcSizeAlt", 43); + methodIndexMap.put("getWorkAccessibility", 44); + methodIndexMap.put("getNonMandatoryAccessibilityAlt", 45); + methodIndexMap.put("getToursLeft", 46); + methodIndexMap.put("getMaxWindow", 47); + } + + public void setMcLogsum(int sampleIndex, double logsum) + { + modeChoiceLogsums[sampleIndex] = logsum; + } + + public double getLogsumDestAlt(int alt) + { + return getMcLogsumDestAlt(alt); + } + + public int getPersonIsFullTimeWorker() + { + return person.getPersonIsFullTimeWorker(); + } + + /* + * public int getSubtourType() { if ( + * tour.getTourCategory().equalsIgnoreCase( ModelStructure.AT_WORK_CATEGORY + * ) ) return tour.getTourPurposeIndex(); else return 0; } + */ + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 3: + return getMcLogsumDestAlt(arrayIndex); + case 4: + return getNumGradeSchoolStudents(); + case 5: + return getNumHighSchoolStudents(); + case 8: + return getHouseholdsDestAlt(arrayIndex); + case 9: + return getPopulationDestAlt(arrayIndex); + case 10: + return getGradeSchoolEnrollmentDestAlt(arrayIndex); + case 11: + return getHighSchoolEnrollmentDestAlt(arrayIndex); + case 16: + return getUniversityEnrollmentDestAlt(arrayIndex); + case 20: + return getPersonIsWorker(); + case 21: + return getPersonHasBachelors(); + case 22: + return getPersonType(); + case 24: + return getDcSoaCorrectionsAlt(arrayIndex); + case 25: + return getNumberOfNonWorkingAdults(); + case 26: + return getNumPreschool(); + case 27: + return getFemale(); + case 28: + return getIncome(); + case 29: + return getFemaleWorker(); + case 30: + return getIncomeInDollars(); + case 31: + return getAutos(); + case 32: + return getWorkers(); + case 33: + return getNumChildrenUnder16(); + case 34: + return getNumChildrenUnder19(); + case 35: + return getAge(); + case 36: + return getFullTimeWorker(); + case 37: + return getWorkTaz(); + case 38: + return getWorkTourModeIsSOV(); + case 39: + return getTourIsJoint(); + case 42: + return getOpSovDistanceAlt(arrayIndex); + case 43: + return getLnDcSizeAlt(arrayIndex); + case 44: + return getWorkAccessibility(); + case 45: + return getNonMandatoryAccessibilityAlt(arrayIndex); + case 46: + return getToursLeftCount(); + case 47: + return getMaxContinuousAvailableWindow(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceSoaTwoStageTazDistUtilityDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceSoaTwoStageTazDistUtilityDMU.java new file mode 100644 index 0000000..62e1688 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagDestChoiceSoaTwoStageTazDistUtilityDMU.java @@ -0,0 +1,66 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.DestChoiceTwoStageSoaTazDistanceUtilityDMU; + +public class SandagDestChoiceSoaTwoStageTazDistUtilityDMU + extends DestChoiceTwoStageSoaTazDistanceUtilityDMU +{ + + public SandagDestChoiceSoaTwoStageTazDistUtilityDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getLnDestChoiceSizeTazAlt", 0); + methodIndexMap.put("getSizeTazAlt", 1); + methodIndexMap.put("getUniversityEnrollmentTazAlt", 2); + methodIndexMap.put("getGradeSchoolDistrictTazAlt", 3); + methodIndexMap.put("getHighSchoolDistrictTazAlt", 4); + methodIndexMap.put("getHomeTazGradeSchoolDistrict", 5); + methodIndexMap.put("getHomeTazHighSchoolDistrict", 6); + methodIndexMap.put("getGradeSchoolEnrollmentTazAlt", 7); + methodIndexMap.put("getHighSchoolEnrollmentTazAlt", 8); + methodIndexMap.put("getHouseholdsTazAlt", 9); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getLnDestChoiceSizeTazAlt(arrayIndex); + case 1: + return getSizeTazAlt(arrayIndex); + case 2: + return getUniversityEnrollmentTazAlt(arrayIndex); + case 3: + return getGradeSchoolDistrictTazAlt(arrayIndex); + case 4: + return getHighSchoolDistrictTazAlt(arrayIndex); + case 5: + return getHomeTazGradeSchoolDistrict(); + case 6: + return getHomeTazHighSchoolDistrict(); + case 7: + return getGradeSchoolEnrollmentTazAlt(arrayIndex); + case 8: + return getHighSchoolEnrollmentTazAlt(arrayIndex); + case 9: + return getHouseholdsTazAlt(arrayIndex); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagHouseholdDataManager.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagHouseholdDataManager.java new file mode 100644 index 0000000..805df60 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagHouseholdDataManager.java @@ -0,0 +1,624 @@ +package org.sandag.abm.application; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.HouseholdDataManager; +import org.sandag.abm.ctramp.Person; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * @author Jim Hicks + * + * Class for managing household and person object data read from + * synthetic population files. + */ +public class SandagHouseholdDataManager + extends HouseholdDataManager +{ + + public static final String HH_DATA_SERVER_NAME = SandagHouseholdDataManager.class + .getCanonicalName(); + public static final String HH_DATA_SERVER_ADDRESS = "127.0.0.1"; + public static final int HH_DATA_SERVER_PORT = 1139; + + public static final String PROPERTIES_OCCUP_CODES = "PopulationSynthesizer.OccupCodes"; + public static final String PROPERTIES_INDUSTRY_CODES = "PopulationSynthesizer.IndustryCodes"; + + public SandagHouseholdDataManager() + { + super(); + } + + /** + * Associate data in hh and person TableDataSets read from synthetic + * population files with Household objects and Person objects with + * Households. + * + */ + public void mapTablesToHouseholdObjects() + { + + logger.info("mapping popsyn household and person data records to objects."); + + int id = -1; + Household[] hhArray = new Household[hhTable.getRowCount()]; + + int invalidPersonTypeCount1 = 0; + int invalidPersonTypeCount2 = 0; + int invalidPersonTypeCount3 = 0; + + // read the corrrespondence files for mapping persons to occupation and + int[] occCodes = readOccupCorrespondenceData(); + int[] indCodes = readIndustryCorrespondenceData(); + + // get the maximum HH id value to use to dimension the hhIndex + // correspondence + // array. + // the hhIndex array will store the hhArray index number for the given + // hh + // index. + int maxHhId = 0; + for (int r = 1; r <= hhTable.getRowCount(); r++) + { + id = (int) hhTable.getValueAt(r, hhTable.getColumnPosition(HH_ID_FIELD_NAME)); + if (id > maxHhId) maxHhId = id; + } + hhIndexArray = new int[maxHhId + 1]; + int[] sortedIndices = getRandomOrderHhIndexArray(hhTable.getRowCount()); + + // for each household table record + for (int r = 1; r <= hhTable.getRowCount(); r++) + { + + try + { + + // create a Household object + Household hh = new Household(modelStructure); + + // get required values from table record and store in Household + // object + id = (int) hhTable.getValueAt(r, hhTable.getColumnPosition(HH_ID_FIELD_NAME)); + hh.setHhId(id, inputRandomSeed); + + // set the household in the hhIndexArray in random order + int index = sortedIndices[r - 1]; + hhIndexArray[hh.getHhId()] = index; + + int htaz = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_HOME_TAZ_FIELD_NAME)); + hh.setHhTaz(htaz); + + int hmgra = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_HOME_MGRA_FIELD_NAME)); + hh.setHhMgra(hmgra); + + double rn = hh.getHhRandom().nextDouble(); + int origWalkSubzone = getInitialOriginWalkSegment(htaz, rn); + hh.setHhWalkSubzone(origWalkSubzone); + + // autos could be modeled or from PUMA + int numAutos = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_AUTOS_FIELD_NAME)); + hh.setHhAutos(numAutos); + + // set the hhSize variable and create Person objects for each + // person + int numPersons = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_SIZE_FIELD_NAME)); + hh.setHhSize(numPersons); + + int numWorkers = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_WORKERS_FIELD_NAME)); + hh.setHhWorkers(numWorkers); + + int incomeCat = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_INCOME_CATEGORY_FIELD_NAME)); + hh.setHhIncomeCategory(incomeCat); + + int incomeInDollars = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_INCOME_DOLLARS_FIELD_NAME)); + hh.setHhIncomeInDollars(incomeInDollars); + + // 0=Housing unit, 1=Institutional group quarters, + // 2=Noninstitutional + // group quarters + int unitType = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_UNITTYPE_FIELD_NAME)); + hh.setUnitType(unitType); + + // 1=Family household:married-couple, 2=Family household:male + // householder,no wife present, 3=Family household:female + // householder,no + // husband present + // 4=Nonfamily household:male householder, living alone, + // 5=Nonfamily + // household:male householder, not living alone, + // 6=Nonfamily household:female householder, living alone, + // 7=Nonfamily household:female householder, not living alone + int type = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_TYPE_FIELD_NAME)); + hh.setHhType(type); + + // 1=mobile home, 2=one-family house detached from any other + // house, + // 3=one-family house attached to one or more houses, + // 4=building with 2 apartments, 5=building with 3 or 4 + // apartments, + // 6=building with 5 to 9 apartments, + // 7=building with 10 to 19 apartments, 8=building with 20 to 49 + // apartments, + // 9=building with 50 or more apartments, 10=Boat,RV,van,etc. + int bldgsz = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_BLDGSZ_FIELD_NAME)); + hh.setHhBldgsz(bldgsz); + + hh.initializeWindows(); + hhArray[index] = hh; + + } catch (Exception e) + { + + logger.fatal(String + .format("exception caught mapping household data record to a Household object, r=%d, id=%d.", + r, id)); + throw new RuntimeException(e); + + } + + } + + int hhid = -1; + int oldHhid = -1; + int i = -1; + int persNum = -1; + int persId = -1; + int fieldCount = 0; + + // for each person table record + for (int r = 1; r <= personTable.getRowCount(); r++) + { + + try + { + + // get the Household object for this person data to be stored in + hhid = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_HH_ID_FIELD_NAME)); + int index = hhIndexArray[hhid]; + Household hh = hhArray[index]; + fieldCount = 1; + + if (oldHhid < hhid) + { + oldHhid = hhid; + persNum = 1; + } + + // get the Person object for this person data to be stored in + persId = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_PERSON_ID_FIELD_NAME)); + Person person = hh.getPerson(persNum++); + person.setPersId(persId); + fieldCount++; + + // get required values from table record and store in Person + // object + int age = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_AGE_FIELD_NAME)); + person.setPersAge(age); + fieldCount++; + + int gender = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_GENDER_FIELD_NAME)); + person.setPersGender(gender); + fieldCount++; + + int occcen1 = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_OCCCEN1_FIELD_NAME)); + int pecasOccup = occCodes[occcen1]; + + if (pecasOccup == 0) logger.warn("pecasOccup==0 for occcen1=" + occcen1); + + int indcen = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_INDCEN_FIELD_NAME)); + int activityCode = indCodes[indcen]; + + if ((pecasOccup == 71) + && (activityCode == 2 || activityCode == 4 || activityCode == 6 + || activityCode == 8 || activityCode == 29)) activityCode++; + + if ((pecasOccup == 76) + && (activityCode == 3 || activityCode == 5 || activityCode == 7 + || activityCode == 9 || activityCode == 30)) activityCode--; + + if ((pecasOccup == 76) && (activityCode == 13)) activityCode = 14; + + if ((pecasOccup == 71) && (activityCode == 14)) activityCode = 13; + + if ((pecasOccup == 75) && (activityCode == 18)) activityCode = 22; + + if ((pecasOccup == 71) && (activityCode == 22)) activityCode = 18; + + if (activityCode == 28) pecasOccup = 77; + + person.setPersActivityCode(activityCode); + fieldCount++; + + person.setPersPecasOccup(pecasOccup); + fieldCount++; + + // Employment status (1-employed FT, 2-employed PT, 3-not + // employed, + // 4-under age 16) + int empCat = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_EMPLOYMENT_CATEGORY_FIELD_NAME)); + person.setPersEmploymentCategory(empCat); + fieldCount++; + + // Student status (1 - student in grade or high school; 2 - + // student + // in college or higher; 3 - not a student) + int studentCat = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_STUDENT_CATEGORY_FIELD_NAME)); + person.setPersStudentCategory(studentCat); + fieldCount++; + + // Person type (1-FT worker age 16+, 2-PT worker nonstudent age + // 16+, + // 3-university student, 4-nonworker nonstudent age 16-64, + // 5-nonworker nonstudent age 65+, + // 6-"age 16-19 student, not FT wrkr or univ stud", 7-age 6-15 + // schpred, 8 under age 6 presch + int personType = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_TYPE_CATEGORY_FIELD_NAME)); + person.setPersonTypeCategory(personType); + fieldCount++; + + // Person educational attainment level to determine high school + // graduate status ( < 9 - not a graduate, 10+ - high school + // graduate + // and + // beyond) + int educ = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_EDUCATION_ATTAINMENT_FIELD_NAME)); + if (educ >= 9) person.setPersonIsHighSchoolGraduate(true); + else person.setPersonIsHighSchoolGraduate(false); + fieldCount++; + + // Person educational attainment level to determine higher + // education + // status ( > 12 - at least a bachelor's degree ) + if (educ >= 13) person.setPersonHasBachelors(true); + else person.setPersonHasBachelors(false); + fieldCount++; + + // Person grade enrolled in ( 0-"not enrolled", 1-"preschool", + // 2-"Kindergarten", 3-"Grade 1 to grade 4", + // 4-"Grade 5 to grade 8", 5-"Grade 9 to grade 12", + // 6-"College undergraduate", + // 7-"Graduate or professional school" ) + int grade = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_GRADE_ENROLLED_FIELD_NAME)); + person.setPersonIsGradeSchool(false); + person.setPersonIsHighSchool(false); + if (grade >= 2 && grade <= 4) person.setPersonIsGradeSchool(true); + else if (grade == 5) person.setPersonIsHighSchool(true); + fieldCount++; + + // if person is a university student but has school age student + // category value, reset student category value + if (personType == Person.PersonType.University_student.ordinal() + && studentCat != Person.StudentStatus.STUDENT_COLLEGE_OR_HIGHER.ordinal()) + { + studentCat = Person.StudentStatus.STUDENT_COLLEGE_OR_HIGHER.ordinal(); + person.setPersStudentCategory(studentCat); + invalidPersonTypeCount1++; + // if person is a student of any kind but has full-time + // employment + // status, reset student category value to non-student + } else if (studentCat != Person.StudentStatus.NON_STUDENT.ordinal() + && empCat == Person.EmployStatus.FULL_TIME.ordinal()) + { + studentCat = Person.StudentStatus.NON_STUDENT.ordinal(); + person.setPersStudentCategory(studentCat); + invalidPersonTypeCount2++; + } + fieldCount++; + + // check consistency of student category and person type + if (studentCat == Person.StudentStatus.NON_STUDENT.ordinal()) + { + + if (person.getPersonIsStudentNonDriving() == 1 + || person.getPersonIsStudentDriving() == 1) + { + studentCat = Person.StudentStatus.STUDENT_HIGH_SCHOOL_OR_LESS.ordinal(); + person.setPersStudentCategory(studentCat); + invalidPersonTypeCount3++; + } + + } + fieldCount++; + + } catch (Exception e) + { + + logger.fatal("exception caught mapping person data record to a Person object, " + + String.format( + "r=%d, i=%d, hhid=%d, persid=%d, persnum=%d, fieldCount=%d.", r, i, + hhid, persId, persNum, fieldCount)); + throw new RuntimeException(e); + + } + + } // person loop + + hhs = hhArray; + + logger.warn(invalidPersonTypeCount1 + + " person type = university and student category = non-student person records" + + " had their student category changed to university or higher."); + logger.warn(invalidPersonTypeCount2 + + " Student category = student and employment category = full-time worker person records" + + " had their student category changed to non-student."); + logger.warn(invalidPersonTypeCount3 + + " Student category = non-student and person type = student person records" + + " had their student category changed to student high school or less."); + + } + + /** + * if called, must be called after readData so that the size of the full + * population is known. + * + * @param hhFileName + * @param persFileName + * @param numHhs + */ + public void createSamplePopulationFiles(String hhFileName, String persFileName, + String newHhFileName, String newPersFileName, int numHhs) + { + + int maximumHhId = 0; + for (int i = 0; i < hhs.length; i++) + { + int id = hhs[i].getHhId(); + if (id > maximumHhId) maximumHhId = id; + } + + int[] testHhs = new int[maximumHhId + 1]; + + int[] sortedIndices = getRandomOrderHhIndexArray(hhs.length); + + for (int i = 0; i < numHhs; i++) + { + int k = sortedIndices[i]; + int hhId = hhs[k].getHhId(); + testHhs[hhId] = 1; + } + + String hString = ""; + int hCount = 0; + try + { + + logger.info(String.format("writing sample household file for %d households", numHhs)); + + PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(newHhFileName))); + BufferedReader in = new BufferedReader(new FileReader(hhFileName)); + + // read headers and write to output files + hString = in.readLine(); + out.write(hString + "\n"); + hCount++; + int count = 0; + + while ((hString = in.readLine()) != null) + { + hCount++; + int endOfField = hString.indexOf(','); + int hhId = Integer.parseInt(hString.substring(0, endOfField)); + + // if it's a sample hh, write the hh and the person records + if (testHhs[hhId] == 1) + { + out.write(hString + "\n"); + count++; + if (count == numHhs) break; + } + } + + out.close(); + + } catch (IOException e) + { + logger.fatal("IO Exception caught creating sample synpop household file."); + logger.fatal(String.format("reading hh file = %s, writing sample hh file = %s.", + hhFileName, newHhFileName)); + logger.fatal(String.format("hString = %s, hCount = %d.", hString, hCount)); + } + + String pString = ""; + int pCount = 0; + try + { + + logger.info(String.format("writing sample person file for selected households")); + + PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(newPersFileName))); + BufferedReader in = new BufferedReader(new FileReader(persFileName)); + + // read headers and write to output files + pString = in.readLine(); + out.write(pString + "\n"); + pCount++; + int count = 0; + int oldId = 0; + while ((pString = in.readLine()) != null) + { + pCount++; + int endOfField = pString.indexOf(','); + int hhId = Integer.parseInt(pString.substring(0, endOfField)); + + // if it's a sample hh, write the hh and the person records + if (testHhs[hhId] == 1) + { + out.write(pString + "\n"); + if (hhId > oldId) count++; + } else + { + if (count == numHhs) break; + } + + oldId = hhId; + + } + + out.close(); + + } catch (IOException e) + { + logger.fatal("IO Exception caught creating sample synpop person file."); + logger.fatal(String.format( + "reading person file = %s, writing sample person file = %s.", persFileName, + newPersFileName)); + logger.fatal(String.format("pString = %s, pCount = %d.", pString, pCount)); + } + + } + + public static void main(String[] args) throws Exception + { + + String serverAddress = HH_DATA_SERVER_ADDRESS; + int serverPort = HH_DATA_SERVER_PORT; + + // optional arguments + for (int i = 0; i < args.length; i++) + { + if (args[i].equalsIgnoreCase("-hostname")) + { + serverAddress = args[i + 1]; + } + + if (args[i].equalsIgnoreCase("-port")) + { + serverPort = Integer.parseInt(args[i + 1]); + } + } + + Remote.config(serverAddress, HH_DATA_SERVER_PORT, null, 0); + + SandagHouseholdDataManager hhDataManager = new SandagHouseholdDataManager(); + + ItemServer.bind(hhDataManager, HH_DATA_SERVER_NAME); + + System.out.println(String.format( + "SandagHouseholdDataManager server class started on: %s:%d", serverAddress, + serverPort)); + + } + + public int[] getJointToursByHomeMgra(String purposeString) + { + // TODO Auto-generated method stub + return null; + } + + private int[] readOccupCorrespondenceData() + { + + TableDataSet occTable = null; + + // construct input household file name from properties file values + String occupFileName = propertyMap.get(PROPERTIES_OCCUP_CODES); + String fileName = projectDirectory + "/" + occupFileName; + + try + { + logger.info("reading occupation codes data file for creating occupation segments."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + occTable = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String.format( + "Exception occurred occupation codes data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + // get the array of indices from the TableDataSet + int[] occcen1Col = occTable.getColumnAsInt("occcen1"); + int[] occupCol = occTable.getColumnAsInt("pecas_occ"); + + // get the max index value, to use for array dimensions + int maxOcc = 0; + for (int occ : occcen1Col) + if (occ > maxOcc) maxOcc = occ; + + int[] occcen1Occup = new int[maxOcc + 1]; + for (int i = 0; i < occcen1Col.length; i++) + { + int index = occcen1Col[i]; + int value = occupCol[i]; + occcen1Occup[index] = value; + } + + return occcen1Occup; + } + + private int[] readIndustryCorrespondenceData() + { + + TableDataSet indTable = null; + + // construct input household file name from properties file values + String indFileName = propertyMap.get(PROPERTIES_INDUSTRY_CODES); + String fileName = projectDirectory + "/" + indFileName; + + try + { + logger.info("reading industry codes data file for creating industry segments."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + indTable = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading indistry codes data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + // get the array of indices from the TableDataSet + int[] indcenCol = indTable.getColumnAsInt("indcen"); + int[] activityCol = indTable.getColumnAsInt("activity_code"); + + // get the max index value, to use for array dimensions + int maxInd = 0; + for (int ind : indcenCol) + if (ind > maxInd) maxInd = ind; + + int[] indcenIndustry = new int[maxInd + 1]; + for (int i = 0; i < indcenCol.length; i++) + { + int index = indcenCol[i]; + int value = activityCol[i]; + indcenIndustry[index] = value; + } + + return indcenIndustry; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagHouseholdDataManager2.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagHouseholdDataManager2.java new file mode 100644 index 0000000..d6364c4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagHouseholdDataManager2.java @@ -0,0 +1,788 @@ +package org.sandag.abm.application; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; + +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.HouseholdDataManager; +import org.sandag.abm.ctramp.Person; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.IndexSort; +import com.pb.common.util.PropertyMap; + +/** + * @author Jim Hicks + * + * Class for managing household and person object data read from + * synthetic population files. + */ +public class SandagHouseholdDataManager2 + extends HouseholdDataManager +{ + + public static final String HH_DATA_SERVER_NAME = SandagHouseholdDataManager.class + .getCanonicalName(); + public static final String HH_DATA_SERVER_ADDRESS = "127.0.0.1"; + public static final int HH_DATA_SERVER_PORT = 1139; + + public static final String PROPERTIES_OCCUP_CODES = "PopulationSynthesizer.OccupCodes"; + public static final String PROPERTIES_INDUSTRY_CODES = "PopulationSynthesizer.IndustryCodes"; + public static final String PROPERTIES_MILITARY_INDUSTRY_RANGE = "PopulationSynthesizer.MilitaryIndustryRange"; + + + private int militaryIndustryLow; + private int militaryIndustryHigh; + + public SandagHouseholdDataManager2() + { + super(); + } + + /** + * Associate data in hh and person TableDataSets read from synthetic + * population files with Household objects and Person objects with + * Households. + * + */ + public void mapTablesToHouseholdObjects() + { + + logger.info("mapping popsyn household and person data records to objects."); + + int id = -1; + + int invalidPersonTypeCount1 = 0; + int invalidPersonTypeCount2 = 0; + int invalidPersonTypeCount3 = 0; + + // read the correspondence files for mapping persons to occupation and + HashMap occCodes = readOccupCorrespondenceData(); + int[] indCodes = readIndustryCorrespondenceData(); + + // get the maximum HH id value to use to dimension the hhIndex + // correspondence + // array. The hhIndex array will store the hhArray index number for the + // given + // hh index. + int maxHhId = 0; + int hhIDColumn = hhTable.getColumnPosition(HH_ID_FIELD_NAME); + + for (int r = 1; r <= hhTable.getRowCount(); r++) + { + id = (int) hhTable.getValueAt(r, hhIDColumn); + if (id > maxHhId) maxHhId = id; + } + hhIndexArray = new int[maxHhId + 1]; + + // get an index array for households sorted in random order - to remove + // the original order + int[] firstSortedIndices = getRandomOrderHhIndexArray(hhTable.getRowCount()); + + // get a second index array for households sorted in random order - to + // select a sample from the randomly ordered hhs + int[] randomSortedIndices = getRandomOrderHhIndexArray(hhTable.getRowCount()); + + hhs = null; + + int numHouseholdsInSample = (int) (hhTable.getRowCount() * sampleRate); + Household[] hhArray = new Household[numHouseholdsInSample]; + + // String outputFileName = "sample_hh_mgra_taz_seed_" + sampleSeed + + // ".csv"; + // PrintWriter outStream = null; + // try { + // outStream = new PrintWriter(new BufferedWriter(new FileWriter(new + // File(outputFileName)))); + // outStream.println("i,mgra,taz"); + // } + // catch (IOException e) { + // logger.fatal(String.format("Exception occurred opening output skims file: %s.", + // outputFileName)); + // throw new RuntimeException(e); + // } + + int[] tempFreqArray = new int[40000]; + int[] hhOriginSortArray = new int[numHouseholdsInSample]; + for (int i = 0; i < numHouseholdsInSample; i++) + { + int r = firstSortedIndices[randomSortedIndices[i]] + 1; + // int hhId = (int) hhTable.getValueAt(r, + // hhTable.getColumnPosition(HH_ID_FIELD_NAME)); + int hhMgra = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_HOME_MGRA_FIELD_NAME)); + int hhTaz = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_HOME_TAZ_FIELD_NAME)); + hhOriginSortArray[i] = hhMgra; + tempFreqArray[hhMgra]++; + + // outStream.println(i + "," + hhMgra + "," + hhTaz); + } + + // outStream.close(); + // System.exit(1); + + int mgrasInSample = 0; + for (int i = 0; i < tempFreqArray.length; i++) + { + if (tempFreqArray[i] > 0) mgrasInSample++; + } + logger.info(mgrasInSample + " unique MGRA values in the " + (sampleRate * 100) + + "% sample."); + + // get an index array for households sorted in order of home mgra + int[] newOrder = new int[numHouseholdsInSample]; + int[] sortedIndices = IndexSort.indexSort(hhOriginSortArray); + for (int i = 0; i < sortedIndices.length; i++) + { + int k = sortedIndices[i]; + newOrder[k] = i; + } + + // for each household in the sample + for (int i = 0; i < numHouseholdsInSample; i++) + { + int r = firstSortedIndices[randomSortedIndices[i]] + 1; + try + { + // create a Household object + Household hh = new Household(modelStructure); + + // get required values from table record and store in Household + // object + id = (int) hhTable.getValueAt(r, hhTable.getColumnPosition(HH_ID_FIELD_NAME)); + hh.setHhId(id, inputRandomSeed); + + // set the household in the hhIndexArray in random order + int newIndex = newOrder[i]; + hhIndexArray[hh.getHhId()] = newIndex; + + int htaz = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_HOME_TAZ_FIELD_NAME)); + hh.setHhTaz(htaz); + + int hmgra = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_HOME_MGRA_FIELD_NAME)); + hh.setHhMgra(hmgra); + + // autos could be modeled or from PUMA + int numAutos = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_AUTOS_FIELD_NAME)); + hh.setHhAutos(numAutos); + + // set the hhSize variable and create Person objects for each + // person + int numPersons = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_SIZE_FIELD_NAME)); + hh.setHhSize(numPersons); + + int numWorkers = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_WORKERS_FIELD_NAME)); + hh.setHhWorkers(numWorkers); + + int incomeCat = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_INCOME_CATEGORY_FIELD_NAME)); + hh.setHhIncomeCategory(incomeCat); + + int incomeInDollars = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_INCOME_DOLLARS_FIELD_NAME)); + hh.setHhIncomeInDollars(incomeInDollars); + + // 0=Housing unit, 1=Institutional group quarters, + // 2=Noninstitutional + // group quarters + int unitType = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_UNITTYPE_FIELD_NAME)); + hh.setUnitType(unitType); + + // 1=Family household:married-couple, 2=Family household:male + // householder,no wife present, 3=Family household:female + // householder,no + // husband present + // 4=Nonfamily household:male householder, living alone, + // 5=Nonfamily + // household:male householder, not living alone, + // 6=Nonfamily household:female householder, living alone, + // 7=Nonfamily household:female householder, not living alone + int type = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_TYPE_FIELD_NAME)); + hh.setHhType(type); + + // 1=mobile home, 2=one-family house detached from any other + // house, + // 3=one-family house attached to one or more houses, + // 4=building with 2 apartments, 5=building with 3 or 4 + // apartments, + // 6=building with 5 to 9 apartments, + // 7=building with 10 to 19 apartments, 8=building with 20 to 49 + // apartments, + // 9=building with 50 or more apartments, 10=Boat,RV,van,etc. + int bldgsz = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(HH_BLDGSZ_FIELD_NAME)); + hh.setHhBldgsz(bldgsz); + + hh.initializeWindows(); + hhArray[newIndex] = hh; + + } catch (Exception e) + { + + logger.fatal(String + .format("exception caught mapping household data record to a Household object, r=%d, id=%d.", + r, id)); + throw new RuntimeException(e); + + } + + } + + int[] personHhStart = new int[maxHhId + 1]; + int[] personHhEnd = new int[maxHhId + 1]; + + // get hhid for person record 1 + int hhid = (int) personTable.getValueAt(1, + personTable.getColumnPosition(PERSON_HH_ID_FIELD_NAME)); + personHhStart[hhid] = 1; + int oldHhid = hhid; + + for (int r = 1; r <= personTable.getRowCount(); r++) + { + + // get the Household object for this person data to be stored in + hhid = (int) personTable.getValueAt(r, + personTable.getColumnPosition(PERSON_HH_ID_FIELD_NAME)); + + if (hhid != oldHhid) + { + personHhEnd[oldHhid] = r - 1; + oldHhid = hhid; + personHhStart[hhid] = r; + } + + } + personHhEnd[hhid] = personTable.getRowCount(); + + int r = 0; + int p = 0; + int persId = 0; + int persNum = 0; + int fieldCount = 0; + + for (int i = 0; i < numHouseholdsInSample; i++) + { + + try + { + + r = firstSortedIndices[randomSortedIndices[i]] + 1; + + hhid = (int) hhTable.getValueAt(r, + hhTable.getColumnPosition(PERSON_HH_ID_FIELD_NAME)); + + int index = hhIndexArray[hhid]; + Household hh = hhArray[index]; + + persNum = 1; + + for (p = personHhStart[hhid]; p <= personHhEnd[hhid]; p++) + { + + fieldCount = 0; + + // get the Person object for this person data to be stored + // in + persId = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_PERSON_ID_FIELD_NAME)); + Person person = hh.getPerson(persNum++); + person.setPersId(persId); + fieldCount++; + + // get required values from table record and store in Person + // object + int age = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_AGE_FIELD_NAME)); + person.setPersAge(age); + fieldCount++; + + int gender = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_GENDER_FIELD_NAME)); + person.setPersGender(gender); + fieldCount++; + /* + * int occcen1 = (int) personTable.getValueAt(p, + * personTable.getColumnPosition(PERSON_SOC_FIELD_NAME)); + * int pecasOccup = occCodes[occcen1]; + */ + int military = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_MILITARY_FIELD_NAME)); + int pecasOccup = 0; + + String occsoc = personTable.getStringValueAt(p, + personTable.getColumnPosition(PERSON_SOC_FIELD_NAME)); + + int indcen = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_INDCEN_FIELD_NAME)); + int activityCode = indCodes[indcen]; + + if (military == 1) // in active military + pecasOccup = 56; + else if (military != 1 && indcen >= militaryIndustryLow + && indcen <= militaryIndustryHigh) // not active + // military but + // military + // contractor + pecasOccup = 56; + else + { + if (!occCodes.containsKey(occsoc)) + { + logger.fatal("Error: Occupation code " + occsoc + " for hhid " + hhid + + " person " + p + " not found in occupation file"); + throw new RuntimeException(); + } + pecasOccup = occCodes.get(occsoc); // everyone else + if (pecasOccup == 0) logger.warn("pecasOccup==0 for occsoc==" + occsoc); + } + + person.setPersActivityCode(activityCode); + fieldCount++; + + person.setPersPecasOccup(pecasOccup); + fieldCount++; + + /* + * These are the old codes, based upon census occupation + * definitions if ((pecasOccup == 71) && (activityCode == 2 + * || activityCode == 4 || activityCode == 6 || activityCode + * == 8 || activityCode == 29)) activityCode++; + * + * if ((pecasOccup == 76) && (activityCode == 3 || + * activityCode == 5 || activityCode == 7 || activityCode == + * 9 || activityCode == 30)) activityCode--; + * + * if ((pecasOccup == 76) && (activityCode == 13)) + * activityCode = 14; + * + * if ((pecasOccup == 71) && (activityCode == 14)) + * activityCode = 13; + * + * if ((pecasOccup == 75) && (activityCode == 18)) + * activityCode = 22; + * + * if ((pecasOccup == 71) && (activityCode == 22)) + * activityCode = 18; + * + * if (activityCode == 28) pecasOccup = 77; + */ + + // Employment status (1-employed FT, 2-employed PT, 3-not + // employed, 4-under age 16) + int empCat = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_EMPLOYMENT_CATEGORY_FIELD_NAME)); + + // recode PEMPLOY to 3 for persons whose age is 16 or + // greater and who have PEMPLOY set to 4 + if (empCat == 4 && age >= 16) empCat = 3; + person.setPersEmploymentCategory(empCat); + + fieldCount++; + + // Student status (1 - student in grade or high school; 2 - + // student in college or higher; 3 - not a student) + int studentCat = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_STUDENT_CATEGORY_FIELD_NAME)); + person.setPersStudentCategory(studentCat); + fieldCount++; + + // Person type (1-FT worker age 16+, 2-PT worker nonstudent + // age + // 16+, 3-university student, 4-nonworker nonstudent age + // 16-64, + // 5-nonworker nonstudent age 65+, + // 6-"age 16-19 student, not FT wrkr or univ stud", 7-age + // 6-15 + // schpred, 8 under age 6 presch + int personType = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_TYPE_CATEGORY_FIELD_NAME)); + person.setPersonTypeCategory(personType); + fieldCount++; + + // Person educational attainment level to determine high + // school + // graduate status ( < 9 - not a graduate, 10+ - high school + // graduate + // and beyond) + int educ = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_EDUCATION_ATTAINMENT_FIELD_NAME)); + if (educ >= 9) person.setPersonIsHighSchoolGraduate(true); + else person.setPersonIsHighSchoolGraduate(false); + fieldCount++; + + // Person educational attainment level to determine higher + // education status ( > 12 - at least a bachelor's degree ) + if (educ >= 13) person.setPersonHasBachelors(true); + else person.setPersonHasBachelors(false); + fieldCount++; + + // Person grade enrolled in ( 0-"not enrolled", + // 1-"preschool", + // 2-"Kindergarten", 3-"Grade 1 to grade 4", + // 4-"Grade 5 to grade 8", 5-"Grade 9 to grade 12", + // 6-"College undergraduate", + // 7-"Graduate or professional school" + // ) + int grade = (int) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_GRADE_ENROLLED_FIELD_NAME)); + person.setPersonIsGradeSchool(false); + person.setPersonIsHighSchool(false); + if (grade >= 2 && grade <= 4) + { + // change person type if person was 5 or under but + // enrolled in K-8. + if (person.getPersonIsPreschoolChild() == 1) + person.setPersonTypeCategory(Person.PersonType.Student_age_6_15_schpred + .ordinal()); + + person.setPersonIsGradeSchool(true); + } else if (grade == 5) + { + person.setPersonIsHighSchool(true); + } + fieldCount++; + + // if person is a university student but has school age + // student + // category value, reset student category value + if (personType == Person.PersonType.University_student.ordinal() + && studentCat != Person.StudentStatus.STUDENT_COLLEGE_OR_HIGHER + .ordinal()) + { + studentCat = Person.StudentStatus.STUDENT_COLLEGE_OR_HIGHER.ordinal(); + person.setPersStudentCategory(studentCat); + invalidPersonTypeCount1++; + } else if (studentCat != Person.StudentStatus.NON_STUDENT.ordinal() + && empCat == Person.EmployStatus.FULL_TIME.ordinal()) + { + // if person is a student of any kind but has full-time + // employment status, reset student category value to + // non-student + studentCat = Person.StudentStatus.NON_STUDENT.ordinal(); + person.setPersStudentCategory(studentCat); + invalidPersonTypeCount2++; + } + fieldCount++; + + // check consistency of student category and person type + if (studentCat == Person.StudentStatus.NON_STUDENT.ordinal()) + { + + if (person.getPersonIsStudentNonDriving() == 1 + || person.getPersonIsStudentDriving() == 1) + { + studentCat = Person.StudentStatus.STUDENT_HIGH_SCHOOL_OR_LESS.ordinal(); + person.setPersStudentCategory(studentCat); + invalidPersonTypeCount3++; + } + + } + fieldCount++; + + double timeFactorWork = 1.0; + double timeFactorNonWork = 1.0; + if(readTimeFactors){ + timeFactorWork = (double) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_TIMEFACTOR_WORK_FIELD_NAME)); + timeFactorNonWork = (double) personTable.getValueAt(p, + personTable.getColumnPosition(PERSON_TIMEFACTOR_NONWORK_FIELD_NAME)); + } + person.setTimeFactorWork(timeFactorWork); + person.setTimeFactorNonWork(timeFactorNonWork); + + } + + } catch (Exception e) + { + + logger.fatal(String + .format("exception caught mapping person data record to a Person object, i=%d, r=%d, p=%d, hhid=%d, persid=%d, persnum=%d, fieldCount=%d.", + i, r, p, hhid, persId, persNum, fieldCount)); + throw new RuntimeException(e); + + } + + } // person loop + + hhs = hhArray; + + logger.warn(invalidPersonTypeCount1 + + " person type = university and student category = non-student person records had their student category changed to university or higher."); + logger.warn(invalidPersonTypeCount2 + + " Student category = student and employment category = full-time worker person records had their student category changed to non-student."); + logger.warn(invalidPersonTypeCount3 + + " Student category = non-student and person type = student person records had their student category changed to student high school or less."); + + // logger.info("Setting distributed values of time. "); + // setDistributedValuesOfTime(); + + } + + /** + * if called, must be called after readData so that the size of the full + * population is known. + * + * @param hhFileName + * @param persFileName + * @param numHhs + */ + public void createSamplePopulationFiles(String hhFileName, String persFileName, + String newHhFileName, String newPersFileName, int numHhs) + { + + int maximumHhId = 0; + for (int i = 0; i < hhs.length; i++) + { + int id = hhs[i].getHhId(); + if (id > maximumHhId) maximumHhId = id; + } + + int[] testHhs = new int[maximumHhId + 1]; + + int[] sortedIndices = getRandomOrderHhIndexArray(hhs.length); + + for (int i = 0; i < numHhs; i++) + { + int k = sortedIndices[i]; + int hhId = hhs[k].getHhId(); + testHhs[hhId] = 1; + } + + String hString = ""; + int hCount = 0; + try + { + + logger.info(String.format("writing sample household file for %d households", numHhs)); + + PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(newHhFileName))); + BufferedReader in = new BufferedReader(new FileReader(hhFileName)); + + // read headers and write to output files + hString = in.readLine(); + out.write(hString + "\n"); + hCount++; + int count = 0; + + while ((hString = in.readLine()) != null) + { + hCount++; + int endOfField = hString.indexOf(','); + int hhId = Integer.parseInt(hString.substring(0, endOfField)); + + // if it's a sample hh, write the hh and the person records + if (testHhs[hhId] == 1) + { + out.write(hString + "\n"); + count++; + if (count == numHhs) break; + } + } + + out.close(); + + } catch (IOException e) + { + logger.fatal("IO Exception caught creating sample synpop household file."); + logger.fatal(String.format("reading hh file = %s, writing sample hh file = %s.", + hhFileName, newHhFileName)); + logger.fatal(String.format("hString = %s, hCount = %d.", hString, hCount)); + } + + String pString = ""; + int pCount = 0; + try + { + + logger.info(String.format("writing sample person file for selected households")); + + PrintWriter out = new PrintWriter(new BufferedWriter(new FileWriter(newPersFileName))); + BufferedReader in = new BufferedReader(new FileReader(persFileName)); + + // read headers and write to output files + pString = in.readLine(); + out.write(pString + "\n"); + pCount++; + int count = 0; + int oldId = 0; + while ((pString = in.readLine()) != null) + { + pCount++; + int endOfField = pString.indexOf(','); + int hhId = Integer.parseInt(pString.substring(0, endOfField)); + + // if it's a sample hh, write the hh and the person records + if (testHhs[hhId] == 1) + { + out.write(pString + "\n"); + if (hhId > oldId) count++; + } else + { + if (count == numHhs) break; + } + + oldId = hhId; + + } + + out.close(); + + } catch (IOException e) + { + logger.fatal("IO Exception caught creating sample synpop person file."); + logger.fatal(String.format( + "reading person file = %s, writing sample person file = %s.", persFileName, + newPersFileName)); + logger.fatal(String.format("pString = %s, pCount = %d.", pString, pCount)); + } + + } + + public static void main(String[] args) throws Exception + { + + String serverAddress = HH_DATA_SERVER_ADDRESS; + int serverPort = HH_DATA_SERVER_PORT; + + // optional arguments + for (int i = 0; i < args.length; i++) + { + if (args[i].equalsIgnoreCase("-hostname")) + { + serverAddress = args[i + 1]; + } + + if (args[i].equalsIgnoreCase("-port")) + { + serverPort = Integer.parseInt(args[i + 1]); + } + } + + Remote.config(serverAddress, serverPort, null, 0); + + SandagHouseholdDataManager2 hhDataManager = new SandagHouseholdDataManager2(); + + ItemServer.bind(hhDataManager, HH_DATA_SERVER_NAME); + + System.out.println(String.format( + "SandagHouseholdDataManager2 server class started on: %s:%d", serverAddress, + serverPort)); + + } + + public int[] getJointToursByHomeMgra(String purposeString) + { + // TODO Auto-generated method stub + return null; + } + + /** + * This method reads a cross-walk file between the occsoc code in Census and + * the PECAS occupation categories. It stores the result in a HashMap and + * returns it. + * + * @return + */ + private HashMap readOccupCorrespondenceData() + { + + int[] militaryRange = PropertyMap.getIntegerArrayFromPropertyMap(propertyMap, + PROPERTIES_MILITARY_INDUSTRY_RANGE); + militaryIndustryLow = militaryRange[0]; + militaryIndustryHigh = militaryRange[1]; + + TableDataSet occTable = null; + + // construct input household file name from properties file values + String occupFileName = propertyMap.get(PROPERTIES_OCCUP_CODES); + String fileName = projectDirectory + "/" + occupFileName; + + try + { + logger.info("reading occupation codes data file for creating occupation segments."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + occTable = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String.format( + "Exception occurred occupation codes data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + HashMap occMap = new HashMap(); + + for (int i = 1; i <= occTable.getRowCount(); ++i) + { + + String soc = occTable.getStringValueAt(i, "occsoc5"); + int occ = (int) occTable.getValueAt(i, "commodity_id"); + occMap.put(soc, occ); + } + + return occMap; + } + + private int[] readIndustryCorrespondenceData() + { + + TableDataSet indTable = null; + + // construct input household file name from properties file values + String indFileName = propertyMap.get(PROPERTIES_INDUSTRY_CODES); + String fileName = projectDirectory + "/" + indFileName; + + try + { + logger.info("reading industry codes data file for creating industry segments."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + indTable = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading indistry codes data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + // get the array of indices from the TableDataSet + int[] indcenCol = indTable.getColumnAsInt("indcen"); + int[] activityCol = indTable.getColumnAsInt("activity_code"); + + // get the max index value, to use for array dimensions + int maxInd = 0; + for (int ind : indcenCol) + if (ind > maxInd) maxInd = ind; + + int[] indcenIndustry = new int[maxInd + 1]; + for (int i = 0; i < indcenCol.length; i++) + { + int index = indcenCol[i]; + int value = activityCol[i]; + indcenIndustry[index] = value; + } + + return indcenIndustry; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagIndividualMandatoryTourFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagIndividualMandatoryTourFrequencyDMU.java new file mode 100644 index 0000000..0a40886 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagIndividualMandatoryTourFrequencyDMU.java @@ -0,0 +1,101 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.IndividualMandatoryTourFrequencyDMU; + +/** + * ArcIndividualMandatoryTourFrequencyDMU is a class that ... + * + * @author Kimberly Grommes + * @version 1.0, Jul 17, 2008 Created by IntelliJ IDEA. + */ +public class SandagIndividualMandatoryTourFrequencyDMU + extends IndividualMandatoryTourFrequencyDMU +{ + + public SandagIndividualMandatoryTourFrequencyDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getDistanceToWorkLocation", 1); + methodIndexMap.put("getDistanceToSchoolLocation", 2); + methodIndexMap.put("getEscortAccessibility", 3); + methodIndexMap.put("getDrivers", 4); + methodIndexMap.put("getPreschoolChildren", 5); + methodIndexMap.put("getNumberOfChildren6To18WithoutMandatoryActivity", 6); + methodIndexMap.put("getNonFamilyHousehold", 7); + methodIndexMap.put("getIncomeInDollars", 8); + methodIndexMap.put("getPersonType", 9); + methodIndexMap.put("getFemale", 10); + methodIndexMap.put("getAutos", 11); + methodIndexMap.put("getAge", 12); + methodIndexMap.put("getBestTimeToWorkLocation", 13); + methodIndexMap.put("getNotEmployed", 14); + methodIndexMap.put("getWorkAtHome", 15); + methodIndexMap.put("getSchoolAtHome", 16); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 1: + return getDistanceToWorkLocation(); + case 2: + return getDistanceToSchoolLocation(); + case 3: + return getEscortAccessibility(); + case 4: + return getDrivers(); + case 5: + return getPreschoolChildren(); + case 6: + return getNumberOfChildren6To18WithoutMandatoryActivity(); + case 7: + return getNonFamilyHousehold(); + case 8: + return getIncomeInDollars(); + case 9: + return getPersonType(); + case 10: + return getFemale(); + case 11: + return getAutos(); + case 12: + return getAge(); + case 13: + return getBestTimeToWorkLocation(); + case 14: + return getNotEmployed(); + case 15: + return getWorkAtHome(); + case 16: + return getSchoolAtHome(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagIndividualNonMandatoryTourFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagIndividualNonMandatoryTourFrequencyDMU.java new file mode 100644 index 0000000..5e675e8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagIndividualNonMandatoryTourFrequencyDMU.java @@ -0,0 +1,272 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.IndividualNonMandatoryTourFrequencyDMU; + +/** + * ArcIndividualNonMandatoryTourFrequencyDMU is a class that ... + * + */ +public class SandagIndividualNonMandatoryTourFrequencyDMU + extends IndividualNonMandatoryTourFrequencyDMU +{ + + public SandagIndividualNonMandatoryTourFrequencyDMU() + { + super(); + setupMethodIndexMap(); + + // set names used in SANDAG stop purpose file + TOUR_FREQ_ALTERNATIVES_FILE_ESCORT_NAME = "escort"; + TOUR_FREQ_ALTERNATIVES_FILE_SHOPPING_NAME = "shopping"; + TOUR_FREQ_ALTERNATIVES_FILE_MAINT_NAME = "othmaint"; + TOUR_FREQ_ALTERNATIVES_FILE_EAT_OUT_NAME = "eatout"; + TOUR_FREQ_ALTERNATIVES_FILE_VISIT_NAME = "visit"; + TOUR_FREQ_ALTERNATIVES_FILE_DISCR_NAME = "othdiscr"; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getIncomeInDollars", 0); + methodIndexMap.put("getHouseholdSize", 1); + methodIndexMap.put("getNumAutos", 2); + methodIndexMap.put("getCarsEqualsWorkers", 3); + methodIndexMap.put("getMoreCarsThanWorkers", 4); + methodIndexMap.put("getNumAdults", 5); + methodIndexMap.put("getNumChildren", 6); + methodIndexMap.put("getPersonIsAdult", 7); + methodIndexMap.put("getPersonIsChild", 8); + methodIndexMap.put("getPersonIsFullTimeWorker", 9); + methodIndexMap.put("getPersonIsPartTimeWorker", 10); + methodIndexMap.put("getPersonIsUniversity", 11); + methodIndexMap.put("getPersonIsNonworker", 12); + methodIndexMap.put("getPersonIsPreschool", 13); + methodIndexMap.put("getPersonIsStudentNonDriving", 14); + methodIndexMap.put("getPersonIsStudentDriving", 15); + methodIndexMap.put("getPersonStaysHome", 16); + methodIndexMap.put("getFemale", 17); + methodIndexMap.put("getFullTimeWorkers", 18); + methodIndexMap.put("getPartTimeWorkers", 19); + methodIndexMap.put("getUniversityStudents", 20); + methodIndexMap.put("getNonWorkers", 21); + methodIndexMap.put("getDrivingAgeStudents", 22); + methodIndexMap.put("getNonDrivingAgeStudents", 23); + methodIndexMap.put("getPreSchoolers", 24); + // methodIndexMap.put("getMaxAdultOverlaps", 26); + // methodIndexMap.put("getMaxChildOverlaps", 27); + // methodIndexMap.put("getMaxMixedOverlaps", 28); + // methodIndexMap.put("getMaxPairwiseOverlapAdult", 29); + // methodIndexMap.put("getMaxPairwiseOverlapChild", 30); + // methodIndexMap.put("getWindowBeforeFirstMandJointTour", 31); + // methodIndexMap.put("getWindowBetweenFirstLastMandJointTour", 32); + // methodIndexMap.put("getWindowAfterLastMandJointTour", 33); + methodIndexMap.put("getNumHhFtWorkers", 34); + methodIndexMap.put("getNumHhPtWorkers", 35); + methodIndexMap.put("getNumHhUnivStudents", 36); + methodIndexMap.put("getNumHhNonWorkAdults", 37); + methodIndexMap.put("getNumHhRetired", 38); + methodIndexMap.put("getNumHhDrivingStudents", 39); + methodIndexMap.put("getNumHhNonDrivingStudents", 40); + methodIndexMap.put("getNumHhPreschool", 41); + methodIndexMap.put("getTravelActiveAdults ", 42); + methodIndexMap.put("getTravelActiveChildren ", 43); + methodIndexMap.put("getNumMandatoryTours", 44); + methodIndexMap.put("getNumJointShoppingTours", 45); + methodIndexMap.put("getNumJointOthMaintTours", 46); + methodIndexMap.put("getNumJointEatOutTours", 47); + methodIndexMap.put("getNumJointSocialTours", 48); + methodIndexMap.put("getNumJointOthDiscrTours", 49); + methodIndexMap.put("getJTours", 50); + methodIndexMap.put("getPreDrivingAtHome", 51); + methodIndexMap.put("getPreschoolAtHome", 52); + methodIndexMap.put("getDistanceToWorkLocation", 53); + methodIndexMap.put("getDistanceToSchoolLocation", 54); + methodIndexMap.put("getEscortAccessibility", 55); + methodIndexMap.put("getShopAccessibility", 56); + methodIndexMap.put("getMaintAccessibility", 57); + methodIndexMap.put("getEatOutAccessibility", 58); + methodIndexMap.put("getVisitAccessibility", 59); + methodIndexMap.put("getDiscrAccessibility", 60); + methodIndexMap.put("getCdapIndex", 61); + methodIndexMap.put("getNonMotorizedDcLogsum", 62); + methodIndexMap.put("getNumPredrivingKidsGoOut", 63); + methodIndexMap.put("getNumPreschoolKidsGoOut", 64); + methodIndexMap.put("getCollegeEducation", 65); + methodIndexMap.put("getLowEducation", 66); + methodIndexMap.put("getDetachedHh", 67); + methodIndexMap.put("getWorksAtHome", 68); + methodIndexMap.put("getWorkAccessibility", 69); + methodIndexMap.put("getSchoolAccessibility", 70); + methodIndexMap.put("getTelecommuteFrequency", 71); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + + case 0: + return getIncomeInDollars(); + case 1: + return getHouseholdSize(); + case 2: + return getNumAutos(); + case 3: + return getCarsEqualsWorkers(); + case 4: + return getMoreCarsThanWorkers(); + case 5: + return getNumAdults(); + case 6: + return getNumChildren(); + case 7: + return getPersonIsAdult(); + case 8: + return getPersonIsChild(); + case 9: + return getPersonIsFullTimeWorker(); + case 10: + return getPersonIsPartTimeWorker(); + case 11: + return getPersonIsUniversity(); + case 12: + return getPersonIsNonworker(); + case 13: + return getPersonIsPreschool(); + case 14: + return getPersonIsStudentNonDriving(); + case 15: + return getPersonIsStudentDriving(); + case 16: + return getPersonStaysHome(); + case 17: + return getFemale(); + case 18: + return getFullTimeWorkers(); + case 19: + return getPartTimeWorkers(); + case 20: + return getUniversityStudents(); + case 21: + return getNonWorkers(); + case 22: + return getDrivingAgeStudents(); + case 23: + return getNonDrivingAgeStudents(); + case 24: + return getPreSchoolers(); + // case 26: + // return getMaxAdultOverlaps(); + // case 27: + // return getMaxChildOverlaps(); + // case 28: + // return getMaxMixedOverlaps(); + // case 29: + // return getMaxPairwiseOverlapAdult(); + // case 30: + // return getMaxPairwiseOverlapChild(); + // case 31: + // return getWindowBeforeFirstMandJointTour(); + // case 32: + // return getWindowBetweenFirstLastMandJointTour(); + // case 33: + // return getWindowAfterLastMandJointTour(); + case 34: + return getNumHhFtWorkers(); + case 35: + return getNumHhPtWorkers(); + case 36: + return getNumHhUnivStudents(); + case 37: + return getNumHhNonWorkAdults(); + case 38: + return getNumHhRetired(); + case 39: + return getNumHhDrivingStudents(); + case 40: + return getNumHhNonDrivingStudents(); + case 41: + return getNumHhPreschool(); + case 42: + return getTravelActiveAdults(); + case 43: + return getTravelActiveChildren(); + case 44: + return getNumMandatoryTours(); + case 45: + return getNumJointShoppingTours(); + case 46: + return getNumJointOthMaintTours(); + case 47: + return getNumJointEatOutTours(); + case 48: + return getNumJointSocialTours(); + case 49: + return getNumJointOthDiscrTours(); + case 50: + return getJTours(); + case 51: + return getPreDrivingAtHome(); + case 52: + return getPreschoolAtHome(); + case 53: + return getDistanceToWorkLocation(); + case 54: + return getDistanceToSchoolLocation(); + case 55: + return getEscortAccessibility(); + case 56: + return getShopAccessibility(); + case 57: + return getMaintAccessibility(); + case 58: + return getEatOutAccessibility(); + case 59: + return getVisitAccessibility(); + case 60: + return getDiscrAccessibility(); + case 61: + return getCdapIndex(); + case 62: + return getNonMotorizedDcLogsum(); + case 63: + return getNumPredrivingKidsGoOut(); + case 64: + return getNumPreschoolKidsGoOut(); + case 65: + return getCollegeEducation(); + case 66: + return getLowEducation(); + case 67: + return getDetachedHh(); + case 68: + return getWorksAtHome(); + case 69: + return getWorkAccessibility(); + case 70: + return getSchoolAccessibility(); + case 71: + return getTelecommuteFrequency(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagInternalExternalTripChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagInternalExternalTripChoiceDMU.java new file mode 100644 index 0000000..fbab4ac --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagInternalExternalTripChoiceDMU.java @@ -0,0 +1,50 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.InternalExternalTripChoiceDMU; + +public class SandagInternalExternalTripChoiceDMU + extends InternalExternalTripChoiceDMU +{ + + private transient Logger logger = Logger.getLogger(SandagInternalExternalTripChoiceDMU.class); + + public SandagInternalExternalTripChoiceDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getDistanceToCordonsLogsum", 0); + methodIndexMap.put("getVehiclesPerHouseholdMember", 1); + methodIndexMap.put("getHhIncomeInDollars", 2); + methodIndexMap.put("getAge", 3); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getDistanceToCordonsLogsum(); + case 1: + return getVehiclesPerHouseholdMember(); + case 2: + return getHhIncomeInDollars(); + case 3: + return getAge(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagJointTourModelsDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagJointTourModelsDMU.java new file mode 100644 index 0000000..f57b1d3 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagJointTourModelsDMU.java @@ -0,0 +1,137 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.JointTourModelsDMU; +import org.sandag.abm.ctramp.ModelStructure; + +public class SandagJointTourModelsDMU + extends JointTourModelsDMU +{ + + public SandagJointTourModelsDMU(ModelStructure modelStructure) + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getActiveCountFullTimeWorkers", 1); + methodIndexMap.put("getActiveCountPartTimeWorkers", 2); + methodIndexMap.put("getActiveCountUnivStudents", 3); + methodIndexMap.put("getActiveCountNonWorkers", 4); + methodIndexMap.put("getActiveCountRetirees", 5); + methodIndexMap.put("getActiveCountDrivingAgeSchoolChildren", 6); + methodIndexMap.put("getActiveCountPreDrivingAgeSchoolChildren", 7); + methodIndexMap.put("getActiveCountPreSchoolChildren", 8); + methodIndexMap.put("getMaxPairwiseAdultOverlapsHh", 9); + methodIndexMap.put("getMaxPairwiseChildOverlapsHh", 10); + methodIndexMap.put("getMaxPairwiseMixedOverlapsHh", 11); + methodIndexMap.put("getMaxPairwiseOverlapOtherAdults", 12); + methodIndexMap.put("getMaxPairwiseOverlapOtherChildren", 13); + methodIndexMap.put("getTravelActiveAdults", 14); + methodIndexMap.put("getTravelActiveChildren", 15); + methodIndexMap.put("getPersonStaysHome", 16); + methodIndexMap.put("getIncomeLessThan30K", 17); + methodIndexMap.put("getIncome30Kto60K", 18); + methodIndexMap.put("getIncomeMoreThan100K", 19); + methodIndexMap.put("getNumAdults", 20); + methodIndexMap.put("getNumChildren", 21); + methodIndexMap.put("getHhWorkers", 22); + methodIndexMap.put("getAutoOwnership", 23); + methodIndexMap.put("getTourPurposeIsMaint", 24); + methodIndexMap.put("getTourPurposeIsEat", 25); + methodIndexMap.put("getTourPurposeIsVisit", 26); + methodIndexMap.put("getTourPurposeIsDiscr", 27); + methodIndexMap.put("getPersonType", 28); + methodIndexMap.put("getJointTourComposition", 29); + methodIndexMap.put("getJTours", 30); + methodIndexMap.put("getShopHOVAccessibility", 31); + methodIndexMap.put("getMaintHOVAccessibility", 32); + methodIndexMap.put("getDiscrHOVAccessibility", 33); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 1: + return getActiveCountFullTimeWorkers(); + case 2: + return getActiveCountPartTimeWorkers(); + case 3: + return getActiveCountUnivStudents(); + case 4: + return getActiveCountNonWorkers(); + case 5: + return getActiveCountRetirees(); + case 6: + return getActiveCountDrivingAgeSchoolChildren(); + case 7: + return getActiveCountPreDrivingAgeSchoolChildren(); + case 8: + return getActiveCountPreSchoolChildren(); + case 9: + return getMaxPairwiseAdultOverlapsHh(); + case 10: + return getMaxPairwiseChildOverlapsHh(); + case 11: + return getMaxPairwiseMixedOverlapsHh(); + case 12: + return getMaxPairwiseOverlapOtherAdults(); + case 13: + return getMaxPairwiseOverlapOtherChildren(); + case 14: + return getTravelActiveAdults(); + case 15: + return getTravelActiveChildren(); + case 16: + return getPersonStaysHome(); + case 17: + return getIncomeLessThan30K(); + case 18: + return getIncome30Kto60K(); + case 19: + return getIncomeMoreThan100K(); + case 20: + return getNumAdults(); + case 21: + return getNumChildren(); + case 22: + return getHhWorkers(); + case 23: + return getAutoOwnership(); + case 24: + return getTourPurposeIsMaint(); + case 25: + return getTourPurposeIsEat(); + case 26: + return getTourPurposeIsVisit(); + case 27: + return getTourPurposeIsDiscr(); + case 28: + return getPersonType(); + case 29: + return getJointTourComposition(); + case 30: + return getJTours(); + case 31: + return getShopHOVAccessibility(); + case 32: + return getMaintHOVAccessibility(); + case 33: + return getDiscrHOVAccessibility(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagMGRAtoPNR.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagMGRAtoPNR.java new file mode 100644 index 0000000..2c74056 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagMGRAtoPNR.java @@ -0,0 +1,287 @@ +package org.sandag.abm.application; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileWriter; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.MissingResourceException; +import java.util.Properties; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.active.sandag.PropertyParser; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.reporting.CsvRow; +import org.sandag.abm.reporting.DataExporter; +import org.sandag.abm.reporting.OMXMatrixDao; + +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +/** + * @author malinovskiyy + * Produces p&r and k&r access connections + * input files: + * impdan_xx.mtx: SOV non toll xx peak period skim matrix (3 cores: *SCST_XX (generalized cost), length(Skim) (distance in mile), and *STM_XX (Skim) (single driver xx time in minutes) + * tap.ptype: tap, lot id, parking type, taz, capacity, distance from lot to tap + * output files + * access.prp + */ +public class SandagMGRAtoPNR { + + private static Logger logger = Logger.getLogger("createPNRAccessFile"); + public static final int MATRIX_DATA_SERVER_PORT = 1171; + + private TapDataManager tapManager; + private int[] taps; + private int[] tazs; + private float[][][] tapParkingInfo; + private HashMap tapMap; + private HashMap> bestTapsMap; + private Matrix distanceMtx; + private Matrix timeMtx; + + private final Properties properties; + private final OMXMatrixDao mtxDao; + + private static final String FORMAL_PREMIUM = "taps.formal.premium.maxDist"; //8.0f; + private static final String FORMAL_EXPRESS = "taps.formal.express.maxDist"; //8.0f; + private static final String FORMAL_LOCAL = "taps.formal.local.maxDist"; //4.0f; + private static final String INFORMAL_PREMIUM = "taps.informal.premium.maxDist"; //4.0f; + private static final String INFORMAL_EXPRESS = "taps.informal.express.maxDist"; //4.0f; + private static final String INFORMAL_LOCAL = "taps.informal.local.maxDist"; //2.0f; + private static final String PREMIUM_MODES = "taps.premium.modes"; //new ArrayList(){{add(4); add(5); add(6); add(7);}}; + private static final String EXPRESS_MODES = "taps.express.modes"; //new ArrayList(){{add(8); add(9);}}; + private static final String LOCAL_MODES = "taps.local.modes"; //new ArrayList(){{add(10);}}; + + private static final String TAPS_SKIM = "taps.skim"; + private static final String TAPS_SKIM_DIST = "taps.skim.dist"; + private static final String TAPS_SKIM_TIME = "taps.skim.time"; + + private static final String EXTERNAL_TAZs = "external.tazs"; + + private double formalPremiumMaxD; + private double formalExpressMaxD; + private double formalLocalMaxD; + private double informalPremiumMaxD; + private double informalExpressMaxD; + private double informalLocalMaxD; + + private ArrayList premiumModes; + private ArrayList expressModes; + private ArrayList localModes; + private ArrayList externalTAZs; + + private static final String PROJECT_PATH_PROPERTY_TOKEN = "%project.folder%"; + + public SandagMGRAtoPNR(Properties theProperties, OMXMatrixDao aMtxDao, String projectPath, HashMap rbMap) + { + this.properties = theProperties; + this.mtxDao = aMtxDao; + + tapManager = TapDataManager.getInstance(rbMap); + //tazManager = TazDataManager.getInstance(rbMap); + this.taps = tapManager.getTaps(); + this.tapParkingInfo = tapManager.getTapParkingInfo(); + this.tapMap = getTAPMap(); + this.bestTapsMap = new HashMap>(); + this.distanceMtx = aMtxDao.getMatrix((String)properties.get(TAPS_SKIM),(String)properties.get(TAPS_SKIM_DIST)); + this.timeMtx = aMtxDao.getMatrix((String)properties.get(TAPS_SKIM),(String)properties.get(TAPS_SKIM_TIME)); + this.tazs = this.distanceMtx.getExternalRowNumbers(); + + + formalPremiumMaxD = Double.parseDouble((String) properties.get(FORMAL_PREMIUM)); + formalExpressMaxD = Double.parseDouble((String) properties.get(FORMAL_EXPRESS)); + formalLocalMaxD = Double.parseDouble((String) properties.get(FORMAL_LOCAL)); + informalPremiumMaxD = Double.parseDouble((String) properties.get(INFORMAL_PREMIUM)); + informalExpressMaxD = Double.parseDouble((String) properties.get(INFORMAL_EXPRESS)); + informalLocalMaxD = Double.parseDouble((String) properties.get(INFORMAL_LOCAL)); + + List stringList = Arrays.asList(((String) properties.get(PREMIUM_MODES)).split("\\s*,\\s*")); + premiumModes = new ArrayList(); + for (int i = 0; i < stringList.size(); i++){ + premiumModes.add(Integer.parseInt(stringList.get(i))); + } + + stringList = Arrays.asList(((String) properties.get(EXPRESS_MODES)).split("\\s*,\\s*")); + expressModes = new ArrayList(); + for (int i = 0; i < stringList.size(); i++){ + expressModes.add(Integer.parseInt(stringList.get(i))); + } + + stringList = Arrays.asList(((String) properties.get(LOCAL_MODES)).split("\\s*,\\s*")); + localModes = new ArrayList(); + for (int i = 0; i < stringList.size(); i++){ + localModes.add(Integer.parseInt(stringList.get(i))); + } + + stringList = Arrays.asList(((String) properties.get(EXTERNAL_TAZs)).split("\\s*,\\s*")); + externalTAZs = new ArrayList(); + for (int i = 0; i < stringList.size(); i++){ + externalTAZs.add(Integer.parseInt(stringList.get(i))); + } + } + + + public HashMap getTAPMap(){ + HashMap tm = new HashMap(); + for(int i = 0; i < taps.length; i++){ + int tap = taps[i]; + if(tap < tapParkingInfo.length && tapParkingInfo[tap] != null && tapParkingInfo[tap][0] != null){ + int taz = (int) tapParkingInfo[tap][1][0]; + tm.put(tap, taz); + } + } + return tm; + } + + public void nearestTAPs(){ + for(int i = 1; i < tazs.length; i++) { + int currTAZ = tazs[i]; + + //Skip externals + if(externalTAZs.contains(currTAZ)) + continue; + + ArrayList reachableTAPs = new ArrayList(); + bestTapsMap.put(currTAZ, reachableTAPs); + + HashMap modeMap = new HashMap(); + ArrayList addedTaps = new ArrayList(); + + for(Integer j : tapMap.keySet()){ + int tapTAZ = tapMap.get(j); + //distance to taz with the current tap + float dist = distanceMtx.getValueAt(currTAZ, tapTAZ); + float time = timeMtx.getValueAt(currTAZ, tapTAZ); + int lotType = (int) tapParkingInfo[j][3][0]; + int mode = (int) tapParkingInfo[j][5][0]; + //dist = (float) (dist + (tapParkingInfo[j][4][0] / 5280.0)); + if(!modeMap.containsKey(mode) || modeMap.get(mode)[2] > dist){ + float[] vals = new float[4]; + vals[0] = j; + vals[1] = time; + vals[2] = dist; + vals[3] = mode; + modeMap.put(mode, vals); + } + + //formal, premium, less than 8 miles + if( (lotType == 1 && premiumModes.contains(mode) && dist < formalPremiumMaxD) || + //formal, express, less than 8 miles + (lotType == 1 && expressModes.contains(mode) && dist < formalExpressMaxD) || + //formal, local, less than 4 miles + (lotType == 1 && localModes.contains(mode) && dist < formalLocalMaxD) || + //informal, premium, less than 4 miles + (lotType > 1 && premiumModes.contains(mode) && dist < informalPremiumMaxD) || + //informal, express, less than 4 miles + (lotType > 1 && expressModes.contains(mode) && dist < informalExpressMaxD) || + //informal, local, less than 2 miles + (lotType > 1 && localModes.contains(mode) && dist < informalLocalMaxD) ){ + float[] vals = new float[4]; + vals[0] = j; + vals[1] = time; + vals[2] = dist; + vals[3] = mode; + bestTapsMap.get(currTAZ).add(vals); + addedTaps.add(j); + } + } + for(Integer m : modeMap.keySet()){ + float[] closestTAPvals = modeMap.get(m); + int tap = (int) closestTAPvals[0]; + if(!addedTaps.contains(tap)){ //Put best taps by mode into bestTapsMap if they are not already there + bestTapsMap.get(currTAZ).add(closestTAPvals); + addedTaps.add(tap); + } + } + } + } + + /*The file has five columns: TAZ, TAP, travel time (min) *100, distance (mile) *100 and mode. + */ + public void writeResults(String filename) throws IOException{ + BufferedWriter writer = null; + try{ + writer = new BufferedWriter(new FileWriter(new File(filename))); + + for(int i = 1; i < tazs.length; i++) { + int currTAZ = tazs[i]; + + //Skip externals + if(externalTAZs.contains(currTAZ)) + continue; + + if(bestTapsMap.get(currTAZ).size() > 0){ + //NEW CSV FORMAT (tabular: TAZ, TAP, TIME, DIST, MODE) + for(int k = 0; k < bestTapsMap.get(currTAZ).size(); k++){ + writer.write( (int)(currTAZ) + "," + + (int)(bestTapsMap.get(currTAZ).get(k)[0]) + "," + + (double)(bestTapsMap.get(currTAZ).get(k)[1]) + "," + + (double)(bestTapsMap.get(currTAZ).get(k)[2]) + "," + + (int)(bestTapsMap.get(currTAZ).get(k)[3]) + "\n"); + } + } + } + }finally{ + if (writer != null) writer.close(); + } + } + + + /** + * @param args + */ + public static void main(String... args) throws Exception + { + HashMap pMap; + String propertiesFile = null; + + logger.info("Generating access**.prp files"); + if (args.length == 0) + { + logger.error(String.format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + + Properties properties = new Properties(); + properties.load(new FileInputStream("conf/sandag_abm.properties")); + + List definedTables = new ArrayList(); + for (String table : properties.getProperty("Report.tables").trim().split(",")) + definedTables.add(table.trim().toLowerCase()); + + String path = ClassLoader.getSystemResource("").getPath(); + path = path.substring(1, path.length() - 2); + String appPath = path.substring(0, path.lastIndexOf("/")); + + for (Object key : properties.keySet()) + { + String value = (String) properties.get(key); + properties.setProperty((String) key, value.replace(PROJECT_PATH_PROPERTY_TOKEN, appPath)); + } + + OMXMatrixDao mtxDao = new OMXMatrixDao(properties); + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + SandagMGRAtoPNR accessWriter = new SandagMGRAtoPNR(properties, mtxDao, appPath, pMap); + accessWriter.nearestTAPs(); + accessWriter.writeResults(properties.getProperty("taz.driveaccess.taps.file")); + } +} + diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagMicromobilityChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagMicromobilityChoiceDMU.java new file mode 100644 index 0000000..ffe60cf --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagMicromobilityChoiceDMU.java @@ -0,0 +1,52 @@ +package org.sandag.abm.application; + +import java.util.HashMap; + +import org.sandag.abm.ctramp.MicromobilityChoiceDMU; + +public class SandagMicromobilityChoiceDMU + extends MicromobilityChoiceDMU +{ + + public SandagMicromobilityChoiceDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getIvtCoeff", 0); + methodIndexMap.put("getCostCoeff", 1); + methodIndexMap.put("getWalkTime", 2); + methodIndexMap.put("getIsTransit", 3); + methodIndexMap.put("getMicroTransitAvailable", 4); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getIvtCoeff(); + case 1: + return getCostCoeff(); + case 2: + return getWalkTime(); + case 3: + return isTransit()? 1 : 0; + case 4: + return isMicroTransitAvailable() ? 1 : 0; + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagModelStructure.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagModelStructure.java new file mode 100644 index 0000000..774844c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagModelStructure.java @@ -0,0 +1,1299 @@ +package org.sandag.abm.application; + +import java.util.ArrayList; +import java.util.HashMap; + +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.modechoice.Modes; + +public class SandagModelStructure + extends ModelStructure +{ + + public final String[] MANDATORY_DC_PURPOSE_NAMES = { + WORK_PURPOSE_NAME, UNIVERSITY_PURPOSE_NAME, SCHOOL_PURPOSE_NAME }; + public final String[] WORK_PURPOSE_SEGMENT_NAMES = { + "low", "med", "high", "very high", "part time" }; + public final String[] UNIVERSITY_PURPOSE_SEGMENT_NAMES = {}; + public final String[] SCHOOL_PURPOSE_SEGMENT_NAMES = { + "predrive", "drive" }; + + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_LO = 1; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_MD = 2; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_HI = 3; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_VHI = 4; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_PT = 5; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_UNIVERSITY_UNIVERSITY = 6; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_SCHOOL_UNDER_SIXTEEN = 7; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_SCHOOL_SIXTEEN_PLUS = 8; + + public final int USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_WORK = 1; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_UNIVERSITY = 2; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_SCHOOL = 3; + + public final int USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_WORK = 1; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_UNIVERSITY = 2; + public final int USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_SCHOOL = 3; + + public final int MANDATORY_STOP_FREQ_UEC_INDEX_WORK = 1; + public final int MANDATORY_STOP_FREQ_UEC_INDEX_UNIVERSITY = 2; + public final int MANDATORY_STOP_FREQ_UEC_INDEX_SCHOOL = 3; + + public final int MANDATORY_STOP_LOC_UEC_INDEX_WORK = 1; + public final int MANDATORY_STOP_LOC_UEC_INDEX_UNIVERSITY = 1; + public final int MANDATORY_STOP_LOC_UEC_INDEX_SCHOOL = 1; + + public final int MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX_WORK = 1; + public final int MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX_UNIVERSITY = 2; + public final int MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX_SCHOOL = 3; + + public final String[] NON_MANDATORY_DC_PURPOSE_NAMES = { + "escort", "shopping", "eatOut", "othMaint", "visit", "othDiscr" }; + public final String[] ESCORT_PURPOSE_SEGMENT_NAMES = { + "kids", "no kids" }; + public final String[] SHOPPING_PURPOSE_SEGMENT_NAMES = {}; + public final String[] EAT_OUT_PURPOSE_SEGMENT_NAMES = {}; + public final String[] OTH_MAINT_PURPOSE_SEGMENT_NAMES = {}; + public final String[] SOCIAL_PURPOSE_SEGMENT_NAMES = {}; + public final String[] OTH_DISCR_PURPOSE_SEGMENT_NAMES = {}; + + /* + * public final int NON_MANDATORY_SOA_UEC_INDEX_ESCORT_KIDS = 9; public + * final int NON_MANDATORY_SOA_UEC_INDEX_ESCORT_NO_KIDS = 10; public final + * int NON_MANDATORY_SOA_UEC_INDEX_SHOPPING = 11; public final int + * NON_MANDATORY_SOA_UEC_INDEX_EAT_OUT = 12; public final int + * NON_MANDATORY_SOA_UEC_INDEX_OTHER_MAINT = 13; public final int + * NON_MANDATORY_SOA_UEC_INDEX_SOCIAL = 14; public final int + * NON_MANDATORY_SOA_UEC_INDEX_OTHER_DISCR = 15; + * + * public final int NON_MANDATORY_DC_UEC_INDEX_ESCORT_KIDS = 4; public final + * int NON_MANDATORY_DC_UEC_INDEX_ESCORT_NO_KIDS = 4; public final int + * NON_MANDATORY_DC_UEC_INDEX_SHOPPING = 5; public final int + * NON_MANDATORY_DC_UEC_INDEX_EAT_OUT = 6; public final int + * NON_MANDATORY_DC_UEC_INDEX_OTHER_MAINT = 7; public final int + * NON_MANDATORY_DC_UEC_INDEX_SOCIAL = 8; public final int + * NON_MANDATORY_DC_UEC_INDEX_OTHER_DISCR = 9; + * + * public final int NON_MANDATORY_MC_UEC_INDEX_ESCORT_KIDS = 4; public final + * int NON_MANDATORY_MC_UEC_INDEX_ESCORT_NO_KIDS = 4; public final int + * NON_MANDATORY_MC_UEC_INDEX_SHOPPING = 4; public final int + * NON_MANDATORY_MC_UEC_INDEX_EAT_OUT = 4; public final int + * NON_MANDATORY_MC_UEC_INDEX_OTHER_MAINT = 4; public final int + * NON_MANDATORY_MC_UEC_INDEX_SOCIAL = 4; public final int + * NON_MANDATORY_MC_UEC_INDEX_OTHER_DISCR = 4; + * + * public final int NON_MANDATORY_STOP_FREQ_UEC_INDEX_ESCORT = 4; public + * final int NON_MANDATORY_STOP_FREQ_UEC_INDEX_SHOPPING = 5; public final + * int NON_MANDATORY_STOP_FREQ_UEC_INDEX_OTHER_MAINT = 6; public final int + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_EAT_OUT = 7; public final int + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_SOCIAL = 8; public final int + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_OTHER_DISCR = 9; + * + * public final int NON_MANDATORY_STOP_LOC_UEC_INDEX_ESCORT = 2; public + * final int NON_MANDATORY_STOP_LOC_UEC_INDEX_SHOPPING = 3; public final int + * NON_MANDATORY_STOP_LOC_UEC_INDEX_EAT_OUT = 4; public final int + * NON_MANDATORY_STOP_LOC_UEC_INDEX_OTHER_MAINT = 5; public final int + * NON_MANDATORY_STOP_LOC_UEC_INDEX_SOCIAL = 6; public final int + * NON_MANDATORY_STOP_LOC_UEC_INDEX_OTHER_DISCR = 7; + * + * public final int NON_MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX = 4; + */ + public final String[] AT_WORK_DC_PURPOSE_NAMES = {"atwork"}; + public final String[] AT_WORK_DC_SIZE_SEGMENT_NAMES = { + "cbd", "urban", "suburban", "rural" }; + + public final int AT_WORK_SOA_UEC_INDEX_EAT = 16; + public final int AT_WORK_SOA_UEC_INDEX_BUSINESS = 17; + public final int AT_WORK_SOA_UEC_INDEX_MAINT = 18; + + public final int AT_WORK_DC_UEC_INDEX_EAT = 10; + public final int AT_WORK_DC_UEC_INDEX_BUSINESS = 10; + public final int AT_WORK_DC_UEC_INDEX_MAINT = 10; + + public final int AT_WORK_MC_UEC_INDEX_EAT = 5; + public final int AT_WORK_MC_UEC_INDEX_BUSINESS = 5; + public final int AT_WORK_MC_UEC_INDEX_MAINT = 5; + + public final int SD_AT_WORK_PURPOSE_INDEX_EAT = 1; + public final int SD_AT_WORK_PURPOSE_INDEX_BUSINESS = 2; + public final int SD_AT_WORK_PURPOSE_INDEX_MAINT = 3; + + public final int AT_WORK_STOP_FREQ_UEC_INDEX_EAT = 9; + public final int AT_WORK_STOP_FREQ_UEC_INDEX_BUSINESS = 9; + public final int AT_WORK_STOP_FREQ_UEC_INDEX_MAINT = 9; + + // TODO: set these values from project specific code. + public static final int[] SOV_ALTS = { + 1 }; + public static final int[] HOV_ALTS = { + 2, 3 }; + public static final int[] HOV2_ALTS = { + 2 }; + public static final int[] HOV3_ALTS = { + 3 }; + public static final int[] WALK_ALTS = {4}; + public static final int[] BIKE_ALTS = {5}; + public static final int[] NON_MOTORIZED_ALTS = { + 4, 5 }; + public static final int[] TRANSIT_ALTS = { + 6, 7, 8, 9 }; + public static final int[] WALK_TRANSIT_ALTS = { + 6 }; + public static final int[] DRIVE_TRANSIT_ALTS = { + 7, 8, 9 }; + public static final int[] PNR_ALTS = { + 7 }; + public static final int[] KNR_ALTS = { + 8, 9 }; + + public static final int TNC_TRANSIT_ALT = 9; + + public static final int[] SCHOOL_BUS_ALTS = {13}; + public static final int[] TRIP_SOV_ALTS = { + 1 }; + public static final int[] TRIP_HOV_ALTS = { + 2,3 }; + + // public static final int[] PAY_ALTS = { + // 2, 4, 6 }; + + public static final int[] OTHER_ALTS = {10,11,12,13}; + + private static final int WALK = 4; + private static final int BIKE = 5; + + public static final int SCHOOL_BUS = 13; + public static final int TAXI = 10; + public static final int[] TNC_ALTS = {11,12}; + public static final int[] MAAS_ALTS = {10,11,12}; + + public static final String[] modeName = {"SOV","SR2","SR3", + "WALK","BIKE","WLK_SET","PNR_SET","KNR_SET","TNC_SET","TAXI","TNC_SINGLE","TNC_SHARED","SCHLBUS"}; + + public static final int MAXIMUM_TOUR_MODE_ALT_INDEX = 13; + + public final double[][] CDAP_6_PLUS_PROPORTIONS = { + {0.0, 0.0, 0.0}, {0.79647, 0.09368, 0.10985}, {0.61678, 0.25757, 0.12565}, + {0.69229, 0.15641, 0.15130}, {0.00000, 0.67169, 0.32831}, {0.00000, 0.54295, 0.45705}, + {0.77609, 0.06004, 0.16387}, {0.68514, 0.09144, 0.22342}, {0.14056, 0.06512, 0.79432} }; + + public static final String[] JTF_ALTERNATIVE_LABELS = { + "0_tours", "1_Shop", "1_Main", "1_Eat", "1_Visit", "1_Disc", "2_SS", "2_SM", "2_SE", + "2_SV", "2_SD", "2_MM", "2_ME", "2_MV", "2_MD", "2_EE", "2_EV", "2_ED", "2_VV", "2_VD", + "2_DD" }; + public static final String[] AWF_ALTERNATIVE_LABELS = { + "0_subTours", "1_eat", "1_business", "1_other", "2_business", "2 other", + "2_eat_business" }; + + public static final int MIN_DRIVING_AGE = 16; + + public static final int MAX_STOPS_PER_DIRECTION = 4; + + public SandagModelStructure() + { + super(); + + jtfAltLabels = JTF_ALTERNATIVE_LABELS; + awfAltLabels = AWF_ALTERNATIVE_LABELS; + + dcSizePurposeSegmentMap = new HashMap>(); + + dcSizeIndexSegmentMap = new HashMap(); + dcSizeSegmentIndexMap = new HashMap(); + dcSizeArrayIndexPurposeMap = new HashMap(); + dcSizeArrayPurposeIndexMap = new HashMap(); + + setMandatoryPurposeNameValues(); + + setUsualWorkAndSchoolLocationSoaUecSheetIndexValues(); + setUsualWorkAndSchoolLocationUecSheetIndexValues(); + setUsualWorkAndSchoolLocationModeChoiceUecSheetIndexValues(); + + setMandatoryStopFreqUecSheetIndexValues(); + setMandatoryStopLocUecSheetIndexValues(); + setMandatoryTripModeChoiceUecSheetIndexValues(); + + setNonMandatoryPurposeNameValues(); + + /* + * setNonMandatoryDcSoaUecSheetIndexValues(); + * setNonMandatoryDcUecSheetIndexValues(); + * setNonMandatoryModeChoiceUecSheetIndexValues(); + * + * setNonMandatoryStopFreqUecSheetIndexValues(); + * setNonMandatoryStopLocUecSheetIndexValues(); + * setNonMandatoryTripModeChoiceUecSheetIndexValues(); + */ + setAtWorkPurposeNameValues(); + + setAtWorkDcSoaUecSheetIndexValues(); + setAtWorkDcUecSheetIndexValues(); + setAtWorkModeChoiceUecSheetIndexValues(); + + setAtWorkStopFreqUecSheetIndexValues(); + + createDcSizePurposeSegmentMap(); + + // mapModelSegmentsToDcSizeArraySegments(); + + } + + /* + * private void mapModelSegmentsToDcSizeArraySegments() { + * + * Logger logger = Logger.getLogger(this.getClass()); + * + * dcSizeDcModelPurposeMap = new HashMap(); + * dcModelDcSizePurposeMap = new HashMap(); + * + * // loop over soa model names and map top dc size array indices for (int i + * = 0; i < dcModelPurposeIndexMap.size(); i++) { String modelSegment = + * dcModelIndexPurposeMap.get(i); + * + * // look for this modelSegment name in the dc size array names map, with + * // and without "_segment". if + * (dcSizeArrayPurposeIndexMap.containsKey(modelSegment)) { + * dcSizeDcModelPurposeMap.put(modelSegment, modelSegment); + * dcModelDcSizePurposeMap.put(modelSegment, modelSegment); } else { int + * underscoreIndex = modelSegment.indexOf('_'); if (underscoreIndex < 0) { + * if (dcSizeArrayPurposeIndexMap.containsKey(modelSegment + "_" + + * modelSegment)) { dcSizeDcModelPurposeMap .put(modelSegment + "_" + + * modelSegment, modelSegment); dcModelDcSizePurposeMap .put(modelSegment, + * modelSegment + "_" + modelSegment); } else { logger .error(String + * .format( + * "could not establish correspondence between DC SOA model purpose string = %s" + * , modelSegment)); + * logger.error(String.format("and a DC array purpose string:")); int j = 0; + * for (String key : dcSizeArrayPurposeIndexMap.keySet()) + * logger.error(String.format("%-2d: %s", ++j, key)); throw new + * RuntimeException(); } } else { // all at-work size segments should map to + * one model segment if (modelSegment.substring(0, + * underscoreIndex).equalsIgnoreCase( AT_WORK_PURPOSE_NAME)) { + * dcSizeDcModelPurposeMap.put(AT_WORK_PURPOSE_NAME + "_" + + * AT_WORK_PURPOSE_NAME, modelSegment); + * dcModelDcSizePurposeMap.put(modelSegment, AT_WORK_PURPOSE_NAME + "_" + + * AT_WORK_PURPOSE_NAME); } else { logger .error(String .format( + * "could not establish correspondence between DC SOA model purpose string = %s" + * , modelSegment)); + * logger.error(String.format("and a DC array purpose string:")); int j = 0; + * for (String key : dcSizeArrayPurposeIndexMap.keySet()) + * logger.error(String.format("%-2d: %s", ++j, key)); throw new + * RuntimeException(); } } } + * + * } + * + * } + */ + + public String getSchoolPurpose(int age) + { + if (age < MIN_DRIVING_AGE) return (schoolPurposeName + "_" + SCHOOL_PURPOSE_SEGMENT_NAMES[0]) + .toLowerCase(); + else return (schoolPurposeName + "_" + SCHOOL_PURPOSE_SEGMENT_NAMES[1]).toLowerCase(); + } + + public String getSchoolPurpose() + { + return schoolPurposeName.toLowerCase(); + } + + public String getUniversityPurpose() + { + return universityPurposeName.toLowerCase(); + } + + public String getWorkPurpose(int incomeCategory) + { + return getWorkPurpose(false, incomeCategory); + } + + public String getWorkPurpose(boolean isPtWorker, int incomeCategory) + { + if (isPtWorker) return (workPurposeName + "_" + WORK_PURPOSE_SEGMENT_NAMES[WORK_PURPOSE_SEGMENT_NAMES.length - 1]) + .toLowerCase(); + else return (workPurposeName + "_" + WORK_PURPOSE_SEGMENT_NAMES[incomeCategory - 1]) + .toLowerCase(); + } + + public boolean getTripModeIsSovOrHov(int tripMode) + { + + for (int i = 0; i < TRIP_SOV_ALTS.length; i++) + { + if (TRIP_SOV_ALTS[i] == tripMode) return true; + } + + for (int i = 0; i < TRIP_HOV_ALTS.length; i++) + { + if (TRIP_HOV_ALTS[i] == tripMode) return true; + } + + return false; + } + + public boolean getTourModeIsSov(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < SOV_ALTS.length; i++) + { + if (SOV_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsHov(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < HOV_ALTS.length; i++) + { + if (HOV_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsS2(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < HOV2_ALTS.length; i++) + { + if (HOV2_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsS3(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < HOV3_ALTS.length; i++) + { + if (HOV3_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsSovOrHov(int tourMode) + { + for (int i = 0; i < SOV_ALTS.length; i++) + { + if (SOV_ALTS[i] == tourMode) return true; + } + + for (int i = 0; i < HOV_ALTS.length; i++) + { + if (HOV_ALTS[i] == tourMode) return true; + } + + // if (tourMode == TAXI) return true; + + return false; + } + + public boolean getTourModeIsNonMotorized(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < NON_MOTORIZED_ALTS.length; i++) + { + if (NON_MOTORIZED_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsBike(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < BIKE_ALTS.length; i++) + { + if (BIKE_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsWalk(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < WALK_ALTS.length; i++) + { + if (WALK_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + + public boolean getTourModeIsTransit(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < TRANSIT_ALTS.length; i++) + { + if (TRANSIT_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsWalkTransit(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < WALK_TRANSIT_ALTS.length; ++i) + { + if (WALK_TRANSIT_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsDriveTransit(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < DRIVE_TRANSIT_ALTS.length; i++) + { + if (DRIVE_TRANSIT_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsPnr(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < PNR_ALTS.length; i++) + { + if (PNR_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsKnr(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < KNR_ALTS.length; i++) + { + if (KNR_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTourModeIsTncTransit(int tourMode) + { + if (TNC_TRANSIT_ALT == tourMode) + return true; + else + return false; + } + + public boolean getTourModeIsMaas(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < MAAS_ALTS.length; i++) + { + if (MAAS_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + public boolean getTourModeIsSchoolBus(int tourMode) + { + boolean returnValue = false; + for (int i = 0; i < SCHOOL_BUS_ALTS.length; i++) + { + if (SCHOOL_BUS_ALTS[i] == tourMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public static boolean getTripModeIsPay(int tripMode) + { + boolean returnValue = false; + /* for (int i = 0; i < PAY_ALTS.length; i++) + { + if (PAY_ALTS[i] == tripMode) + { + returnValue = true; + break; + } + } +*/ + return returnValue; + } + + public boolean getTripModeIsTransit(int tripMode){ + + boolean returnValue = false; + for( int i = 0; i < TRANSIT_ALTS.length;++i ) + if(tripMode==TRANSIT_ALTS[i]){ + returnValue = true; + break; + } + + return returnValue; + } + + /** + * Get the name of the mode + * + * @param mode + * The mode index + * @return The name of the mode + */ + public String getModeName(int mode) + { + + return modeName[mode - 1]; + + } + + private int createPurposeIndexMaps(String purposeName, String[] segmentNames, int index, + String categoryString) + { + + HashMap segmentMap = new HashMap(); + String key = ""; + if (segmentNames.length > 0) + { + for (int i = 0; i < segmentNames.length; i++) + { + segmentMap.put(segmentNames[i].toLowerCase(), i); + key = purposeName.toLowerCase() + "_" + segmentNames[i].toLowerCase(); + dcSizeIndexSegmentMap.put(index, key); + dcSizeSegmentIndexMap.put(key, index++); + } + } else + { + segmentMap.put(purposeName.toLowerCase(), 0); + key = purposeName.toLowerCase() + "_" + purposeName.toLowerCase(); + dcSizeIndexSegmentMap.put(index, key); + dcSizeSegmentIndexMap.put(key, index++); + } + dcSizePurposeSegmentMap.put(purposeName.toLowerCase(), segmentMap); + + return index; + + } + + /** + * This method defines the segmentation for which destination choice size + * variables are calculated. + */ + private void createDcSizePurposeSegmentMap() + { + + int index = 0; + + // put work purpose segments, by which DC Size calculations are + // segmented, + // into a map to be stored by purpose name. + index = createPurposeIndexMaps(WORK_PURPOSE_NAME, WORK_PURPOSE_SEGMENT_NAMES, index, + MANDATORY_CATEGORY); + + // put university purpose segments, by which DC Size calculations are + // segmented, into a map to be stored by purpose name. + index = createPurposeIndexMaps(UNIVERSITY_PURPOSE_NAME, UNIVERSITY_PURPOSE_SEGMENT_NAMES, + index, MANDATORY_CATEGORY); + + // put school purpose segments, by which DC Size calculations are + // segmented, + // into a map to be stored by purpose name. + index = createPurposeIndexMaps(SCHOOL_PURPOSE_NAME, SCHOOL_PURPOSE_SEGMENT_NAMES, index, + MANDATORY_CATEGORY); + + // put escort purpose segments, by which DC Size calculations are + // segmented, + // into a map to be stored by purpose name. + index = createPurposeIndexMaps(ESCORT_PURPOSE_NAME, ESCORT_PURPOSE_SEGMENT_NAMES, index, + INDIVIDUAL_NON_MANDATORY_CATEGORY); + + // put shopping purpose segments, by which DC Size calculations are + // segmented, into a map to be stored by purpose name. + index = createPurposeIndexMaps(SHOPPING_PURPOSE_NAME, SHOPPING_PURPOSE_SEGMENT_NAMES, + index, INDIVIDUAL_NON_MANDATORY_CATEGORY); + + // put eat out purpose segments, by which DC Size calculations are + // segmented, + // into a map to be stored by purpose name. + index = createPurposeIndexMaps(EAT_OUT_PURPOSE_NAME, EAT_OUT_PURPOSE_SEGMENT_NAMES, index, + INDIVIDUAL_NON_MANDATORY_CATEGORY); + + // put oth main purpose segments, by which DC Size calculations are + // segmented, into a map to be stored by purpose name. + index = createPurposeIndexMaps(OTH_MAINT_PURPOSE_NAME, OTH_MAINT_PURPOSE_SEGMENT_NAMES, + index, INDIVIDUAL_NON_MANDATORY_CATEGORY); + + // put social purpose segments, by which DC Size calculations are + // segmented, + // into a map to be stored by purpose name. + index = createPurposeIndexMaps(SOCIAL_PURPOSE_NAME, SOCIAL_PURPOSE_SEGMENT_NAMES, index, + INDIVIDUAL_NON_MANDATORY_CATEGORY); + + // put oth discr purpose segments, by which DC Size calculations are + // segmented, into a map to be stored by purpose name. + index = createPurposeIndexMaps(OTH_DISCR_PURPOSE_NAME, OTH_DISCR_PURPOSE_SEGMENT_NAMES, + index, INDIVIDUAL_NON_MANDATORY_CATEGORY); + + // put at work purpose segments, by which DC Size calculations are + // segmented, + // into a map to be stored by purpose name. + index = createPurposeIndexMaps(AT_WORK_PURPOSE_NAME, AT_WORK_DC_SIZE_SEGMENT_NAMES, index, + AT_WORK_CATEGORY); + + } + + public HashMap> getDcSizePurposeSegmentMap() + { + return dcSizePurposeSegmentMap; + } + + private void setMandatoryPurposeNameValues() + { + + int index = 0; + + WORK_PURPOSE_NAME = "work"; + UNIVERSITY_PURPOSE_NAME = "university"; + SCHOOL_PURPOSE_NAME = "school"; + + int numDcSizePurposeSegments = 0; + if (WORK_PURPOSE_SEGMENT_NAMES.length > 0) numDcSizePurposeSegments += WORK_PURPOSE_SEGMENT_NAMES.length; + else numDcSizePurposeSegments += 1; + if (UNIVERSITY_PURPOSE_SEGMENT_NAMES.length > 0) numDcSizePurposeSegments += UNIVERSITY_PURPOSE_SEGMENT_NAMES.length; + else numDcSizePurposeSegments += 1; + if (SCHOOL_PURPOSE_SEGMENT_NAMES.length > 0) numDcSizePurposeSegments += SCHOOL_PURPOSE_SEGMENT_NAMES.length; + else numDcSizePurposeSegments += 1; + + mandatoryDcModelPurposeNames = new String[numDcSizePurposeSegments]; + + workPurposeName = WORK_PURPOSE_NAME.toLowerCase(); + workPurposeSegmentNames = new String[WORK_PURPOSE_SEGMENT_NAMES.length]; + if (workPurposeSegmentNames.length > 0) + { + for (int i = 0; i < WORK_PURPOSE_SEGMENT_NAMES.length; i++) + { + workPurposeSegmentNames[i] = WORK_PURPOSE_SEGMENT_NAMES[i].toLowerCase(); + mandatoryDcModelPurposeNames[index] = workPurposeName + "_" + + workPurposeSegmentNames[i]; + dcModelPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + dcModelIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + + // a separate size term is calculated for each work + // purpose_segment + dcSizeArrayIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + dcSizeArrayPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + index++; + } + } else + { + mandatoryDcModelPurposeNames[index] = workPurposeName; + dcModelPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + dcModelIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + + // a separate size term is calculated for each work purpose_segment + String name = mandatoryDcModelPurposeNames[index] + "_" + + mandatoryDcModelPurposeNames[index]; + dcSizeArrayIndexPurposeMap.put(index, name); + dcSizeArrayPurposeIndexMap.put(name, index); + index++; + } + + universityPurposeName = UNIVERSITY_PURPOSE_NAME.toLowerCase(); + universityPurposeSegmentNames = new String[UNIVERSITY_PURPOSE_SEGMENT_NAMES.length]; + if (universityPurposeSegmentNames.length > 0) + { + for (int i = 0; i < universityPurposeSegmentNames.length; i++) + { + universityPurposeSegmentNames[i] = UNIVERSITY_PURPOSE_SEGMENT_NAMES[i] + .toLowerCase(); + mandatoryDcModelPurposeNames[index] = universityPurposeName + "_" + + universityPurposeSegmentNames[i]; + dcModelPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + dcModelIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + + // a separate size term is calculated for each university + // purpose_segment + dcSizeArrayIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + dcSizeArrayPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + index++; + } + } else + { + mandatoryDcModelPurposeNames[index] = universityPurposeName; + dcModelPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + dcModelIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + + // a separate size term is calculated for each university + // purpose_segment + String name = mandatoryDcModelPurposeNames[index] + "_" + + mandatoryDcModelPurposeNames[index]; + dcSizeArrayIndexPurposeMap.put(index, name); + dcSizeArrayPurposeIndexMap.put(name, index); + index++; + } + + schoolPurposeName = SCHOOL_PURPOSE_NAME.toLowerCase(); + schoolPurposeSegmentNames = new String[SCHOOL_PURPOSE_SEGMENT_NAMES.length]; + if (schoolPurposeSegmentNames.length > 0) + { + for (int i = 0; i < schoolPurposeSegmentNames.length; i++) + { + schoolPurposeSegmentNames[i] = SCHOOL_PURPOSE_SEGMENT_NAMES[i].toLowerCase(); + mandatoryDcModelPurposeNames[index] = schoolPurposeName + "_" + + schoolPurposeSegmentNames[i]; + dcModelPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + dcModelIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + + // a separate size term is calculated for each school + // purpose_segment + dcSizeArrayIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + dcSizeArrayPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + index++; + } + } else + { + mandatoryDcModelPurposeNames[index] = schoolPurposeName; + dcModelPurposeIndexMap.put(mandatoryDcModelPurposeNames[index], index); + dcModelIndexPurposeMap.put(index, mandatoryDcModelPurposeNames[index]); + + // a separate size term is calculated for each school + // purpose_segment + String name = mandatoryDcModelPurposeNames[index] + "_" + + mandatoryDcModelPurposeNames[index]; + dcSizeArrayIndexPurposeMap.put(index, name); + dcSizeArrayPurposeIndexMap.put(name, index); + } + + } + + private void setUsualWorkAndSchoolLocationSoaUecSheetIndexValues() + { + dcSoaUecIndexMap.put("work_low", USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_LO); + dcSoaUecIndexMap.put("work_med", USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_MD); + dcSoaUecIndexMap.put("work_high", USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_HI); + dcSoaUecIndexMap.put("work_very high", + USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_VHI); + dcSoaUecIndexMap + .put("work_part time", USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_WORK_PT); + dcSoaUecIndexMap.put("university", + USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_UNIVERSITY_UNIVERSITY); + dcSoaUecIndexMap.put("school_predrive", + USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_SCHOOL_UNDER_SIXTEEN); + dcSoaUecIndexMap.put("school_drive", + USUAL_WORK_AND_SCHOOL_LOCATION_SOA_UEC_INDEX_SCHOOL_SIXTEEN_PLUS); + } + + private void setUsualWorkAndSchoolLocationUecSheetIndexValues() + { + dcUecIndexMap.put("work_low", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_WORK); + dcUecIndexMap.put("work_med", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_WORK); + dcUecIndexMap.put("work_high", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_WORK); + dcUecIndexMap.put("work_very high", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_WORK); + dcUecIndexMap.put("work_part time", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_WORK); + dcUecIndexMap.put("university", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_UNIVERSITY); + dcUecIndexMap.put("school_predrive", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_SCHOOL); + dcUecIndexMap.put("school_drive", USUAL_WORK_AND_SCHOOL_LOCATION_UEC_INDEX_SCHOOL); + } + + private void setUsualWorkAndSchoolLocationModeChoiceUecSheetIndexValues() + { + tourModeChoiceUecIndexMap.put("work_low", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_WORK); + tourModeChoiceUecIndexMap.put("work_med", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_WORK); + tourModeChoiceUecIndexMap.put("work_high", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_WORK); + tourModeChoiceUecIndexMap.put("work_very high", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_WORK); + tourModeChoiceUecIndexMap.put("work_part time", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_WORK); + tourModeChoiceUecIndexMap.put("university", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_UNIVERSITY); + tourModeChoiceUecIndexMap.put("school_predrive", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_SCHOOL); + tourModeChoiceUecIndexMap.put("school_drive", + USUAL_WORK_AND_SCHOOL_LOCATION_MODE_CHOICE_UEC_INDEX_SCHOOL); + } + + private void setMandatoryStopFreqUecSheetIndexValues() + { + stopFreqUecIndexMap.put("work_low", MANDATORY_STOP_FREQ_UEC_INDEX_WORK); + stopFreqUecIndexMap.put("work_med", MANDATORY_STOP_FREQ_UEC_INDEX_WORK); + stopFreqUecIndexMap.put("work_high", MANDATORY_STOP_FREQ_UEC_INDEX_WORK); + stopFreqUecIndexMap.put("work_very high", MANDATORY_STOP_FREQ_UEC_INDEX_WORK); + stopFreqUecIndexMap.put("work_part time", MANDATORY_STOP_FREQ_UEC_INDEX_WORK); + stopFreqUecIndexMap.put("university", MANDATORY_STOP_FREQ_UEC_INDEX_UNIVERSITY); + stopFreqUecIndexMap.put("school_predrive", MANDATORY_STOP_FREQ_UEC_INDEX_SCHOOL); + stopFreqUecIndexMap.put("school_drive", MANDATORY_STOP_FREQ_UEC_INDEX_SCHOOL); + } + + private void setMandatoryStopLocUecSheetIndexValues() + { + stopLocUecIndexMap.put(WORK_PURPOSE_NAME, MANDATORY_STOP_LOC_UEC_INDEX_WORK); + stopLocUecIndexMap.put(UNIVERSITY_PURPOSE_NAME, MANDATORY_STOP_LOC_UEC_INDEX_WORK); + stopLocUecIndexMap.put(SCHOOL_PURPOSE_NAME, MANDATORY_STOP_LOC_UEC_INDEX_WORK); + } + + private void setMandatoryTripModeChoiceUecSheetIndexValues() + { + tripModeChoiceUecIndexMap.put(WORK_PURPOSE_NAME, MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX_WORK); + tripModeChoiceUecIndexMap.put(UNIVERSITY_PURPOSE_NAME, + MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX_UNIVERSITY); + tripModeChoiceUecIndexMap.put(SCHOOL_PURPOSE_NAME, + MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX_SCHOOL); + } + + private void setNonMandatoryPurposeNameValues() + { + + ESCORT_PURPOSE_NAME = "escort"; + SHOPPING_PURPOSE_NAME = "shopping"; + EAT_OUT_PURPOSE_NAME = "eatout"; + OTH_MAINT_PURPOSE_NAME = "othmaint"; + SOCIAL_PURPOSE_NAME = "visit"; + OTH_DISCR_PURPOSE_NAME = "othdiscr"; + + // initialize index to the length of the mandatory names list already + // developed. + int index = dcSizeArrayPurposeIndexMap.size(); + + ESCORT_SEGMENT_NAMES = ESCORT_PURPOSE_SEGMENT_NAMES; + + // ESCORT is the only non-mandatory purpose with segments + ArrayList purposeNamesList = new ArrayList(); + for (int i = 0; i < NON_MANDATORY_DC_PURPOSE_NAMES.length; i++) + { + if (NON_MANDATORY_DC_PURPOSE_NAMES[i].equalsIgnoreCase(ESCORT_PURPOSE_NAME)) + { + for (int j = 0; j < ESCORT_SEGMENT_NAMES.length; j++) + { + String name = (ESCORT_PURPOSE_NAME + "_" + ESCORT_SEGMENT_NAMES[j]) + .toLowerCase(); + purposeNamesList.add(name); + dcModelPurposeIndexMap.put(name, index); + dcModelIndexPurposeMap.put(index, name); + + // a separate size term is calculated for each non-mandatory + // purpose_segment + dcSizeArrayIndexPurposeMap.put(index, name); + dcSizeArrayPurposeIndexMap.put(name, index); + index++; + } + } else + { + String name = NON_MANDATORY_DC_PURPOSE_NAMES[i].toLowerCase(); + purposeNamesList.add(name); + dcModelPurposeIndexMap.put(name, index); + dcModelIndexPurposeMap.put(index, name); + + // a separate size term is calculated for each non-mandatory + // purpose_segment + dcSizeArrayIndexPurposeMap.put(index, name + "_" + name); + dcSizeArrayPurposeIndexMap.put(name + "_" + name, index); + index++; + } + } + + int escortOffset = ESCORT_SEGMENT_NAMES.length; + + jointDcModelPurposeNames = new String[purposeNamesList.size() - escortOffset]; + nonMandatoryDcModelPurposeNames = new String[purposeNamesList.size()]; + for (int i = 0; i < purposeNamesList.size(); i++) + { + nonMandatoryDcModelPurposeNames[i] = purposeNamesList.get(i); + if (i > escortOffset - 1) + jointDcModelPurposeNames[i - escortOffset] = purposeNamesList.get(i); + } + + } + + /* + * private void setNonMandatoryDcSoaUecSheetIndexValues() { + * dcSoaUecIndexMap.put("escort_kids", + * NON_MANDATORY_SOA_UEC_INDEX_ESCORT_KIDS); + * dcSoaUecIndexMap.put("escort_no kids", + * NON_MANDATORY_SOA_UEC_INDEX_ESCORT_NO_KIDS); + * dcSoaUecIndexMap.put("shopping", NON_MANDATORY_SOA_UEC_INDEX_SHOPPING); + * dcSoaUecIndexMap.put("eatout", NON_MANDATORY_SOA_UEC_INDEX_EAT_OUT); + * dcSoaUecIndexMap.put("othmaint", + * NON_MANDATORY_SOA_UEC_INDEX_OTHER_MAINT); dcSoaUecIndexMap.put("social", + * NON_MANDATORY_SOA_UEC_INDEX_SOCIAL); dcSoaUecIndexMap.put("othdiscr", + * NON_MANDATORY_SOA_UEC_INDEX_OTHER_DISCR); } + * + * private void setNonMandatoryDcUecSheetIndexValues() { + * dcUecIndexMap.put("escort_kids", NON_MANDATORY_DC_UEC_INDEX_ESCORT_KIDS); + * dcUecIndexMap.put("escort_no kids", + * NON_MANDATORY_DC_UEC_INDEX_ESCORT_NO_KIDS); dcUecIndexMap.put("shopping", + * NON_MANDATORY_DC_UEC_INDEX_SHOPPING); dcUecIndexMap.put("eatout", + * NON_MANDATORY_DC_UEC_INDEX_EAT_OUT); dcUecIndexMap.put("othmaint", + * NON_MANDATORY_DC_UEC_INDEX_OTHER_MAINT); dcUecIndexMap.put("social", + * NON_MANDATORY_DC_UEC_INDEX_SOCIAL); dcUecIndexMap.put("othdiscr", + * NON_MANDATORY_DC_UEC_INDEX_OTHER_DISCR); } + * + * private void setNonMandatoryModeChoiceUecSheetIndexValues() { + * tourModeChoiceUecIndexMap.put("escort_kids", + * NON_MANDATORY_MC_UEC_INDEX_ESCORT_KIDS); + * tourModeChoiceUecIndexMap.put("escort_no kids", + * NON_MANDATORY_MC_UEC_INDEX_ESCORT_NO_KIDS); + * tourModeChoiceUecIndexMap.put("shopping", + * NON_MANDATORY_MC_UEC_INDEX_SHOPPING); + * tourModeChoiceUecIndexMap.put("eatout", + * NON_MANDATORY_MC_UEC_INDEX_EAT_OUT); + * tourModeChoiceUecIndexMap.put("othmaint", + * NON_MANDATORY_MC_UEC_INDEX_OTHER_MAINT); + * tourModeChoiceUecIndexMap.put("social", + * NON_MANDATORY_MC_UEC_INDEX_SOCIAL); + * tourModeChoiceUecIndexMap.put("othdiscr", + * NON_MANDATORY_MC_UEC_INDEX_OTHER_DISCR); } + * + * private void setNonMandatoryStopFreqUecSheetIndexValues() { + * stopFreqUecIndexMap.put("escort_kids", + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_ESCORT); + * stopFreqUecIndexMap.put("escort_no kids", + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_ESCORT); + * stopFreqUecIndexMap.put("shopping", + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_SHOPPING); + * stopFreqUecIndexMap.put("eatout", + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_EAT_OUT); + * stopFreqUecIndexMap.put("othmaint", + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_OTHER_MAINT); + * stopFreqUecIndexMap.put("social", + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_SOCIAL); + * stopFreqUecIndexMap.put("othdiscr", + * NON_MANDATORY_STOP_FREQ_UEC_INDEX_OTHER_DISCR); } + * + * private void setNonMandatoryStopLocUecSheetIndexValues() { + * stopLocUecIndexMap.put(ESCORT_PURPOSE_NAME, + * NON_MANDATORY_STOP_LOC_UEC_INDEX_ESCORT); + * stopLocUecIndexMap.put(SHOPPING_PURPOSE_NAME, + * NON_MANDATORY_STOP_LOC_UEC_INDEX_SHOPPING); + * stopLocUecIndexMap.put(EAT_OUT_PURPOSE_NAME, + * NON_MANDATORY_STOP_LOC_UEC_INDEX_EAT_OUT); stopLocUecIndexMap + * .put(OTH_MAINT_PURPOSE_NAME, + * NON_MANDATORY_STOP_LOC_UEC_INDEX_OTHER_MAINT); + * stopLocUecIndexMap.put(SOCIAL_PURPOSE_NAME, + * NON_MANDATORY_STOP_LOC_UEC_INDEX_SOCIAL); stopLocUecIndexMap + * .put(OTH_DISCR_PURPOSE_NAME, + * NON_MANDATORY_STOP_LOC_UEC_INDEX_OTHER_DISCR); } + * + * private void setNonMandatoryTripModeChoiceUecSheetIndexValues() { + * tripModeChoiceUecIndexMap .put(ESCORT_PURPOSE_NAME, + * NON_MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX); + * tripModeChoiceUecIndexMap.put(SHOPPING_PURPOSE_NAME, + * NON_MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX); + * tripModeChoiceUecIndexMap.put(EAT_OUT_PURPOSE_NAME, + * NON_MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX); + * tripModeChoiceUecIndexMap.put(OTH_MAINT_PURPOSE_NAME, + * NON_MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX); tripModeChoiceUecIndexMap + * .put(SOCIAL_PURPOSE_NAME, NON_MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX); + * tripModeChoiceUecIndexMap.put(OTH_DISCR_PURPOSE_NAME, + * NON_MANDATORY_TRIP_MODE_CHOICE_UEC_INDEX); } + */ + private void setAtWorkPurposeNameValues() + { + + AT_WORK_PURPOSE_NAME = "atwork"; + + AT_WORK_EAT_PURPOSE_NAME = "eat"; + AT_WORK_BUSINESS_PURPOSE_NAME = "business"; + AT_WORK_MAINT_PURPOSE_NAME = "other"; + + AT_WORK_PURPOSE_INDEX_EAT = SD_AT_WORK_PURPOSE_INDEX_EAT; + AT_WORK_PURPOSE_INDEX_BUSINESS = SD_AT_WORK_PURPOSE_INDEX_BUSINESS; + AT_WORK_PURPOSE_INDEX_MAINT = SD_AT_WORK_PURPOSE_INDEX_MAINT; + + AT_WORK_SEGMENT_NAMES = new String[3]; + AT_WORK_SEGMENT_NAMES[0] = AT_WORK_EAT_PURPOSE_NAME; + AT_WORK_SEGMENT_NAMES[1] = AT_WORK_BUSINESS_PURPOSE_NAME; + AT_WORK_SEGMENT_NAMES[2] = AT_WORK_MAINT_PURPOSE_NAME; + + // initialize index to the length of the home-based tour names list + // already + // developed. + int index = dcSizeArrayPurposeIndexMap.size(); + + // the same size term is used by each at-work soa model + dcSizeArrayIndexPurposeMap.put(index, AT_WORK_PURPOSE_NAME + "_" + AT_WORK_PURPOSE_NAME); + dcSizeArrayPurposeIndexMap.put(AT_WORK_PURPOSE_NAME + "_" + AT_WORK_PURPOSE_NAME, index); + + ArrayList purposeNamesList = new ArrayList(); + for (int j = 0; j < AT_WORK_SEGMENT_NAMES.length; j++) + { + String name = (AT_WORK_PURPOSE_NAME + "_" + AT_WORK_SEGMENT_NAMES[j]).toLowerCase(); + purposeNamesList.add(name); + dcModelPurposeIndexMap.put(name, index); + dcModelIndexPurposeMap.put(index, name); + index++; + } + + atWorkDcModelPurposeNames = new String[purposeNamesList.size()]; + for (int i = 0; i < purposeNamesList.size(); i++) + { + atWorkDcModelPurposeNames[i] = purposeNamesList.get(i); + } + + } + + private void setAtWorkDcSoaUecSheetIndexValues() + { + dcSoaUecIndexMap.put("atwork_eat", AT_WORK_SOA_UEC_INDEX_EAT); + dcSoaUecIndexMap.put("atwork_business", AT_WORK_SOA_UEC_INDEX_BUSINESS); + dcSoaUecIndexMap.put("atwork_other", AT_WORK_SOA_UEC_INDEX_MAINT); + } + + private void setAtWorkDcUecSheetIndexValues() + { + dcUecIndexMap.put("atwork_eat", AT_WORK_DC_UEC_INDEX_EAT); + dcUecIndexMap.put("atwork_business", AT_WORK_DC_UEC_INDEX_BUSINESS); + dcUecIndexMap.put("atwork_other", AT_WORK_DC_UEC_INDEX_MAINT); + } + + private void setAtWorkModeChoiceUecSheetIndexValues() + { + tourModeChoiceUecIndexMap.put("atwork_eat", AT_WORK_MC_UEC_INDEX_EAT); + tourModeChoiceUecIndexMap.put("atwork_business", AT_WORK_MC_UEC_INDEX_BUSINESS); + tourModeChoiceUecIndexMap.put("atwork_other", AT_WORK_MC_UEC_INDEX_MAINT); + } + + private void setAtWorkStopFreqUecSheetIndexValues() + { + stopFreqUecIndexMap.put("atwork_eat", AT_WORK_STOP_FREQ_UEC_INDEX_EAT); + stopFreqUecIndexMap.put("atwork_business", AT_WORK_STOP_FREQ_UEC_INDEX_BUSINESS); + stopFreqUecIndexMap.put("atwork_other", AT_WORK_STOP_FREQ_UEC_INDEX_MAINT); + } + + public double[][] getCdap6PlusProps() + { + return CDAP_6_PLUS_PROPORTIONS; + } + + public String getModelPeriodLabel(int period) + { + return MODEL_PERIOD_LABELS[period]; + } + + public int getNumberModelPeriods() + { + return MODEL_PERIOD_LABELS.length; + } + + public String getSkimMatrixPeriodString(int period) + { + int index = getSkimPeriodIndex(period); + return SKIM_PERIOD_STRINGS[index]; + } + + public int getDefaultAmPeriod() + { + return getTimePeriodIndexForTime(800); + } + + public int getDefaultPmPeriod() + { + return getTimePeriodIndexForTime(1700); + } + + public int getDefaultMdPeriod() + { + return getTimePeriodIndexForTime(1400); + } + + public int[] getSkimPeriodCombinationIndices() + { + return SKIM_PERIOD_COMBINATION_INDICES; + } + + public int getSkimPeriodCombinationIndex(int startPeriod, int endPeriod) + { + + int startPeriodIndex = getSkimPeriodIndex(startPeriod); + int endPeriodIndex = getSkimPeriodIndex(endPeriod); + + if (SKIM_PERIOD_COMBINATIONS[startPeriodIndex][endPeriodIndex] < 0) + { + String errorString = String + .format("startPeriod=%d, startPeriod=%d, endPeriod=%d, endPeriod=%d is invalid combination.", + startPeriod, startPeriodIndex, endPeriod, endPeriodIndex); + throw new RuntimeException(errorString); + } else + { + return SKIM_PERIOD_COMBINATIONS[startPeriodIndex][endPeriodIndex]; + } + + } + + public int getMaxTourModeIndex() + { + return MAXIMUM_TOUR_MODE_ALT_INDEX; + } + + public HashMap getWorkSegmentNameIndexMap() + { + return workSegmentNameIndexMap; + } + + public void setWorkSegmentNameIndexMap(HashMap argMap) + { + workSegmentNameIndexMap = argMap; + } + + public HashMap getSchoolSegmentNameIndexMap() + { + return schoolSegmentNameIndexMap; + } + + public void setSchoolSegmentNameIndexMap(HashMap argMap) + { + schoolSegmentNameIndexMap = argMap; + } + + public HashMap getWorkSegmentIndexNameMap() + { + return workSegmentIndexNameMap; + } + + public void setWorkSegmentIndexNameMap(HashMap argMap) + { + workSegmentIndexNameMap = argMap; + } + + public HashMap getSchoolSegmentIndexNameMap() + { + return schoolSegmentIndexNameMap; + } + + public void setSchoolSegmentIndexNameMap(HashMap argMap) + { + schoolSegmentIndexNameMap = argMap; + } + + public void setJtfAltLabels(String[] labels) + { + jtfAltLabels = labels; + } + + public String[] getJtfAltLabels() + { + return jtfAltLabels; + } + + public boolean getTripModeIsWalkTransit(int tripMode) + { + + for (int i = 0; i < WALK_TRANSIT_ALTS.length; i++) + { + if (WALK_TRANSIT_ALTS[i] == tripMode) return true; + } + + return false; + } + + public boolean getTripModeIsPnrTransit(int tripMode) + { + + for (int i = 0; i < PNR_ALTS.length; i++) + { + if (PNR_ALTS[i] == tripMode) return true; + } + + return false; + } + + public boolean getTripModeIsKnrTransit(int tripMode) + { + + for (int i = 0; i < KNR_ALTS.length; i++) + { + if (KNR_ALTS[i] == tripMode) return true; + } + + return false; + } + + public boolean getTripModeIsNonMotorized(int i) + { + + if (i == WALK || i == BIKE) return true; + else return false; + } + + public boolean getTripModeIsS2(int tripMode) + { + boolean returnValue = false; + for (int i = 0; i < HOV2_ALTS.length; i++) + { + if (HOV2_ALTS[i] == tripMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public boolean getTripModeIsS3(int tripMode) + { + boolean returnValue = false; + for (int i = 0; i < HOV3_ALTS.length; i++) + { + if (HOV3_ALTS[i] == tripMode) + { + returnValue = true; + break; + } + } + return returnValue; + } + + public int getMaxStopsPerDirection(){ + + return MAX_STOPS_PER_DIRECTION; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagParkingChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagParkingChoiceDMU.java new file mode 100644 index 0000000..99fb216 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagParkingChoiceDMU.java @@ -0,0 +1,94 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.ParkingChoiceDMU; + +public class SandagParkingChoiceDMU + extends ParkingChoiceDMU +{ + + public SandagParkingChoiceDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getParkMgraAlt", 1); + methodIndexMap.put("getDistanceTripOrigToParkAlt", 2); + methodIndexMap.put("getDistanceTripDestFromParkAlt", 3); + methodIndexMap.put("getDestSameAsParkAlt", 4); + methodIndexMap.put("getPersonType", 5); + methodIndexMap.put("getActivityIntervals", 6); + methodIndexMap.put("getTripDestPurpose", 7); + methodIndexMap.put("getLsWgtAvgCostM", 8); + methodIndexMap.put("getMstallsoth", 9); + methodIndexMap.put("getMstallssam", 10); + methodIndexMap.put("getMparkcost", 11); + methodIndexMap.put("getDstallsoth", 12); + methodIndexMap.put("getDstallssam", 13); + methodIndexMap.put("getDparkcost", 14); + methodIndexMap.put("getHstallsoth", 15); + methodIndexMap.put("getHstallssam", 16); + methodIndexMap.put("getHparkcost", 17); + methodIndexMap.put("getNumfreehrs", 18); + methodIndexMap.put("getReimbPct", 19); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + + case 1: + return getParkMgraAlt(arrayIndex); + case 2: + return getDistanceTripOrigToParkAlt(arrayIndex); + case 3: + return getDistanceTripDestFromParkAlt(arrayIndex); + case 4: + return getDestSameAsParkAlt(arrayIndex); + case 5: + return getPersonType(); + case 6: + return getActivityIntervals(); + case 7: + return getTripDestPurpose(); + case 8: + return getLsWgtAvgCostM(arrayIndex); + case 9: + return getMstallsoth(arrayIndex); + case 10: + return getMstallssam(arrayIndex); + case 11: + return getMparkcost(arrayIndex); + case 12: + return getDstallsoth(arrayIndex); + case 13: + return getDstallssam(arrayIndex); + case 14: + return getDparkcost(arrayIndex); + case 15: + return getHstallsoth(arrayIndex); + case 16: + return getHstallssam(arrayIndex); + case 17: + return getHparkcost(arrayIndex); + case 18: + return getNumfreehrs(arrayIndex); + case 19: + return getReimbPct(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagParkingProvisionChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagParkingProvisionChoiceDMU.java new file mode 100644 index 0000000..a3c242e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagParkingProvisionChoiceDMU.java @@ -0,0 +1,83 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.ParkingProvisionChoiceDMU; + +public class SandagParkingProvisionChoiceDMU + extends ParkingProvisionChoiceDMU +{ + + public SandagParkingProvisionChoiceDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getHhIncomeInDollars", 0); + methodIndexMap.put("getWorkLocMgra", 1); + methodIndexMap.put("getLsWgtAvgCostM", 2); + methodIndexMap.put("getLsWgtAvgCostD", 3); + methodIndexMap.put("getLsWgtAvgCostH", 4); + methodIndexMap.put("getMgraParkArea", 5); + methodIndexMap.put("getNumFreeHours", 6); + methodIndexMap.put("getMStallsOth", 7); + methodIndexMap.put("getMStallsSam", 8); + methodIndexMap.put("getMParkCost", 9); + methodIndexMap.put("getDStallsOth", 10); + methodIndexMap.put("getDStallsSam", 11); + methodIndexMap.put("getDParkCost", 12); + methodIndexMap.put("getHStallsOth", 13); + methodIndexMap.put("getHStallsSam", 14); + methodIndexMap.put("getHParkCost", 15); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getIncomeInDollars(); + case 1: + return getWorkLocMgra(); + case 2: + return getLsWgtAvgCostM(); + case 3: + return getLsWgtAvgCostD(); + case 4: + return getLsWgtAvgCostH(); + case 5: + return getMgraParkArea(); + case 6: + return getNumFreeHours(); + case 7: + return getMStallsOth(); + case 8: + return getMStallsSam(); + case 9: + return getMParkCost(); + case 10: + return getDStallsOth(); + case 11: + return getDStallsSam(); + case 12: + return getDParkCost(); + case 13: + return getHStallsOth(); + case 14: + return getHStallsSam(); + case 15: + return getHParkCost(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagSamplePopulationGenerator.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagSamplePopulationGenerator.java new file mode 100644 index 0000000..1d61c60 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagSamplePopulationGenerator.java @@ -0,0 +1,101 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import com.pb.common.util.ResourceUtil; + +public final class SandagSamplePopulationGenerator +{ + + private static Logger logger = Logger.getLogger(SandagSamplePopulationGenerator.class); + + public static final String PROPERTIES_PROJECT_DIRECTORY = "Project.Directory"; + private ResourceBundle rb; + + /** + * + * @param rb + * , java.util.ResourceBundle containing environment settings + * from a properties file specified on the command line + * @param baseName + * , String containing basename (without .properites) from which + * ResourceBundle was created. + * @param globalIterationNumber + * , int iteration number for which the model is run, set by + * another process controlling a model stream with feedback. + * @param iterationSampleRate + * , float percentage [0.0, 1.0] inicating the portion of all + * households to be modeled. + * + * This object defines the implementation of the ARC tour based, + * activity based travel demand model. + */ + private SandagSamplePopulationGenerator(ResourceBundle rb) + { + this.rb = rb; + } + + private void generateSampleFiles() + { + + // new a ctramp application object + HashMap propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + + // create a new local instance of the household array manager + SandagHouseholdDataManager householdDataManager = new SandagHouseholdDataManager(); + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population files + // and + // apply its tables to objects mapping method. + String inputHouseholdFileName = "data/inputs/hhfile.csv"; + String inputPersonFileName = "data/inputs/personfile.csv"; + householdDataManager.setHouseholdSampleRate(1.0f, 0); + + SandagModelStructure modelStructure = new SandagModelStructure(); + + householdDataManager.setModelStructure(modelStructure); + householdDataManager.readPopulationFiles(inputHouseholdFileName, inputPersonFileName); + householdDataManager.mapTablesToHouseholdObjects(); + + householdDataManager.createSamplePopulationFiles( + "/jim/projects/sandag/data/inputs/hhfile.csv", + "/jim/projects/sandag/data/inputs/personfile.csv", + "/jim/projects/sandag/data/inputs/hhfile_1000.csv", + "/jim/projects/sandag/data/inputs/personfile_1000.csv", 1000); + } + + public static void main(String[] args) + { + + ResourceBundle rb = null; + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + } + + // create an instance of this class for main() to use. + SandagSamplePopulationGenerator mainObject = new SandagSamplePopulationGenerator(rb); + + // run tour based models + try + { + mainObject.generateSampleFiles(); + } catch (RuntimeException e) + { + logger.error( + "RuntimeException caught in SandagSamplePopulationGenerator.main() -- exiting.", + e); + } + + System.exit(0); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagStopFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagStopFrequencyDMU.java new file mode 100644 index 0000000..e0c8a7c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagStopFrequencyDMU.java @@ -0,0 +1,255 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.StopFrequencyDMU; + +public class SandagStopFrequencyDMU + extends StopFrequencyDMU +{ + + // the SANDAG UEC worksheet numbers defined below are used to associate + // worksheet + // pages to CTRAMP purpose indices + private static final int WORK_MODEL_SHEET = 1; + private static final int UNIVERSITY_MODEL_SHEET = 2; + private static final int SCHOOL_MODEL_SHEET = 3; + private static final int ESCORT_MODEL_SHEET = 4; + private static final int SHOPPING_MODEL_SHEET = 5; + private static final int MAINT_MODEL_SHEET = 6; + private static final int EAT_OUT_MODEL_SHEET = 7; + private static final int VISITING_MODEL_SHEET = 8; + private static final int DISCR_MODEL_SHEET = 9; + private static final int WORK_BASED_MODEL_SHEET = 10; + + private HashMap tourPurposeModelSheetMap; + private HashMap tourPurposeChoiceModelIndexMap; + private int[] modelSheetValues; + + public SandagStopFrequencyDMU(ModelStructure modelStructure) + { + super(modelStructure); + setupModelIndexMappings(); + setupMethodIndexMap(); + + // set names used in SANDAG stop purpose file + STOP_PURPOSE_FILE_WORK_NAME = "Work"; + STOP_PURPOSE_FILE_UNIVERSITY_NAME = "University"; + STOP_PURPOSE_FILE_SCHOOL_NAME = "School"; + STOP_PURPOSE_FILE_ESCORT_NAME = "Escort"; + STOP_PURPOSE_FILE_SHOPPING_NAME = "Shop"; + STOP_PURPOSE_FILE_MAINT_NAME = "Maintenance"; + STOP_PURPOSE_FILE_EAT_OUT_NAME = "Eating Out"; + STOP_PURPOSE_FILE_VISIT_NAME = "Visiting"; + STOP_PURPOSE_FILE_DISCR_NAME = "Discretionary"; + STOP_PURPOSE_FILE_WORK_BASED_NAME = "Work-Based"; + } + + private void setupModelIndexMappings() + { + + // setup the mapping from tour primary purpose indices to the worksheet + // page + // indices + tourPurposeModelSheetMap = new HashMap(); + tourPurposeModelSheetMap.put(ModelStructure.WORK_PRIMARY_PURPOSE_INDEX, WORK_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX, + UNIVERSITY_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX, + SCHOOL_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.ESCORT_PRIMARY_PURPOSE_INDEX, + ESCORT_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.SHOPPING_PRIMARY_PURPOSE_INDEX, + SHOPPING_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_INDEX, + MAINT_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.EAT_OUT_PRIMARY_PURPOSE_INDEX, + EAT_OUT_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.VISITING_PRIMARY_PURPOSE_INDEX, + VISITING_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_INDEX, + DISCR_MODEL_SHEET); + tourPurposeModelSheetMap.put(ModelStructure.WORK_BASED_PRIMARY_PURPOSE_INDEX, + WORK_BASED_MODEL_SHEET); + + // setup a mapping between primary tour purpose indices and + // ChoiceModelApplication array indices + // so that only as many ChoiceModelApplication objects are created in + // the + // Stop Frequency model implementation + // as there are worksheet model pages. + tourPurposeChoiceModelIndexMap = new HashMap(); + + int modelIndex = 0; + HashMap modelSheetIndexMap = new HashMap(); + for (int modelPurposeKey : tourPurposeModelSheetMap.keySet()) + { + + // get the sheet number associated with the tour purpose + int modelSheetKey = tourPurposeModelSheetMap.get(modelPurposeKey); + + // if the sheet number already exists in the sheet index to choice + // model + // index mapping, get that index + // and use it for the purpose to model index mapping + if (modelSheetIndexMap.containsKey(modelSheetKey)) + { + int index = modelSheetIndexMap.get(WORK_MODEL_SHEET); + tourPurposeChoiceModelIndexMap.put(modelPurposeKey, index); + } else + { + // otherwise add this sheet number to the model index mapping + // and use + // it + // for the purpose to model index mapping. + modelSheetIndexMap.put(modelSheetKey, modelIndex); + tourPurposeChoiceModelIndexMap.put(modelPurposeKey, modelIndex); + modelIndex++; + } + } + + modelSheetValues = new int[modelIndex]; + int i = 0; + for (int sheet : modelSheetIndexMap.keySet()) + modelSheetValues[i++] = sheet; + + } + + /** + * @return the array of unique worksheet model sheet values for whic a + * ChoiceModelApplication object will be created. The size of this + * array determines the number of ChoiceModelApplication objects. + */ + public int[] getModelSheetValuesArray() + { + return modelSheetValues; + } + + /** + * @return the HashMap that relates primary tour purpose + * indices to ChoiceModelApplication array indices. + */ + public HashMap getTourPurposeChoiceModelIndexMap() + { + return tourPurposeChoiceModelIndexMap; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getNumFtWorkers", 0); + methodIndexMap.put("getNumPtWorkers", 1); + methodIndexMap.put("getIncomeInDollars", 2); + methodIndexMap.put("getPersonType", 3); + methodIndexMap.put("getHhSize", 4); + methodIndexMap.put("getNumHhDrivingStudents", 5); + methodIndexMap.put("getNumHhNonDrivingStudents", 6); + methodIndexMap.put("getNumHhPreschool", 7); + methodIndexMap.put("getWorkTours", 8); + methodIndexMap.put("getTotalTours", 9); + methodIndexMap.put("getTotalHouseholdTours", 10); + methodIndexMap.put("getWorkLocationDistance", 11); + methodIndexMap.put("getSchoolLocationDistance", 12); + methodIndexMap.put("getAge", 13); + methodIndexMap.put("getSchoolTours", 14); + methodIndexMap.put("getEscortTours", 15); + methodIndexMap.put("getShoppingTours", 16); + methodIndexMap.put("getMaintenanceTours", 17); + methodIndexMap.put("getEatTours", 18); + methodIndexMap.put("getVisitTours", 19); + methodIndexMap.put("getDiscretionaryTours", 20); + methodIndexMap.put("getShoppingAccessibility", 21); + methodIndexMap.put("getMaintenanceAccessibility", 22); + methodIndexMap.put("getDiscretionaryAccessibility", 23); + methodIndexMap.put("getIsJoint", 24); + methodIndexMap.put("getTourDurationHours", 25); + methodIndexMap.put("getTourModeIsAuto", 26); + methodIndexMap.put("getTourModeIsTransit", 27); + methodIndexMap.put("getTourModeIsNonMotorized", 28); + methodIndexMap.put("getTourModeIsSchoolBus", 29); + methodIndexMap.put("getTourDepartPeriod", 30); + methodIndexMap.put("getTourArrivePeriod", 31); + methodIndexMap.put("getTelecommuteFrequency", 32); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getNumFtWorkers(); + case 1: + return getNumPtWorkers(); + case 2: + return getIncomeInDollars(); + case 3: + return getPersonType(); + case 4: + return getHhSize(); + case 5: + return getNumHhDrivingStudents(); + case 6: + return getNumHhNonDrivingStudents(); + case 7: + return getNumHhPreschool(); + case 8: + return getWorkTours(); + case 9: + return getTotalTours(); + case 10: + return getTotalHouseholdTours(); + case 11: + return getWorkLocationDistance(); + case 12: + return getSchoolLocationDistance(); + case 13: + return getAge(); + case 14: + return getSchoolTours(); + case 15: + return getEscortTours(); + case 16: + return getShoppingTours(); + case 17: + return getMaintenanceTours(); + case 18: + return getEatTours(); + case 19: + return getVisitTours(); + case 20: + return getDiscretionaryTours(); + case 21: + return getShoppingAccessibility(); + case 22: + return getMaintenanceAccessibility(); + case 23: + return getDiscretionaryAccessibility(); + case 24: + return getTourIsJoint(); + case 25: + return getTourDurationInHours(); + case 26: + return getTourModeIsAuto(); + case 27: + return getTourModeIsTransit(); + case 28: + return getTourModeIsNonMotorized(); + case 29: + return getTourModeIsSchoolBus(); + case 30: + return getTourDepartPeriod(); + case 31: + return getTourArrivePeriod(); + case 32: + return getTelecommuteFrequency(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagStopLocationDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagStopLocationDMU.java new file mode 100644 index 0000000..40f1885 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagStopLocationDMU.java @@ -0,0 +1,132 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import java.util.Map; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.BikeLogsum; +import org.sandag.abm.ctramp.BikeLogsumSegment; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Stop; +import org.sandag.abm.ctramp.StopLocationDMU; +import org.sandag.abm.ctramp.Tour; + +public class SandagStopLocationDMU + extends StopLocationDMU +{ + public SandagStopLocationDMU(ModelStructure modelStructure, Map rbMap) + { + super(modelStructure); + setupMethodIndexMap(); + } + + public void setStopObject(Stop myStop) + { + super.setStopObject(myStop); + } + + + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getSlcSoaCorrectionsAlt", 0); + methodIndexMap.put("getOrigToMgraDistanceAlt", 1); + methodIndexMap.put("getMgraToDestDistanceAlt", 2); + methodIndexMap.put("getOdDistance", 3); + methodIndexMap.put("getTourModeIsWalk", 4); + methodIndexMap.put("getTourModeIsBike", 5); + methodIndexMap.put("getTourModeIsWalkTransit", 6); + methodIndexMap.put("getWalkTransitAvailableAlt", 7); + methodIndexMap.put("getLnSlcSizeAlt", 8); + methodIndexMap.put("getStopPurpose", 9); + methodIndexMap.put("getTourPurpose", 10); + methodIndexMap.put("getTourMode", 11); + methodIndexMap.put("getStopNumber", 12); + methodIndexMap.put("getStopsOnHalfTour", 13); + methodIndexMap.put("getInboundStop", 14); + methodIndexMap.put("getTourIsJoint", 15); + methodIndexMap.put("getFemale", 16); + methodIndexMap.put("getAge", 17); + methodIndexMap.put("getTourOrigToMgraDistanceAlt", 18); + methodIndexMap.put("getMgraToTourDestDistanceAlt", 19); + methodIndexMap.put("getMcLogsumAlt", 20); + methodIndexMap.put("getSampleMgraAlt", 21); + methodIndexMap.put("getLnSlcSizeSampleAlt", 22); + methodIndexMap.put("getIncome", 23); + methodIndexMap.put("getOrigToMgraBikeLogsumAlt", 24); + methodIndexMap.put("getMgraToDestBikeLogsumAlt", 25); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getSlcSoaCorrectionsAlt(arrayIndex); + case 1: + return getOrigToMgraDistanceAlt(arrayIndex); + case 2: + return getMgraToDestDistanceAlt(arrayIndex); + case 3: + return getOdDistance(); + case 4: + return getTourModeIsWalk(); + case 5: + return getTourModeIsBike(); + case 6: + return getTourModeIsWalkTransit(); + case 7: + return getWalkTransitAvailableAlt(arrayIndex); + case 8: + return getLnSlcSizeAlt(arrayIndex); + case 9: + return getStopPurpose(); + case 10: + return getTourPurpose(); + case 11: + return getTourMode(); + case 12: + return getStopNumber(); + case 13: + return getStopsOnHalfTour(); + case 14: + return getInboundStop(); + case 15: + return getTourIsJoint(); + case 16: + return getFemale(); + case 17: + return getAge(); + case 18: + return getTourOrigToMgraDistanceAlt(arrayIndex); + case 19: + return getMgraToTourDestDistanceAlt(arrayIndex); + case 20: + return getMcLogsumAlt(arrayIndex); + case 21: + return getSampleMgraAlt(arrayIndex); + case 22: + return getLnSlcSizeSampleAlt(arrayIndex); + case 23: + return getIncomeInDollars(); + case 24: + return getOrigToMgraBikeLogsumAlt(arrayIndex); + case 25: + return getMgraToDestBikeLogsumAlt(arrayIndex); + + default: + Logger logger = Logger.getLogger(StopLocationDMU.class); + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagSummitFile.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagSummitFile.java new file mode 100644 index 0000000..dfa63ff --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagSummitFile.java @@ -0,0 +1,820 @@ +package org.sandag.abm.application; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import java.util.ResourceBundle; +import java.util.StringTokenizer; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.summit.ConcreteSummitRecord; +import com.pb.common.summit.SummitHeader; +import com.pb.common.summit.SummitRecordTable; +import com.pb.common.util.ResourceUtil; + +public class SandagSummitFile +{ + + private static Logger logger = Logger.getLogger(SandagSummitFile.class); + + private HashMap personsOver18; + private HashMap autosOwned; + + // Summit record table (one per file) + private SummitRecordTable summitRecordTable; + + private TableDataSet tourData; + + // Some parameters + private int modes; + private int upperEA; // Upper + // limit + // on + // time + // of + // day + // for + // the + // Early + // morning + // time + // period + private int upperAM; // Upper + // limit + // on + // time + // of + // day + // for + // the + // AM + // peak + // time + // period + private int upperMD; // Upper + // limit + // on + // time + // of + // day + // for + // the + // Midday + // time + // period + private int upperPM; // Upper + // limit + // on + // time + // of + // day + // for + // the + // PM + // time + // peak + // period + private int[] walkTransitModes; + private int[] driveTransitModes; + + // an array of file numbers, one per purpose + private int[] fileNumber; + private int numberOfFiles; + + private static final String[] PURPOSE_NAME = {"Work", "University", "School", "Escort", + "Shop", "Maintenance", "EatingOut", "Visiting", "Discretionary", "WorkBased"}; + private float[] ivtCoeff; + private String[] fileName; + + ResourceBundle rb; + MgraDataManager mdm; + TazDataManager tdm; + + public SandagSummitFile(String resourceFile) + { + + rb = ResourceUtil.getPropertyBundle(new File(resourceFile)); + mdm = MgraDataManager.getInstance(ResourceUtil.changeResourceBundleIntoHashMap(rb)); + tdm = TazDataManager.getInstance(ResourceUtil.changeResourceBundleIntoHashMap(rb)); + + // Time period limits + upperEA = Integer.valueOf(rb.getString("summit.upperEA")); + upperAM = Integer.valueOf(rb.getString("summit.upperAM")); + upperMD = Integer.valueOf(rb.getString("summit.upperMD")); + upperPM = Integer.valueOf(rb.getString("summit.upperPM")); + + // Find what file to store each purpose in + numberOfFiles = 0; + fileNumber = new int[PURPOSE_NAME.length]; + for (int i = 0; i < PURPOSE_NAME.length; ++i) + { + String fileString = "summit.purpose." + PURPOSE_NAME[i]; + fileNumber[i] = Integer.valueOf(rb.getString(fileString)) - 1; + numberOfFiles = Math.max(fileNumber[i] + 1, numberOfFiles); + } + + // Get the name of each file + fileName = new String[numberOfFiles]; + for (int i = 0; i < numberOfFiles; ++i) + { + String nameString = "summit.filename." + (i + 1); + fileName[i] = rb.getString(nameString); + } + + // Get the ivt coefficients for each file + ivtCoeff = new float[numberOfFiles]; + for (int i = 0; i < numberOfFiles; ++i) + { + String ivtString = "summit.ivt.file." + (i + 1); + ivtCoeff[i] = Float.valueOf(rb.getString(ivtString)); + } + + // set the arrays + modes = Integer.valueOf(rb.getString("summit.modes")); + walkTransitModes = new int[modes]; + driveTransitModes = new int[modes]; + + String modeArray = rb.getString("summit.mode.array").replace(" ", ""); + StringTokenizer inToken = new StringTokenizer(modeArray, ","); + int mode = 0; + while (inToken.hasMoreElements()) + { + int modeValue = Integer.valueOf(inToken.nextToken()); + logger.info("Mode " + mode + " value " + modeValue); + if (modeValue == 1) walkTransitModes[mode] = 1; + else if (modeValue == 2) driveTransitModes[mode] = 1; + + ++mode; + } + + } + + /** + * Create Summit files for all purposes and both individual and joint tour + * files. + * + */ + public void createSummitFiles() + { + + // Read the household file + String directory = rb.getString("Project.Directory"); + String hhFile = rb.getString("Results.HouseholdDataFile"); + readHouseholdFile(directory + hhFile); + + // Read the person file + String perFile = rb.getString("Results.PersonDataFile"); + readPersonFile(directory + perFile); + + // Open the individual tour file and start processing + String tourFile = rb.getString("Results.IndivTourDataFile"); + openTourFile(directory + tourFile); + + String outputDirectory = rb.getString("summit.output.directory"); + + for (int i = 0; i < getNumberOfFiles(); ++i) + { + + // Create the summit table + createSummitFile(i); + + // Write the summit output file + String purpose = getPurpose(i); + writeFile(outputDirectory + purpose + ".bin", i); + + } + + // Open the joint tour file and start processing + tourFile = rb.getString("Results.JointTourDataFile"); + openTourFile(directory + tourFile); + + for (int i = 0; i < getNumberOfFiles(); ++i) + { + + // Create the summit table + createSummitFile(i); + + // Write the summit output file + String purpose = getPurpose(i); + writeFile(outputDirectory + "jnt_" + purpose + ".bin", i); + + } + + } + + /** + * Get the number of SUMMIT Files as set in the properties file. + * + * @return The number of SUMMIT files. + */ + public int getNumberOfFiles() + { + return numberOfFiles; + } + + /** + * Read household records and store autos owned. + * + * @param fileName + * household file path/name. + */ + public void readHouseholdFile(String fileName) + { + + autosOwned = new HashMap(); + + logger.info("Begin reading the data in file " + fileName); + + TableDataSet hhData; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + hhData = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + // iterate through the table and save number of autos + for (int i = 1; i <= hhData.getRowCount(); ++i) + { + long hhID = (long) hhData.getValueAt(i, "hh_ID"); + int autos = (int) hhData.getValueAt(i, "autos"); + autosOwned.put(hhID, autos); + } + logger.info("End reading the data in file " + fileName); + } + + /** + * Read person file and store persons >= 18. + * + * @param fileName + * Person file path/name. + */ + public void readPersonFile(String fileName) + { + personsOver18 = new HashMap(); + + logger.info("Begin reading the data in file " + fileName); + + TableDataSet personData; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + personData = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + // iterate through the table and save number of persons>=18 + int personCount = 0; + long hhID_last = -99; + for (int i = 1; i <= personData.getRowCount(); ++i) + { + long hhID = (long) personData.getValueAt(i, "hh_ID"); + int age = (int) personData.getValueAt(i, "age"); + + // this record is a new household + if (hhID != hhID_last && i > 1) + { + personsOver18.put(hhID_last, personCount); + personCount = 0; + } + + if (age >= 18) ++personCount; + + hhID_last = hhID; + } + // save the last household + personsOver18.put(hhID_last, personCount); + + logger.info("End reading the data in file " + fileName); + + } + + /** + * Open a tour file for subsequent reading. + */ + public void openTourFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + tourData = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + } + + /** + * This is the main workhorse method in this class. It creates a + * SummitRecordTable, and then iterates over records in the tour file. If + * the tour purpose for the record is mapped to the fileNumber argument, a + * ConcreteSummitRecord is created and the attributes are set, and the + * record is added to the SummitRecordTable. After all tour records have + * been read, the table is finalized. + * + * After this method is run, the file header information can be set and the + * SummitRecordTable can be written to a SUMMIT file. + * + * @param fileNumber + */ + public void createSummitFile(int fileNumber) + { + + String purpose = getPurpose(fileNumber); + logger.info("Begin creating SUMMIT record table for purpose " + purpose); + + // get column for start of utilities, probabilities + int start_util = tourData.getColumnPosition("util_1"); + int start_prob = tourData.getColumnPosition("prob_1"); + + boolean jointTour = tourData.containsColumn("tour_participants"); + int participantsCol = 0; + if (jointTour) + { + participantsCol = tourData.getColumnPosition("tour_participants"); + } + + // arrays of utilities, probabilities + float[] util = new float[modes]; + float[] prob = new float[modes]; + + // Instantiate a new SummitRecordTable + summitRecordTable = new SummitRecordTable(); + + // iterate through the tour data and save summit record tables + for (int i = 1; i <= tourData.getRowCount(); ++i) + { + + //if (i <= 5 || i % 1000 == 0) logger.info("Reading record " + i); + + String tourPurpose = tourData.getStringValueAt(i, "tour_purpose"); + int tableNumber = calculateSummitTable(tourPurpose); + + if (tableNumber != fileNumber) continue; + + long hhID = (long) tourData.getValueAt(i, "hh_id"); + + int originMGRA = (int) tourData.getValueAt(i, "orig_maz"); + int destinationMGRA = (int) tourData.getValueAt(i, "dest_maz"); + + int departPeriod = (int) tourData.getValueAt(i, "start_period"); + int arrivePeriod = (int) tourData.getValueAt(i, "end_period"); + + // get utilities, probabilities + for (int j = 0; j < modes; ++j) + { + util[j] = tourData.getValueAt(i, start_util + j); + prob[j] = tourData.getValueAt(i, start_prob + j); + } + + // calculate some necessary information for the SUMMIT record + int autoSufficiency = calculateAutoSufficiency(hhID); + short originTAZ = (short) mdm.getTaz(originMGRA); + short destinationTAZ = (short) mdm.getTaz(destinationMGRA); + int periodMarket = calculatePeriodMarket(departPeriod, arrivePeriod); + short marketSegment = (short) calculateMarketSegment(autoSufficiency, periodMarket); + float expUtility = calculateNonTransitExpUtility(util); // not used + float wtAvailShare = calculateWalkTransitAvailableShare(prob); + float dtAvailShare = calculateDriveTransitOnlyShare(prob, wtAvailShare); + float wtProb = calculateTransitShareOfWalkTransit(prob, wtAvailShare); + float dtProb = calculateTransitShareOfDriveTransitOnly(prob, dtAvailShare); + float aggExpUtility = calculateAggregateExpUtility(util); + + float participants = 1.0f; + if (jointTour) + { + String participantString = tourData.getStringValueAt(i, participantsCol); + for (int j = 0; j < participantString.length(); ++j) + if (participantString.charAt(j) == ' ') participants += 1; + } + // Create a new summit record, and set all attributes + ConcreteSummitRecord summitRecord = new ConcreteSummitRecord(); + + summitRecord.setPtaz(originTAZ); + summitRecord.setAtaz(destinationTAZ); + summitRecord.setMarket(marketSegment); + summitRecord.setTrips(participants); + summitRecord.setMotorizedTrips(participants); + summitRecord.setExpAuto(aggExpUtility); + summitRecord.setWalkTransitAvailableShare(wtAvailShare); + summitRecord.setDriveTransitOnlyShare(dtAvailShare); + summitRecord.setTransitShareOfWalkTransit(wtProb); + summitRecord.setTransitShareOfDriveTransitOnly(dtProb); + + // Insert the record into the record table + summitRecordTable.insertRecord(summitRecord); + + } + + logger.info("End creating SUMMIT record table for purpose " + purpose); + + logger.info("Begin finalizing table"); + summitRecordTable.finalizeTable(); + logger.info("End finalizing table"); + + } + + /** + * Calculate and return the market for the departure and arrival time + * periods. + * + * Market 0 = Departure & arrival in peak Market 1 = Departure & arrival in + * mixed periods (peak and off-peak) Market 2 = Departure & arrival in + * off-peak + * + * @param departPeriod + * 1-39 representing time in 30 min. increments, starting at 5 AM + * @param arrivePeriod + * 1-39 representing time in 30 min. increments, starting at 5 AM + * @return Market, as defined above. + */ + public int calculatePeriodMarket(int departPeriod, int arrivePeriod) + { + + int departPeak = 0; + int arrivePeak = 0; + + // check if departure is in peak period + if (departPeriod > upperEA && departPeriod <= upperAM) departPeak = 1; + else if (departPeriod > upperMD && departPeriod <= upperPM) departPeak = 1; + + // check if arrival is in peak period + if (arrivePeriod > upperEA && arrivePeriod <= upperAM) arrivePeak = 1; + else if (arrivePeriod > upperMD && arrivePeriod <= upperPM) arrivePeak = 1; + + /* + * Arrival & departure = peak, period = 0 Mixed peak & off-peak, period + * = 1 Arrival & departure = off-peal, period = 2 + */ + if (departPeak == 1 && arrivePeak == 1) return 0; + else if (departPeak == 0 && arrivePeak == 0) return 2; + + return 1; + } + + /** + * Calculate and return market segment based on auto sufficiency and time + * period combination. + * + * Market AutoSuff Period 1 0 0 Peak 2 0 1 Mixed 2 0 2 Off-Peak 3 1 0 Peak 4 + * 1 1 Mixed 4 1 2 Off-Peak 5 2 0 Peak 6 2 1 Mixed 6 2 2 Off-Peak + * + * + * @param autoSufficiency + * 0 = 0 autos, 1=autos < adults, 2 = autos >= adults + * @param periodMarket + * 0 = Peak, 1 = Mixed, 2 = Off-Peak + * @return Market for Summit record, as per above table. + */ + public int calculateMarketSegment(int autoSufficiency, int periodMarket) + { + + int market = 0; + + switch (autoSufficiency) + { + case 0: + market = (periodMarket == 0) ? 1 : 2; + break; + case 1: + market = (periodMarket == 0) ? 3 : 4; + break; + case 2: + market = (periodMarket == 0) ? 5 : 6; + break; + default: + logger.fatal("Error: Could not calculate market segment auto sufficiency " + + autoSufficiency); + throw new RuntimeException(); + } + + return market; + } + + /** + * Determine what table to use for tour purpose, based on fileNumber array + * set from properties file. + * + * @param tourPurpose + * @return Table for tour purpose + */ + public int calculateSummitTable(String tourPurpose) + { + + if (tourPurpose.contentEquals("Work")) return fileNumber[0]; + else if (tourPurpose.contentEquals("University")) return fileNumber[1]; + else if (tourPurpose.contentEquals("School")) return fileNumber[2]; + else if (tourPurpose.contentEquals("Escort")) return fileNumber[3]; + else if (tourPurpose.contentEquals("Shop")) return fileNumber[4]; + else if (tourPurpose.contentEquals("Maintenance")) return fileNumber[5]; + else if (tourPurpose.contentEquals("Eating Out")) return fileNumber[6]; + else if (tourPurpose.contentEquals("Visiting")) return fileNumber[7]; + else if (tourPurpose.contentEquals("Discretionary")) return fileNumber[8]; + else if (tourPurpose.contentEquals("Work-Based")) return fileNumber[9]; + else + { + logger.error("Error: Tour purpose " + tourPurpose + " not recognized"); + } + + return 99; + } + + /** + * Look up the purpose string based on the file number, for use in SUMMIT + * file header. + * + * @param fileNumber + * @return A string for the purpose (see above). + */ + public String getPurpose(int fileNumber) + { + + return fileName[fileNumber]; + } + + /** + * Calculate market segment (auto sufficiency) + * + * 0 = 0 autos owned 1 = autos > 0 & autos < adults (persons 18+) 2 = autos + * > adults + * + * @param hhID + * Household ID + * @return marketSegment + */ + public int calculateAutoSufficiency(long hhID) + { + + int drivers = personsOver18.get(hhID); + int autos = autosOwned.get(hhID); + + if (autos > 0) if (autos < drivers) return 1; + else return 2; + + return 0; + } + + /** + * Calculate the total non-transit exponentiated utility. The method uses + * the walkTransitModes array and the driveTransitModes array to determine + * which modes are non-transit, and the sum of their exponentiated utilities + * is calculated and returned. + * + * @param util + * An array of utilities, by mode. -999 indicates mode not + * available. + * @return Sum of exponentiated utilities of non-transit modes. + */ + public float calculateNonTransitExpUtility(float[] util) + { + + float expUtility = 0.0f; + + for (int i = 0; i < modes; ++i) + if (walkTransitModes[i] != 1 && driveTransitModes[i] != 1) + expUtility += (float) Math.exp(util[i]); + return expUtility; + } + + /** + * Calculate the share of walk-transit available: 1 if any walk-transit mode + * is available, as indicated by a non-zero probability, else 0. The method + * iterates through the probability array and returns a 1 if the probability + * is non-zero for any walk-transit mode, as indicated by the + * walkTransitModes array. + * + * @param prob + * An array of probabilities, dimensioned by modes. + * @return 1 if walk-transit is available for the record, else 0. + */ + public float calculateWalkTransitAvailableShare(float[] prob) + { + + // iterate through the probability array + for (int i = 0; i < modes; ++i) + if (walkTransitModes[i] == 1 && prob[i] > 0) return 1.0f; + + // no walk-transit modes with non-zero probability + return 0.0f; + } + + /** + * Calculate the share of drive-transit only available: 1 if any + * drive-transit mode is available, as indicated by a non-zero probability, + * and all walk-transit modes are not available. The method iterates through + * the probability array and returns a 1 if the probability is non-zero for + * any drive-transit mode, as indicated by the driveTransitModes array. + * + * @param prob + * An array of probabilities, dimensioned by modes. + * @param walkTransitAvailableShare + * 1 if walk-transit available, else 0. + * @return 1 if drive-transit only is available for the record, else 0. + */ + + public float calculateDriveTransitOnlyShare(float[] prob, float walkTransitAvailableShare) + { + + // if walk-transit is available, then drive-transit only share is 0. + if (walkTransitAvailableShare > 0) return 0.0f; + + // iterate through the probability array + for (int i = 0; i < modes; ++i) + if (driveTransitModes[i] == 1 && prob[i] > 0) return 1.0f; + + // no drive-transit modes with non-zero probability + return 0.0f; + + } + + /** + * Calculate the total transit probability for records with walk-transit + * available. The method returns 0 if walk-transit is not available. If + * walk-transit is available, the method iterates through the probability + * array, adding all transit mode probabilities. The sum is returned. + * + * @param prob + * An array of probabilities, one per mode. + * @param walkTransitAvailableShare + * 1 if walk-transit is available, else 0. + * @return The total transit probability if walk-transit is available, else + * 0. + */ + public float calculateTransitShareOfWalkTransit(float[] prob, float walkTransitAvailableShare) + { + + float transitShare = 0.0f; + + // if walk-transit is unavailable, then walk-transit share is 0. + if (walkTransitAvailableShare == 0) return transitShare; + + // iterate through the probability array + for (int i = 0; i < modes; ++i) + if (walkTransitModes[i] == 1 || driveTransitModes[i] == 1) transitShare += prob[i]; + + return transitShare; + + } + + /** + * Calculate the total transit probability for records where only + * drive-transit available. The method returns 0 if only drive-transit is + * not available. If only drive-transit is available, the method iterates + * through the probability array, adding all drive-transit mode + * probabilities. The sum is returned. + * + * @param prob + * An array of probabilities, one per mode. + * @param driveTransitOnlyAvailableShare + * 1 if only drive-transit is available, else 0. + * @return The total transit probability if only drive-transit is available, + * else 0. + */ + public float calculateTransitShareOfDriveTransitOnly(float[] prob, + float driveTransitOnlyAvailableShare) + { + + float transitShare = 0.0f; + + // if drive-transit is unavailable, then walk-transit share is 0. + if (driveTransitOnlyAvailableShare == 0) return transitShare; + + // iterate through the probability array + for (int i = 0; i < modes; ++i) + if (driveTransitModes[i] == 1) transitShare += prob[i]; + + return transitShare; + + } + + /** + * Calculate the logsum by taking ln[Sum (exp(utility)). + * + * @param util + * Array of utilities + * @return Logsum + */ + public float calculateAggregateExpUtility(float[] util) + { + + float aggExpUtility = 0.0f; + + for (int i = 0; i < util.length; ++i) + aggExpUtility += Math.exp(util[i]); + + return aggExpUtility; + } + + /** + * Get the in-tNCVehicle time coefficient for the file, based on the values + * read in the properties file. + * + * @param fileNumber + * @return The in-tNCVehicle time coefficient for the file. + */ + public float getIVTCoefficient(int fileNumber) + { + return ivtCoeff[fileNumber]; + } + + /** + * Create a Summit file header. + * + * @param fileNumber + * @return Header record for Summit file. + */ + public SummitHeader createSummitHeader(int fileNumber) + { + + SummitHeader header = new SummitHeader(); + + int zones = tdm.getMaxTaz(); + String purpose = getPurpose(fileNumber); + header.setZones(zones); + header.setMarketSegments(6); + + float ivt = getIVTCoefficient(fileNumber); + header.setTransitInVehicleTime(ivt); + header.setAutoInVehicleTime(ivt); + + header.setPurpose(purpose); + header.setTimeOfDay("ALL"); + header.setTitle("SANDAG CT-RAMP MODEL SUMMIT FILE"); + return header; + } + + public void writeFile(String fileName, int fileNumber) + { + + SummitHeader header = createSummitHeader(fileNumber); + summitRecordTable.writeTable(fileName, header); + + } + + /** + * @param args + */ + public static void main(String[] args) + { + + // Create a new SandagSummitFile + String propertiesFile = "D:\\projects\\SANDAG\\AB_Model\\SUMMIT\\sandag_abm.properties"; + SandagSummitFile summitFile = new SandagSummitFile(propertiesFile); + + // Read the household file + String hhFile = "D:\\projects\\SANDAG\\AB_Model\\SUMMIT\\householdData_1.csv"; + summitFile.readHouseholdFile(hhFile); + + // Read the person file + String perFile = "D:\\projects\\SANDAG\\AB_Model\\SUMMIT\\personData_1.csv"; + summitFile.readPersonFile(perFile); + + // Open the individual tour file and start processing + String tourFile = "D:\\projects\\SANDAG\\AB_Model\\SUMMIT\\indivTourData_1.csv"; + summitFile.openTourFile(tourFile); + + for (int i = 0; i < summitFile.getNumberOfFiles(); ++i) + { + + // Create the summit table + summitFile.createSummitFile(i); + + // Write the summit output file + String outputFile = "D:\\projects\\SANDAG\\AB_Model\\SUMMIT\\"; + String purpose = summitFile.getPurpose(i); + summitFile.writeFile(outputFile + purpose + ".bin", i); + + } + + // Open the joint tour file and start processing + tourFile = "D:\\projects\\SANDAG\\AB_Model\\SUMMIT\\jointTourData_1.csv"; + summitFile.openTourFile(tourFile); + + for (int i = 0; i < summitFile.getNumberOfFiles(); ++i) + { + + // Create the summit table + summitFile.createSummitFile(i); + + // Write the summit output file + String outputFile = "D:\\projects\\SANDAG\\AB_Model\\SUMMIT\\jnt_"; + String purpose = summitFile.getPurpose(i); + summitFile.writeFile(outputFile + purpose + ".bin", i); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTelecommuteDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTelecommuteDMU.java new file mode 100644 index 0000000..e0f4051 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTelecommuteDMU.java @@ -0,0 +1,67 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.ParkingChoiceDMU; +import org.sandag.abm.ctramp.TelecommuteDMU; + +public class SandagTelecommuteDMU + extends TelecommuteDMU +{ + + public SandagTelecommuteDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getIncomeInDollars", 1); + methodIndexMap.put("getNumberOfAdults", 2); + methodIndexMap.put("getHasKids_0_5", 3); + methodIndexMap.put("getHasKids_6_12", 4); + methodIndexMap.put("getFemale", 5); + methodIndexMap.put("getPersonType", 6); + methodIndexMap.put("getNumberOfAutos", 7); + methodIndexMap.put("getOccupation", 8); + methodIndexMap.put("getPaysToPark", 9); + methodIndexMap.put("getWorkDistance", 10); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + + case 1: + return getIncomeInDollars(); + case 2: + return getNumberOfAdults(); + case 3: + return getHasKids_0_5(); + case 4: + return getHasKids_6_12(); + case 5: + return getFemale(); + case 6: + return getPersonType(); + case 7: + return getNumberOfAutos(); + case 8: + return getOccupation(); + case 9: + return getPaysToPark(); + case 10: + return getWorkDistance(); + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTestSOA.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTestSOA.java new file mode 100644 index 0000000..92ba6ff --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTestSOA.java @@ -0,0 +1,216 @@ +package org.sandag.abm.application; + +import com.pb.common.matrix.Matrix; + +public class SandagTestSOA +{ + + private Matrix distanceMatrix; + private Matrix expDistanceMatrix; + private float[] size; + private float[] lnSize; + + public SandagTestSOA() + { + + } + + /** + * Create the distance matrix + * + * @param zones + * The number of zones + */ + public void createDistanceMatrix(int zones) + { + + distanceMatrix = new Matrix(zones, zones); + + for (int i = 1; i <= zones; ++i) + for (int j = 1; j <= zones; ++j) + { + float distance = (float) Math.random() * 100; + distanceMatrix.setValueAt(i, j, distance); + } + } + + /** + * Create the exponentiated distance matrix + * + * @param zones + * The number of zones + */ + public void createExpDistanceMatrix(float distParam, int zones) + { + + long createTime = -System.currentTimeMillis(); + expDistanceMatrix = new Matrix(zones, zones); + + for (int i = 1; i <= zones; ++i) + for (int j = 1; j <= zones; ++j) + { + float expDist = (float) distParam * distanceMatrix.getValueAt(i, j); + expDist = (float) Math.exp(expDist); + expDistanceMatrix.setValueAt(i, j, expDist); + } + createTime += System.currentTimeMillis(); + System.out.println("Time to exponentiate distance matrix " + createTime); + } + + /** + * Create the size terms + */ + public void createSizeTerms(int zones) + { + + size = new float[zones + 1]; + lnSize = new float[zones + 1]; + + for (int i = 1; i <= zones; ++i) + { + size[i] = (float) Math.random() * 1000; + lnSize[i] = (float) Math.log(size[i]); + } + } + + public void calculateProbabilitiesOldWay(int observations, int zones, float distParam) + { + + long oldWayTime = -System.currentTimeMillis(); + + float[] prob = new float[zones + 1]; + float[] expUtil = new float[zones + 1]; + float sumExp = 0; + + for (int obs = 0; obs < observations; ++obs) + { + + int origin = (int) (Math.random() * (zones - 1)) + 1; + int destination = (int) (Math.random() * (zones - 1)) + 1; + + float odDist = distanceMatrix.getValueAt(origin, destination); + + // calculate utilities + for (int stop = 1; stop <= zones; ++stop) + { + float osDist = distanceMatrix.getValueAt(origin, stop); + float sdDist = distanceMatrix.getValueAt(stop, destination); + + float util = distParam * (osDist + sdDist - odDist) + lnSize[stop]; + expUtil[stop] = (float) Math.exp(util); + sumExp += expUtil[stop]; + } + + // calculate probabilities + for (int stop = 1; stop <= zones; ++stop) + prob[stop] = expUtil[stop] / sumExp; + } + oldWayTime += System.currentTimeMillis(); + System.out.println("Time to calculate probabilities old way tazs " + oldWayTime); + + } + + public void calculateProbabilitiesOldWayMGRAs(int observations, int zones, float distParam, + int mgras) + { + + long oldWayMGRATime = -System.currentTimeMillis(); + + float[] prob = new float[mgras + 1]; + float[] expUtil = new float[mgras + 1]; + float sumExp = 0; + + for (int obs = 0; obs < observations; ++obs) + { + + int origin = (int) (Math.random() * (zones - 1)) + 1; + int destination = (int) (Math.random() * (zones - 1)) + 1; + + float odDist = distanceMatrix.getValueAt(origin, destination); + + int stopIndex = 1; + // calculate utilities + for (int stop = 1; stop <= mgras; ++stop) + { + + float osDist = distanceMatrix.getValueAt(origin, stopIndex); + float sdDist = distanceMatrix.getValueAt(stopIndex, destination); + + float util = distParam * (osDist + sdDist - odDist) + lnSize[stopIndex]; + expUtil[stopIndex] = (float) Math.exp(util); + sumExp += expUtil[stopIndex]; + + ++stopIndex; + if (stopIndex > zones) stopIndex = 1; + } + + // calculate probabilities + for (int stop = 1; stop <= mgras; ++stop) + prob[stop] = expUtil[stop] / sumExp; + + } + oldWayMGRATime += System.currentTimeMillis(); + System.out.println("Time to calculate probabilities old way mgras " + oldWayMGRATime); + + } + + public void calculateProbabilitiesNewWay(int observations, int zones) + { + + long newWayTime = -System.currentTimeMillis(); + + float[] prob = new float[zones + 1]; + float[] expUtil = new float[zones + 1]; + float sumExp = 0; + + for (int obs = 0; obs < observations; ++obs) + { + + int origin = (int) (Math.random() * (zones - 1)) + 1; + int destination = (int) (Math.random() * (zones - 1)) + 1; + + float odExpDist = expDistanceMatrix.getValueAt(origin, destination); + + // calculate utilities + for (int stop = 1; stop <= zones; ++stop) + { + float osExpDist = expDistanceMatrix.getValueAt(origin, stop); + float sdExpDist = expDistanceMatrix.getValueAt(stop, destination); + + expUtil[stop] = osExpDist * sdExpDist / odExpDist * size[stop]; + sumExp += expUtil[stop]; + } + + // calculate probabilities + for (int stop = 1; stop <= zones; ++stop) + prob[stop] = expUtil[stop] / sumExp; + } + + newWayTime += System.currentTimeMillis(); + System.out.println("Time to calculate probabilities new way tazs " + newWayTime); + } + + /** + * @param args + */ + public static void main(String[] args) + { + + int zones = 4600; + int observations = 500000; + float distParam = (float) -0.05; + int mgras = 32000; + + SandagTestSOA soa = new SandagTestSOA(); + + soa.createDistanceMatrix(zones); + soa.createExpDistanceMatrix(distParam, zones); + soa.createSizeTerms(zones); + + soa.calculateProbabilitiesOldWayMGRAs(observations, zones, distParam, mgras); + soa.calculateProbabilitiesOldWay(observations, zones, distParam); + soa.calculateProbabilitiesNewWay(observations, zones); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourBasedModel.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourBasedModel.java new file mode 100644 index 0000000..86aaf7e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourBasedModel.java @@ -0,0 +1,358 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; + +import org.sandag.abm.ctramp.HouseholdDataManager; +import org.sandag.abm.ctramp.HouseholdDataManagerIf; +import org.sandag.abm.ctramp.HouseholdDataManagerRmi; +import com.pb.common.util.ResourceUtil; + +public final class SandagTourBasedModel +{ + + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + + public static final String PROPERTIES_PROJECT_DIRECTORY = "Project.Directory"; + + private static final int DEFAULT_ITERATION_NUMBER = 1; + private static final float DEFAULT_SAMPLE_RATE = 1.0f; + private static final int DEFAULT_SAMPLE_SEED = 0; + + public static final int DEBUG_CHOICE_MODEL_HHID = 740151; + + private ResourceBundle rb; + + // values for these variables are set as command line arguments, or default + // vaues + // are used if no command line arguments are specified. + private int globalIterationNumber = 0; + private float iterationSampleRate = 0f; + private int sampleSeed = 0; + private boolean calculateLandUseAccessibilities = false; + + /** + * + * @param rb + * , java.util.ResourceBundle containing environment settings + * from a properties file specified on the command line + * @param globalIterationNumber + * , int iteration number for which the model is run, set by + * another process controlling a model stream with feedback. + * @param iterationSampleRate + * , float percentage [0.0, 1.0] inicating the portion of all + * households to be modeled. + * + * This object defines the implementation of the ARC tour based, + * activity based travel demand model. + */ + private SandagTourBasedModel(ResourceBundle aRb, HashMap aPropertyMap, + int aGlobalIterationNumber, float aIterationSampleRate, boolean aCalculateLandUseAccessibilities) + { + rb = aRb; + globalIterationNumber = aGlobalIterationNumber; + iterationSampleRate = aIterationSampleRate; + sampleSeed = Integer.parseInt(rb.getString("Model.Random.Seed")); + calculateLandUseAccessibilities = aCalculateLandUseAccessibilities; + } + + private void runTourBasedModel(HashMap propertyMap) + { + + // new a ctramp application object + SandagCtrampApplication ctrampApplication = new SandagCtrampApplication(rb, propertyMap, + calculateLandUseAccessibilities); + + // create modelStructure object + SandagModelStructure modelStructure = new SandagModelStructure(); + + boolean localHandlers = false; + + String hhHandlerAddress = ""; + int hhServerPort = 0; + try + { + // get household server address. if none is specified a local server + // in + // the current process will be started. + hhHandlerAddress = rb.getString("RunModel.HouseholdServerAddress"); + try + { + // get household server port. + hhServerPort = Integer.parseInt(rb.getString("RunModel.HouseholdServerPort")); + localHandlers = false; + } catch (MissingResourceException e) + { + // if no household data server address entry is found, the + // object + // will be created in the local process + localHandlers = true; + } + } catch (MissingResourceException e) + { + localHandlers = true; + } + + String testString; + // if ( localHandlers ) { + // tazDataHandler = new SandagTazDataHandler(rb, projectDirectory); + // } + // else { + // tazDataHandler = new TazDataHandlerRmi( + // ArcTazDataHandler.ZONAL_DATA_SERVER_ADDRESS, + // ArcTazDataHandler.ZONAL_DATA_SERVER_PORT, + // ArcTazDataHandler.ZONAL_DATA_SERVER_NAME ); + // testString = tazDataHandler.testRemote(); + // logger.info ( "TazDataHandler test: " + testString ); + // } + + // setup the ctramp application + ctrampApplication.setupModels(modelStructure); + + // generate the synthetic population + // ARCPopulationSynthesizer populationSynthesizer = new + // ARCPopulationSynthesizer( propertiesFileBaseName ); + // ctrampApplication.runPopulationSynthesizer( populationSynthesizer ); + + HouseholdDataManagerIf householdDataManager; + + try + { + + if (localHandlers) + { + + // create a new local instance of the household array manager + householdDataManager = new SandagHouseholdDataManager2(); + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population + // files and apply its tables to objects mapping method. + String inputHouseholdFileName = rb + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = rb + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(iterationSampleRate, sampleSeed); + householdDataManager.setupHouseholdDataManager(modelStructure, + inputHouseholdFileName, inputPersonFileName); + + } else + { + + householdDataManager = new HouseholdDataManagerRmi(hhHandlerAddress, hhServerPort, + SandagHouseholdDataManager2.HH_DATA_SERVER_NAME); + testString = householdDataManager.testRemote(); + logger.info("HouseholdDataManager test: " + testString); + + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population + // files and apply its tables to objects mapping method. + boolean restartHhServer = false; + try + { + // possible values for the following can be none, ao, cdap, + // imtf, + // imtod, awf, awl, awtod, jtf, jtl, jtod, inmtf, inmtl, + // inmtod, + // stf, stl + String restartModel = rb.getString("RunModel.RestartWithHhServer"); + if (restartModel.equalsIgnoreCase("none")) restartHhServer = true; + else if (restartModel.equalsIgnoreCase("uwsl") + || restartModel.equalsIgnoreCase("ao") + || restartModel.equalsIgnoreCase("fp") + || restartModel.equalsIgnoreCase("cdap") + || restartModel.equalsIgnoreCase("imtf") + || restartModel.equalsIgnoreCase("imtod") + || restartModel.equalsIgnoreCase("awf") + || restartModel.equalsIgnoreCase("awl") + || restartModel.equalsIgnoreCase("awtod") + || restartModel.equalsIgnoreCase("jtf") + || restartModel.equalsIgnoreCase("jtl") + || restartModel.equalsIgnoreCase("jtod") + || restartModel.equalsIgnoreCase("inmtf") + || restartModel.equalsIgnoreCase("inmtl") + || restartModel.equalsIgnoreCase("inmtod") + || restartModel.equalsIgnoreCase("stf") + || restartModel.equalsIgnoreCase("stl")) restartHhServer = false; + } catch (MissingResourceException e) + { + restartHhServer = true; + } + + if (restartHhServer) + { + + householdDataManager.setDebugHhIdsFromHashmap(); + + String inputHouseholdFileName = rb + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = rb + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(iterationSampleRate, sampleSeed); + householdDataManager.setupHouseholdDataManager(modelStructure, + inputHouseholdFileName, inputPersonFileName); + + } else + { + + householdDataManager.setHouseholdSampleRate(iterationSampleRate, sampleSeed); + householdDataManager.setDebugHhIdsFromHashmap(); + householdDataManager.setTraceHouseholdSet(); + + // set the random number sequence for household objects + // accordingly based on which model components are + // assumed to have already run and are stored in the remote + // HouseholdDataManager object. + ctrampApplication.restartModels(householdDataManager); + + } + + } + + // create a factory object to pass to various model components from + // which + // they can create DMU objects + SandagCtrampDmuFactory dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + // run the models + ctrampApplication.runModels(householdDataManager, dmuFactory, globalIterationNumber, + iterationSampleRate); + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + } + + public static void main(String[] args) + { + Runtime gfg = Runtime.getRuntime(); + long memory1; + // checking the total memeory + System.out.println("Total memory is: "+ gfg.totalMemory()); + // checking free memory + memory1 = gfg.freeMemory(); + System.out.println("Initial free memory at Resident model: "+ memory1); + // calling the garbage collector on demand + gfg.gc(); + memory1 = gfg.freeMemory(); + System.out.println("Free memory after garbage "+ "collection: " + memory1); + + long startTime = System.currentTimeMillis(); + int globalIterationNumber = -1; + float iterationSampleRate = -1.0f; + //int sampleSeed = -1; + boolean calculateLandUseAccessibilities = false; + + ResourceBundle rb = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + pMap = ResourceUtil.getResourceBundleAsHashMap(args[0]); + + // optional arguments + for (int i = 1; i < args.length; i++) + { + + if (args[i].equalsIgnoreCase("-iteration")) + { + globalIterationNumber = Integer.parseInt(args[i + 1]); + logger.info(String.format("-iteration %d.", globalIterationNumber)); + } + + if (args[i].equalsIgnoreCase("-sampleRate")) + { + iterationSampleRate = Float.parseFloat(args[i + 1]); + logger.info(String.format("-sampleRate %.4f.", iterationSampleRate)); + } + + /* + if (args[i].equalsIgnoreCase("-sampleSeed")) + { + sampleSeed = Integer.parseInt(args[i + 1]); + logger.info(String.format("-sampleSeed %d.", sampleSeed)); + } + */ + + if (args[i].equalsIgnoreCase("-luAcc")) + { + calculateLandUseAccessibilities = Boolean.parseBoolean(args[i + 1]); + logger.info(String.format("-luAcc %s.", calculateLandUseAccessibilities)); + } + + } + + if (globalIterationNumber < 0) + { + globalIterationNumber = DEFAULT_ITERATION_NUMBER; + logger.info(String.format("no -iteration flag, default value %d used.", + globalIterationNumber)); + } + + if (iterationSampleRate < 0) + { + iterationSampleRate = DEFAULT_SAMPLE_RATE; + logger.info(String.format("no -sampleRate flag, default value %.4f used.", + iterationSampleRate)); + } + + /* + if (sampleSeed < 0) + { + sampleSeed = DEFAULT_SAMPLE_SEED; + logger.info(String + .format("no -sampleSeed flag, default value %d used.", sampleSeed)); + } + */ + + } + + // create an instance of this class for main() to use. + SandagTourBasedModel mainObject = new SandagTourBasedModel(rb, pMap, globalIterationNumber, + iterationSampleRate, calculateLandUseAccessibilities); + + // run tour based models + try + { + + logger.info(""); + logger.info("starting tour based model."); + mainObject.runTourBasedModel(pMap); + + } catch (RuntimeException e) + { + logger.error( + "RuntimeException caught in org.sandag.abm.application.SandagTourBasedModel.main() -- exiting.", + e); + } + + logger.info(""); + logger.info(""); + logger.info("SANDAG Activity Based Model finished in " + + ((System.currentTimeMillis() - startTime) / 60000.0) + " minutes."); + + System.exit(0); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourDepartureTimeAndDurationDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourDepartureTimeAndDurationDMU.java new file mode 100644 index 0000000..6971a98 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourDepartureTimeAndDurationDMU.java @@ -0,0 +1,345 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.Definitions; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.TourDepartureTimeAndDurationDMU; + +/** + * ArcTourDepartureTimeAndDurationDMU is a class that ... + * + * @author Kimberly Grommes + * @version 1.0, Jul 17, 2008 Created by IntelliJ IDEA. + */ +public class SandagTourDepartureTimeAndDurationDMU + extends TourDepartureTimeAndDurationDMU +{ + + public SandagTourDepartureTimeAndDurationDMU(ModelStructure modelStructure) + { + super(modelStructure); + setupMethodIndexMap(); + } + + public double getDestinationEmploymentDensity() + { + return destEmpDen; + } + + public int getIncomeLessThan30k() + { + float incomeInDollars = (float) household.getIncomeInDollars(); + return (incomeInDollars < 30000) ? 1 : 0; + } + + public int getIncome30kTo60k() + { + float incomeInDollars = (float) household.getIncomeInDollars(); + return (incomeInDollars >= 30000 && incomeInDollars < 60000) ? 1 : 0; + } + + public int getIncomeHigherThan100k() + { + float incomeInDollars = (float) household.getIncomeInDollars(); + return (incomeInDollars >= 100000) ? 1 : 0; + } + + public int getAge() + { + return getPersonAge(); + } + + public int getFemale() + { + return getPersonIsFemale(); + } + + public int getFemaleWithPreschooler() + { + return ((getPersonIsFemale() == 1) && (getNumPreschoolChildrenInHh() > 1)) ? 1 : 0; + } + + public int getDrivingAgeStudent() + { + return (getStudentDrivingAge() == 1) ? 1 : 0; + } + + public int getSchoolChildWithMandatoryTour() + { + return (getStudentNonDrivingAge() == 1 && getPersonMandatoryTotal() > 0) ? 1 : 0; + } + + public int getUniversityWithMandatoryPattern() + { + return (getUniversityStudent() == 1 && person.getCdapActivity().equalsIgnoreCase( + Definitions.MANDATORY_PATTERN)) ? 1 : 0; + } + + public int getWorkerWithMandatoryPattern() + { + return ((getFullTimeWorker() == 1 || getPartTimeWorker() == 1) && person.getCdapActivity() + .equalsIgnoreCase(Definitions.MANDATORY_PATTERN)) ? 1 : 0; + } + + public int getPreschoolChildWithMandatoryTour() + { + return (getPreschool() == 1 && getPersonMandatoryTotal() > 0) ? 1 : 0; + } + + public int getNonWorkerInHH() + { + return (getNumNonWorkingAdultsInHh() > 0) ? 1 : 0; + } + + public int getJointTour() + { + return (tour.getTourCategory() + .equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) ? 1 : 0; + } + + public int getIndividualTour() + { + return (tour.getTourCategory() + .equalsIgnoreCase(ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY)) ? 1 : 0; + } + + public int getJointTourInHH() + { + return (getHhJointTotal() > 0) ? 1 : 0; + } + + public int getSubsequentTourIsWorkTour() + { + return subsequentTourIsWork; + } + + public int getSubsequentTourIsSchoolTour() + { + return subsequentTourIsSchool; + } + + public int getNumberOfNonEscortingIndividualTours() + { + return getPersonNonMandatoryTotalNoEscort(); + } + + public int getNumberOfDiscretionaryTours() + { + return getPersonJointAndIndivDiscrToursTotal(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getDestinationEmploymentDensity", 1); + methodIndexMap.put("getIncomeLessThan30k", 2); + methodIndexMap.put("getIncome30kTo60k", 3); + methodIndexMap.put("getIncomeHigherThan100k", 4); + methodIndexMap.put("getAge", 5); + methodIndexMap.put("getFemale", 6); + methodIndexMap.put("getFemaleWithPreschooler", 7); + methodIndexMap.put("getFullTimeWorker", 8); + methodIndexMap.put("getPartTimeWorker", 9); + methodIndexMap.put("getUniversityStudent", 10); + methodIndexMap.put("getDrivingAgeStudent", 11); + methodIndexMap.put("getNonWorkerInHH", 12); + methodIndexMap.put("getJointTourInHH", 13); + methodIndexMap.put("getFirstTour", 14); + methodIndexMap.put("getSubsequentTour", 15); + methodIndexMap.put("getModeChoiceLogsumAlt", 16); + methodIndexMap.put("getSubsequentTourIsWorkTour", 17); + methodIndexMap.put("getSubsequentTourIsSchoolTour", 18); + methodIndexMap.put("getEndOfPreviousTour", 19); + methodIndexMap.put("getAllAdultsFullTimeWorkers", 20); + methodIndexMap.put("getNonWorker", 21); + methodIndexMap.put("getRetired", 22); + methodIndexMap.put("getSchoolChildWithMandatoryTour", 23); + methodIndexMap.put("getPreschoolChildWithMandatoryTour", 24); + methodIndexMap.put("getNumberOfNonEscortingIndividualTours", 25); + methodIndexMap.put("getNumberOfDiscretionaryTours", 26); + methodIndexMap.put("getIndividualTour", 27); + methodIndexMap.put("getJointTour", 28); + methodIndexMap.put("getHouseholdSize", 29); + methodIndexMap.put("getKidsOnJointTour", 30); + methodIndexMap.put("getAdditionalShoppingTours", 31); + methodIndexMap.put("getAdditionalMaintenanceTours", 32); + methodIndexMap.put("getAdditionalVisitingTours", 33); + methodIndexMap.put("getAdditionalDiscretionaryTours", 34); + methodIndexMap.put("getMaximumAvailableTimeWindow", 35); + methodIndexMap.put("getWorkerWithMandatoryPattern", 36); + methodIndexMap.put("getUnivStudentWithMandatoryPattern", 37); + methodIndexMap.put("getHhChildUnder16", 38); + methodIndexMap.put("getToursLeftToSchedule", 39); + methodIndexMap.put("getPreDrivingAgeChild", 40); + methodIndexMap.put("getJointTourPartySize", 41); + methodIndexMap.put("getSubtourPurposeIsEatOut", 42); + methodIndexMap.put("getSubtourPurposeIsBusiness", 43); + methodIndexMap.put("getSubtourPurposeIsOther", 44); + methodIndexMap.put("getMaxJointTimeWindow", 45); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + case 1: + returnValue = getDestinationEmploymentDensity(); + break; + case 2: + returnValue = getIncomeLessThan30k(); + break; + case 3: + returnValue = getIncome30kTo60k(); + break; + case 4: + returnValue = getIncomeHigherThan100k(); + break; + case 5: + returnValue = getAge(); + break; + case 6: + returnValue = getFemale(); + break; + case 7: + returnValue = getFemaleWithPreschooler(); + break; + case 8: + returnValue = getFullTimeWorker(); + break; + case 9: + returnValue = getPartTimeWorker(); + break; + case 10: + returnValue = getUniversityStudent(); + break; + case 11: + returnValue = getDrivingAgeStudent(); + break; + case 12: + returnValue = getNonWorkerInHH(); + break; + case 13: + returnValue = getJointTourInHH(); + break; + case 14: + returnValue = getFirstTour(); + break; + case 15: + returnValue = getSubsequentTour(); + break; + case 16: + returnValue = getModeChoiceLogsumAlt(arrayIndex); + break; + case 17: + returnValue = getSubsequentTourIsWorkTour(); + break; + case 18: + returnValue = getSubsequentTourIsSchoolTour(); + break; + case 19: + returnValue = getEndOfPreviousTour(); + break; + case 20: + returnValue = getAllAdultsFullTimeWorkers(); + break; + case 21: + returnValue = getNonWorker(); + break; + case 22: + returnValue = getRetired(); + break; + case 23: + returnValue = getSchoolChildWithMandatoryTour(); + break; + case 24: + returnValue = getPreschoolChildWithMandatoryTour(); + break; + case 25: + returnValue = getNumberOfNonEscortingIndividualTours(); + break; + case 26: + returnValue = getNumberOfDiscretionaryTours(); + break; + case 27: + returnValue = getIndividualTour(); + break; + case 28: + returnValue = getJointTour(); + break; + case 29: + returnValue = getHouseholdSize(); + break; + case 30: + returnValue = getKidsOnJointTour(); + break; + case 31: + returnValue = getNumIndivShopTours() - 1; + break; + case 32: + returnValue = getNumIndivMaintTours() - 1; + break; + case 33: + returnValue = getNumIndivVisitTours() - 1; + break; + case 34: + returnValue = getNumIndivDiscrTours() - 1; + break; + case 35: + returnValue = getMaximumAvailableTimeWindow(); + break; + case 36: + returnValue = getWorkerWithMandatoryPattern(); + break; + case 37: + returnValue = getUniversityWithMandatoryPattern(); + break; + case 38: + returnValue = getNumChildrenUnder16InHh() > 0 ? 1 : 0; + break; + case 39: + returnValue = getToursLeftToSchedule(); + break; + case 40: + returnValue = getPreDrivingAgeChild(); + break; + case 41: + returnValue = getJointTourPartySize(); + break; + case 42: + returnValue = getSubtourPurposeIsEatOut(); + break; + case 43: + returnValue = getSubtourPurposeIsBusiness(); + break; + case 44: + returnValue = getSubtourPurposeIsOther(); + break; + case 45: + returnValue = getMaxJointTimeWindow(); + break; + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourModeChoiceDMU.java new file mode 100644 index 0000000..79e76ed --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTourModeChoiceDMU.java @@ -0,0 +1,502 @@ +package org.sandag.abm.application; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.TourModeChoiceDMU; +import org.sandag.abm.ctramp.BikeLogsum; +import org.sandag.abm.ctramp.BikeLogsumSegment; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Tour; +import org.sandag.abm.ctramp.TourModeChoiceDMU; +import org.sandag.abm.ctramp.ModelStructure; + + +public class SandagTourModeChoiceDMU + extends TourModeChoiceDMU +{ + + private int setPersonHhTourCounter = 0; + private BikeLogsum bls; + protected double inboundFemaleBikeLogsum; + protected double outboundFemaleBikeLogsum; + protected double inboundMaleBikeLogsum; + protected double outboundMaleBikeLogsum; + protected double femaleInParty; + protected double maleInParty; + + public SandagTourModeChoiceDMU(ModelStructure modelStructure, Logger aLogger) + { + super(modelStructure, aLogger); + setupMethodIndexMap(); + } + + public float getTimeOutbound() + { + return tour.getTourDepartPeriod(); + } + + public float getTimeInbound() + { + return tour.getTourArrivePeriod(); + } + + public int getIncome() + { + return hh.getIncomeInDollars(); + } + + public int getAdults() + { + return hh.getNumPersons18plus(); + } + + public int getFemale() + { + return person.getPersonIsFemale(); + } + + public void setOrigDuDen(double arg) + { + origDuDen = arg; + } + + public void setOrigEmpDen(double arg) + { + origEmpDen = arg; + } + + public void setOrigTotInt(double arg) + { + origTotInt = arg; + } + + public void setDestDuDen(double arg) + { + destDuDen = arg; + } + + public void setDestEmpDen(double arg) + { + destEmpDen = arg; + } + + public void setDestTotInt(double arg) + { + destTotInt = arg; + } + + public double getODUDen() + { + return origDuDen; + } + + public double getOEmpDen() + { + return origEmpDen; + } + + public double getOTotInt() + { + return origTotInt; + } + + public double getDDUDen() + { + return destDuDen; + } + + public double getDEmpDen() + { + return destEmpDen; + } + + public double getDTotInt() + { + return destTotInt; + } + + public double getNm_walkTime_out() + { + return getNmWalkTimeOut(); + } + + public double getNm_walkTime_in() + { + return getNmWalkTimeIn(); + } + + public double getNm_bikeTime_out() + { + return getNmBikeTimeOut(); + } + + public double getNm_bikeTime_in() + { + return getNmBikeTimeIn(); + } + + + public void setBikeLogsum(BikeLogsum bls) + { + this.bls = bls; + } + + public void setPersonObject(Person person) + { + super.setPersonObject(person); + checkSetPersonHhTour(); + } + + public void setHouseholdObject(Household hh) + { + super.setHouseholdObject(hh); + checkSetPersonHhTour(); + } + + public void setTourObject(Tour tour) + { + super.setTourObject(tour); + checkSetPersonHhTour(); + } + + private void checkSetPersonHhTour() + { + setPersonHhTourCounter = (setPersonHhTourCounter+1) % 3; + if (setPersonHhTourCounter == 0) { + setParty(person,tour,hh); + setBikeLogsum(); + } + } + + public double getFemaleInParty() + { + return femaleInParty; + } + + public double getMaleInParty() + { + return maleInParty; + } + + public void setParty(Person person, Tour tour, Household hh) + { + if (person != null) { + femaleInParty = person.getPersonIsFemale(); + maleInParty = femaleInParty == 0 ? 1 : 0; + } else { + femaleInParty = 0; + maleInParty = 0; + for (int participant : tour.getPersonNumArray()) { + if (hh.getPerson(participant).getPersonIsFemale() == 1) + femaleInParty = 1; + else + maleInParty = 1; + } + } + } + + public double getInboundFemaleBikeLogsum() + { + return inboundFemaleBikeLogsum; + } + + public double getOutboundFemaleBikeLogsum() + { + return outboundFemaleBikeLogsum; + } + + public double getInboundMaleBikeLogsum() + { + return inboundMaleBikeLogsum; + } + + public double getOutboundMaleBikeLogsum() + { + return outboundMaleBikeLogsum; + } + + + private void setBikeLogsum(double inboundFemaleBikeLogsum, double outboundFemaleBikeLogsum, + double inboundMaleBikeLogsum , double outboundMaleBikeLogsum) + { + this.inboundFemaleBikeLogsum = inboundFemaleBikeLogsum; + this.outboundFemaleBikeLogsum = outboundFemaleBikeLogsum; + this.inboundMaleBikeLogsum = inboundMaleBikeLogsum; + this.outboundMaleBikeLogsum = outboundMaleBikeLogsum; + } + + private void setBikeLogsum() + { + int origin = tour.getTourOrigMgra(); + int dest = tour.getTourDestMgra(); + boolean mandatory = tour.getTourPrimaryPurposeIndex() <= 3; + setBikeLogsum(bls.getLogsum(new BikeLogsumSegment(true,mandatory,true),dest,origin), + bls.getLogsum(new BikeLogsumSegment(true,mandatory,false),origin,dest), + bls.getLogsum(new BikeLogsumSegment(false,mandatory,true),dest,origin), + bls.getLogsum(new BikeLogsumSegment(false,mandatory,false),origin,dest)); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTimeOutbound", 0); + methodIndexMap.put("getTimeInbound", 1); + methodIndexMap.put("getIncomeCategory", 2); + methodIndexMap.put("getAdults", 3); + methodIndexMap.put("getFemale", 4); + methodIndexMap.put("getHhSize", 5); + methodIndexMap.put("getAutos", 6); + methodIndexMap.put("getAge", 7); + methodIndexMap.put("getTourCategoryJoint", 8); + methodIndexMap.put("getNumberOfParticipantsInJointTour", 9); + methodIndexMap.put("getWorkTourModeIsSov", 10); + methodIndexMap.put("getWorkTourModeIsBike", 11); + methodIndexMap.put("getWorkTourModeIsHov", 12); + methodIndexMap.put("getPTazTerminalTime", 14); + methodIndexMap.put("getATazTerminalTime", 15); + methodIndexMap.put("getODUDen", 16); + methodIndexMap.put("getOEmpDen", 17); + methodIndexMap.put("getOTotInt", 18); + methodIndexMap.put("getDDUDen", 19); + methodIndexMap.put("getDEmpDen", 20); + methodIndexMap.put("getDTotInt", 21); + methodIndexMap.put("getTourCategoryEscort", 22); + methodIndexMap.put("getMonthlyParkingCost", 23); + methodIndexMap.put("getDailyParkingCost", 24); + methodIndexMap.put("getHourlyParkingCost", 25); + methodIndexMap.put("getReimburseProportion", 26); + methodIndexMap.put("getPersonType", 27); + methodIndexMap.put("getFreeParkingEligibility", 28); + methodIndexMap.put("getParkingArea", 29); + + methodIndexMap.put("getWorkTimeFactor", 30); + methodIndexMap.put("getNonWorkTimeFactor", 31); + methodIndexMap.put("getJointTourTimeFactor", 32); + methodIndexMap.put("getTransponderOwnership", 33); + + methodIndexMap.put("getFemaleInParty", 50); + methodIndexMap.put("getMaleInParty", 51); + methodIndexMap.put("getInboundFemaleBikeLogsum", 52); + methodIndexMap.put("getOutboundFemaleBikeLogsum", 53); + methodIndexMap.put("getInboundMaleBikeLogsum", 54); + methodIndexMap.put("getOutboundMaleBikeLogsum", 55); + + methodIndexMap.put("getIvtCoeff", 56); + methodIndexMap.put("getCostCoeff", 57); + methodIndexMap.put("getIncomeInDollars", 58); + methodIndexMap.put("getWalkSetLogSum", 59); + methodIndexMap.put("getPnrSetLogSum", 60); + methodIndexMap.put("getKnrSetLogSum", 61); + + methodIndexMap.put( "getOrigTaxiWaitTime", 70 ); + methodIndexMap.put( "getDestTaxiWaitTime", 71 ); + methodIndexMap.put( "getOrigSingleTNCWaitTime", 72 ); + methodIndexMap.put( "getDestSingleTNCWaitTime", 73 ); + methodIndexMap.put( "getOrigSharedTNCWaitTime", 74 ); + methodIndexMap.put( "getDestSharedTNCWaitTime", 75 ); + methodIndexMap.put( "getUseOwnedAV", 76); + + methodIndexMap.put("getNm_walkTime_out", 90); + methodIndexMap.put("getNm_walkTime_in", 91); + methodIndexMap.put("getNm_bikeTime_out", 92); + methodIndexMap.put("getNm_bikeTime_in", 93); + + methodIndexMap.put("getOriginMgra", 96); + methodIndexMap.put("getDestMgra", 97); + + + + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getTimeOutbound(); + break; + case 1: + returnValue = getTimeInbound(); + break; + case 2: + returnValue = getIncomeCategory(); + break; + case 3: + returnValue = getAdults(); + break; + case 4: + returnValue = getFemale(); + break; + case 5: + returnValue = getHhSize(); + break; + case 6: + returnValue = getAutos(); + break; + case 7: + returnValue = getAge(); + break; + case 8: + returnValue = getTourCategoryJoint(); + break; + case 9: + returnValue = getNumberOfParticipantsInJointTour(); + break; + case 10: + returnValue = getWorkTourModeIsSov(); + break; + case 11: + returnValue = getWorkTourModeIsBike(); + break; + case 12: + returnValue = getWorkTourModeIsHov(); + break; + case 14: + returnValue = getPTazTerminalTime(); + break; + case 15: + returnValue = getATazTerminalTime(); + break; + case 16: + returnValue = getODUDen(); + break; + case 17: + returnValue = getOEmpDen(); + break; + case 18: + returnValue = getOTotInt(); + break; + case 19: + returnValue = getDDUDen(); + break; + case 20: + returnValue = getDEmpDen(); + break; + case 21: + returnValue = getDTotInt(); + break; + case 22: + returnValue = getTourCategoryEscort(); + break; + case 23: + returnValue = getMonthlyParkingCost(); + break; + case 24: + returnValue = getDailyParkingCost(); + break; + case 25: + returnValue = getHourlyParkingCost(); + break; + case 26: + returnValue = getReimburseProportion(); + break; + case 27: + returnValue = getPersonType(); + break; + case 28: + returnValue = getFreeParkingEligibility(); + break; + case 29: + returnValue = getParkingArea(); + break; + case 30: + returnValue = getWorkTimeFactor(); + break; + case 31: + returnValue = getNonWorkTimeFactor(); + break; + case 32: + returnValue = getJointTourTimeFactor(); + break; + case 33: + returnValue = getTransponderOwnership(); + break; + case 50: + returnValue = getFemaleInParty(); + break; + case 51: + returnValue = getMaleInParty(); + break; + case 52: + returnValue = getInboundFemaleBikeLogsum(); + break; + case 53: + returnValue = getOutboundFemaleBikeLogsum(); + break; + case 54: + returnValue = getInboundMaleBikeLogsum(); + break; + case 55: + returnValue = getOutboundMaleBikeLogsum(); + break; + case 56: + returnValue = getIvtCoeff(); + break; + case 57: + returnValue = getCostCoeff(); + break; + case 58: + returnValue = getIncomeInDollars(); + break; + case 59: + returnValue = getTransitLogSum(WTW, true) + getTransitLogSum(WTW, false); + break; + case 60: + returnValue = getTransitLogSum(WTD, true) + getTransitLogSum(DTW, false); + break; + case 61: + returnValue = getTransitLogSum(WTD, true) + getTransitLogSum(DTW, false); + break; + + case 70: return getOrigTaxiWaitTime(); + case 71: return getDestTaxiWaitTime(); + case 72: return getOrigSingleTNCWaitTime(); + case 73: return getDestSingleTNCWaitTime(); + case 74: return getOrigSharedTNCWaitTime(); + case 75: return getDestSharedTNCWaitTime(); + case 76: return getUseOwnedAV(); + + + + + + + + + + case 90: + returnValue = getNmWalkTimeOut(); + break; + case 91: + returnValue = getNmWalkTimeIn(); + break; + case 92: + returnValue = getNmBikeTimeOut(); + break; + case 93: + returnValue = getNmBikeTimeIn(); + break; + case 96: + returnValue = getOriginMgra(); + break; + case 97: + returnValue = getDestMgra(); + break; + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + } + + return returnValue; + + } +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTransponderChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTransponderChoiceDMU.java new file mode 100644 index 0000000..0ac87da --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTransponderChoiceDMU.java @@ -0,0 +1,56 @@ +package org.sandag.abm.application; + +import java.util.HashMap; +import org.sandag.abm.ctramp.TransponderChoiceDMU; + +public class SandagTransponderChoiceDMU + extends TransponderChoiceDMU +{ + + public SandagTransponderChoiceDMU() + { + super(); + setupMethodIndexMap(); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getAutoOwnership", 0); + methodIndexMap.put("getPctHighIncome", 1); + methodIndexMap.put("getPctMultipleAutos", 2); + methodIndexMap.put("getAvgtts", 3); + methodIndexMap.put("getDistanceFromFacility", 4); + methodIndexMap.put("getPctAltTimeCBD", 5); + methodIndexMap.put("getAvgTransitAccess", 6); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getAutoOwnership(); + case 1: + return getPctIncome100Kplus(); + case 2: + return getPctTazMultpleAutos(); + case 3: + return getExpectedTravelTimeSavings(); + case 4: + return getTransponderDistance(); + case 5: + return getPctDetour(); + case 6: + return getAccessibility(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTripModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTripModeChoiceDMU.java new file mode 100644 index 0000000..a2a3b2f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTripModeChoiceDMU.java @@ -0,0 +1,572 @@ +package org.sandag.abm.application; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.BikeLogsum; +import org.sandag.abm.ctramp.BikeLogsumSegment; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Tour; +import org.sandag.abm.ctramp.TripModeChoiceDMU; + +import com.pb.common.calculator.IndexValues; + +public class SandagTripModeChoiceDMU + extends TripModeChoiceDMU +{ + private int setPersonHhTourCounter = 0; + private BikeLogsum bls; + protected double femaleBikeLogsum; + protected double maleBikeLogsum; + protected double femaleInParty; + protected double maleInParty; + + public SandagTripModeChoiceDMU(ModelStructure modelStructure, Logger aLogger) + { + super(modelStructure, aLogger); + setupMethodIndexMap(); + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU destination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getEscortTour() + { + return escortTour; + } + + @Override + public int getTourCategoryJoint() + { + return jointTour; + } + + @Override + public int getNumberOfParticipantsInJointTour() + { + return partySize; + } + + public int getAutos() + { + return autos; + } + + public int getAge() + { + return age; + } + + public int getAdults() + { + return adults; + } + + public int getHhSize() + { + return hhSize; + } + + public int getFemale() + { + return personIsFemale; + } + + public int getIncome() + { + return incomeInDollars; + } + + @Override + public float getTimeOutbound() + { + return departPeriod; + } + + @Override + public float getTimeInbound() + { + return arrivePeriod; + } + + public int getTimeTrip() + { + return tripPeriod; + } + + public int getOutboundStops() + { + return outboundStops; + } + + public int getReturnStops() + { + return inboundStops; + } + + public int getTourModeIsDA() + { + return tourModeIsDA; + } + + public int getTourModeIsS2() + { + return tourModeIsS2; + } + + public int getTourModeIsS3() + { + return tourModeIsS3; + } + + public int getTourModeIsWalk() + { + return tourModeIsWalk; + } + + public int getTourModeIsBike() + { + return tourModeIsBike; + } + + public int getTourModeIsWTran() + { + return tourModeIsWTran; + } + + public int getTourModeIsPNR() + { + return tourModeIsPnr; + } + + public int getTourModeIsKNR() + { + return tourModeIsKnr; + } + + public int getTourModeIsSchBus() + { + return tourModeIsSchBus; + } + + public void setBikeLogsum(BikeLogsum bls) + { + this.bls = bls; + } + + public void setPersonObject(Person person) + { + super.setPersonObject(person); + checkSetPersonHhTour(); + } + + public void setHouseholdObject(Household hh) + { + super.setHouseholdObject(hh); + checkSetPersonHhTour(); + } + + public void setTourObject(Tour tour) + { + super.setTourObject(tour); + checkSetPersonHhTour(); + } + + private void checkSetPersonHhTour() + { + setPersonHhTourCounter = (setPersonHhTourCounter+1) % 3; + if (setPersonHhTourCounter == 0) { + setParty(person,tour,hh); + } + } + + public double getFemaleInParty() + { + return femaleInParty; + } + + public double getMaleInParty() + { + return maleInParty; + } + + public void setParty(Person person, Tour tour, Household hh) + { + if (person != null) { + femaleInParty = person.getPersonIsFemale(); + maleInParty = femaleInParty == 0 ? 1 : 0; + } else { + femaleInParty = 0; + maleInParty = 0; + for (int participant : tour.getPersonNumArray()) { + if (hh.getPerson(participant).getPersonIsFemale() == 1) + femaleInParty = 1; + else + maleInParty = 1; + } + } + } + + public void setBikeLogsum(int origin, int dest, boolean inbound) { + boolean mandatory = tour.getTourPrimaryPurposeIndex() <= 3; + femaleBikeLogsum = bls.getLogsum(new BikeLogsumSegment(true,mandatory,inbound),origin,dest); + maleBikeLogsum = bls.getLogsum(new BikeLogsumSegment(false,mandatory,inbound),origin,dest); + } + + public double getFemaleBikeLogsum() { + return femaleBikeLogsum; + } + + public double getMaleBikeLogsum() { + return maleBikeLogsum; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getAutos", 1); + methodIndexMap.put("getAdults", 2); + methodIndexMap.put("getHhSize", 3); + methodIndexMap.put("getFemale", 4); + methodIndexMap.put("getIncomeCategory", 5); + methodIndexMap.put("getTimeOutbound", 6); + methodIndexMap.put("getTimeInbound", 7); + methodIndexMap.put("getTimeTrip", 8); + methodIndexMap.put("getTourCategoryJoint", 9); + methodIndexMap.put("getNumberOfParticipantsInJointTour", 10); + methodIndexMap.put("getOutboundStops", 11); + methodIndexMap.put("getReturnStops", 12); + methodIndexMap.put("getFirstTrip", 13); + methodIndexMap.put("getLastTrip", 14); + methodIndexMap.put("getTourModeIsDA", 15); + methodIndexMap.put("getTourModeIsS2", 16); + methodIndexMap.put("getTourModeIsS3", 17); + methodIndexMap.put("getTourModeIsWalk", 18); + methodIndexMap.put("getTourModeIsBike", 19); + methodIndexMap.put("getTourModeIsWTran", 20); + methodIndexMap.put("getTourModeIsPNR", 21); + methodIndexMap.put("getTourModeIsKNR", 22); + methodIndexMap.put("getODUDen", 23); + methodIndexMap.put("getOEmpDen", 24); + methodIndexMap.put("getOTotInt", 25); + methodIndexMap.put("getDDUDen", 26); + methodIndexMap.put("getDEmpDen", 27); + methodIndexMap.put("getDTotInt", 28); + methodIndexMap.put("getPTazTerminalTime", 30); + methodIndexMap.put("getATazTerminalTime", 31); + methodIndexMap.put("getAge", 32); + methodIndexMap.put("getTourModeIsSchBus", 33); + methodIndexMap.put("getEscortTour", 34); + methodIndexMap.put("getAutoModeAllowedForTripSegment", 35); + methodIndexMap.put("getWalkModeAllowedForTripSegment", 36); + methodIndexMap.put("getSegmentIsIk", 37); + methodIndexMap.put("getReimburseAmount", 38); + methodIndexMap.put("getMonthlyParkingCostTourDest", 39); + methodIndexMap.put("getDailyParkingCostTourDest", 40); + methodIndexMap.put("getHourlyParkingCostTourDest", 41); + methodIndexMap.put("getHourlyParkingCostTripOrig", 42); + methodIndexMap.put("getHourlyParkingCostTripDest", 43); + methodIndexMap.put("getTripOrigIsTourDest", 44); + methodIndexMap.put("getTripDestIsTourDest", 45); + methodIndexMap.put("getFreeOnsite", 46); + methodIndexMap.put("getPersonType", 47); + + methodIndexMap.put("getFemaleInParty", 50); + methodIndexMap.put("getMaleInParty", 51); + methodIndexMap.put("getFemaleBikeLogsum", 52); + methodIndexMap.put("getMaleBikeLogsum", 53); + + methodIndexMap.put("getTransponderOwnership", 54); + methodIndexMap.put("getWorkTimeFactor", 55); + methodIndexMap.put("getNonWorkTimeFactor", 56); + methodIndexMap.put("getJointTourTimeFactor", 57); + + methodIndexMap.put("getInbound",58); + + methodIndexMap.put("getIncomeInDollars",59); + methodIndexMap.put("getIvtCoeff", 60); + methodIndexMap.put("getCostCoeff", 61); + + methodIndexMap.put("getWalkSetLogSum", 62); + methodIndexMap.put("getPnrSetLogSum", 63); + methodIndexMap.put("getKnrSetLogSum", 64); + + methodIndexMap.put("getWaitTimeTaxi", 70); + methodIndexMap.put("getWaitTimeSingleTNC", 71); + methodIndexMap.put("getWaitTimeSharedTNC", 72); + methodIndexMap.put("getUseOwnedAV", 73); + + methodIndexMap.put("getNm_walkTime", 90); + methodIndexMap.put("getNm_bikeTime", 91); + + methodIndexMap.put("getOriginMgra", 93); + methodIndexMap.put("getDestMgra", 94); + + + methodIndexMap.put("getTourModeIsTncTransit", 95); + methodIndexMap.put("getTourModeIsMaas", 96); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 1: + returnValue = getAutos(); + break; + case 2: + returnValue = getAdults(); + break; + case 3: + returnValue = getHhSize(); + break; + case 4: + returnValue = getFemale(); + break; + case 5: + returnValue = getIncome(); + break; + case 6: + returnValue = getTimeOutbound(); + break; + case 7: + returnValue = getTimeInbound(); + break; + case 8: + returnValue = getTimeTrip(); + break; + case 9: + returnValue = getTourCategoryJoint(); + break; + case 10: + returnValue = getNumberOfParticipantsInJointTour(); + break; + case 11: + returnValue = getOutboundStops(); + break; + case 12: + returnValue = getReturnStops(); + break; + case 13: + returnValue = getFirstTrip(); + break; + case 14: + returnValue = getLastTrip(); + break; + case 15: + returnValue = getTourModeIsDA(); + break; + case 16: + returnValue = getTourModeIsS2(); + break; + case 17: + returnValue = getTourModeIsS3(); + break; + case 18: + returnValue = getTourModeIsWalk(); + break; + case 19: + returnValue = getTourModeIsBike(); + break; + case 20: + returnValue = getTourModeIsWTran(); + break; + case 21: + returnValue = getTourModeIsPnr(); + break; + case 22: + returnValue = getTourModeIsKnr(); + break; + case 23: + returnValue = getODUDen(); + break; + case 24: + returnValue = getOEmpDen(); + break; + case 25: + returnValue = getOTotInt(); + break; + case 26: + returnValue = getDDUDen(); + break; + case 27: + returnValue = getDEmpDen(); + break; + case 28: + returnValue = getDTotInt(); + break; + case 30: + returnValue = getPTazTerminalTime(); + break; + case 31: + returnValue = getATazTerminalTime(); + break; + case 32: + returnValue = getAge(); + break; + case 33: + returnValue = getTourModeIsSchBus(); + break; + case 34: + returnValue = getEscortTour(); + break; + case 35: + returnValue = getAutoModeAllowedForTripSegment(); + break; + case 36: + returnValue = getWalkModeAllowedForTripSegment(); + break; + case 37: + returnValue = getSegmentIsIk(); + break; + case 38: + returnValue = getReimburseAmount(); + break; + case 39: + returnValue = getMonthlyParkingCostTourDest(); + break; + case 40: + returnValue = getDailyParkingCostTourDest(); + break; + case 41: + returnValue = getHourlyParkingCostTourDest(); + break; + case 42: + returnValue = getHourlyParkingCostTripOrig(); + break; + case 43: + returnValue = getHourlyParkingCostTripDest(); + break; + case 44: + returnValue = getTripOrigIsTourDest(); + break; + case 45: + returnValue = getTripDestIsTourDest(); + break; + case 46: + returnValue = getFreeOnsite(); + break; + case 47: + returnValue = getPersonType(); + break; + case 50: + returnValue = getFemaleInParty(); + break; + case 51: + returnValue = getMaleInParty(); + break; + case 52: + returnValue = getFemaleBikeLogsum(); + break; + case 53: + returnValue = getMaleBikeLogsum(); + break; + case 54: + returnValue = getTransponderOwnership(); + break; + case 55: + returnValue = getWorkTimeFactor(); + break; + case 56: + returnValue = getNonWorkTimeFactor(); + break; + case 57: + returnValue = getJointTourTimeFactor(); + break; + case 58: + returnValue = getInbound(); + break; + case 59: + returnValue = getIncomeInDollars(); + break; + case 60: + returnValue = getIvtCoeff(); + break; + case 61: + returnValue = getCostCoeff(); + break; + case 62: + returnValue = getTransitLogSum(WTW); + break; + case 63: + if ( outboundHalfTourDirection == 1 ) + returnValue = getTransitLogSum(DTW); + else + returnValue = getTransitLogSum(WTD); + break; + case 64: + if ( outboundHalfTourDirection == 1 ) + returnValue = getTransitLogSum(DTW); + else + returnValue = getTransitLogSum(WTD); + break; + case 70: return getWaitTimeTaxi(); + case 71: return getWaitTimeSingleTNC(); + case 72: return getWaitTimeSharedTNC(); + case 73: return getUseOwnedAV(); + case 90: + returnValue = getNm_walkTime(); + break; + case 91: + returnValue = getNm_bikeTime(); + break; + case 93: + returnValue = getOriginMgra(); + break; + case 94: + returnValue = getDestMgra(); + break; + case 95: + returnValue = getTourModeIsTncTransit(); + break; + case 96: + returnValue = getTourModeIsMaas(); + break; + + + default: + logger.error( "method number = " + variableIndex + " not found" ); + throw new RuntimeException( "method number = " + variableIndex + " not found" ); + } + return returnValue; + } +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/application/SandagTripTables.java b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTripTables.java new file mode 100644 index 0000000..a8c81f0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/application/SandagTripTables.java @@ -0,0 +1,904 @@ +package org.sandag.abm.application; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixIO32BitJvm; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.util.ResourceUtil; + +public class SandagTripTables +{ + + private static Logger logger = Logger.getLogger("tripTables"); + + public static final int MATRIX_DATA_SERVER_PORT = 1171; + + private static final String VOT_THRESHOLD_LOW = "valueOfTime.threshold.low"; + private static final String VOT_THRESHOLD_MED = "valueOfTime.threshold.med"; + + + private TableDataSet indivTripData; + private TableDataSet jointTripData; + + // Some parameters + private int[] modeIndex; // an + private int[] matrixIndex; // an + + // array modes: AUTO, NON-MOTORIZED, TRANSIT, OTHER + private int autoModes = 0; + private int tranModes = 0; + private int nmotModes = 0; + private int othrModes = 0; + + // one file per time period + private int numberOfPeriods; + + private String[] purposeName = {"Work", "University", "School", + "Escort", "Shop", "Maintenance", "EatingOut", "Visiting", "Discretionary", "WorkBased"}; + + // matrices are indexed by modes (auto, non-mot,tran,other), valueoftime bins, and sub-modes(shared2gp, etc). + private Matrix[][][] matrix; + + private HashMap rbMap; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private TapDataManager tapManager; + private SandagModelStructure modelStructure; + + + private float[][] CBDVehicles; // an // period + private float[][] PNRVehicles; // an + private float sampleRate; + private int iteration; + private MatrixType mt; + private MatrixDataServerRmi ms; + + private String[] indivColumns = {"stop_period", "orig_mgra", + "dest_mgra", "trip_mode", "inbound", "trip_board_tap", "trip_alight_tap", "set", + "parking_mgra", "tour_purpose", "valueOfTime", "transponder_avail" }; + + private String[] jointColumns = {"stop_period", "orig_mgra", + "dest_mgra", "trip_mode", "inbound", "trip_board_tap", "trip_alight_tap", "set", + "parking_mgra", "tour_purpose", "num_participants", "valueOfTime", "transponder_avail"}; + + private HashMap averageOcc3Plus; // a + + private float valueOfTimeThresholdLow = 0; + private float valueOfTimeThresholdMed = 0; + //value of time bins by mode group + int[] votBins = {3,1,1,1}; + + boolean segmentByTransponderOwnership; + + public int numSkimSets; + + + /** + * Constructor. + * + * @param rbMap + * HashMap formed from a property map, which includes environment + * variables and arguments passed in as -d to VM + * @param sampleRate + * Sample rate 0->1.0 + * @param iteration + * Iteration number, program will look for trip file names with + * _iteration appended + */ + public SandagTripTables(HashMap rbMap, float sampleRate, int iteration) + { + + this.rbMap = rbMap; + numSkimSets = Util.getIntegerValueFromPropertyMap(rbMap,"utility.bestTransitPath.skim.sets"); + + segmentByTransponderOwnership = Util.getBooleanValueFromPropertyMap(rbMap,"Results.segmentByTransponderOwnership"); + tazManager = TazDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + modelStructure = new SandagModelStructure(); + + // Time period limits + numberOfPeriods = modelStructure.getNumberModelPeriods(); + + // number of modes + modeIndex = new int[modelStructure.MAXIMUM_TOUR_MODE_ALT_INDEX + 1]; + matrixIndex = new int[modeIndex.length]; + + // set the mode arrays + for (int i = 1; i < modeIndex.length; ++i) + { + if (modelStructure.getTourModeIsSovOrHov(i)) + { + modeIndex[i] = 0; + matrixIndex[i] = autoModes; + ++autoModes; + logger.info("Tour mode "+i+" is auto"); + } else if (modelStructure.getTourModeIsNonMotorized(i)) + { + modeIndex[i] = 1; + matrixIndex[i] = nmotModes; + ++nmotModes; + logger.info("Tour mode "+i+" is non-motorized"); + } else if (modelStructure.getTourModeIsWalkTransit(i) + || modelStructure.getTourModeIsDriveTransit(i)) + { + modeIndex[i] = 2; + matrixIndex[i] = tranModes; + ++tranModes; + logger.info("Tour mode "+i+" is transit"); + } else + { + modeIndex[i] = 3; + matrixIndex[i] = othrModes; + ++othrModes; + logger.info("Tour mode "+i+" is other"); + } + } + logger.info("Total auto modes = "+autoModes); + logger.info("Total non-motorized modes = "+nmotModes); + logger.info("Total transit modes = "+tranModes); + logger.info("Total other modes = "+othrModes); + + readOccupancies(); + // Initialize arrays (need for all periods, so initialize here) + CBDVehicles = new float[mgraManager.getMaxMgra() + 1][numberOfPeriods]; + PNRVehicles = new float[tapManager.getMaxTap() + 1][numberOfPeriods]; + + setSampleRate(sampleRate); + setIteration(iteration); + + //value of time thresholds + valueOfTimeThresholdLow = new Float(rbMap.get(VOT_THRESHOLD_LOW)); + valueOfTimeThresholdMed = new Float(rbMap.get(VOT_THRESHOLD_MED)); + + } + + /** + * Read occupancies from the properties file and store in the + * averageOcc3Plus HashMap + */ + public void readOccupancies() + { + + averageOcc3Plus = new HashMap(); + + for (int i = 0; i < purposeName.length; ++i) + { + String searchString = "occ3plus.purpose." + purposeName[i]; + float occupancy = new Float(Util.getStringValueFromPropertyMap(rbMap, searchString)); + averageOcc3Plus.put(purposeName[i], occupancy); + } + } + + /** + * Initialize all the matrices for the given time period. + * + * @param periodName + * The name of the time period. + */ + public void initializeMatrices(String periodName) + { + + /* + * This won't work because external stations aren't listed in the MGRA + * file int[] tazIndex = tazManager.getTazsOneBased(); int tazs = + * tazIndex.length-1; + */ + // Instead, use maximum taz number + int maxTaz = tazManager.getMaxTaz(); + int[] tazIndex = new int[maxTaz + 1]; + + // assume zone numbers are sequential + for (int i = 1; i < tazIndex.length; ++i) + tazIndex[i] = i; + + // get the tap index + int[] tapIndex = tapManager.getTaps(); + int taps = tapIndex.length - 1; + + // Initialize matrices; one for each mode group (auto, non-mot, tran, + // other) and value of time group + // All matrices will be dimensioned by TAZs except for transit, which is + // dimensioned by TAPs + int numberOfModes = 4; + matrix = new Matrix[numberOfModes][][]; + for (int i = 0; i < numberOfModes; ++i) + { + matrix[i] = new Matrix[votBins[i]][]; + + for(int j = 0; j< votBins[i];++j){ + + String modeName; + + + if (i == 0) + { + + int autoModeSegments = autoModes; + String transponderLabel = ""; + + if(segmentByTransponderOwnership) { + autoModeSegments *=2; //twice as many since segmentation would be by number of auto modes and by 0,1 for ownership + transponderLabel = "NOTRPDR"; + } + matrix[i][j] = new Matrix[autoModeSegments]; + + for (int k = 0; k < autoModes; ++k) + { + modeName = modelStructure.getModeName(k + 1); + matrix[i][j][k] = new Matrix(modeName + transponderLabel + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + + for (int k = autoModes; k < autoModeSegments; ++k) + { + modeName = modelStructure.getModeName((k + 1)-autoModes); + matrix[i][j][k] = new Matrix(modeName + "TRPDR"+ "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + + + + } else if (i == 1){ + + matrix[i][j] = new Matrix[nmotModes]; + for (int k = 0; k < nmotModes; ++k) + { + modeName = modelStructure.getModeName(k + 1 + autoModes); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + + } else if (i == 2){ + + matrix[i][j] = new Matrix[tranModes*numSkimSets]; + for (int k = 0; k < tranModes; ++k) + { + for(int l=0;l1) + votBin = getValueOfTimeBin(valueOfTime); + + if (mode == 0) + { + if(segmentByTransponderOwnership) { + int ownsTransponder = (int) tripData.getValueAt(i, "transponder_avail"); + if(ownsTransponder==1) + mat = mat + SandagModelStructure.TRIP_SOV_ALTS.length + SandagModelStructure.TRIP_HOV_ALTS.length; + } + // look up what taz the parking mgra is in, and re-assign the + // trip destination to the parking taz + if (parkingMGRA > 0) + { + parkingTaz = mgraManager.getTaz(parkingMGRA); + destinationTAZ = parkingTaz; + CBDVehicles[parkingMGRA][period] = CBDVehicles[parkingMGRA][period] + + vehicleTrips; + } + + + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + vehicleTrips)); + } else if (mode == 1) + { + + + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } else if (mode == 2) + { + + if (boardTap == 0 || alightTap == 0) continue; + + //store transit trips in matrices + mat = (matrixIndex[tripMode]*numSkimSets)+set; + + float value=0; + try{ + value = matrix[mode][votBin][mat].getValueAt(boardTap, alightTap); + }catch(Exception e){ + + logger.fatal("Error trying to get transit trips from matrix"); + logger.fatal("boardTap,alightTap,set: "+boardTap+","+alightTap+","+set); + logger.fatal("tripMode,mode,votBin,mat: "+tripMode+","+mode+","+votBin+","+mat); + logger.fatal("number of skimsets: "+numSkimSets); + logger.fatal("total board taps in matrix:" + matrix[mode][votBin][mat].getRowCount()); + logger.fatal("total alight taps in matrix:" + matrix[mode][votBin][mat].getColumnCount()); + throw new RuntimeException(e); + } + matrix[mode][votBin][mat].setValueAt(boardTap, alightTap, (value + personTrips)); + + // Store PNR transit trips in SOV free mode skim (mode 0 mat 0) + if (modelStructure.getTourModeIsDriveTransit(tripMode)) + { + + // add the tNCVehicle trip portion to the trip table + if (inbound == 0) + { // from origin to lot (boarding tap) + int PNRTAZ = tapManager.getTazForTap(boardTap); + + + value = matrix[0][votBin][0].getValueAt(originTAZ, PNRTAZ); + matrix[0][votBin][0].setValueAt(originTAZ, PNRTAZ, (value + vehicleTrips)); + + // and increment up the array of parked vehicles at the + // lot + ++PNRVehicles[boardTap][period]; + + } else + { // from lot (alighting tap) to destination + int PNRTAZ = tapManager.getTazForTap(alightTap); + + + value = matrix[0][votBin][0].getValueAt(PNRTAZ, destinationTAZ); + matrix[0][votBin][0].setValueAt(PNRTAZ, destinationTAZ, (value + vehicleTrips)); + } + + } + } else + { + + + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } + } + + //logger.info("End creating trip tables for period " + timePeriod); + } + + /** + * Return the value of time bin 0 through 2 based on the thresholds provided in the property map + * @param valueOfTime + * @return value of time bin 0 through 2 + */ + public int getValueOfTimeBin(float valueOfTime){ + + if(valueOfTime1) + end[i][j] = "_" + per + "_"+ votBinName[j]+ ".omx"; + else + end[i][j] = "_" + per + ".omx"; + } + } + + for (int i = 0; i < 4; ++i) + { + for(int j = 0; j < votBins[i];++j){ + try + { + //Delete the file if it exists + File f = new File(fileName[i]+end[i][j]); + if(f.exists()){ + logger.info("Deleting existing trip file: "+fileName[i]+end[i][j]); + f.delete(); + } + + if (ms != null) ms.writeMatrixFile(fileName[i]+end[i][j], matrix[i][j], mt); + else writeMatrixFile(fileName[i]+end[i][j], matrix[i][j]); + } catch (Exception e) + { + logger.error("exception caught writing " + mt.toString() + " matrix file = " + + fileName[i] +end[i][j] + ", for mode index = " + i, e); + throw new RuntimeException(); + } + } + } + + } + + + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + public void writeMatrixFile(String fileName, Matrix[] m) + { + + // auto trips + MatrixWriter writer = MatrixWriter.createWriter(fileName); + String[] names = new String[m.length]; + + for (int i = 0; i < m.length; i++) + { + names[i] = m[i].getName(); + logger.info(m[i].getName() + " has " + m[i].getRowCount() + " rows, " + + m[i].getColumnCount() + " cols, and a total of " + m[i].getSum()); + } + + writer.writeMatrices(names, m); + } + + /** + * Connect to matrix server + */ + private void connectToMatrixServer() + { + + + // get matrix server address and port + String matrixServerAddress = Util.getStringValueFromPropertyMap(rbMap, "RunModel.MatrixServerAddress"); + int serverPort = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, "RunModel.MatrixServerPort")); + + ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + logger.info("connected to matrix data server"); + } + + /** + * Write a file of vehicles parking in parking-constrained areas by MGRA. + * + * @param fileName + * The name of the csv file to write to. + */ + public void writeCBDFile(String fileName) + { + + try + { + FileWriter writer = new FileWriter(fileName); + + // write header + writer.append("MGRA,"); + + for (int j = 0; j < numberOfPeriods; ++j) + writer.append(modelStructure.getModelPeriodLabel(j) + ","); + + writer.append("Total\n"); + + // iterate through mgras + for (int i = 0; i < CBDVehicles.length; ++i) + { + + float totalVehicles = 0; + for (int j = 0; j < numberOfPeriods; ++j) + { + totalVehicles += CBDVehicles[i][j]; + } + + // only write the mgra if there are vehicles parked there + if (totalVehicles > 0) + { + + writer.append(Integer.toString(i)); + + // iterate through periods + for (int j = 0; j < numberOfPeriods; ++j) + writer.append("," + Float.toString(CBDVehicles[i][j])); + + writer.append("," + Float.toString(totalVehicles) + "\n"); + writer.flush(); + } + } + writer.flush(); + writer.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + + } + + /** + * Write a file of vehicles parking in PNR lots by TAP. + * + * @param fileName + * The name of the csv file to write to. + */ + public void writePNRFile(String fileName) + { + + try + { + FileWriter writer = new FileWriter(fileName); + + // write header + writer.append("TAP,"); + + for (int j = 0; j < numberOfPeriods; ++j) + writer.append(modelStructure.getModelPeriodLabel(j) + ","); + + writer.append("Total\n"); + + // iterate through taps + for (int i = 0; i < PNRVehicles.length; ++i) + { + + float totalVehicles = 0; + for (int j = 0; j < numberOfPeriods; ++j) + { + totalVehicles += PNRVehicles[i][j]; + } + + // only write the tap if there are vehicles parked there + if (totalVehicles > 0) + { + + writer.append(Integer.toString(i)); + + // iterate through periods + for (int j = 0; j < numberOfPeriods; ++j) + writer.append("," + Float.toString(PNRVehicles[i][j])); + + writer.append("," + Float.toString(totalVehicles) + "\n"); + writer.flush(); + } + } + writer.flush(); + writer.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + + } + + /** + * Set the sample rate + * + * @param sampleRate + * The sample rate, used for expanding trips + */ + public void setSampleRate(float sampleRate) + { + this.sampleRate = sampleRate; + } + + /** + * Set the iteration number + * + * @param sampleRate + * The iteration number, should be appended to trip files as + * _iteration + */ + public void setIteration(int iteration) + { + this.iteration = iteration; + } + + + public static void main(String[] args) + { + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Trip Table Generation Program using CT-RAMP version %s", + CtrampApplication.VERSION)); + + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + + float sampleRate = 1.0f; + int iteration = 1; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + + logger.info(String.format("-sampleRate %.4f.", sampleRate)); + logger.info("-iteration " + iteration); + + SandagTripTables tripTables = new SandagTripTables(pMap, sampleRate, iteration); + + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + tripTables.mt = MatrixType.lookUpMatrixType(matrixTypeName); + tripTables.createTripTables(tripTables.mt); + + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderDmuFactory.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderDmuFactory.java new file mode 100644 index 0000000..00b2800 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderDmuFactory.java @@ -0,0 +1,51 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.crossborder; + +import java.io.Serializable; + +/** + * ArcCtrampDmuFactory is a class that creates Visitor Model DMU objects + * + * @author Joel Freedman + */ +public class CrossBorderDmuFactory + implements CrossBorderDmuFactoryIf, Serializable +{ + + private CrossBorderModelStructure crossBorderModelStructure; + + public CrossBorderDmuFactory(CrossBorderModelStructure modelStructure) + { + this.crossBorderModelStructure = modelStructure; + } + + public CrossBorderTourModeChoiceDMU getCrossBorderTourModeChoiceDMU() + { + return new CrossBorderTourModeChoiceDMU(crossBorderModelStructure); + } + + public CrossBorderTripModeChoiceDMU getCrossBorderTripModeChoiceDMU() + { + return new CrossBorderTripModeChoiceDMU(crossBorderModelStructure, null); + } + + public CrossBorderStationDestChoiceDMU getCrossBorderStationChoiceDMU() + { + return new CrossBorderStationDestChoiceDMU(crossBorderModelStructure); + } + + public CrossBorderStopLocationChoiceDMU getCrossBorderStopLocationChoiceDMU() + { + return new CrossBorderStopLocationChoiceDMU(crossBorderModelStructure); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderDmuFactoryIf.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderDmuFactoryIf.java new file mode 100644 index 0000000..70b68da --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderDmuFactoryIf.java @@ -0,0 +1,17 @@ +package org.sandag.abm.crossborder; + +/** + * A DMU factory interface + */ +public interface CrossBorderDmuFactoryIf +{ + + CrossBorderTourModeChoiceDMU getCrossBorderTourModeChoiceDMU(); + + CrossBorderStationDestChoiceDMU getCrossBorderStationChoiceDMU(); + + CrossBorderTripModeChoiceDMU getCrossBorderTripModeChoiceDMU(); + + CrossBorderStopLocationChoiceDMU getCrossBorderStopLocationChoiceDMU(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderModel.java new file mode 100644 index 0000000..48f2c2b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderModel.java @@ -0,0 +1,525 @@ +package org.sandag.abm.crossborder; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.crossborder.CrossBorderTourManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; +import com.pb.sawdust.util.concurrent.DnCRecursiveAction; + +public class CrossBorderModel +{ + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + public static final String RUN_MODEL_CONCURRENT_PROPERTY_KEY = "crossBorder.run.concurrent"; + public static final String CONCURRENT_PARALLELISM_PROPERTY_KEY = "crossBorder.concurrent.parallelism"; + + private static final Logger LOGGER = Logger.getLogger(SandagTourBasedModel.class); + private static final Object INITIALIZATION_LOCK = new Object(); + + private MatrixDataServerRmi ms; + private HashMap rbMap; + private AutoTazSkimsCalculator tazDistanceCalculator; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private CrossBorderTourManager tourManager; + + private boolean seek; + private int traceId; + private double sampleRate = 1; + + /** + * Constructor + * + * @param rbMap + */ + public CrossBorderModel(HashMap rbMap) + { + this.rbMap = rbMap; + + synchronized (INITIALIZATION_LOCK) + { // lock to make sure only one of + // these actually initializes + // things so we don't cross + // threads + mgraManager = MgraDataManager.getInstance(rbMap); + tazManager = TazDataManager.getInstance(rbMap); + tourManager = new CrossBorderTourManager(rbMap); + } + + seek = Boolean.valueOf(Util.getStringValueFromPropertyMap(rbMap, "crossBorder.seek")); + traceId = Integer.valueOf(Util.getStringValueFromPropertyMap(rbMap, "crossBorder.trace")); + + } + + // global variable used for reporting + private static final AtomicInteger TOUR_COUNTER = new AtomicInteger(0); + private final AtomicBoolean calculatorsInitialized = new AtomicBoolean(false); + + /** + * Run the model for a subset of tours in an array of tours. + * + * @param tours + * The array of tours. + * @param start + * The starting index of the tours to process. + * @param end + * The (exclusive) ending index of the tours to process. + */ + private void runModel(CrossBorderTour[] tours, int start, int end) + { + CrossBorderModelStructure modelStructure = new CrossBorderModelStructure(); + CrossBorderDmuFactoryIf dmuFactory = new CrossBorderDmuFactory(modelStructure); + + if (!calculatorsInitialized.get()) + { + // only let one thread in to initialize + synchronized (calculatorsInitialized) + { + // if still not initialized, then this is the first in so do the + // initialization (otherwise skip) + if (!calculatorsInitialized.get()) + { + tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + calculatorsInitialized.set(true); + } + } + } + + CrossBorderTourTimeOfDayChoiceModel todChoiceModel = new CrossBorderTourTimeOfDayChoiceModel( + rbMap); + CrossBorderStationDestChoiceModel destChoiceModel = new CrossBorderStationDestChoiceModel( + rbMap, modelStructure, dmuFactory, tazDistanceCalculator); + CrossBorderTourModeChoiceModel tourModeChoiceModel = new CrossBorderTourModeChoiceModel(rbMap, modelStructure, dmuFactory, + tazDistanceCalculator); + + CrossBorderTripModeChoiceModel tripModeChoiceModel = new CrossBorderTripModeChoiceModel(rbMap, modelStructure, + dmuFactory, tazDistanceCalculator); + destChoiceModel.calculateSizeTerms(dmuFactory); + destChoiceModel.calculateTazProbabilities(dmuFactory); + + CrossBorderStopFrequencyModel stopFrequencyModel = new CrossBorderStopFrequencyModel(rbMap); + CrossBorderStopPurposeModel stopPurposeModel = new CrossBorderStopPurposeModel(rbMap); + + CrossBorderStopTimeOfDayChoiceModel stopTodChoiceModel = new CrossBorderStopTimeOfDayChoiceModel( + rbMap); + CrossBorderStopLocationChoiceModel stopLocationChoiceModel = new CrossBorderStopLocationChoiceModel( + rbMap, modelStructure, dmuFactory, tazDistanceCalculator); + + double[][] mgraSizeTerms = destChoiceModel.getMgraSizeTerms(); + double[][] tazSizeTerms = destChoiceModel.getTazSizeTerms(); + double[][][] mgraProbabilities = destChoiceModel.getMgraProbabilities(); + stopLocationChoiceModel.setMgraSizeTerms(mgraSizeTerms); + stopLocationChoiceModel.setTazSizeTerms(tazSizeTerms); + stopLocationChoiceModel.setMgraProbabilities(mgraProbabilities); + String purposeControlFileName = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory")+"input/crossBorder_tourPurpose_control.csv"; + + for (int i = start; i < end; i++) + { + CrossBorderTour tour = tours[i]; + + // sample tours + double rand = tour.getRandom(); + if (rand > sampleRate) continue; + + int tourCount = TOUR_COUNTER.incrementAndGet(); + if (tourCount % 1000 == 0) LOGGER.info("Processing tour " + tourCount); + + if (seek && tour.getID() != traceId) continue; + + if (tour.getID() == traceId) tour.setDebugChoiceModels(true); + + todChoiceModel.calculateTourTOD(tour); + destChoiceModel.chooseStationAndDestination(tour); + resetCrossingPurpose(purposeControlFileName,tour); + tourModeChoiceModel.chooseTourMode(tour); + stopFrequencyModel.calculateStopFrequency(tour); + stopPurposeModel.calculateStopPurposes(tour); + + int outboundStops = tour.getNumberOutboundStops(); + int inboundStops = tour.getNumberInboundStops(); + + // choose TOD for stops and location of each + if (outboundStops > 0) + { + CrossBorderStop[] stops = tour.getOutboundStops(); + for (CrossBorderStop stop : stops) + { + stopTodChoiceModel.chooseTOD(tour, stop); + stopLocationChoiceModel.chooseStopLocation(tour, stop); + } + } + if (inboundStops > 0) + { + CrossBorderStop[] stops = tour.getInboundStops(); + for (CrossBorderStop stop : stops) + { + stopTodChoiceModel.chooseTOD(tour, stop); + stopLocationChoiceModel.chooseStopLocation(tour, stop); + } + } + + // generate trips and choose mode for them + CrossBorderTrip[] trips = new CrossBorderTrip[outboundStops + inboundStops + 2]; + int tripNumber = 0; + + // outbound stops + if (outboundStops > 0) + { + CrossBorderStop[] stops = tour.getOutboundStops(); + for (CrossBorderStop stop : stops) + { + // generate a trip to the stop and choose a mode for it + trips[tripNumber] = new CrossBorderTrip(tour, stop, true); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + // generate a trip from the last stop to the tour destination + trips[tripNumber] = new CrossBorderTrip(tour, stops[stops.length - 1], false); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + + } else + { + // generate an outbound trip from the tour origin to the + // destination and choose a mode + trips[tripNumber] = new CrossBorderTrip(tour, true); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + + // inbound stops + if (inboundStops > 0) + { + CrossBorderStop[] stops = tour.getInboundStops(); + for (CrossBorderStop stop : stops) + { + // generate a trip to the stop and choose a mode for it + trips[tripNumber] = new CrossBorderTrip(tour, stop, true); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + // generate a trip from the last stop to the tour origin + trips[tripNumber] = new CrossBorderTrip(tour, stops[stops.length - 1], false); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } else + { + + // generate an inbound trip from the tour destination to the + // origin and choose a mode + trips[tripNumber] = new CrossBorderTrip(tour, false); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + + // set the trips in the tour object + tour.setTrips(trips); + + } + + } + + /** + * This class is the divide-and-conquer action (void return task) for + * running the cross-border model using the fork-join framework. The + * divisible problem is an array of tours, and the actual work is the + * {@link CrossBorderModel#runModel(CrossBorderTour[],int,int)} method, + * applied to a section of the array. + */ + private class CrossBorderModelAction + extends DnCRecursiveAction + { + private final HashMap rbMap; + private final CrossBorderTour[] tours; + + private CrossBorderModelAction(HashMap rbMap, CrossBorderTour[] tours) + { + super(0, tours.length); + this.rbMap = rbMap; + this.tours = tours; + } + + private CrossBorderModelAction(HashMap rbMap, CrossBorderTour[] tours, + long start, long length, DnCRecursiveAction next) + { + super(start, length, next); + this.rbMap = rbMap; + this.tours = tours; + } + + @Override + protected void computeAction(long start, long length) + { + runModel(tours, (int) start, (int) (start + length)); + } + + @Override + protected DnCRecursiveAction getNextAction(long start, long length, DnCRecursiveAction next) + { + return new CrossBorderModelAction(rbMap, tours, start, length, next); + } + + @Override + protected boolean continueDividing(long length) + { + // if there are 3 extra tasks queued up, then start executing + // if there are 1000 or less tours to process, then start executing + // otherwise, keep dividing to build up tasks for the threads to + // process + return getSurplusQueuedTaskCount() < 3 && length > 1000; + } + } + + /** + * Run visitor model. + */ + public void runModel() + { + tourManager.generateCrossBorderTours(); + CrossBorderTour[] tours = tourManager.getTours(); + + // get new keys to see if we want to run in concurrent mode, and the + // parallelism + // (defaults to single threaded and parallelism = # of processors) + // note that concurrent can use up memory very quickly, so setting the + // parallelism might be prudent + boolean concurrent = rbMap.containsKey(RUN_MODEL_CONCURRENT_PROPERTY_KEY) + && Boolean.valueOf(Util.getStringValueFromPropertyMap(rbMap, + RUN_MODEL_CONCURRENT_PROPERTY_KEY)); + int parallelism = rbMap.containsKey(CONCURRENT_PARALLELISM_PROPERTY_KEY) ? Integer + .valueOf(Util.getStringValueFromPropertyMap(rbMap, + CONCURRENT_PARALLELISM_PROPERTY_KEY)) : Runtime.getRuntime() + .availableProcessors(); + + if (concurrent) + { // use fork-join + CrossBorderModelAction action = new CrossBorderModelAction(rbMap, tours); + new ForkJoinPool(parallelism).execute(action); + action.getResult(); // wait for finish + } else + { // single-threaded: call the model runner in this thread + runModel(tours, 0, tours.length); + } + + tourManager.writeOutputFile(rbMap); + LOGGER.info("Cross Border Model successfully completed!"); + } + + /** + * @return the sampleRate + */ + public double getSampleRate() + { + return sampleRate; + } + + /** + * @param sampleRate + * the sampleRate to set + */ + public void setSampleRate(double sampleRate) + { + this.sampleRate = sampleRate; + } + + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + LOGGER.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + LOGGER.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * Reset tour NB crossing purpose using purpose distribution by POE from 2011 survey + */ + private void resetCrossingPurpose(String purposeControlFile, CrossBorderTour tour) { + int poe=tour.getPoe(); + double [][] purpDistributionByPoe=new double[5][CrossBorderModelStructure.NUMBER_CROSSBORDER_PURPOSES]; + + // Read the distributions by poe + for (int i=0; i<5; i++) { + purpDistributionByPoe[i] = tourManager.setPurposeDistribution(purposeControlFile,purpDistributionByPoe[i],i+3); + } + int purpose = tourManager.choosePurpose(tour.getRandom(), purpDistributionByPoe[poe]); + tour.setPurpose((byte) purpose); + } + + /** + * @param args + */ + public static void main(String[] args) + { + Runtime gfg = Runtime.getRuntime(); + long memory1; + // checking the total memeory + System.out.println("Total memory is: "+ gfg.totalMemory()); + // checking free memory + memory1 = gfg.freeMemory(); + System.out.println("Initial free memory at Xborder model: "+ memory1); + // calling the garbage collector on demand + gfg.gc(); + memory1 = gfg.freeMemory(); + System.out.println("Free memory after garbage "+ "collection: " + memory1); + + String propertiesFile = null; + HashMap pMap; + + LOGGER.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + LOGGER.info(String.format("Running Cross-Border Model")); + + if (args.length == 0) + { + LOGGER.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + float sampleRate = 1.0f; + int iteration = 1; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + + LOGGER.info("Crossborder Model:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + CrossBorderModel crossBorderModel = new CrossBorderModel(pMap); + crossBorderModel.setSampleRate(sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = crossBorderModel.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + crossBorderModel.ms = matrixServer; + } else + { + crossBorderModel.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + crossBorderModel.ms.testRemote("CrossBorderModel"); + + // these methods need to be called to set the matrix data + // manager in the matrix data server + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(crossBorderModel.ms); + } + + } + + } catch (Exception e) + { + + LOGGER.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + crossBorderModel.runModel(); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderModelStructure.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderModelStructure.java new file mode 100644 index 0000000..d8baad1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderModelStructure.java @@ -0,0 +1,106 @@ +package org.sandag.abm.crossborder; + +import org.sandag.abm.application.SandagModelStructure; + +public class CrossBorderModelStructure + extends SandagModelStructure +{ + + public static final byte NUMBER_CROSSBORDER_PURPOSES = 6; + public static final byte WORK = 0; + public static final byte SCHOOL = 1; + public static final byte CARGO = 2; + public static final byte SHOP = 3; + public static final byte VISIT = 4; + public static final byte OTHER = 5; + + public static final String[] CROSSBORDER_PURPOSES = {"WORK", "SCHOOL", "CARGO", "SHOP", + "VISIT", "OTHER" }; + + public static final byte DEPARTURE = 0; + public static final byte ARRIVAL = 1; + + public static final int AM = 0; + public static final int PM = 1; + public static final int OP = 2; + public static final int[] SKIM_PERIODS = {AM, PM, OP}; + public static final String[] SKIM_PERIOD_STRINGS = {"AM", "PM", "OP"}; + public static final int UPPER_EA = 3; + public static final int UPPER_AM = 9; + public static final int UPPER_MD = 22; + public static final int UPPER_PM = 29; + public static final String[] MODEL_PERIOD_LABELS = {"EA", "AM", "MD", "PM", "EV"}; + + public static final byte TOUR_MODES = 4; + + public static final byte DRIVEALONE = 1; + public static final byte SHARED2 = 2; + public static final byte SHARED3 = 3; + public static final byte WALK = 4; + + // note that time periods start at 1 and go to 40 + public static final byte TIME_PERIODS = 40; + + /** + * Calculate and return the destination choice size term segment + * + * @param purpose + * @return Right now, just the purpose is returned. + */ + public static int getDCSizeSegment(int purpose) + { + + return purpose; + + } + + /** + * Calculate the purpose from the dc size segment. + * + * @param segment + * The dc size segment (0-17) + * @return The purpose + */ + public static int getPurposeFromDCSizeSegment(int segment) + { + + return segment; + } + + /** + * return the Skim period index 0=am, 1=pm, 2=off-peak + */ + public static int getSkimPeriodIndex(int departPeriod) + { + + int skimPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_AM) skimPeriodIndex = AM; + else if (departPeriod <= UPPER_MD) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_PM) skimPeriodIndex = PM; + else skimPeriodIndex = OP; + + return skimPeriodIndex; + + } + + /** + * return the Model period index 0=EA, 1=AM, 2=MD, 3=PM, 4=EV + */ + public static int getModelPeriodIndex(int departPeriod) + { + + int modelPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) modelPeriodIndex = 0; + else if (departPeriod <= UPPER_AM) modelPeriodIndex = 1; + else if (departPeriod <= UPPER_MD) modelPeriodIndex = 2; + else if (departPeriod <= UPPER_PM) modelPeriodIndex = 3; + else modelPeriodIndex = 4; + + return modelPeriodIndex; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStationDestChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStationDestChoiceDMU.java new file mode 100644 index 0000000..b72dfc7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStationDestChoiceDMU.java @@ -0,0 +1,405 @@ +package org.sandag.abm.crossborder; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class CrossBorderStationDestChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger("crossBorderModel"); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected float tourDepartPeriod; + protected float tourArrivePeriod; + protected int purpose; + protected double[][] sizeTerms; // by + // purpose, + // alternative + // (station-taz + // or + // sampled + // station-mgra) + protected double[] stationSizeTerms; // by + // alternative + // (station-taz + // or + // sampled + // station-mgra) + protected double[] correctionFactors; // by + // alternative + // (sampled + // station-mgra + // pair, + // for + // full + // model + // only) + protected double[] tourModeLogsums; // by + // alternative + // (sampled + // station-mgra + // pair, + // for + // full + // model + // only) + protected int[] poeNumbers; // by + // alternative + // (station-taz + // or + // sampled + // station-mgra) + protected int[] originTazs; // by + // alternative + // (station-taz + // or + // sampled + // station-mgra) + protected int[] destinationTazs; // by + // alternative + // (station-taz + // or + // sampled + // station-mgra) + + protected double nmWalkTimeOut; + protected double nmWalkTimeIn; + protected double nmBikeTimeOut; + protected double nmBikeTimeIn; + protected double lsWgtAvgCostM; + protected double lsWgtAvgCostD; + protected double lsWgtAvgCostH; + + public CrossBorderStationDestChoiceDMU(CrossBorderModelStructure modelStructure) + { + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Get the POE number for the alternative. + * + * @param alt + * Either station-taz or sampled station-mgra + * @return + */ + public int getPoe(int alt) + { + return poeNumbers[alt]; + } + + /** + * Set the poe number array + * + * @param poeNumbers + * An array of POE numbers, one for each alternative (either + * station-taz or sampled station-mgra) + */ + public void setPoeNumbers(int[] poeNumbers) + { + this.poeNumbers = poeNumbers; + } + + /** + * Get the tour mode choice logsum for the sampled station-mgra pair. + * + * @param alt + * Sampled station-mgra + * @return + */ + public double getTourModeLogsum(int alt) + { + return tourModeLogsums[alt]; + } + + /** + * Set the tour mode choice logsums + * + * @param poeNumbers + * An array of tour mode choice logsums, one for each alternative + * (sampled station-mgra) + */ + public void setTourModeLogsums(double[] logsums) + { + this.tourModeLogsums = logsums; + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + /** + * @return the sizeTerms. The size term is the size of the alternative north + * of the border. It is indexed by alternative, where alternative is + * either taz-station pair or mgra-station pair, depending on + * whether the DMU is being used for the SOA model or the actual + * model. + */ + public double getSizeTerm(int alt) + { + return sizeTerms[purpose][alt]; + } + + /** + * @param sizeTerms + * the sizeTerms to set. The size term is the size of the + * alternative north of the border. It is indexed by alternative, + * where alternative is either taz-station pair or mgra-station + * pair, depending on whether the DMU is being used for the SOA + * model or the actual model. + */ + public void setSizeTerms(double[][] sizeTerms) + { + this.sizeTerms = sizeTerms; + } + + /** + * @return the accessibility of the station to population south of the + * border. The size term is indexed by alternative, where + * alternative is either taz-station pair or mgra-station pair, + * depending on whether the DMU is being used for the SOA model or + * the actual model. + */ + public double getStationPopulationAccessibility(int alt) + { + return stationSizeTerms[alt]; + } + + /** + * @param accessibilities + * is the accessibility of the station to population south of the + * border. The size term is indexed by alternative, where + * alternative is either taz-station pair or mgra-station pair, + * depending on whether the DMU is being used for the SOA model + * or the actual model. + */ + public void setStationPopulationAccessibilities(double[] accessibilities) + { + this.stationSizeTerms = accessibilities; + } + + /** + * @return the correctionFactors + */ + public double getCorrectionFactor(int alt) + { + return correctionFactors[alt]; + } + + /** + * @param correctionFactors + * the correctionFactors to set + */ + public void setCorrectionFactors(double[] correctionFactors) + { + this.correctionFactors = correctionFactors; + } + + /** + * @return the origin taz + */ + public int getOriginTaz(int alt) + { + return originTazs[alt]; + } + + /** + * @param originTazs + * The origin tazs to set + */ + public void setOriginTazs(int[] originTazs) + { + this.originTazs = originTazs; + } + + /** + * @return the destination taz + */ + public int getDestinationTaz(int alt) + { + return destinationTazs[alt]; + } + + /** + * @param stopTazs + * The destination tazs to set + */ + public void setDestinationTazs(int[] destinationTazs) + { + this.destinationTazs = destinationTazs; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the purpose + */ + public int getPurpose() + { + return purpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(int purpose) + { + this.purpose = purpose; + } + + public float getTimeOutbound() + { + return tourDepartPeriod; + } + + public float getTimeInbound() + { + return tourArrivePeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(float tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(float tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTimeOutbound", 0); + methodIndexMap.put("getTimeInbound", 1); + methodIndexMap.put("getStationPopulationAccessibility", 2); + methodIndexMap.put("getSizeTerm", 3); + methodIndexMap.put("getCorrectionFactor", 4); + methodIndexMap.put("getPoe", 5); + methodIndexMap.put("getPurpose", 6); + methodIndexMap.put("getTourModeLogsum", 7); + methodIndexMap.put("getOriginTaz", 8); + methodIndexMap.put("getDestinationTaz", 9); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getTimeOutbound(); + break; + case 1: + returnValue = getTimeInbound(); + break; + case 2: + returnValue = getStationPopulationAccessibility(arrayIndex); + break; + case 3: + returnValue = getSizeTerm(arrayIndex); + break; + case 4: + returnValue = getCorrectionFactor(arrayIndex); + break; + case 5: + returnValue = getPoe(arrayIndex); + break; + case 6: + returnValue = getPurpose(); + break; + case 7: + returnValue = getTourModeLogsum(arrayIndex); + break; + case 8: + returnValue = getOriginTaz(arrayIndex); + break; + case 9: + returnValue = getDestinationTaz(arrayIndex); + break; + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStationDestChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStationDestChoiceModel.java new file mode 100644 index 0000000..14a6600 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStationDestChoiceModel.java @@ -0,0 +1,818 @@ +package org.sandag.abm.crossborder; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + +/** + * This class is used for both the sample of alternatives and the full + * destination choice model for border crossing tours. + * + * The model first calculates a set of station-level logsums which represent the + * attractiveness of each station based upon the accessibility to Mexico + * populations (taking into account population size of Colonias and distance + * between each station and each Colonia. The model then creates a sample of + * alternatives where each alternative is a pair of border crossing station + * (entry MGRA) and destination MGRA in San Diego County, by tour purpose. This + * is sampled from for each tour, and a mode choice logsum is calculated for + * each station-MGRA pair. The full destination choice model is run on the + * sample with the mode choice logsums influencing station - destination choice, + * and a station-MGRA pair is chosen for each tour. + * + * @author Freedman + * + */ +public class CrossBorderStationDestChoiceModel +{ + + private double[][] mgraSizeTerms; // by purpose, MGRA + private double[][] tazSizeTerms; // by purpose, TAZ + private double[][] tazStationProbabilities; // by purpose, station-TAZ + // alternative + private double[][][] mgraProbabilities; // by purpose, TAZ, MGRA + private double[] stationLogsums; // by entry station, logsum + // from colonia to + // station + private double[] soaStationLogsums; // by station-TAZ + // alternative, station + // logsums + private double[][] soaSizeTerms; // by purpose, station-TAZ + // alternative, + // size terms for tazs + private int[] soaOriginTazs; // by station-TAZ + // alternative, origin Taz + private int[] soaDestinationTazs; // by station-TAZ + // alternative, destination + // Taz + + private int[] sampledDestinationMgra; // destination mgra for each + // of n + // samples + private int[] sampledEntryMgra; // entry mgra for each of n + // samples + private double[][] sampledSizeTerms; // size term for each of n + // samples (1st + // dimension is purpose) + private double[] sampledStationLogsums; // station logsum for each of + // n + // samples + private int[] sampledStations; // POE for each of n samples + private int[] sampledOriginTazs; // Origin Taz for each of n + // samples + private int[] sampledDestinationTazs; // Destination Taz for each + // of n + // samples + + private double[] sampledCorrectionFactors; // correction factor for each + // of + // n samples + private double[] tourModeChoiceLogsums; // mode choice logsum for + // each of n + // samples + + private class KeyClass + { + int station; + int mgra; + + @Override + public boolean equals(Object obj) + { + if (obj instanceof KeyClass) + { + return station == (((KeyClass) obj).station) && mgra == (((KeyClass) obj).mgra); + } + return false; + } + + @Override + public int hashCode() + { + return station * 10000 + mgra; + } + + } + + private KeyClass key; + private HashMap frequencyChosen; // by + // alternative, + // number + // of + // times + // chosen + + private TableDataSet alternativeData; // the + // alternatives, + // with + // the + // following + // fields: + // "EntryMGRA" + // - + // indicating + // border + // crossing + // entry + // MGRA + // "dest" + // - + // indicating + // the + // destination + // TAZ + // in + // San + // Diego + // County + + private int stations; // number + // of + // stations + private int sampleRate; + + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private ChoiceModelApplication soaModel; + private ChoiceModelApplication destModel; + private CrossBorderTourModeChoiceModel tourModeChoiceModel; + CrossBorderStationDestChoiceDMU dmu; + McLogsumsCalculator logsumHelper; + + private UtilityExpressionCalculator sizeTermUEC; + private Tracer tracer; + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + private boolean seek; + private HashMap rbMap; + + /** + * Constructor + * + * @param propertyMap + * Resource properties file map. + * @param dmuFactory + * Factory object for creation of cross border model DMUs + */ + public CrossBorderStationDestChoiceModel(HashMap rbMap, + CrossBorderModelStructure myStructure, CrossBorderDmuFactoryIf dmuFactory, + AutoTazSkimsCalculator tazDistanceCalculator) + { + + this.rbMap = rbMap; + + tazManager = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String crossBorderDCSoaFileName = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.soa.uec.file"); + crossBorderDCSoaFileName = uecFileDirectory + crossBorderDCSoaFileName; + + int soaDataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.soa.data.page")); + int soaSizePage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.soa.size.page")); + int soaModelPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.soa.model.page")); + + String crossBorderDCFileName = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.uec.file"); + crossBorderDCFileName = uecFileDirectory + crossBorderDCFileName; + + int dataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.data.page")); + int modelPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.model.page")); + + // read the model pages from the property file, create one choice model + // for each + CrossBorderStationDestChoiceDMU dcDmu = dmuFactory.getCrossBorderStationChoiceDMU(); + + // create a ChoiceModelApplication object for the SOA model. + soaModel = new ChoiceModelApplication(crossBorderDCSoaFileName, soaModelPage, soaDataPage, + rbMap, (VariableTable) dcDmu); + + // create a ChoiceModelApplication object for the full model. + destModel = new ChoiceModelApplication(crossBorderDCFileName, modelPage, dataPage, rbMap, + (VariableTable) dcDmu); + sampleRate = destModel.getAlternativeNames().length; + + // get the alternative data from the model + UtilityExpressionCalculator uec = soaModel.getUEC(); + alternativeData = uec.getAlternativeData(); + + // create a UEC to solve size terms for each MGRA + sizeTermUEC = new UtilityExpressionCalculator(new File(crossBorderDCSoaFileName), + soaSizePage, soaDataPage, rbMap, dmuFactory.getCrossBorderStationChoiceDMU()); + // set up the tracer object + trace = Util.getBooleanValueFromPropertyMap(rbMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbMap, "Trace.dtaz"); + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + seek = Util.getBooleanValueFromPropertyMap(rbMap, "Seek"); + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String coloniaDistanceFile = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.colonia.file"); + coloniaDistanceFile = directory + coloniaDistanceFile; + + // calculate logsums for each station (based on Super-Colonia population + // and distance to station) + float distanceParam = new Float(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.dc.colonia.distance.parameter")); + calculateStationLogsum(coloniaDistanceFile, distanceParam); + + // arrays of sampled station-mgra pairs + sampledDestinationMgra = new int[sampleRate + 1]; + sampledEntryMgra = new int[sampleRate + 1]; + sampledCorrectionFactors = new double[sampleRate + 1]; + frequencyChosen = new HashMap(); + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(rbMap); + + // this sets by thread, so do it outside of initialization + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + // set up a tour mode choice model for calculation of tour mode + // probabilities + tourModeChoiceModel = new CrossBorderTourModeChoiceModel(rbMap, myStructure, dmuFactory, + tazDistanceCalculator); + + tourModeChoiceLogsums = new double[sampleRate + 1]; + sampledSizeTerms = new double[myStructure.CROSSBORDER_PURPOSES.length][sampleRate + 1]; + sampledStationLogsums = new double[sampleRate + 1]; + sampledStations = new int[sampleRate + 1]; + + sampledOriginTazs = new int[sampleRate + 1]; + sampledDestinationTazs = new int[sampleRate + 1]; + + + } + + /** + * Calculate the station logsum. Station logsums are based on distance from + * supercolonia to station and population of supercolonia, as follows: + * + * stationLogsum_i = LN [ Sum( exp(distanceParam * distance) * population) ] + * + * supercolonia population and distances are stored in @param fileName. + * Fields in file include: + * + * Population Population of supercolonia Distance_MGRANumber where + * MGRANumber is the number of the MGRA corresponding to the entry station, + * with one field for each possible entry station. + * + * @param fileName + * Name of file containing supercolonia population and distance + * @param distanceParameter + * Parameter for distance. + */ + private void calculateStationLogsum(String fileName, float distanceParameter) + { + + logger.info("Calculating Station Logsum"); + + logger.info("Begin reading the data in file " + fileName); + TableDataSet coloniaTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + coloniaTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + stations = 0; + // iterate through columns in table, calculate number of station + // alternatives (entry stations) + String[] columnLabels = coloniaTable.getColumnLabels(); + for (int i = 0; i < columnLabels.length; ++i) + { + String label = columnLabels[i]; + if (label.contains("Distance_")) + { + ++stations; + } + } + + // iterate through stations and calculate logsum + stationLogsums = new double[stations]; + int colonias = coloniaTable.getRowCount(); + for (int i = 0; i < colonias; ++i) + { + + float population = coloniaTable.getValueAt(i + 1, "Population"); + + for (int j = 0; j < stations; ++j) + { + + float distance = coloniaTable.getValueAt(i + 1, "Distance_poe" + j); + if (population > 0) + stationLogsums[j] += Math.exp(distanceParameter * distance) * population; + } + } + + // take natural log + for (int i = 0; i < stations; ++i) + stationLogsums[i] = Math.log(stationLogsums[i]); + + logger.info("Finished Calculating Border Crossing Station Logsum"); + + } + + /** + * Calculate size terms + */ + public void calculateSizeTerms(CrossBorderDmuFactoryIf dmuFactory) + { + + logger.info("Calculating Cross Border Model MGRA Size Terms"); + + ArrayList mgras = mgraManager.getMgras(); + int[] mgraTaz = mgraManager.getMgraTaz(); + int maxMgra = mgraManager.getMaxMgra(); + int maxTaz = tazManager.getMaxTaz(); + int purposes = sizeTermUEC.getNumberOfAlternatives(); + + mgraSizeTerms = new double[purposes][maxMgra + 1]; + tazSizeTerms = new double[purposes][maxTaz + 1]; + IndexValues iv = new IndexValues(); + CrossBorderStationDestChoiceDMU aDmu = dmuFactory.getCrossBorderStationChoiceDMU(); + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + int taz = mgraTaz[mgra]; + iv.setZoneIndex(mgra); + double[] utilities = sizeTermUEC.solve(iv, aDmu, null); + + // store the size terms + for (int purpose = 0; purpose < purposes; ++purpose) + { + + mgraSizeTerms[purpose][mgra] = utilities[purpose]; + tazSizeTerms[purpose][taz] += utilities[purpose]; + } + + // log + if (tracer.isTraceOn() && tracer.isTraceZone(taz)) + { + + logger.info("Size Term calculations for mgra " + mgra); + sizeTermUEC.logResultsArray(logger, 0, mgra); + + } + } + + // now calculate probability of selecting each MGRA within each TAZ for + // SOA + mgraProbabilities = new double[purposes][maxTaz + 1][]; + int[] tazs = tazManager.getTazs(); + + for (int purpose = 0; purpose < purposes; ++purpose) + { + for (int taz = 0; taz < tazs.length; ++taz) + { + int tazNumber = tazs[taz]; + int[] mgraArray = tazManager.getMgraArray(tazNumber); + + // initialize the vector of mgras for this purpose-taz + mgraProbabilities[purpose][tazNumber] = new double[mgraArray.length]; + + // now calculate the cumulative probability distribution + double lastProb = 0.0; + for (int mgra = 0; mgra < mgraArray.length; ++mgra) + { + + int mgraNumber = mgraArray[mgra]; + if (tazSizeTerms[purpose][tazNumber] > 0.0) + mgraProbabilities[purpose][tazNumber][mgra] = lastProb + + mgraSizeTerms[purpose][mgraNumber] + / tazSizeTerms[purpose][tazNumber]; + lastProb = mgraProbabilities[purpose][tazNumber][mgra]; + } + if (tazSizeTerms[purpose][tazNumber] > 0.0 && Math.abs(lastProb - 1.0) > 0.000001) + logger.info("Error: purpose " + purpose + " taz " + tazNumber + + " cum prob adds up to " + lastProb); + } + + } + + // calculate logged size terms for mgra and taz vectors to be used in + // dmu + for (int purpose = 0; purpose < purposes; ++purpose) + { + for (int taz = 0; taz < tazSizeTerms[purpose].length; ++taz) + if (tazSizeTerms[purpose][taz] > 0.0) + tazSizeTerms[purpose][taz] = Math.log(tazSizeTerms[purpose][taz] + 1.0); + + for (int mgra = 0; mgra < mgraSizeTerms[purpose].length; ++mgra) + if (mgraSizeTerms[purpose][mgra] > 0.0) + mgraSizeTerms[purpose][mgra] = Math.log(mgraSizeTerms[purpose][mgra] + 1.0); + + } + logger.info("Finished Calculating Cross Border Model MGRA Size Terms"); + } + + /** + * Calculate taz probabilities. This method initializes and calculates the + * tazProbabilities array. + */ + public void calculateTazProbabilities(CrossBorderDmuFactoryIf dmuFactory) + { + + if (tazSizeTerms == null) + { + logger.error("Error: attemping to execute CrossBorderStationDestChoiceModel.calculateTazProbabilities() before calling calculateMgraProbabilities()"); + throw new RuntimeException(); + } + + logger.info("Calculating Cross Border Model TAZ-Station Probabilities Arrays"); + + // initialize taz probabilities array + int purposes = tazSizeTerms.length; + + // initialize the index for station population accessibility and taz + // size term + int alternatives = soaModel.getNumberOfAlternatives(); + soaStationLogsums = new double[alternatives + 1]; // by station-TAZ + // alternative - + // station logsums + soaSizeTerms = new double[purposes][alternatives + 1]; // by purpose, + // station-TAZ + // alternative - + // size terms + // for tazs + soaOriginTazs = new int[alternatives + 1]; + soaDestinationTazs = new int[alternatives + 1]; + + // iterate through the alternatives in the alternatives file and set the + // size term and station logsum for each alternative + UtilityExpressionCalculator soaModelUEC = soaModel.getUEC(); + TableDataSet altData = soaModelUEC.getAlternativeData(); + + int rowCount = altData.getRowCount(); + for (int row = 1; row <= rowCount; ++row) + { + + int entryMgra = (int) altData.getValueAt(row, "mgra_entry"); + int poe = (int) altData.getValueAt(row, "poe"); + int destinationTaz = (int) altData.getValueAt(row, "dest"); + + soaStationLogsums[row] = stationLogsums[poe]; + + for (int purpose = 0; purpose < purposes; ++purpose) + soaSizeTerms[purpose][row] = tazSizeTerms[purpose][destinationTaz]; + + // set the origin taz + soaOriginTazs[row] = mgraManager.getTaz(entryMgra); + + // set the destination taz + soaDestinationTazs[row] = destinationTaz; + + } + + dmu = dmuFactory.getCrossBorderStationChoiceDMU(); + + // set size terms for each taz + dmu.setSizeTerms(soaSizeTerms); + + // set population accessibility for each station + dmu.setStationPopulationAccessibilities(soaStationLogsums); + + // set the stations for each alternative + int poeField = altData.getColumnPosition("poe"); + int[] poeNumbers = altData.getColumnAsInt(poeField, 1); // return field + // as 1-based + + dmu.setPoeNumbers(poeNumbers); + + // set origin and destination tazs + dmu.setOriginTazs(soaOriginTazs); + dmu.setDestinationTazs(soaDestinationTazs); + + // initialize array to hold taz-station probabilities + tazStationProbabilities = new double[purposes][alternatives + 1]; + + // iterate through purposes, calculate probabilities for each and store + // in array + for (int purpose = 0; purpose < purposes; ++purpose) + { + + dmu.setPurpose(purpose); + + // Calculate utilities & probabilities + soaModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + // Store probabilities (by purpose) + tazStationProbabilities[purpose] = Arrays.copyOf(soaModel.getCumulativeProbabilities(), + soaModel.getCumulativeProbabilities().length); + } + logger.info("Finished Calculating Cross Border Model TAZ-Station Probabilities Arrays"); + } + + /** + * Choose a Station-MGRA alternative for sampling + * + * @param tour + * CrossBorderTour with purpose and Random + * @return An array of station-mgra pairs + */ + private void chooseStationMgraSample(CrossBorderTour tour) + { + + frequencyChosen.clear(); + + // choose sample, set station logsums and mgra size terms + int purpose = tour.getPurpose(); + for (int sample = 1; sample <= sampleRate; ++sample) + { + + // first find a TAZ and station + int alt = 0; + double[] tazCumProb = tazStationProbabilities[purpose]; + double altProb = 0; + double cumProb = 0; + double random = tour.getRandom(); + for (int i = 0; i < tazCumProb.length; ++i) + { + if (tazCumProb[i] > random) + { + alt = i; + if (i != 0) + { + cumProb = tazCumProb[i - 1]; + altProb = tazCumProb[i] - tazCumProb[i - 1]; + } else + { + altProb = tazCumProb[i]; + } + break; + } + } + + // get the taz number of the alternative, and an array of mgras in + // that taz + int destinationTaz = (int) alternativeData.getValueAt(alt + 1, "dest"); + int poe = (int) alternativeData.getValueAt(alt + 1, "poe"); + int entryMgra = (int) alternativeData.getValueAt(alt + 1, "mgra_entry"); + sampledEntryMgra[sample] = entryMgra; + int[] mgraArray = tazManager.getMgraArray(destinationTaz); + + // set the origin taz + sampledOriginTazs[sample] = (int) alternativeData.getValueAt(alt + 1, "poe_taz"); + + // set the destination taz + sampledDestinationTazs[sample] = destinationTaz; + + // now find an MGRA in the taz corresponding to the random number + // drawn: + // note that the indexing needs to be offset by the cumulative + // probability of the chosen taz and the + // mgra probabilities need to be scaled by the alternatives + // probability + int mgraNumber = 0; + double[] mgraCumProb = mgraProbabilities[purpose][destinationTaz]; + for (int i = 0; i < mgraCumProb.length; ++i) + { + cumProb += mgraCumProb[i] * altProb; + if (cumProb > random && mgraCumProb[i] > 0) + { + mgraNumber = mgraArray[i]; + sampledDestinationMgra[sample] = mgraNumber; + + // for now, store the probability in the correction factors + // array + sampledCorrectionFactors[sample] = mgraCumProb[i] * altProb; + + break; + } + } + + // store frequency chosen + key = new KeyClass(); + key.mgra = mgraNumber; + key.station = entryMgra; + if (!frequencyChosen.containsKey(key)) + { + frequencyChosen.put(key, 1); + } else + { + int freq = frequencyChosen.get(key); + frequencyChosen.put(key, freq + 1); + } + + // set station logsums + sampledStationLogsums[sample] = stationLogsums[poe]; + + // set the size terms for the sample + sampledSizeTerms[purpose][sample] = mgraSizeTerms[purpose][mgraNumber]; + + // set the sampled station number + sampledStations[sample] = poe; + + } + // calculate correction factors + for (int sample = 1; sample <= sampleRate; ++sample) + { + key = new KeyClass(); + key.mgra = sampledDestinationMgra[sample]; + key.station = sampledEntryMgra[sample]; + int freq = frequencyChosen.get(key); + sampledCorrectionFactors[sample] = (float) Math.log((double) freq + / sampledCorrectionFactors[sample]); + + } + + } + + /** + * Use the tour mode choice model to calculate the logsum for each sampled + * station-mgra pair and store in the array. + * + * @param tour + * The tour attributes used are tour purpose, depart and arrive + * periods, and sentri availability. + */ + private void calculateLogsumsForSample(CrossBorderTour tour) + { + + for (int sample = 1; sample <= sampleRate; ++sample) + { + + if (sampledEntryMgra[sample] > 0) + { + + int originMgra = sampledEntryMgra[sample]; + int destinationMgra = sampledDestinationMgra[sample]; + + tour.setOriginMGRA(originMgra); + tour.setOriginTAZ(sampledOriginTazs[sample]); + tour.setDestinationMGRA(destinationMgra); + tour.setDestinationTAZ(mgraManager.getTaz(destinationMgra)); + tour.setPoe(sampledStations[sample]); + + double logsum = tourModeChoiceModel.getLogsum(tour, logger, "Sample logsum " + + sample, "tour " + tour.getID()); + tourModeChoiceLogsums[sample] = logsum; + } else tourModeChoiceLogsums[sample] = 0; + + } + + } + + /** + * Choose a station and internal destination MGRA for the tour. + * + * @param tour + * A cross border tour with a tour purpose and departure\arrival + * time and SENTRI availability members. + */ + public void chooseStationAndDestination(CrossBorderTour tour) + { + + chooseStationMgraSample(tour); + calculateLogsumsForSample(tour); + + double random = tour.getRandom(); + dmu.setPurpose(tour.getPurpose()); + + // set size terms for each sampled station-mgra pair corresponding to + // mgra + dmu.setSizeTerms(sampledSizeTerms); + + // set population accessibility for each station-mgra pair corresponding + // to station + dmu.setStationPopulationAccessibilities(sampledStationLogsums); + + // set the sampled stations + dmu.setPoeNumbers(sampledStations); + + // set the correction factors + dmu.setCorrectionFactors(sampledCorrectionFactors); + + // set the tour mode choice logsums + dmu.setTourModeLogsums(tourModeChoiceLogsums); + + // set the origin and destination tazs + dmu.setOriginTazs(sampledOriginTazs); + dmu.setDestinationTazs(sampledDestinationTazs); + + if (tour.getDebugChoiceModels()) + { + logger.info("***"); + logger.info("Choosing station-destination alternative from sample"); + tour.logTourObject(logger, 1000); + + // log the sample + logSample(); + destModel.choiceModelUtilityTraceLoggerHeading("Station-destination model", "tour " + + tour.getID()); + } + + destModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + if (tour.getDebugChoiceModels()) + { + destModel.logUECResults(logger, "Station-destination model"); + } + int alt = destModel.getChoiceResult(random); + + int entryMgra = sampledEntryMgra[alt]; + int primaryDestination = sampledDestinationMgra[alt]; + int poe = sampledStations[alt]; + int taz = sampledOriginTazs[alt]; + + tour.setOriginMGRA(entryMgra); + tour.setOriginTAZ(taz); + tour.setDestinationMGRA(primaryDestination); + tour.setDestinationTAZ(mgraManager.getTaz(primaryDestination)); + tour.setPoe(poe); + + } + + public CrossBorderTourModeChoiceModel getTourModeChoiceModel() + { + return tourModeChoiceModel; + } + + public void logSample() + { + + logger.info("Sampled station-destination alternatives"); + + logger.info("\nAlt POE EntryMgra DestMgra"); + for (int i = 1; i <= sampleRate; ++i) + { + logger.info(i + " " + sampledStations[i] + " " + sampledEntryMgra[i] + " " + + sampledDestinationMgra[i]); + } + logger.info(""); + } + + /** + * @return the mgraSizeTerms + */ + public double[][] getMgraSizeTerms() + { + return mgraSizeTerms; + } + + /** + * @return the tazSizeTerms + */ + public double[][] getTazSizeTerms() + { + return tazSizeTerms; + } + + /** + * @return the mgraProbabilities + */ + public double[][][] getMgraProbabilities() + { + return mgraProbabilities; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStop.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStop.java new file mode 100644 index 0000000..6382a30 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStop.java @@ -0,0 +1,187 @@ +package org.sandag.abm.crossborder; + +import java.io.Serializable; +import org.apache.log4j.Logger; + +public class CrossBorderStop + implements Serializable +{ + + private int id; + private int mode; + private int period; + private boolean inbound; + private int mgra; + private int TAZ; + private byte purpose; + + CrossBorderTour parentTour; + + public CrossBorderStop(CrossBorderTour parentTour, int id, boolean inbound) + { + this.parentTour = parentTour; + this.id = id; + this.inbound = inbound; + } + + /** + * @return the mgra + */ + public int getMgra() + { + return mgra; + } + + /** + * @param mgra + * the mgra to set + */ + public void setMgra(int mgra) + { + this.mgra = mgra; + } + + public int getTAZ() + { + return TAZ; + } + + public void setTAZ(int tAZ) + { + TAZ = tAZ; + } + + public void setMode(int mode) + { + this.mode = mode; + } + + public void setPeriod(int period) + { + this.period = period; + } + + /** + * @return the id + */ + public int getId() + { + return id; + } + + /** + * @param id + * the id to set + */ + public void setId(int id) + { + this.id = id; + } + + /** + * @return the inbound + */ + public boolean isInbound() + { + return inbound; + } + + /** + * @param inbound + * the inbound to set + */ + public void setInbound(boolean inbound) + { + this.inbound = inbound; + } + + /** + * @return the parentTour + */ + public CrossBorderTour getParentTour() + { + return parentTour; + } + + /** + * @param parentTour + * the parentTour to set + */ + public void setParentTour(CrossBorderTour parentTour) + { + this.parentTour = parentTour; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(byte stopPurposeIndex) + { + this.purpose = stopPurposeIndex; + } + + public byte getPurpose() + { + return purpose; + } + + public int getMode() + { + return mode; + } + + public int getStopPeriod() + { + return period; + } + + public CrossBorderTour getTour() + { + return parentTour; + } + + public int getStopId() + { + return id; + } + + public void logStopObject(Logger logger, int totalChars) + { + + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "-"; + + String purposeString = CrossBorderModelStructure.CROSSBORDER_PURPOSES[purpose]; + logHelper(logger, "stopId: ", id, totalChars); + logHelper(logger, "mgra: ", mgra, totalChars); + logHelper(logger, "mode: ", mode, totalChars); + logHelper(logger, "purpose: ", purposeString, totalChars); + logHelper(logger, "direction: ", inbound ? "inbound" : "outbound", totalChars); + logHelper(logger, inbound ? "outbound departPeriod: " : "inbound arrivePeriod: ", period, + totalChars); + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public static void logHelper(Logger logger, String label, int value, int totalChars) + { + int labelChars = label.length() + 2; + int remainingChars = totalChars - labelChars - 4; + String formatString = String.format(" %%%ds %%%dd", label.length(), remainingChars); + String logString = String.format(formatString, label, value); + logger.info(logString); + } + + public static void logHelper(Logger logger, String label, String value, int totalChars) + { + int labelChars = label.length() + 2; + int remainingChars = totalChars - labelChars - 4; + String formatString = String.format(" %%%ds %%%ds", label.length(), remainingChars); + String logString = String.format(formatString, label, value); + logger.info(logString); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopFrequencyModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopFrequencyModel.java new file mode 100644 index 0000000..b546780 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopFrequencyModel.java @@ -0,0 +1,316 @@ +package org.sandag.abm.crossborder; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the stop frequency model for cross border tours. It is + * currently based on a static probability distribution stored in an input file, + * and indexed into by tour purpose and duration. + * + * @author Freedman + * + */ +public class CrossBorderStopFrequencyModel +{ + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + private double[][] cumProbability; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + private int[][] lowerBoundDurationHours; // by + // purpose, + // alternative: + // lower + // bound + // in + // hours + private int[][] upperBoundDurationHours; // by + // purpose, + // alternative: + // upper + // bound + // in + // hours + private int[][] outboundStops; // by + // purpose, + // alternative: + // number + // of + // outbound + // stops + private int[][] inboundStops; // by + // purpose, + // alternative: + // number + // of + // inbound + // stops + CrossBorderModelStructure modelStructure; + + /** + * Constructor. + */ + public CrossBorderStopFrequencyModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String stopFrequencyFile = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.stop.frequency.file"); + stopFrequencyFile = directory + stopFrequencyFile; + + modelStructure = new CrossBorderModelStructure(); + + readStopFrequencyFile(stopFrequencyFile); + + } + + /** + * Read the stop frequency distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readStopFrequencyFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating stop frequency probability distribution"); + + int purposes = modelStructure.NUMBER_CROSSBORDER_PURPOSES; // start at 0 + + int[] alts = new int[purposes]; + + // take a pass through the data and see how many alternatives there are + // for each purpose + int rowCount = probabilityTable.getRowCount(); + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose"); + ++alts[purpose]; + } + + // initialize all the arrays + cumProbability = new double[purposes][]; + lowerBoundDurationHours = new int[purposes][]; + upperBoundDurationHours = new int[purposes][]; + outboundStops = new int[purposes][]; + inboundStops = new int[purposes][]; + + for (int i = 0; i < purposes; ++i) + { + cumProbability[i] = new double[alts[i]]; + lowerBoundDurationHours[i] = new int[alts[i]]; + upperBoundDurationHours[i] = new int[alts[i]]; + outboundStops[i] = new int[alts[i]]; + inboundStops[i] = new int[alts[i]]; + } + + // fill up arrays + int lastPurpose = 0; + int lastLowerBound = 0; + double cumProb = 0; + int alt = 0; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose"); + int lowerBound = (int) probabilityTable.getValueAt(row, "DurationLo"); + int upperBound = (int) probabilityTable.getValueAt(row, "DurationHi"); + int outStops = (int) probabilityTable.getValueAt(row, "Outbound"); + int inbStops = (int) probabilityTable.getValueAt(row, "Inbound"); + + // reset cumulative probability if new purpose or lower-bound + if (purpose != lastPurpose || lowerBound != lastLowerBound) + { + + // log cumulative probability just in case + /* + logger.info("Cumulative probability for purpose " + purpose + " lower bound " + + lowerBound + " is " + cumProb); + */ + cumProb = 0; + } + + if (purpose != lastPurpose) alt = 0; + + // calculate cumulative probability and store in array + cumProb += probabilityTable.getValueAt(row, "Percent"); + cumProbability[purpose][alt] = cumProb; + lowerBoundDurationHours[purpose][alt] = lowerBound; + upperBoundDurationHours[purpose][alt] = upperBound; + outboundStops[purpose][alt] = outStops; + inboundStops[purpose][alt] = inbStops; + + ++alt; + + lastPurpose = purpose; + lastLowerBound = lowerBound; + } + + logger.info("End calculating stop frequency probability distribution"); +/* + for (int purp = 0; purp < purposes; ++purp) + { + for (int a = 0; a < cumProbability[purp].length; ++a) + { + logger.info("Purpose " + purp + " lower " + lowerBoundDurationHours[purp][a] + + " upper " + upperBoundDurationHours[purp][a] + " cumProb " + + cumProbability[purp][a]); + } + } +*/ + } + + /** + * Calculate tour time of day for the tour. + * + * @param tour + * A cross border tour (with purpose) + */ + public void calculateStopFrequency(CrossBorderTour tour) + { + + int purpose = tour.getPurpose(); + double random = tour.getRandom(); + + if (tour.getDebugChoiceModels()) + { + logger.info("Choosing stop frequency for purpose " + + modelStructure.CROSSBORDER_PURPOSES[purpose] + " using random number " + + random); + tour.logTourObject(logger, 100); + } + + for (int i = 0; i < cumProbability[purpose].length; ++i) + { + + if (!tourIsInRange(tour, lowerBoundDurationHours[purpose][i], + upperBoundDurationHours[purpose][i])) continue; + + if (random < cumProbability[purpose][i]) + { + int outStops = outboundStops[purpose][i]; + int inbStops = inboundStops[purpose][i]; + + if (outStops > 0) + { + CrossBorderStop[] stops = generateOutboundStops(tour, outStops); + tour.setOutboundStops(stops); + } + + if (inbStops > 0) + { + CrossBorderStop[] stops = generateInboundStops(tour, inbStops); + tour.setInboundStops(stops); + } + if (tour.getDebugChoiceModels()) + { + logger.info(""); + logger.info("Chose " + outStops + " outbound stops and " + inbStops + + " inbound stops"); + logger.info(""); + } + break; + } + } + + } + + /** + * Check if the tour duration is in range + * + * @param tour + * @param lowerBound + * @param upperBound + * @return True if tour duration is greater than or equal to lower and + */ + private boolean tourIsInRange(CrossBorderTour tour, int lowerBound, int upperBound) + { + + float depart = (float) tour.getDepartTime(); + float arrive = (float) tour.getArriveTime(); + + float halfHours = arrive + 1 - depart; // at least 30 minutes + float tourDurationInHours = halfHours * (float) 0.5; + + if (tourDurationInHours >= lowerBound && tourDurationInHours <= upperBound) return true; + + return false; + } + + /** + * Generate an array of outbound stops, from tour origin to primary + * destination, in order. + * + * @param tour + * The parent tour. + * @param numberOfStops + * Number of stops from stop frequency model. + * @return The array of outbound stops. + */ + private CrossBorderStop[] generateOutboundStops(CrossBorderTour tour, int numberOfStops) + { + + CrossBorderStop[] stops = new CrossBorderStop[numberOfStops]; + + for (int i = 0; i < stops.length; ++i) + { + CrossBorderStop stop = new CrossBorderStop(tour, i, false); + stops[i] = stop; + stop.setInbound(false); + stop.setParentTour(tour); + } + + return stops; + } + + /** + * Generate an array of inbound stops, from primary dest back to tour + * origin, in order. + * + * @param tour + * Parent tour. + * @param numberOfStops + * Number of stops from stop frequency model. + * @return The array of inbound stops. + */ + private CrossBorderStop[] generateInboundStops(CrossBorderTour tour, int numberOfStops) + { + + CrossBorderStop[] stops = new CrossBorderStop[numberOfStops]; + + for (int i = 0; i < stops.length; ++i) + { + CrossBorderStop stop = new CrossBorderStop(tour, i, true); + stops[i] = stop; + stop.setInbound(true); + stop.setParentTour(tour); + + } + + return stops; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopLocationChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopLocationChoiceDMU.java new file mode 100644 index 0000000..1307d94 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopLocationChoiceDMU.java @@ -0,0 +1,406 @@ +package org.sandag.abm.crossborder; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class CrossBorderStopLocationChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger("crossBorderModel"); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected int purpose; + protected int stopsOnHalfTour; + protected int stopNumber; + protected int inboundStop; + protected int tourDuration; + + protected double[][] sizeTerms; // by + // purpose, + // alternative + // (taz + // or + // sampled + // mgra) + protected double[] correctionFactors; // by + // alternative + // (sampled + // mgra, + // for + // full + // model + // only) + + protected int[] sampleNumber; // by + // alternative + // (taz + // or + // sampled + // mgra) + + protected double[] osMcLogsumAlt; + protected double[] sdMcLogsumAlt; + + protected double[] tourOrigToStopDistanceAlt; + protected double[] stopToTourDestDistanceAlt; + + public CrossBorderStopLocationChoiceDMU(CrossBorderModelStructure modelStructure) + { + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + /** + * @return the stopsOnHalfTour + */ + public int getStopsOnHalfTour() + { + return stopsOnHalfTour; + } + + /** + * @param stopsOnHalfTour + * the stopsOnHalfTour to set + */ + public void setStopsOnHalfTour(int stopsOnHalfTour) + { + this.stopsOnHalfTour = stopsOnHalfTour; + } + + /** + * @return the stopNumber + */ + public int getStopNumber() + { + return stopNumber; + } + + /** + * @param stopNumber + * the stopNumber to set + */ + public void setStopNumber(int stopNumber) + { + this.stopNumber = stopNumber; + } + + /** + * @return the inboundStop + */ + public int getInboundStop() + { + return inboundStop; + } + + /** + * @param inboundStop + * the inboundStop to set + */ + public void setInboundStop(int inboundStop) + { + this.inboundStop = inboundStop; + } + + /** + * @return the tourDuration + */ + public int getTourDuration() + { + return tourDuration; + } + + /** + * @param tourDuration + * the tourDuration to set + */ + public void setTourDuration(int tourDuration) + { + this.tourDuration = tourDuration; + } + + /** + * @return the sampleNumber + */ + public int getSampleNumber(int alt) + { + return sampleNumber[alt]; + } + + /** + * @param sampleNumber + * the sampleNumber to set + */ + public void setSampleNumber(int[] sampleNumber) + { + this.sampleNumber = sampleNumber; + } + + /** + * @return the osMcLogsumAlt + */ + public double getOsMcLogsumAlt(int alt) + { + return osMcLogsumAlt[alt]; + } + + /** + * @param osMcLogsumAlt + * the osMcLogsumAlt to set + */ + public void setOsMcLogsumAlt(double[] osMcLogsumAlt) + { + this.osMcLogsumAlt = osMcLogsumAlt; + } + + /** + * @return the sdMcLogsumAlt + */ + public double getSdMcLogsumAlt(int alt) + { + return sdMcLogsumAlt[alt]; + } + + /** + * @param sdMcLogsumAlt + * the sdMcLogsumAlt to set + */ + public void setSdMcLogsumAlt(double[] sdMcLogsumAlt) + { + this.sdMcLogsumAlt = sdMcLogsumAlt; + } + + /** + * @return the tourOrigToStopDistanceAlt + */ + public double getTourOrigToStopDistanceAlt(int alt) + { + return tourOrigToStopDistanceAlt[alt]; + } + + /** + * @param tourOrigToStopDistanceAlt + * the tourOrigToStopDistanceAlt to set + */ + public void setTourOrigToStopDistanceAlt(double[] tourOrigToStopDistanceAlt) + { + this.tourOrigToStopDistanceAlt = tourOrigToStopDistanceAlt; + } + + /** + * @return the stopToTourDestDistanceAlt + */ + public double getStopToTourDestDistanceAlt(int alt) + { + return stopToTourDestDistanceAlt[alt]; + } + + /** + * @param stopToTourDestDistanceAlt + * the stopToTourDestDistanceAlt to set + */ + public void setStopToTourDestDistanceAlt(double[] stopToTourDestDistanceAlt) + { + this.stopToTourDestDistanceAlt = stopToTourDestDistanceAlt; + } + + /** + * @return the sizeTerms. The size term is the size of the alternative north + * of the border. It is indexed by alternative, where alternative is + * either taz-station pair or mgra-station pair, depending on + * whether the DMU is being used for the SOA model or the actual + * model. + */ + public double getSizeTerm(int alt) + { + return sizeTerms[purpose][alt]; + } + + /** + * @param sizeTerms + * the sizeTerms to set. The size term is the size of the + * alternative north of the border. It is indexed by alternative, + * where alternative is either taz-station pair or mgra-station + * pair, depending on whether the DMU is being used for the SOA + * model or the actual model. + */ + public void setSizeTerms(double[][] sizeTerms) + { + this.sizeTerms = sizeTerms; + } + + /** + * @return the correctionFactors + */ + public double getCorrectionFactor(int alt) + { + return correctionFactors[alt]; + } + + /** + * @param correctionFactors + * the correctionFactors to set + */ + public void setCorrectionFactors(double[] correctionFactors) + { + this.correctionFactors = correctionFactors; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the purpose + */ + public int getPurpose() + { + return purpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(int purpose) + { + this.purpose = purpose; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + methodIndexMap.put("getPurpose", 0); + methodIndexMap.put("getStopsOnHalfTour", 1); + methodIndexMap.put("getStopNumber", 2); + methodIndexMap.put("getInboundStop", 3); + methodIndexMap.put("getTourDuration", 4); + + methodIndexMap.put("getSizeTerm", 5); + methodIndexMap.put("getCorrectionFactor", 6); + methodIndexMap.put("getSampleNumber", 7); + methodIndexMap.put("getOsMcLogsumAlt", 8); + methodIndexMap.put("getSdMcLogsumAlt", 9); + methodIndexMap.put("getTourOrigToStopDistanceAlt", 10); + methodIndexMap.put("getStopToTourDestDistanceAlt", 11); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getPurpose(); + break; + case 1: + returnValue = getStopsOnHalfTour(); + break; + case 2: + returnValue = getStopNumber(); + break; + case 3: + returnValue = getInboundStop(); + break; + case 4: + returnValue = getTourDuration(); + break; + case 5: + returnValue = getSizeTerm(arrayIndex); + break; + case 6: + returnValue = getCorrectionFactor(arrayIndex); + break; + case 7: + returnValue = getSampleNumber(arrayIndex); + break; + case 8: + returnValue = getOsMcLogsumAlt(arrayIndex); + break; + case 9: + returnValue = getSdMcLogsumAlt(arrayIndex); + break; + case 10: + returnValue = getTourOrigToStopDistanceAlt(arrayIndex); + break; + case 11: + returnValue = getStopToTourDestDistanceAlt(arrayIndex); + break; + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopLocationChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopLocationChoiceModel.java new file mode 100644 index 0000000..4394466 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopLocationChoiceModel.java @@ -0,0 +1,536 @@ +package org.sandag.abm.crossborder; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.ConcreteAlternative; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class CrossBorderStopLocationChoiceModel +{ + + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + // private McLogsumsCalculator logsumHelper; + private CrossBorderModelStructure modelStructure; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private CrossBorderStopLocationChoiceDMU dmu; + private CrossBorderTripModeChoiceModel tripModeChoiceModel; + double logsum = 0; + private ChoiceModelApplication soaModel; + private ChoiceModelApplication destModel; + private McLogsumsCalculator logsumHelper; + + + // the following arrays are calculated in the station-destination choice + // model and passed in the constructor. + private double[][] mgraSizeTerms; // by + // purpose, + // MGRA + private double[][][] mgraProbabilities; // by + // purpose, + // TAZ, + // MGRA + + private TableDataSet alternativeData; // the + // alternatives, + // with + // a + // "dest" + // - + // indicating + // the + // destination + // TAZ + // in + // San + // Diego + // County + + // following are used for each taz alternative + private double[] soaTourOrigToStopDistanceAlt; // by + // TAZ + private double[] soaStopToTourDestDistanceAlt; // by + // TAZ + private double[][] tazSizeTerms; // by + // purpose, + // TAZ + // - + // set + // by + // constructor + + // following are used for sampled mgras + private int sampleRate; + private double[][] sampledSizeTerms; // by + // purpose, + // alternative + // (taz + // or + // sampled + // mgra) + private double[] correctionFactors; // by + // alternative + // (sampled + // mgra, + // for + // full + // model + // only) + private int[] sampledTazs; // by + // alternative + // (sampled + // taz) + private int[] sampledMgras; // by + // alternative(sampled + // mgra) + private double[] tourOrigToStopDistanceAlt; + private double[] stopToTourDestDistanceAlt; + private double[] osMcLogsumAlt; + private double[] sdMcLogsumAlt; + + HashMap frequencyChosen; + + private CrossBorderTrip trip; + + private int originMgra; // the + // origin + // MGRA + // of + // the + // stop + // (originMgra + // -> + // stopMgra + // -> + // destinationMgra) + private int destinationMgra; // the + // destination + // MGRA + // of + // the + // stop + // (originMgra + // -> + // stopMgra + // -> + // destinationMgra) + private int originTAZ; + private int destinationTAZ; + private AutoTazSkimsCalculator tazDistanceCalculator; + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public CrossBorderStopLocationChoiceModel(HashMap propertyMap, + CrossBorderModelStructure myModelStructure, CrossBorderDmuFactoryIf dmuFactory, AutoTazSkimsCalculator tazDistanceCalculator) + { + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + modelStructure = myModelStructure; + + this.tazDistanceCalculator = tazDistanceCalculator; + setupStopLocationChoiceModel(propertyMap, dmuFactory); + + frequencyChosen = new HashMap(); + + trip = new CrossBorderTrip(); + + } + + /** + * Read the UEC file and set up the stop destination choice model. + * + * @param propertyMap + * @param dmuFactory + */ + private void setupStopLocationChoiceModel(HashMap rbMap, + CrossBorderDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up cross border stop location choice model.")); + + dmu = dmuFactory.getCrossBorderStopLocationChoiceDMU(); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String crossBorderStopLocationSoaFileName = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.slc.soa.uec.file"); + crossBorderStopLocationSoaFileName = uecFileDirectory + crossBorderStopLocationSoaFileName; + + int soaDataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.slc.soa.data.page")); + int soaModelPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.slc.soa.model.page")); + + String crossBorderStopLocationFileName = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.slc.uec.file"); + crossBorderStopLocationFileName = uecFileDirectory + crossBorderStopLocationFileName; + + int dataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.slc.data.page")); + int modelPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.slc.model.page")); + + // create a ChoiceModelApplication object for the SOA model. + soaModel = new ChoiceModelApplication(crossBorderStopLocationSoaFileName, soaModelPage, + soaDataPage, rbMap, (VariableTable) dmu); + + // create a ChoiceModelApplication object for the full model. + destModel = new ChoiceModelApplication(crossBorderStopLocationFileName, modelPage, + dataPage, rbMap, (VariableTable) dmu); + sampleRate = destModel.getAlternativeNames().length; + + // get the alternative data + UtilityExpressionCalculator uec = soaModel.getUEC(); + alternativeData = uec.getAlternativeData(); + int purposes = modelStructure.CROSSBORDER_PURPOSES.length; + + sampledSizeTerms = new double[purposes][sampleRate + 1]; // by purpose, + // alternative + // (taz or + // sampled + // mgra) + correctionFactors = new double[sampleRate + 1]; // by alternative + // (sampled mgra, for + // full model only) + sampledTazs = new int[sampleRate + 1]; // by alternative (sampled taz) + sampledMgras = new int[sampleRate + 1]; // by alternative (sampled mgra) + tourOrigToStopDistanceAlt = new double[sampleRate + 1]; + stopToTourDestDistanceAlt = new double[sampleRate + 1]; + osMcLogsumAlt = new double[sampleRate + 1]; + sdMcLogsumAlt = new double[sampleRate + 1]; + + tripModeChoiceModel = new CrossBorderTripModeChoiceModel(rbMap, modelStructure, + dmuFactory, tazDistanceCalculator); + logsumHelper = tripModeChoiceModel.getMcLogsumsCalculator(); + + + } + + /** + * Create a sample for the tour and stop. + * + * @param tour + * @param stop + */ + private void createSample(CrossBorderTour tour, CrossBorderStop stop) + { + + int purpose = tour.getPurpose(); + int period = modelStructure.AM; + + dmu.setPurpose(purpose); + boolean inbound = stop.isInbound(); + if (inbound) + { + dmu.setInboundStop(1); + dmu.setStopsOnHalfTour(tour.getNumberInboundStops()); + + // destination for inbound stops is always tour origin + destinationMgra = tour.getOriginMGRA(); + destinationTAZ = mgraManager.getTaz(destinationMgra); + + // origin for inbound stops is tour destination if first stop, or + // last chosen stop location + if (stop.getId() == 0) + { + originMgra = tour.getDestinationMGRA(); + originTAZ = mgraManager.getTaz(originMgra); + } else + { + CrossBorderStop[] stops = tour.getInboundStops(); + originMgra = stops[stop.getId() - 1].getMgra(); + originTAZ = mgraManager.getTaz(originMgra); + } + + } else + { + dmu.setInboundStop(0); + dmu.setStopsOnHalfTour(tour.getNumberOutboundStops()); + + // destination for outbound stops is always tour destination + destinationMgra = tour.getDestinationMGRA(); + destinationTAZ = mgraManager.getTaz(destinationMgra); + + // origin for outbound stops is tour origin if first stop, or last + // chosen stop location + if (stop.getId() == 0) + { + originMgra = tour.getOriginMGRA(); + originTAZ = mgraManager.getTaz(originMgra); + } else + { + CrossBorderStop[] stops = tour.getOutboundStops(); + originMgra = stops[stop.getId() - 1].getMgra(); + originTAZ = mgraManager.getTaz(originMgra); + } + } + dmu.setStopNumber(stop.getId() + 1); + dmu.setDmuIndexValues(originTAZ, originTAZ, originTAZ, 0, false); + + // distances + soaTourOrigToStopDistanceAlt = logsumHelper.getAnmSkimCalculator().getTazDistanceFromTaz( + originTAZ, period); + soaStopToTourDestDistanceAlt = logsumHelper.getAnmSkimCalculator().getTazDistanceToTaz( + destinationTAZ, period); + dmu.setTourOrigToStopDistanceAlt(soaTourOrigToStopDistanceAlt); + dmu.setStopToTourDestDistanceAlt(soaStopToTourDestDistanceAlt); + + dmu.setSizeTerms(tazSizeTerms); + + // solve for each sample + frequencyChosen.clear(); + for (int sample = 1; sample <= sampleRate; ++sample) + { + + // solve the UEC + soaModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + // choose a TAZ + double random = tour.getRandom(); + ConcreteAlternative[] alts = soaModel.getAlternatives(); + double cumProb = 0; + double altProb = 0; + int sampledTaz = -1; + for (int i = 0; i < alts.length; ++i) + { + cumProb += alts[i].getProbability(); + if (random < cumProb) + { + sampledTaz = (int) alternativeData.getValueAt(i + 1, "dest"); + altProb = alts[i].getProbability(); + break; + } + } + + // set the sampled taz in the array + sampledTazs[sample] = sampledTaz; + + // now find an MGRA in the taz corresponding to the random number + // drawn: + // note that the indexing needs to be offset by the cumulative + // probability of the chosen taz and the + // mgra probabilities need to be scaled by the alternatives + // probability + int[] mgraArray = tazManager.getMgraArray(sampledTaz); + int mgraNumber = 0; + double[] mgraCumProb = mgraProbabilities[purpose][sampledTaz]; + + if (mgraCumProb == null) + { + logger.error("Error: mgraCumProb array is null for purpose " + purpose + + " sampledTaz " + sampledTaz + " hhID " + tour.getID()); + throw new RuntimeException(); + } + for (int i = 0; i < mgraCumProb.length; ++i) + { + cumProb += mgraCumProb[i] * altProb; + if (cumProb > random && mgraCumProb[i] > 0) + { + mgraNumber = mgraArray[i]; + sampledMgras[sample] = mgraNumber; + + // for now, store the probability in the correction factors + // array + correctionFactors[sample] = mgraCumProb[i] * altProb; + + break; + } + } + + // store frequency chosen + if (!frequencyChosen.containsKey(mgraNumber)) + { + frequencyChosen.put(mgraNumber, 1); + } else + { + int freq = frequencyChosen.get(mgraNumber); + frequencyChosen.put(mgraNumber, freq + 1); + } + + // set the size terms for the sample + sampledSizeTerms[purpose][sample] = mgraSizeTerms[purpose][mgraNumber]; + + // set the distances for the sample + tourOrigToStopDistanceAlt[sample] = soaTourOrigToStopDistanceAlt[sampledTaz]; + stopToTourDestDistanceAlt[sample] = soaStopToTourDestDistanceAlt[sampledTaz]; + + } + // calculate correction factors + for (int sample = 1; sample <= sampleRate; ++sample) + { + int mgra = sampledMgras[sample]; + int freq = frequencyChosen.get(mgra); + correctionFactors[sample] = (float) Math.log((double) freq / correctionFactors[sample]); + + } + + } + + /** + * Choose a stop location from the sample. + * + * @param tour + * The cross border tour. + * @param stop + * The cross border stop. + */ + public void chooseStopLocation(CrossBorderTour tour, CrossBorderStop stop) + { + + // create a sample of mgras and set all of the dmu properties + createSample(tour, stop); + dmu.setCorrectionFactors(correctionFactors); + dmu.setSizeTerms(sampledSizeTerms); + dmu.setTourOrigToStopDistanceAlt(stopToTourDestDistanceAlt); + dmu.setStopToTourDestDistanceAlt(stopToTourDestDistanceAlt); + dmu.setSampleNumber(sampledMgras); + + // calculate trip mode choice logsums to and from stop + for (int i = 1; i <= sampleRate; ++i) + { + + // to stop (originMgra -> stopMgra ) + trip.initializeFromStop(tour, stop, true); + trip.setOriginMgra(originMgra); + trip.setOriginTAZ(originTAZ); + trip.setDestinationMgra(sampledMgras[i]); + trip.setDestinationTAZ(mgraManager.getTaz(sampledMgras[i])); + double logsum = tripModeChoiceModel.computeUtilities(tour, trip); + osMcLogsumAlt[i] = logsum; + + // from stop (stopMgra -> destinationMgra) + trip.initializeFromStop(tour, stop, true); + trip.setOriginMgra(sampledMgras[i]); + trip.setOriginTAZ(mgraManager.getTaz(sampledMgras[i])); + trip.setDestinationMgra(destinationMgra); + trip.setDestinationTAZ(destinationTAZ); + logsum = tripModeChoiceModel.computeUtilities(tour, trip); + sdMcLogsumAlt[i] = logsum; + + } + dmu.setOsMcLogsumAlt(osMcLogsumAlt); + dmu.setSdMcLogsumAlt(sdMcLogsumAlt); + + // log headers to traceLogger + if (tour.getDebugChoiceModels()) + { + String decisionMakerLabel = "Tour ID " + tour.getID() + " stop id " + stop.getId() + + " purpose " + modelStructure.CROSSBORDER_PURPOSES[stop.getPurpose()]; + destModel.choiceModelUtilityTraceLoggerHeading( + "Intermediate stop location choice model", decisionMakerLabel); + } + + destModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + double random = tour.getRandom(); + int alt = destModel.getChoiceResult(random); + int destMgra = sampledMgras[alt]; + stop.setMgra(destMgra); + stop.setTAZ(mgraManager.getTaz(destMgra)); + + // write UEC calculation results and choice + if (tour.getDebugChoiceModels()) + { + String decisionMakerLabel = "Tour ID " + tour.getID() + " stop id " + stop.getId() + + " purpose " + modelStructure.CROSSBORDER_PURPOSES[stop.getPurpose()]; + String loggingHeader = String.format("%s %s", + "Intermediate stop location choice model", decisionMakerLabel); + destModel.logUECResults(logger, loggingHeader); + logger.info("Chose alternative " + alt + " mgra " + destMgra + " with random number " + + random); + logger.info(""); + logger.info(""); + } + + } + + /** + * @return the mgraSizeTerms + */ + public double[][] getMgraSizeTerms() + { + return mgraSizeTerms; + } + + /** + * @return the mgraProbabilities + */ + public double[][][] getMgraProbabilities() + { + return mgraProbabilities; + } + + /** + * @return the tazSizeTerms + */ + public double[][] getTazSizeTerms() + { + return tazSizeTerms; + } + + /** + * Set mgra size terms: must call before choosing location. + * + * @param mgraSizeTerms + */ + public void setMgraSizeTerms(double[][] mgraSizeTerms) + { + + if (mgraSizeTerms == null) + { + logger.error("Error attempting to set MGRASizeTerms in CrossBorderStopLocationChoiceModel: MGRASizeTerms are null"); + throw new RuntimeException(); + } + this.mgraSizeTerms = mgraSizeTerms; + } + + /** + * Set taz size terms: must call before choosing location. + * + * @param tazSizeTerms + */ + public void setTazSizeTerms(double[][] tazSizeTerms) + { + if (tazSizeTerms == null) + { + logger.error("Error attempting to set TazSizeTerms in CrossBorderStopLocationChoiceModel: TazSizeTerms are null"); + throw new RuntimeException(); + } + this.tazSizeTerms = tazSizeTerms; + } + + /** + * Set the mgra probabilities. Must call before choosing location. + * + * @param mgraProbabilities + */ + public void setMgraProbabilities(double[][][] mgraProbabilities) + { + if (mgraProbabilities == null) + { + logger.error("Error attempting to set mgraProbabilities in CrossBorderStopLocationChoiceModel: mgraProbabilities are null"); + throw new RuntimeException(); + } + this.mgraProbabilities = mgraProbabilities; + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopPurposeModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopPurposeModel.java new file mode 100644 index 0000000..a2cdfb5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopPurposeModel.java @@ -0,0 +1,233 @@ +package org.sandag.abm.crossborder; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the stop purpose choice model for cross border tours. It is + * currently based on a static probability distribution stored in an input file, + * and indexed into by purpose, tour leg direction (inbound or outbound), the + * stop number, and whether there is just one or multiple stops on the tour leg. + * + * @author Freedman + * + */ +public class CrossBorderStopPurposeModel +{ + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + private double[][] cumProbability; // by + // alternative, + // stop + // purpose: + // cumulative + // probability + // distribution + CrossBorderModelStructure modelStructure; + + HashMap arrayElementMap; // Hashmap + // used + // to + // get + // the + // element + // number + // of + // the + // cumProbability + // array + // based + // on + // the + // tour + // purpose, + // tour + // leg + // direction, + // stop + // number, + // and + // stop + // complexity. + + /** + * Constructor. + */ + public CrossBorderStopPurposeModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String stopFrequencyFile = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.stop.purpose.file"); + stopFrequencyFile = directory + stopFrequencyFile; + + modelStructure = new CrossBorderModelStructure(); + + arrayElementMap = new HashMap(); + readStopPurposeFile(stopFrequencyFile); + + } + + /** + * Read the stop frequency distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readStopPurposeFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating stop purpose probability distribution"); + + // take a pass through the data and see how many alternatives there are + // for each purpose + int rowCount = probabilityTable.getRowCount(); + int purposes = modelStructure.NUMBER_CROSSBORDER_PURPOSES; // start at 0 + + cumProbability = new double[rowCount][purposes]; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "TourPurp"); + + int inbound = (int) probabilityTable.getValueAt(row, "Inbound"); + int stopNumber = (int) probabilityTable.getValueAt(row, "StopNum"); + int multiple = (int) probabilityTable.getValueAt(row, "Multiple"); + + // store cumulative probabilities + float cumProb = 0; + for (int p = 0; p < purposes; ++p) + { + String label = "StopPurp" + p; + cumProb += probabilityTable.getValueAt(row, label); + cumProbability[row - 1][p] += cumProb; + } + + if (Math.abs(cumProb - 1.0) > 0.00001) + logger.info("Cumulative probability for tour purpose " + purpose + " inbound " + + inbound + " stopNumber " + stopNumber + " multiple " + multiple + " is " + + cumProb); + + int key = getKey(purpose, inbound, stopNumber, multiple); + arrayElementMap.put(key, row - 1); + + } + + logger.info("End calculating stop purpose probability distribution"); + + } + + /** + * Get the key for the arrayElementMap. + * + * @param tourPurp + * Tour purpose + * @param isInbound + * 1 if the stop is on the inbound direction, else 0. + * @param stopNumber + * The number of the stop. + * @param multipleStopsOnLeg + * 1 if multiple stops on leg, else 0. + * @return arrayElementMap key. + */ + private int getKey(int tourPurp, int isInbound, int stopNumber, int multipleStopsOnLeg) + { + + return tourPurp * 1000 + isInbound * 100 + stopNumber * 10 + multipleStopsOnLeg; + } + + /** + * Calculate purposes all stops on the tour + * + * @param tour + * A cross border tour (with tour purpose) + */ + public void calculateStopPurposes(CrossBorderTour tour) + { + + // outbound stops first + if (tour.getNumberOutboundStops() != 0) + { + + int tourPurp = tour.getPurpose(); + CrossBorderStop[] stops = tour.getOutboundStops(); + int multiple = 0; + if (stops.length > 1) multiple = 1; + + // iterate through stop list and calculate purpose for each + for (int i = 0; i < stops.length; ++i) + { + int key = getKey(tourPurp, 0, i + 1, multiple); + int element = arrayElementMap.get(key); + double[] cumProb = cumProbability[element]; + double rand = tour.getRandom(); + int purpose = chooseFromDistribution(rand, cumProb); + stops[i].setPurpose((byte) purpose); + } + } + // inbound stops last + if (tour.getNumberInboundStops() != 0) + { + + int tourPurp = tour.getPurpose(); + CrossBorderStop[] stops = tour.getInboundStops(); + int multiple = 0; + if (stops.length > 1) multiple = 1; + + // iterate through stop list and calculate purpose for each + for (int i = 0; i < stops.length; ++i) + { + int key = getKey(tourPurp, 1, i + 1, multiple); + int element = arrayElementMap.get(key); + double[] cumProb = cumProbability[element]; + double rand = tour.getRandom(); + int purpose = chooseFromDistribution(rand, cumProb); + stops[i].setPurpose((byte) purpose); + } + } + } + + /** + * Choose purpose from the cumulative probability distribution + * + * @param random + * Uniformly distributed random number + * @param cumProb + * Cumulative probability distribution + * @return Stop purpose (0 init). + */ + private int chooseFromDistribution(double random, double[] cumProb) + { + + int choice = -1; + for (int i = 0; i < cumProb.length; ++i) + { + if (random < cumProb[i]) + { + choice = i; + break; + } + + } + return choice; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopTimeOfDayChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopTimeOfDayChoiceModel.java new file mode 100644 index 0000000..5e3d4a1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderStopTimeOfDayChoiceModel.java @@ -0,0 +1,365 @@ +package org.sandag.abm.crossborder; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the TOD choice model for cross border tours. It is currently + * based on a static probability distribution stored in an input file, and + * indexed into by purpose. + * + * @author Freedman + * + */ +public class CrossBorderStopTimeOfDayChoiceModel +{ + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + private double[][] outboundCumProbability; // by + // alternative: + // outbound + // cumulative + // probability + // distribution + private int[] outboundOffsets; // by + // alternative: + // offsets + // for + // outbound + // stop + // duration + // choice + + private double[][] inboundCumProbability; // by + // alternative: + // inbound + // cumulative + // probability + // distribution + private int[] inboundOffsets; // by + // alternative: + // offsets + // for + // inbound + // stop + // duration + // choice + private CrossBorderModelStructure modelStructure; + + private HashMap outboundElementMap; // Hashmap + // used + // to + // get + // the + // element + // number + // of + // the + // cumProbability + // array + // based + // on + // the + // tour duration and stop number. + + private HashMap inboundElementMap; // Hashmap + // used + // to + // get + // the + // element + // number + // of + // the + // cumProbability + // array + // based + // on + // the + + // tour duration and stop number. + + /** + * Constructor. + */ + public CrossBorderStopTimeOfDayChoiceModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String outboundDurationFile = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.stop.outbound.duration.file"); + String inboundDurationFile = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.stop.inbound.duration.file"); + + outboundDurationFile = directory + outboundDurationFile; + inboundDurationFile = directory + inboundDurationFile; + + modelStructure = new CrossBorderModelStructure(); + + outboundElementMap = new HashMap(); + readOutboundFile(outboundDurationFile); + + inboundElementMap = new HashMap(); + readInboundFile(inboundDurationFile); + } + + /** + * Read the outbound stop duration file and store the cumulative probability + * distribution as well as the offsets and set the key map to index into the + * probability array. + * + * @param fileName + */ + public void readOutboundFile(String fileName) + { + TableDataSet outboundTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + outboundTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + int columns = outboundTable.getColumnCount(); + int rows = outboundTable.getRowCount(); + outboundCumProbability = new double[rows][columns - 3]; + + // first three columns are index fields, rest are offsets + outboundOffsets = new int[columns - 3]; + for (int i = 4; i <= columns; ++i) + { + String offset = outboundTable.getColumnLabel(i); + outboundOffsets[i - 4] = new Integer(offset); + } + + // now fill in cumulative probability array + for (int row = 1; row <= rows; ++row) + { + + int lowerBound = (int) outboundTable.getValueAt(row, "RemainingLow"); + int upperBound = (int) outboundTable.getValueAt(row, "RemainingHigh"); + int stopNumber = (int) outboundTable.getValueAt(row, "Stop"); + + for (int duration = lowerBound; duration <= upperBound; ++duration) + { + int key = getKey(stopNumber, duration); + outboundElementMap.put(key, row - 1); + } + + // cumulative probability distribution + double cumProb = 0; + for (int col = 4; col <= columns; ++col) + { + cumProb += outboundTable.getValueAt(row, col); + outboundCumProbability[row - 1][col - 4] = cumProb; + } + + } + + } + + /** + * Read the inbound stop duration file and store the cumulative probability + * distribution as well as the offsets and set the key map to index into the + * probability array. + * + * @param fileName + */ + public void readInboundFile(String fileName) + { + TableDataSet inboundTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + inboundTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + int columns = inboundTable.getColumnCount(); + int rows = inboundTable.getRowCount(); + inboundCumProbability = new double[rows][columns - 3]; + + // first three columns are index fields, rest are offsets + inboundOffsets = new int[columns - 3]; + for (int i = 4; i <= columns; ++i) + { + String offset = inboundTable.getColumnLabel(i); + inboundOffsets[i - 4] = new Integer(offset); + } + + // now fill in cumulative probability array + for (int row = 1; row <= rows; ++row) + { + + int lowerBound = (int) inboundTable.getValueAt(row, "RemainingLow"); + int upperBound = (int) inboundTable.getValueAt(row, "RemainingHigh"); + int stopNumber = (int) inboundTable.getValueAt(row, "Stop"); + + for (int duration = lowerBound; duration <= upperBound; ++duration) + { + int key = getKey(stopNumber, duration); + inboundElementMap.put(key, row - 1); + } + // cumulative probability distribution + double cumProb = 0; + for (int col = 4; col <= columns; ++col) + { + cumProb += inboundTable.getValueAt(row, col); + inboundCumProbability[row - 1][col - 4] = cumProb; + } + + } + + } + + /** + * Get the key for the arrayElementMap. + * + * @param stopNumber + * stop number + * @param periodsRemaining + * Remaining time periods + * @return arrayElementMap key. + */ + private int getKey(int stopNumber, int periodsRemaining) + { + + return periodsRemaining * 10 + stopNumber; + } + + /** + * Choose the stop time of day period. + * + * @param tour + * @param stop + */ + public void chooseTOD(CrossBorderTour tour, CrossBorderStop stop) + { + + boolean inbound = stop.isInbound(); + int stopNumber = stop.getId() + 1; + int arrivalPeriod = tour.getArriveTime(); + + if (!inbound) + { + + // find the departure time + int departPeriod = 0; + if (stop.getId() == 0) departPeriod = tour.getDepartTime(); + else + { + CrossBorderStop[] stops = tour.getOutboundStops(); + departPeriod = stops[stop.getId() - 1].getStopPeriod(); + } + + int periodsRemaining = arrivalPeriod - departPeriod; + + int key = getKey(stopNumber, periodsRemaining); + int element = outboundElementMap.get(key); + double[] cumProb = outboundCumProbability[element]; + double random = tour.getRandom(); + + // iterate through the offset distribution, choose an offset, and + // set in the stop + if (tour.getDebugChoiceModels()) + { + logger.info("Stop TOD Choice Model for tour " + tour.getID() + " outbound stop " + + stop.getId() + " periods remaining " + periodsRemaining); + logger.info(" random number " + random); + } + for (int i = 0; i < cumProb.length; ++i) + { + if (random < cumProb[i]) + { + int offset = outboundOffsets[i]; + int period = departPeriod + offset; + stop.setPeriod(period); + + if (tour.getDebugChoiceModels()) + { + logger.info("***"); + logger.info("Chose alt " + i + " offset " + offset + " from depart period " + + departPeriod); + logger.info("Stop period is " + stop.getStopPeriod()); + + } + break; + + } + } + } else + { + // inbound stop + + // find the departure time + int departPeriod = 0; + + // first inbound stop + if (stop.getId() == 0) + { + + // there were outbound stops + if (tour.getOutboundStops() != null) + { + CrossBorderStop[] outboundStops = tour.getOutboundStops(); + departPeriod = outboundStops[outboundStops.length - 1].getStopPeriod(); + } else + { + // no outbound stops + departPeriod = tour.getDepartTime(); + } + } else + { + // not first inbound stop + CrossBorderStop[] stops = tour.getInboundStops(); + departPeriod = stops[stop.getId() - 1].getStopPeriod(); + } + + int periodsRemaining = arrivalPeriod - departPeriod; + + int key = getKey(stopNumber, periodsRemaining); + int element = inboundElementMap.get(key); + double[] cumProb = inboundCumProbability[element]; + double random = tour.getRandom(); + if (tour.getDebugChoiceModels()) + { + logger.info("Stop TOD Choice Model for tour " + tour.getID() + " inbound stop " + + stop.getId() + " periods remaining " + periodsRemaining); + logger.info("Random number " + random); + } + for (int i = 0; i < cumProb.length; ++i) + { + if (random < cumProb[i]) + { + int offset = inboundOffsets[i]; + int arrivePeriod = tour.getArriveTime(); + int period = arrivePeriod + offset; + stop.setPeriod(period); + + if (tour.getDebugChoiceModels()) + { + logger.info("***"); + logger.info("Chose alt " + i + " offset " + offset + " from arrive period " + + arrivePeriod); + logger.info("Stop period is " + stop.getStopPeriod()); + + } + break; + } + } + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTour.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTour.java new file mode 100644 index 0000000..59d9c2b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTour.java @@ -0,0 +1,367 @@ +package org.sandag.abm.crossborder; + +import java.io.Serializable; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Household; +import com.pb.common.math.MersenneTwister; + +public class CrossBorderTour + implements Serializable +{ + + private MersenneTwister random; + private int ID; + + // following variables determined via simulation + private byte purpose; + private boolean sentriAvailable; + + private CrossBorderStop[] outboundStops; + private CrossBorderStop[] inboundStops; + + private CrossBorderTrip[] trips; + + private int departTime; + private int arriveTime; + + private boolean debugChoiceModels; + + // following variables chosen via choice models + private int poe; + private int originMGRA; + private int destinationMGRA; + private int originTAZ; + private int destinationTAZ; + private byte tourMode; + private float workTimeFactor; + private float nonWorkTimeFactor; + private float valueOfTime; + + private boolean avAvailable; + + /** + * Public constructor. + * + * @param seed + * A seed for the random number generator. + */ + public CrossBorderTour(long seed) + { + + random = new MersenneTwister(seed); + } + + /** + * @return the iD + */ + public int getID() + { + return ID; + } + + /** + * @param iD + * the iD to set + */ + public void setID(int iD) + { + ID = iD; + } + + /** + * @return the sentriAvailable + */ + public boolean isSentriAvailable() + { + return sentriAvailable; + } + + /** + * @return the poe + */ + public int getPoe() + { + return poe; + } + + /** + * @param poe + * the poe to set + */ + public void setPoe(int poe) + { + this.poe = poe; + } + + /** + * @param sentriAvailable + * the sentriAvailable to set + */ + public void setSentriAvailable(boolean sentriAvailable) + { + this.sentriAvailable = sentriAvailable; + } + + /** + * @return the purpose + */ + public byte getPurpose() + { + return purpose; + } + + /** + * @return the outboundStops + */ + public CrossBorderStop[] getOutboundStops() + { + return outboundStops; + } + + /** + * @param outboundStops + * the outboundStops to set + */ + public void setOutboundStops(CrossBorderStop[] outboundStops) + { + this.outboundStops = outboundStops; + } + + /** + * @return the inboundStops + */ + public CrossBorderStop[] getInboundStops() + { + return inboundStops; + } + + /** + * @param inboundStops + * the inboundStops to set + */ + public void setInboundStops(CrossBorderStop[] inboundStops) + { + this.inboundStops = inboundStops; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(byte purpose) + { + this.purpose = purpose; + } + + /** + * @return the departTime + */ + public int getDepartTime() + { + return departTime; + } + + /** + * @param departTime + * the departTime to set + */ + public void setDepartTime(int departTime) + { + this.departTime = departTime; + } + + public CrossBorderTrip[] getTrips() + { + return trips; + } + + public void setTrips(CrossBorderTrip[] trips) + { + this.trips = trips; + } + + /** + * @return the originMGRA + */ + public int getOriginMGRA() + { + return originMGRA; + } + + /** + * @param originMGRA + * the originMGRA to set + */ + public void setOriginMGRA(int originMGRA) + { + this.originMGRA = originMGRA; + } + + public int getOriginTAZ() + { + return originTAZ; + } + + public void setOriginTAZ(int originTAZ) + { + this.originTAZ = originTAZ; + } + + public int getDestinationTAZ() + { + return destinationTAZ; + } + + public void setDestinationTAZ(int destinationTAZ) + { + this.destinationTAZ = destinationTAZ; + } + + /** + * @return the tour mode + */ + public byte getTourMode() + { + return tourMode; + } + + /** + * @param mode + * the tour mode to set + */ + public void setTourMode(byte mode) + { + this.tourMode = mode; + } + + /** + * Get a random number from the parties random class. + * + * @return A random number. + */ + public double getRandom() + { + return random.nextDouble(); + } + + /** + * @return the debugChoiceModels + */ + public boolean getDebugChoiceModels() + { + return debugChoiceModels; + } + + /** + * @param debugChoiceModels + * the debugChoiceModels to set + */ + public void setDebugChoiceModels(boolean debugChoiceModels) + { + this.debugChoiceModels = debugChoiceModels; + } + + + /** + * Get the number of outbound stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberOutboundStops() + { + if (outboundStops == null) return 0; + else return outboundStops.length; + + } + + /** + * Get the number of return stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberInboundStops() + { + if (inboundStops == null) return 0; + else return inboundStops.length; + + } + + /** + * @return the destinationMGRA + */ + public int getDestinationMGRA() + { + return destinationMGRA; + } + + /** + * @param destinationMGRA + * the destinationMGRA to set + */ + public void setDestinationMGRA(int destinationMGRA) + { + this.destinationMGRA = destinationMGRA; + } + + public void setArriveTime(int arriveTime) + { + this.arriveTime = arriveTime; + } + + public int getArriveTime() + { + return arriveTime; + } + + public double getWorkTimeFactor() { + return workTimeFactor; + } + + public void setWorkTimeFactor(float workTimeFactor) { + this.workTimeFactor = workTimeFactor; + } + + public double getNonWorkTimeFactor() { + return nonWorkTimeFactor; + } + + public void setNonWorkTimeFactor(float nonWorkTimeFactor) { + this.nonWorkTimeFactor = nonWorkTimeFactor; + } + + public float getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(float valueOfTime) { + this.valueOfTime = valueOfTime; + } + + public boolean isAvAvailable() { + return avAvailable; + } + + public void setAvAvailable(boolean avAvailable) { + this.avAvailable = avAvailable; + } + + public void logTourObject(Logger logger, int totalChars) + { + + Household.logHelper(logger, "tourId: ", ID, totalChars); + Household.logHelper(logger, "tourPurpose: ", purpose, totalChars); + Household.logHelper(logger, "tourOrigMgra: ", originMGRA, totalChars); + Household.logHelper(logger, "tourDestMgra: ", destinationMGRA, totalChars); + Household.logHelper(logger, "tourDepartPeriod: ", departTime, totalChars); + Household.logHelper(logger, "tourArrivePeriod: ", arriveTime, totalChars); + Household.logHelper(logger, "tourMode: ", tourMode, totalChars); + Household.logHelper(logger, "avAvailable:", (avAvailable ? 0 : 1), totalChars); + + String tempString = null; + + logger.info(tempString); + + logger.info(tempString); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourManager.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourManager.java new file mode 100644 index 0000000..97bfdb7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourManager.java @@ -0,0 +1,358 @@ +package org.sandag.abm.crossborder; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.TimeCoefficientDistributions; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +public class CrossBorderTourManager +{ + + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + + private CrossBorderTour[] tours; + private int totalTours; + + private double sentriShare; + + private double[] sentriPurposeDistribution; + private double[] nonSentriPurposeDistribution; + + CrossBorderModelStructure modelStructure; + SandagModelStructure sandagStructure; + private boolean seek; + private int traceId; + + private float avShare; + + TimeCoefficientDistributions timeDistributions; + + boolean distributedTimeCoefficients = false; + + /** + * Constructor. Reads properties file and opens/stores all probability + * distributions for sampling. Estimates number of airport travel parties + * and initializes parties[]. + * + * @param resourceFile + * Property file. + * + * Creates the array of cross-border tours. + */ + public CrossBorderTourManager(HashMap rbMap) + { + + modelStructure = new CrossBorderModelStructure(); + sandagStructure = new SandagModelStructure(); + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String nonSentriPurposeFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "crossBorder.purpose.nonsentri.file"); + String sentriPurposeFile = directory + + Util.getStringValueFromPropertyMap(rbMap, "crossBorder.purpose.sentri.file"); + + // the share of cross-border tours that are sentri is an input + sentriShare = new Double(Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.sentriShare")); + + // Read the distributions + sentriPurposeDistribution = setPurposeDistribution(sentriPurposeFile, + sentriPurposeDistribution,2); + nonSentriPurposeDistribution = setPurposeDistribution(nonSentriPurposeFile, + nonSentriPurposeDistribution,2); + totalTours = new Integer(Util.getStringValueFromPropertyMap(rbMap, "crossBorder.tours") + .replace(",", "")); + + seek = new Boolean(Util.getStringValueFromPropertyMap(rbMap, "crossBorder.seek")); + traceId = new Integer(Util.getStringValueFromPropertyMap(rbMap, "crossBorder.trace")); + + distributedTimeCoefficients = new Boolean(Util.getStringValueFromPropertyMap(rbMap, "distributedTimeCoefficients")); + + if(distributedTimeCoefficients) { + timeDistributions = new TimeCoefficientDistributions(); + timeDistributions.createTimeDistributions(rbMap); + } + + avShare = Util.getFloatValueFromPropertyMap(rbMap, "crossBorder.avShare"); + + } + + /** + * Generate and attribute cross border tours + */ + public void generateCrossBorderTours() + { + + // calculate total number of cross border tours + tours = new CrossBorderTour[totalTours]; + + logger.info("Total cross border tours: " + totalTours); + + for (int i = 0; i < tours.length; ++i) + { + + long seed = i * 10 + 1001; + CrossBorderTour tour = new CrossBorderTour(seed); + + tours[i] = tour; + + tour.setID(i + 1); + + // determine if tour is sentri, and calculate tour purpose + if (tour.getRandom() < sentriShare) + { + tour.setSentriAvailable(true); + int purpose = choosePurpose(tour.getRandom(), sentriPurposeDistribution); + tour.setPurpose((byte) purpose); + } else + { + tour.setSentriAvailable(false); + int purpose = choosePurpose(tour.getRandom(), nonSentriPurposeDistribution); + tour.setPurpose((byte) purpose); + } + + //set time factors + double workTimeFactor = 1.0; + double nonWorkTimeFactor = 1.0; + + if(distributedTimeCoefficients){ + double rnum = tour.getRandom(); + workTimeFactor = timeDistributions.sampleFromWorkDistribution(rnum); + nonWorkTimeFactor = timeDistributions.sampleFromNonWorkDistribution(rnum); + + } + tour.setWorkTimeFactor((float)workTimeFactor); + tour.setNonWorkTimeFactor((float)nonWorkTimeFactor); + + if(tour.getRandom() < avShare) + tour.setAvAvailable(true); + + } + } + + /** + * Read file containing probabilities by purpose. Store cumulative + * distribution in purposeDistribution. + * + * @param fileName + * Name of file containing two columns, one row for each purpose. + * First column has purpose number, second column has + * probability. + */ + protected double[] setPurposeDistribution(String fileName, double[] purposeDistribution, int position) + { + //logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + int purposes = modelStructure.NUMBER_CROSSBORDER_PURPOSES; + purposeDistribution = new double[purposes]; + + double total_prob = 0.0; + // calculate and store cumulative probability distribution + for (int purp = 0; purp < purposes; ++purp) + { + + double probability = probabilityTable.getValueAt(purp + 1, position); + + total_prob += probability; + purposeDistribution[purp] = total_prob; + + } + //logger.info("End storing cumulative probabilies from file " + fileName); + + return purposeDistribution; + } + + /** + * Choose a purpose. + * + * @param random + * A uniform random number. + * @return the purpose. + */ + protected int choosePurpose(double random, double[] purposeDistribution) + { + // iterate through the probability array and choose + for (int alt = 0; alt < purposeDistribution.length; ++alt) + { + if (purposeDistribution[alt] > random) return alt; + } + return -99; + } + + /** + * Create a text file and write all records to the file. + * + */ + public void writeOutputFile(HashMap rbMap) + { + + // Open file and print header + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String tourFileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "crossBorder.tour.output.file"); + String tripFileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "crossBorder.trip.output.file"); + + logger.info("Writing cross border tours to file " + tourFileName); + logger.info("Writing cross border trips to file " + tripFileName); + + PrintWriter tourWriter = null; + try + { + tourWriter = new PrintWriter(new BufferedWriter(new FileWriter(tourFileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + tourFileName + " for writing\n"); + throw new RuntimeException(); + } + String tourHeaderString = new String( + "id,purpose,sentri,poe,departTime,arriveTime,originMGRA,destinationMGRA,originTAZ,destinationTAZ,tourMode,avAvailable,workTimeFactor,nonWorkTimeFactor,valueOfTime\n"); + tourWriter.print(tourHeaderString); + + PrintWriter tripWriter = null; + try + { + tripWriter = new PrintWriter(new BufferedWriter(new FileWriter(tripFileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + tripFileName + " for writing\n"); + throw new RuntimeException(); + } + String tripHeaderString = new String( + "tourID,tripID,originPurp,destPurp,originMGRA,destinationMGRA,originTAZ,destinationTAZ,inbound,originIsTourDestination,destinationIsTourDestination,period,tripMode,avAvailable,boardingTap,alightingTap,set,workTimeFactor,nonWorkTimeFactor,valueOfTime,parkingCost\n"); + tripWriter.print(tripHeaderString); + + // Iterate through the array, printing records to the file + for (int i = 0; i < tours.length; ++i) + { + + CrossBorderTour tour = tours[i]; + + if (seek && tour.getID() != traceId) continue; + + CrossBorderTrip[] trips = tours[i].getTrips(); + + if (trips == null) continue; + + writeTour(tour, tourWriter); + + for (int j = 0; j < trips.length; ++j) + { + writeTrip(tour, trips[j], j + 1, tripWriter); + } + } + + tourWriter.close(); + tripWriter.close(); + + } + + /** + * Write the tour to the PrintWriter + * + * @param tour + * @param writer + */ + private void writeTour(CrossBorderTour tour, PrintWriter writer) + { + String record = new String(tour.getID() + "," + tour.getPurpose() + "," + + tour.isSentriAvailable() + "," + tour.getPoe() + "," + tour.getDepartTime() + "," + + tour.getArriveTime() + "," + tour.getOriginMGRA() + "," + + tour.getDestinationMGRA() + "," + tour.getOriginTAZ() + "," + + tour.getDestinationTAZ() + "," + tour.getTourMode() + "," + + (tour.isAvAvailable() ? 1 : 0) + "," + + String.format("%9.2f",tour.getWorkTimeFactor()) + "," + + String.format("%9.2f",tour.getNonWorkTimeFactor()) + "," + + String.format("%9.2f", tour.getValueOfTime()) +"\n"); + writer.print(record); + + } + + /** + * Write the trip to the PrintWriter + * + * @param tour + * @param trip + * @param tripNumber + * @param writer + */ + private void writeTrip(CrossBorderTour tour, CrossBorderTrip trip, int tripNumber, + PrintWriter writer) + { + + String record = new String(tour.getID() + "," + tripNumber + "," + trip.getOriginPurpose() + + "," + trip.getDestinationPurpose() + "," + trip.getOriginMgra() + "," + + trip.getDestinationMgra() + "," + trip.getOriginTAZ() + "," + + trip.getDestinationTAZ() + "," + trip.isInbound() + "," + + trip.isOriginIsTourDestination() + "," + trip.isDestinationIsTourDestination() + + "," + trip.getPeriod() + "," + trip.getTripMode() + "," + + (tour.isAvAvailable() ? 1 : 0) + "," + + trip.getBoardTap() + "," + trip.getAlightTap() + "," + + trip.getSet() + "," + + String.format("%9.2f",tour.getWorkTimeFactor()) + "," + + String.format("%9.2f",tour.getNonWorkTimeFactor()) + "," + + String.format("%9.2f", trip.getValueOfTime()) + "," + + String.format("%9.2f", trip.getParkingCost())+ "\n"); + writer.print(record); + } + /** + * @return the parties + */ + public CrossBorderTour[] getTours() + { + return tours; + } + + public static void main(String[] args) + { + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running Cross Border Model Tour Manager")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + CrossBorderTourManager apm = new CrossBorderTourManager(pMap); + apm.generateCrossBorderTours(); + apm.writeOutputFile(pMap); + + logger.info("Cross-Border Tour Manager successfully completed!"); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourModeChoiceDMU.java new file mode 100644 index 0000000..9fbf960 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourModeChoiceDMU.java @@ -0,0 +1,406 @@ +package org.sandag.abm.crossborder; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.TourModeChoiceDMU; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class CrossBorderTourModeChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TourModeChoiceDMU.class); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected double tourPurpose; + protected double tourModelsSentri; + protected double borderWaitStd; + protected double borderWaitPed; + protected double borderWaitSentri; + + protected double outboundTripMcLogsumDA; + protected double outboundTripMcLogsumSR2; + protected double outboundTripMcLogsumSR3; + protected double outboundTripMcLogsumWalk; + protected double inboundTripMcLogsumDA; + protected double inboundTripMcLogsumSR2; + protected double inboundTripMcLogsumSR3; + protected double inboundTripMcLogsumWalk; + + /** + * Constructor. + * + * @param modelStructure + */ + public CrossBorderTourModeChoiceDMU(CrossBorderModelStructure modelStructure) + { + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * @return the tourPurpose + */ + public double getTourPurpose() + { + return tourPurpose; + } + + /** + * @param tourPurpose + * the tourPurpose to set + */ + public void setTourPurpose(double tourPurpose) + { + this.tourPurpose = tourPurpose; + } + + /** + * @return the tourModelsSentri + */ + public double getTourModelsSentri() + { + return tourModelsSentri; + } + + /** + * @param tourModelsSentri + * the tourModelsSentri to set + */ + public void setTourModelsSentri(double tourModelsSentri) + { + this.tourModelsSentri = tourModelsSentri; + } + + /** + * @return the borderWaitStd + */ + public double getBorderWaitStd() + { + return borderWaitStd; + } + + /** + * @param borderWaitStd + * the borderWaitStd to set + */ + public void setBorderWaitStd(double borderWaitStd) + { + this.borderWaitStd = borderWaitStd; + } + + /** + * @return the borderWaitPed + */ + public double getBorderWaitPed() + { + return borderWaitPed; + } + + /** + * @param borderWaitPed + * the borderWaitPed to set + */ + public void setBorderWaitPed(double borderWaitPed) + { + this.borderWaitPed = borderWaitPed; + } + + /** + * @return the borderWaitSentri + */ + public double getBorderWaitSentri() + { + return borderWaitSentri; + } + + /** + * @param borderWaitSentri + * the borderWaitSentri to set + */ + public void setBorderWaitSentri(double borderWaitSentri) + { + this.borderWaitSentri = borderWaitSentri; + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the outboundTripMcLogsumDA + */ + public double getOutboundTripMcLogsumDA() + { + return outboundTripMcLogsumDA; + } + + /** + * @param outboundTripMcLogsumDA + * the outboundTripMcLogsumDA to set + */ + public void setOutboundTripMcLogsumDA(double outboundTripMcLogsumDA) + { + this.outboundTripMcLogsumDA = outboundTripMcLogsumDA; + } + + /** + * @return the outboundTripMcLogsumSR2 + */ + public double getOutboundTripMcLogsumSR2() + { + return outboundTripMcLogsumSR2; + } + + /** + * @param outboundTripMcLogsumSR2 + * the outboundTripMcLogsumSR2 to set + */ + public void setOutboundTripMcLogsumSR2(double outboundTripMcLogsumSR2) + { + this.outboundTripMcLogsumSR2 = outboundTripMcLogsumSR2; + } + + /** + * @return the outboundTripMcLogsumSR3 + */ + public double getOutboundTripMcLogsumSR3() + { + return outboundTripMcLogsumSR3; + } + + /** + * @param outboundTripMcLogsumSR3 + * the outboundTripMcLogsumSR3 to set + */ + public void setOutboundTripMcLogsumSR3(double outboundTripMcLogsumSR3) + { + this.outboundTripMcLogsumSR3 = outboundTripMcLogsumSR3; + } + + /** + * @return the outboundTripMcLogsumWalk + */ + public double getOutboundTripMcLogsumWalk() + { + return outboundTripMcLogsumWalk; + } + + /** + * @param outboundTripMcLogsumWalk + * the outboundTripMcLogsumWalk to set + */ + public void setOutboundTripMcLogsumWalk(double outboundTripMcLogsumWalk) + { + this.outboundTripMcLogsumWalk = outboundTripMcLogsumWalk; + } + + /** + * @return the inboundTripMcLogsumDA + */ + public double getInboundTripMcLogsumDA() + { + return inboundTripMcLogsumDA; + } + + /** + * @param inboundTripMcLogsumDA + * the inboundTripMcLogsumDA to set + */ + public void setInboundTripMcLogsumDA(double inboundTripMcLogsumDA) + { + this.inboundTripMcLogsumDA = inboundTripMcLogsumDA; + } + + /** + * @return the inboundTripMcLogsumSR2 + */ + public double getInboundTripMcLogsumSR2() + { + return inboundTripMcLogsumSR2; + } + + /** + * @param inboundTripMcLogsumSR2 + * the inboundTripMcLogsumSR2 to set + */ + public void setInboundTripMcLogsumSR2(double inboundTripMcLogsumSR2) + { + this.inboundTripMcLogsumSR2 = inboundTripMcLogsumSR2; + } + + /** + * @return the inboundTripMcLogsumSR3 + */ + public double getInboundTripMcLogsumSR3() + { + return inboundTripMcLogsumSR3; + } + + /** + * @param inboundTripMcLogsumSR3 + * the inboundTripMcLogsumSR3 to set + */ + public void setInboundTripMcLogsumSR3(double inboundTripMcLogsumSR3) + { + this.inboundTripMcLogsumSR3 = inboundTripMcLogsumSR3; + } + + /** + * @return the inboundTripMcLogsumWalk + */ + public double getInboundTripMcLogsumWalk() + { + return inboundTripMcLogsumWalk; + } + + /** + * @param inboundTripMcLogsumWalk + * the inboundTripMcLogsumWalk to set + */ + public void setInboundTripMcLogsumWalk(double inboundTripMcLogsumWalk) + { + this.inboundTripMcLogsumWalk = inboundTripMcLogsumWalk; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTourPurpose", 0); + methodIndexMap.put("getTourModelsSentri", 1); + methodIndexMap.put("getBorderWaitStd", 2); + methodIndexMap.put("getBorderWaitPed", 3); + methodIndexMap.put("getBorderWaitSentri", 4); + + methodIndexMap.put("getOutboundTripMcLogsumDA", 30); + methodIndexMap.put("getOutboundTripMcLogsumSR2", 31); + methodIndexMap.put("getOutboundTripMcLogsumSR3", 32); + methodIndexMap.put("getOutboundTripMcLogsumWalk", 33); + methodIndexMap.put("getInboundTripMcLogsumDA", 34); + methodIndexMap.put("getInboundTripMcLogsumSR2", 35); + methodIndexMap.put("getInboundTripMcLogsumSR3", 36); + methodIndexMap.put("getInboundTripMcLogsumWalk", 37); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getTourPurpose(); + break; + case 1: + returnValue = getTourModelsSentri(); + break; + case 2: + returnValue = getBorderWaitStd(); + break; + case 3: + returnValue = getBorderWaitPed(); + break; + case 4: + returnValue = getBorderWaitSentri(); + break; + case 30: + returnValue = getOutboundTripMcLogsumDA(); + break; + case 31: + returnValue = getOutboundTripMcLogsumSR2(); + break; + case 32: + returnValue = getOutboundTripMcLogsumSR3(); + break; + case 33: + returnValue = getOutboundTripMcLogsumWalk(); + break; + case 34: + returnValue = getInboundTripMcLogsumDA(); + break; + case 35: + returnValue = getInboundTripMcLogsumSR2(); + break; + case 36: + returnValue = getInboundTripMcLogsumSR3(); + break; + case 37: + returnValue = getInboundTripMcLogsumWalk(); + break; + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourModeChoiceModel.java new file mode 100644 index 0000000..aa15f6f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourModeChoiceModel.java @@ -0,0 +1,590 @@ +package org.sandag.abm.crossborder; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class CrossBorderTourModeChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + public static final boolean DEBUG_BEST_PATHS = false; + + private MgraDataManager mgraManager; + + /** + * A private class used as a key to store the wait times for a particular + * station. + * + * @author Freedman + * + */ + private class WaitTimeClass + { + int[] beginPeriod; // by time periods + int[] endPeriod; // by time periods + float[] StandardWait; // by time periods + float[] SENTRIWait; // by time periods + float[] PedestrianWait; // by time periods + } + + HashMap waitTimeMap; + + private static final String PROPERTIES_UEC_TOUR_MODE_CHOICE = "crossBorder.tour.mc.uec.file"; + private static final String PROPERTIES_UEC_TOUR_DATA_SHEET = "crossBorder.tour.mc.data.page"; + private static final String PROPERTIES_UEC_MANDATORY_MODEL_SHEET = "crossBorder.tour.mc.mandatory.model.page"; + private static final String PROPERTIES_UEC_NONMANDATORY_MODEL_SHEET = "crossBorder.tour.mc.nonmandatory.model.page"; + private static final String PROPERTIES_POE_WAITTIMES = "crossBorder.poe.waittime.file"; + + private ChoiceModelApplication[] mcModel; // by + // segment + // - + // mandatory + // vs + // non-mandatory + // (each + // has + // different + // nesting + // coefficients) + private CrossBorderTripModeChoiceModel tripModeChoiceModel; + private CrossBorderTourModeChoiceDMU mcDmuObject; + private McLogsumsCalculator logsumHelper; + + private CrossBorderModelStructure modelStructure; + + private String tourCategory; + + private String[] modeAltNames; + + private boolean saveUtilsProbsFlag = false; + + double logsum = 0; + + // placeholders for calculation of logsums + private CrossBorderTour tour; + private CrossBorderTrip trip; + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public CrossBorderTourModeChoiceModel(HashMap propertyMap, + CrossBorderModelStructure myModelStructure, CrossBorderDmuFactoryIf dmuFactory, + AutoTazSkimsCalculator tazDistanceCalculator) + { + + mgraManager = MgraDataManager.getInstance(propertyMap); + modelStructure = myModelStructure; + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + mcDmuObject = dmuFactory.getCrossBorderTourModeChoiceDMU(); + setupModeChoiceModelApplicationArray(propertyMap); + + // Create a trip mode choice model object for calculation of logsums + tripModeChoiceModel = new CrossBorderTripModeChoiceModel(propertyMap, myModelStructure, + dmuFactory, tazDistanceCalculator); + + tour = new CrossBorderTour(0); + trip = new CrossBorderTrip(); + + String directory = Util.getStringValueFromPropertyMap(propertyMap, "Project.Directory"); + String waitTimeFile = Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_POE_WAITTIMES); + waitTimeFile = directory + waitTimeFile; + + readWaitTimeFile(waitTimeFile); + } + + /** + * Read UECs and create model application objects. + * + * @param propertyMap + */ + private void setupModeChoiceModelApplicationArray(HashMap propertyMap) + { + + logger.info(String + .format("Setting up cross border tour (border crossing) mode choice model.")); + + // locate the mandatory tour mode choice model UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_TOUR_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + logger.info("Will read mcUECFile " + mcUecFile); + int dataPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_TOUR_DATA_SHEET)); + int mandatoryModelPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_MANDATORY_MODEL_SHEET)); + int nonmandatoryModelPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_NONMANDATORY_MODEL_SHEET)); + + // default is to not save the tour mode choice utils and probs for each + // tour + String saveUtilsProbsString = propertyMap + .get(CtrampApplication.PROPERTIES_SAVE_TOUR_MODE_CHOICE_UTILS); + if (saveUtilsProbsString != null) + { + if (saveUtilsProbsString.equalsIgnoreCase("true")) saveUtilsProbsFlag = true; + } + + mcModel = new ChoiceModelApplication[2]; + + mcModel[0] = new ChoiceModelApplication(mcUecFile, mandatoryModelPage, dataPage, + propertyMap, (VariableTable) mcDmuObject); + mcModel[1] = new ChoiceModelApplication(mcUecFile, nonmandatoryModelPage, dataPage, + propertyMap, (VariableTable) mcDmuObject); + + modeAltNames = mcModel[0].getAlternativeNames(); + + } + + /** + * Get the Logsum. + * + * @param tour + * @param modelLogger + * @param choiceModelDescription + * @param decisionMakerLabel + * @return + */ + public double getLogsum(CrossBorderTour tour, Logger modelLogger, + String choiceModelDescription, String decisionMakerLabel) + { + + // set all tour mode DMU attributes including calculation of trip mode + // choice logsums for inbound & outbound directions. + setDmuAttributes(tour); + + return getModeChoiceLogsum(tour, modelLogger, choiceModelDescription, decisionMakerLabel); + + } + + /** + * Set the tour mode choice attributes. + * + * @param tour + */ + public void setDmuAttributes(CrossBorderTour tour) + { + + codeWaitTime(tour); + setTripLogsums(tour); + } + + /** + * Code wait times in the mc dmu object. + * + * @param tour + * The tour with an origin MGRA and departure time period. + */ + public void codeWaitTime(CrossBorderTour tour) + { + + // get the wait time class from the waitTimeMap HashMap + int station = tour.getPoe(); + int period = tour.getDepartTime(); + WaitTimeClass wait = waitTimeMap.get(station); + int[] beginTime = wait.beginPeriod; + int[] endTime = wait.endPeriod; + + // iterate through time arrays, find corresponding row, and set wait + // times + for (int i = 0; i < beginTime.length; ++i) + { + if (period >= beginTime[i] && period <= endTime[i]) + { + mcDmuObject.borderWaitStd = wait.StandardWait[i]; + mcDmuObject.borderWaitSentri = wait.SENTRIWait[i]; + mcDmuObject.borderWaitPed = wait.PedestrianWait[i]; + break; + } + } + } + + /** + * Set trip mode choice logsums (outbound and inbound) for calculation of + * tour mode choice model. + * + * @param tour + * The tour with other attributes such as origin, destination, + * purpose coded. + */ + public void setTripLogsums(CrossBorderTour tour) + { + + // outbound + trip.initializeFromTour(tour, true); + + // DA logsum + tour.setTourMode(modelStructure.DRIVEALONE); + double logsumDAOut = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setOutboundTripMcLogsumDA(logsumDAOut); + + // S2 logsum + tour.setTourMode(modelStructure.SHARED2); + double logsumS2Out = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setOutboundTripMcLogsumSR2(logsumS2Out); + + // S2 logsum + tour.setTourMode(modelStructure.SHARED3); + double logsumS3Out = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setOutboundTripMcLogsumSR3(logsumS3Out); + + // walk logsum + tour.setTourMode(modelStructure.WALK); + double logsumWalkOut = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setOutboundTripMcLogsumWalk(logsumWalkOut); + + // inbound + trip.initializeFromTour(tour, false); + + // DA logsum + tour.setTourMode(modelStructure.DRIVEALONE); + double logsumDAIn = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setInboundTripMcLogsumDA(logsumDAIn); + + // S2 logsum + tour.setTourMode(modelStructure.SHARED2); + double logsumS2In = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setInboundTripMcLogsumSR2(logsumS2In); + + // S2 logsum + tour.setTourMode(modelStructure.SHARED3); + double logsumS3In = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setInboundTripMcLogsumSR3(logsumS3In); + + // walk logsum + tour.setTourMode(modelStructure.WALK); + double logsumWalkIn = tripModeChoiceModel.computeUtilities(tour, trip); + mcDmuObject.setInboundTripMcLogsumWalk(logsumWalkIn); + + } + + /** + * Get an index into the mcModel array for the tour purpose. + * + * @param tour + * @return The index. + */ + public int getModelIndex(CrossBorderTour tour) + { + int modelIndex = 1; + if (tour.getPurpose() == modelStructure.WORK || tour.getPurpose() == modelStructure.SCHOOL) + modelIndex = 0; + return modelIndex; + } + + /** + * Get the tour mode choice logsum. + * + * @param tour + * @param modelLogger + * @param choiceModelDescription + * @param decisionMakerLabel + * @return Tour mode choice logsum + */ + public double getModeChoiceLogsum(CrossBorderTour tour, Logger modelLogger, + String choiceModelDescription, String decisionMakerLabel) + { + setDmuAttributes(tour); + + int modelIndex = getModelIndex(tour); + + // log headers to traceLogger + if (tour.getDebugChoiceModels()) + { + + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + } + + mcModel[modelIndex].computeUtilities(mcDmuObject, mcDmuObject.getDmuIndexValues()); + + double logsum = mcModel[modelIndex].getLogsum(); + + // write UEC calculation results to separate model specific log file + if (tour.getDebugChoiceModels()) + { + String loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + mcModel[modelIndex].logUECResults(modelLogger, loggingHeader); + modelLogger.info(choiceModelDescription + " Logsum value: " + logsum); + modelLogger.info(""); + modelLogger.info(""); + } + + return logsum; + + } + + /** + * Use to choose tour mode and set result in tour object. Also set value of time in tour object. + * + * @param tour + * The crossborder tour + */ + public void chooseTourMode(CrossBorderTour tour) + { + + byte tourMode = (byte) getModeChoice(tour); + tour.setTourMode(tourMode); + + float valueOfTime = tripModeChoiceModel.getTourValueOfTime(tourMode); + tour.setValueOfTime(valueOfTime); + } + + /** + * Use to return the tour mode without setting in the tour object. + * + * @param tour + * The cross border tour whose mode to choose. + * @return An integer corresponding to the tour mode. + */ + public int getModeChoice(CrossBorderTour tour) + { + int modelIndex = getModelIndex(tour); + + Logger modelLogger = null; + modelLogger = logger; + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + String separator = ""; + + if (tour.getDebugChoiceModels()) + { + String purposeName = modelStructure.CROSSBORDER_PURPOSES[tour.getPurpose()]; + choiceModelDescription = String.format( + "%s Tour Mode Choice Model for: Purpose=%s, Origin=%d, Dest=%d", tourCategory, + purposeName, tour.getOriginMGRA(), tour.getDestinationMGRA()); + decisionMakerLabel = String.format(" tour ID =%d", tour.getID()); + loggingHeader = String.format("%s %s", choiceModelDescription, decisionMakerLabel); + + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + + tour.logTourObject(modelLogger, loggingHeader.length()); + } + + setDmuAttributes(tour); + + mcModel[modelIndex].computeUtilities(mcDmuObject, mcDmuObject.getDmuIndexValues()); + + double rn = tour.getRandom(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen; + if (mcModel[modelIndex].getAvailabilityCount() > 0) + { + + chosen = mcModel[modelIndex].getChoiceResult(rn); + + } else + { + + String purposeName = modelStructure.CROSSBORDER_PURPOSES[tour.getPurpose()]; + choiceModelDescription = String + .format("No alternatives available for %s Tour Mode Choice Model for: Purpose=%s, Orig=%d, Dest=%d", + tourCategory, purposeName, tour.getOriginMGRA(), + tour.getDestinationMGRA()); + decisionMakerLabel = String.format("TourId=%d", tour.getID()); + loggingHeader = String.format("%s %s", choiceModelDescription, decisionMakerLabel); + + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + + tour.logTourObject(modelLogger, loggingHeader.length()); + + mcModel[modelIndex].logUECResults(modelLogger, loggingHeader); + modelLogger.info(""); + modelLogger.info(""); + + logger.error(String + .format("Exception caught for HHID=%d, no available %s tour mode alternatives to choose from in choiceModelApplication.", + tour.getID(), tourCategory)); + throw new RuntimeException(); + } + + // debug output + if (tour.getDebugChoiceModels()) + { + + double[] utilities = mcModel[modelIndex].getUtilities(); // 0s-indexing + double[] probabilities = mcModel[modelIndex].getProbabilities(); // 0s-indexing + boolean[] availabilities = mcModel[modelIndex].getAvailabilities(); // 1s-indexing + String[] altNames = mcModel[modelIndex].getAlternativeNames(); // 0s-indexing + + modelLogger.info("Tour Id: " + tour.getID()); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("-------------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < mcModel[modelIndex].getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %s", k + 1, altNames[k]); + modelLogger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", altString, + availabilities[k + 1], utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %s", chosen, altNames[chosen - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f", altString, rn)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to log file + mcModel[modelIndex].logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + mcModel[modelIndex].logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, + chosen); + mcModel[modelIndex].logLogitCalculations(choiceModelDescription, decisionMakerLabel); + + // write UEC calculation results to separate model specific log file + mcModel[modelIndex].logUECResults(modelLogger, loggingHeader); + } + + if (saveUtilsProbsFlag) + { + + // get the utilities and probabilities arrays for the tour mode + // choice + // model for this tour and save them to the tour object + double[] dUtils = mcModel[modelIndex].getUtilities(); + double[] dProbs = mcModel[modelIndex].getProbabilities(); + + float[] utils = new float[dUtils.length]; + float[] probs = new float[dUtils.length]; + for (int k = 0; k < dUtils.length; k++) + { + utils[k] = (float) dUtils[k]; + probs[k] = (float) dProbs[k]; + } + + // tour.setTourModalUtilities(utils); + // tour.setTourModalProbabilities(probs); + + } + + return chosen; + + } + + /** + * Read wait time file and store wait times in waitTimeMap HashMap. + * + * @param fileName + * Name of file containing station, beginPeriod, endPeriod and + * wait time for standard, SENTRI, and pedestrians. + */ + protected void readWaitTimeFile(String fileName) + { + logger.info("Begin reading the data in file " + fileName); + TableDataSet waitTimeTable; + waitTimeMap = new HashMap(); + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + waitTimeTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + int rowCount = waitTimeTable.getRowCount(); + + // iterate through file and fill up waitTimeMap + int lastStation = -999; + int index = 0; + WaitTimeClass wait = null; + for (int row = 1; row <= rowCount; ++row) + { + + int station = (int) waitTimeTable.getValueAt(row, "poe"); + if (station != lastStation) + { + wait = new WaitTimeClass(); + wait.beginPeriod = new int[modelStructure.TIME_PERIODS]; + wait.endPeriod = new int[modelStructure.TIME_PERIODS]; + wait.StandardWait = new float[modelStructure.TIME_PERIODS]; + wait.SENTRIWait = new float[modelStructure.TIME_PERIODS]; + wait.PedestrianWait = new float[modelStructure.TIME_PERIODS]; + index = 0; + lastStation = station; + } else + { + ++index; + } + + wait.beginPeriod[index] = (int) waitTimeTable.getValueAt(row, "StartPeriod"); + wait.endPeriod[index] = (int) waitTimeTable.getValueAt(row, "EndPeriod"); + wait.StandardWait[index] = waitTimeTable.getValueAt(row, "StandardWait"); + wait.SENTRIWait[index] = waitTimeTable.getValueAt(row, "SENTRIWait"); + wait.PedestrianWait[index] = waitTimeTable.getValueAt(row, "PedestrianWait"); + + waitTimeMap.put(station, wait); + + } + logger.info("End reading the data in file " + fileName); + + } + + public String[] getModeAltNames(int purposeIndex) + { + return modeAltNames; + } + + /** + * @return the tripModeChoiceModel + */ + public CrossBorderTripModeChoiceModel getTripModeChoiceModel() + { + return tripModeChoiceModel; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourTimeOfDayChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourTimeOfDayChoiceModel.java new file mode 100644 index 0000000..31e4bb6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTourTimeOfDayChoiceModel.java @@ -0,0 +1,188 @@ +package org.sandag.abm.crossborder; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the TOD choice model for cross border tours. It is currently + * based on a static probability distribution stored in an input file, and + * indexed into by purpose. + * + * @author Freedman + * + */ +public class CrossBorderTourTimeOfDayChoiceModel +{ + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + private double[][] cumProbability; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + private int[][] outboundPeriod; // by + // purpose, + // alternative: + // outbound + // period + private int[][] returnPeriod; // by + // purpose, + // alternative: + // return + // period + CrossBorderModelStructure modelStructure; + + /** + * Constructor. + */ + public CrossBorderTourTimeOfDayChoiceModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String stationDiurnalFile = Util.getStringValueFromPropertyMap(rbMap, + "crossBorder.tour.tod.file"); + stationDiurnalFile = directory + stationDiurnalFile; + + modelStructure = new CrossBorderModelStructure(); + + readTODFile(stationDiurnalFile); + + } + + /** + * Read the TOD distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readTODFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating tour TOD probability distribution"); + + int purposes = modelStructure.NUMBER_CROSSBORDER_PURPOSES; // start at 0 + int periods = modelStructure.TIME_PERIODS; // start at 1 + int periodCombinations = periods * (periods + 1) / 2; + + cumProbability = new double[purposes][periodCombinations]; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + outboundPeriod = new int[purposes][periodCombinations]; // by purpose, + // alternative: + // outbound + // period + returnPeriod = new int[purposes][periodCombinations]; // by purpose, + // alternative: + // return period + + // fill up arrays + int rowCount = probabilityTable.getRowCount(); + int lastPurpose = -99; + double cumProb = 0; + int alt = 0; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose"); + int outPer = (int) probabilityTable.getValueAt(row, "EntryPeriod"); + int retPer = (int) probabilityTable.getValueAt(row, "ReturnPeriod"); + + // continue if return period before outbound period + if (retPer < outPer) continue; + + // reset if new purpose + if (purpose != lastPurpose) + { + + // log cumulative probability just in case + /* + if (lastPurpose != -99) + logger.info("Cumulative probability for purpose " + purpose + " is " + cumProb); + */ + cumProb = 0; + alt = 0; + } + + // calculate cumulative probability and store in array + cumProb += probabilityTable.getValueAt(row, "Percent"); + cumProbability[purpose][alt] = cumProb; + outboundPeriod[purpose][alt] = outPer; + returnPeriod[purpose][alt] = retPer; + + //temporary + //logger.info("row="+row+" alt="+alt+" purpose="+purpose+" outPer="+outPer+" retPer="+retPer+" cumProb="+cumProb); + + ++alt; + + lastPurpose = purpose; + } + + logger.info("End calculating tour TOD probability distribution"); + + } + + /** + * Calculate tour time of day for the tour. + * + * @param tour + * A cross border tour (with purpose) + */ + public void calculateTourTOD(CrossBorderTour tour) + { + + int purpose = tour.getPurpose(); + double random = tour.getRandom(); + + if (tour.getDebugChoiceModels()) + { + logger.info("Choosing tour time of day for purpose " + + modelStructure.CROSSBORDER_PURPOSES[purpose] + " using random number " + + random); + tour.logTourObject(logger, 100); + } + + for (int i = 0; i < cumProbability[purpose].length; ++i) + { + + if (random < cumProbability[purpose][i]) + { + int depart = outboundPeriod[purpose][i]; + int arrive = returnPeriod[purpose][i]; + tour.setDepartTime(depart); + tour.setArriveTime(arrive); + break; + } + } + + if (tour.getDebugChoiceModels()) + { + logger.info(""); + logger.info("Chose depart period " + tour.getDepartTime() + " and arrival period " + + tour.getArriveTime()); + logger.info(""); + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTrip.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTrip.java new file mode 100644 index 0000000..02d205c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTrip.java @@ -0,0 +1,502 @@ +package org.sandag.abm.crossborder; + +public class CrossBorderTrip +{ + + private int originMgra; + private int destinationMgra; + private int originTAZ; + private int destinationTAZ; + private int tripMode; + private byte originPurpose; + private byte destinationPurpose; + private byte period; + private boolean inbound; + private boolean firstTrip; + private boolean lastTrip; + private boolean originIsTourDestination; + private boolean destinationIsTourDestination; + + private float parkingCost; + + private int boardTap; + private int alightTap; + private int set = -1; + float valueOfTime; + + /** + * Default constructor; nothing initialized. + */ + public CrossBorderTrip() + { + + } + + /** + * Create a cross border trip from a tour leg (no stops). + * + * @param tour + * The tour. + * @param outbound + * Outbound direction + */ + public CrossBorderTrip(CrossBorderTour tour, boolean outbound) + { + + initializeFromTour(tour, outbound); + + } + + /** + * Initilize from the tour. + * + * @param tour + * The tour. + * @param outbound + * Outbound direction. + */ + public void initializeFromTour(CrossBorderTour tour, boolean outbound) + { + // Note: mode is unknown + if (outbound) + { + this.originMgra = tour.getOriginMGRA(); + this.destinationMgra = tour.getDestinationMGRA(); + this.originTAZ = tour.getOriginTAZ(); + this.destinationTAZ = tour.getDestinationTAZ(); + this.originPurpose = -1; + this.destinationPurpose = tour.getPurpose(); + this.period = (byte) tour.getDepartTime(); + this.inbound = false; + this.firstTrip = true; + this.lastTrip = false; + this.originIsTourDestination = false; + this.destinationIsTourDestination = true; + } else + { + this.originMgra = tour.getDestinationMGRA(); + this.destinationMgra = tour.getOriginMGRA(); + this.originTAZ = tour.getDestinationTAZ(); + this.destinationTAZ = tour.getOriginTAZ(); + this.originPurpose = tour.getPurpose(); + this.destinationPurpose = -1; + this.period = (byte) tour.getArriveTime(); + this.inbound = true; + this.firstTrip = false; + this.lastTrip = true; + this.originIsTourDestination = true; + this.destinationIsTourDestination = false; + } + + } + + /** + * Create a cross border trip from a tour\stop. Note: trip mode is unknown. + * Stop period is only known for first, last stop on tour. + * + * @param tour + * The tour. + * @param stop + * The stop + */ + public CrossBorderTrip(CrossBorderTour tour, CrossBorderStop stop, boolean toStop) + { + + initializeFromStop(tour, stop, toStop); + } + + /** + * Initialize from stop attributes. A trip will be created to the stop if + * toStop is true, else a trip will be created from the stop. Use after all + * stop locations are known, or else reset the stop origin and destination + * mgras accordingly after using. + * + * @param tour + * @param stop + * @param toStop + */ + public void initializeFromStop(CrossBorderTour tour, CrossBorderStop stop, boolean toStop) + { + + this.inbound = stop.isInbound(); + this.destinationIsTourDestination = false; + this.originIsTourDestination = false; + + // if trip to stop, destination is stop mgra; else origin is stop mgra + if (toStop) + { + this.destinationMgra = stop.getMgra(); + this.destinationTAZ = stop.getTAZ(); + this.destinationPurpose = stop.getPurpose(); + } else + { + this.originMgra = stop.getMgra(); + this.originTAZ = stop.getTAZ(); + this.originPurpose = stop.getPurpose(); + } + CrossBorderStop[] stops; + + if (!inbound) stops = tour.getOutboundStops(); + else stops = tour.getInboundStops(); + + // if outbound, and trip is to stop + if (!inbound && toStop) + { + + // first trip on outbound journey, origin is tour origin + if (stop.getId() == 0) + { + this.originMgra = tour.getOriginMGRA(); + this.originTAZ = tour.getOriginTAZ(); + this.originPurpose = -1; + this.period = (byte) tour.getDepartTime(); + } else + { + // not first trip on outbound journey, origin is last stop + this.originMgra = stops[stop.getId() - 1].getMgra(); // last + // stop + // location + this.originTAZ = stops[stop.getId() - 1].getTAZ(); // last stop + // location + this.originPurpose = stops[stop.getId() - 1].getPurpose(); // last + // stop + // location + this.period = (byte) stops[stop.getId() - 1].getStopPeriod(); + } + } else if (!inbound && !toStop) + { + // outbound and trip is from stop to either next stop or tour + // destination. + + // last trip on outbound journey, destination is tour destination + if (stop.getId() == (stops.length - 1)) + { + this.destinationMgra = tour.getDestinationMGRA(); + this.destinationTAZ = tour.getDestinationTAZ(); + this.destinationPurpose = tour.getPurpose(); + this.destinationIsTourDestination = true; + } else + { + // not last trip on outbound journey, destination is next stop + this.destinationMgra = stops[stop.getId() + 1].getMgra(); + this.destinationTAZ = stops[stop.getId() + 1].getTAZ(); + this.destinationPurpose = stops[stop.getId() + 1].getPurpose(); + } + + // the period for the trip is the origin for the trip + if (stop.getId() == 0) this.period = (byte) tour.getDepartTime(); + else this.period = (byte) stops[stop.getId() - 1].getStopPeriod(); + + } else if (inbound && toStop) + { + // inbound, trip is to stop from either tour destination or last + // stop. + + // first inbound trip; origin is tour destination + if (stop.getId() == 0) + { + this.originMgra = tour.getDestinationMGRA(); + this.originTAZ = tour.getDestinationTAZ(); + this.originPurpose = tour.getPurpose(); + this.originIsTourDestination = true; + } else + { + // not first inbound trip; origin is last stop + this.originMgra = stops[stop.getId() - 1].getMgra(); // last + // stop + // location + this.originTAZ = stops[stop.getId() - 1].getTAZ(); // last stop + // location + this.originPurpose = stops[stop.getId() - 1].getPurpose(); + } + + // the period for the trip is the destination for the trip + if (stop.getId() == stops.length - 1) this.period = (byte) tour.getArriveTime(); + else this.period = (byte) stops[stop.getId() + 1].getStopPeriod(); + } else + { + // inbound, trip is from stop to either next stop or tour origin. + + // last trip, destination is back to tour origin + if (stop.getId() == (stops.length - 1)) + { + this.destinationMgra = tour.getOriginMGRA(); + this.destinationTAZ = tour.getOriginTAZ(); + this.destinationPurpose = -1; + this.period = (byte) tour.getArriveTime(); + } else + { + // not last trip, destination is next stop + this.destinationMgra = stops[stop.getId() + 1].getMgra(); + this.destinationTAZ = stops[stop.getId() + 1].getTAZ(); + this.destinationPurpose = stops[stop.getId() + 1].getPurpose(); + this.period = (byte) stops[stop.getId() + 1].getStopPeriod(); + } + } + + // code period for first trip on tour + if (toStop && !inbound && stop.getId() == 0) + { + this.firstTrip = true; + this.lastTrip = false; + this.period = (byte) tour.getDepartTime(); + } + // code period for last trip on tour + if (!toStop && inbound && stop.getId() == (stops.length - 1)) + { + this.firstTrip = false; + this.lastTrip = true; + this.period = (byte) tour.getArriveTime(); + } + + } + + /** + * @return the period + */ + public byte getPeriod() + { + return period; + } + + /** + * @param period + * the period to set + */ + public void setPeriod(byte period) + { + this.period = period; + } + + /** + * @return the origin purpose + */ + public byte getOriginPurpose() + { + return originPurpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setOriginPurpose(byte purpose) + { + this.originPurpose = purpose; + } + + /** + * @return the destination purpose + */ + public byte getDestinationPurpose() + { + return destinationPurpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setDestinationPurpose(byte purpose) + { + this.destinationPurpose = purpose; + } + + /** + * @return the originMgra + */ + public int getOriginMgra() + { + return originMgra; + } + + /** + * @param originMgra + * the originMgra to set + */ + public void setOriginMgra(int originMgra) + { + this.originMgra = originMgra; + } + + /** + * @return the destinationMgra + */ + public int getDestinationMgra() + { + return destinationMgra; + } + + /** + * @param destinationMgra + * the destinationMgra to set + */ + public void setDestinationMgra(int destinationMgra) + { + this.destinationMgra = destinationMgra; + } + + public int getOriginTAZ() + { + return originTAZ; + } + + public void setOriginTAZ(int originTAZ) + { + this.originTAZ = originTAZ; + } + + public int getDestinationTAZ() + { + return destinationTAZ; + } + + public void setDestinationTAZ(int destinationTAZ) + { + this.destinationTAZ = destinationTAZ; + } + + /** + * @return the tripMode + */ + public int getTripMode() + { + return tripMode; + } + + /** + * @param tripMode + * the tripMode to set + */ + public void setTripMode(int tripMode) + { + this.tripMode = tripMode; + } + + + /** + * @return the inbound + */ + public boolean isInbound() + { + return inbound; + } + + /** + * @param inbound + * the inbound to set + */ + public void setInbound(boolean inbound) + { + this.inbound = inbound; + } + + /** + * @return the firstTrip + */ + public boolean isFirstTrip() + { + return firstTrip; + } + + /** + * @param firstTrip + * the firstTrip to set + */ + public void setFirstTrip(boolean firstTrip) + { + this.firstTrip = firstTrip; + } + + /** + * @return the lastTrip + */ + public boolean isLastTrip() + { + return lastTrip; + } + + /** + * @param lastTrip + * the lastTrip to set + */ + public void setLastTrip(boolean lastTrip) + { + this.lastTrip = lastTrip; + } + + /** + * @return the originIsTourDestination + */ + public boolean isOriginIsTourDestination() + { + return originIsTourDestination; + } + + /** + * @param originIsTourDestination + * the originIsTourDestination to set + */ + public void setOriginIsTourDestination(boolean originIsTourDestination) + { + this.originIsTourDestination = originIsTourDestination; + } + + /** + * @return the destinationIsTourDestination + */ + public boolean isDestinationIsTourDestination() + { + return destinationIsTourDestination; + } + + /** + * @param destinationIsTourDestination + * the destinationIsTourDestination to set + */ + public void setDestinationIsTourDestination(boolean destinationIsTourDestination) + { + this.destinationIsTourDestination = destinationIsTourDestination; + } + + public int getBoardTap() { + return boardTap; + } + + public void setBoardTap(int boardTap) { + this.boardTap = boardTap; + } + + public int getAlightTap() { + return alightTap; + } + + public void setAlightTap(int alightTap) { + this.alightTap = alightTap; + } + + public int getSet() { + return set; + } + + public void setSet(int set) { + this.set = set; + } + + public float getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(float valueOfTime) { + this.valueOfTime = valueOfTime; + } + + public float getParkingCost() { + return parkingCost; + } + + public void setParkingCost(float parkingCost) { + this.parkingCost = parkingCost; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripModeChoiceDMU.java new file mode 100644 index 0000000..da3854f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripModeChoiceDMU.java @@ -0,0 +1,762 @@ +package org.sandag.abm.crossborder; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.McLogsumsCalculator; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class CrossBorderTripModeChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(CrossBorderTripModeChoiceDMU.class); + + protected static final int WTW = McLogsumsCalculator.WTW; + protected static final int WTD = McLogsumsCalculator.WTD; + protected static final int DTW = McLogsumsCalculator.DTW; + protected static final int NUM_ACC_EGR = McLogsumsCalculator.NUM_ACC_EGR; + + protected static final int OUT = McLogsumsCalculator.OUT; + protected static final int IN = McLogsumsCalculator.IN; + protected static final int NUM_DIR = McLogsumsCalculator.NUM_DIR; + + protected int tourDepartPeriod; + protected int tourArrivePeriod; + protected int tripPeriod; + protected int workTour; + protected int outboundStops; + protected int returnStops; + protected int firstTrip; + protected int lastTrip; + protected int tourModeIsDA; + protected int tourModeIsS2; + protected int tourModeIsS3; + protected int tourModeIsWalk; + protected int tourCrossingIsSentri; + protected float hourlyParkingCostTourDest; + protected float dailyParkingCostTourDest; + protected float monthlyParkingCostTourDest; + protected int tripOrigIsTourDest; + protected int tripDestIsTourDest; + protected float hourlyParkingCostTripOrig; + protected float hourlyParkingCostTripDest; + protected float workTimeFactor; + protected float nonWorkTimeFactor; + protected int avAvailable; + + protected double nmWalkTime; + protected double nmBikeTime; + protected HashMap methodIndexMap; + protected double ivtCoeff; + protected double costCoeff; + protected double walkTransitLogsum; + protected double pnrTransitLogsum; + protected double knrTransitLogsum; + + protected IndexValues dmuIndex; + protected int outboundHalfTourDirection; + + protected float waitTimeTaxi; + protected float waitTimeSingleTNC; + protected float waitTimeSharedTNC; + + public CrossBorderTripModeChoiceDMU(CrossBorderModelStructure modelStructure, Logger aLogger) + { + if (aLogger == null) + { + aLogger = Logger.getLogger("crossBorderModel"); + } + logger = aLogger; + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the tripPeriod + */ + public int getTripPeriod() + { + return tripPeriod; + } + + /** + * @param tripPeriod + * the tripPeriod to set + */ + public void setTripPeriod(int tripPeriod) + { + this.tripPeriod = tripPeriod; + } + + /** + * @return the workTour + */ + public int getWorkTour() + { + return workTour; + } + + /** + * @param workTour + * the workTour to set + */ + public void setWorkTour(int workTour) + { + this.workTour = workTour; + } + + /** + * @return the outboundStops + */ + public int getOutboundStops() + { + return outboundStops; + } + + /** + * @param outboundStops + * the outboundStops to set + */ + public void setOutboundStops(int outboundStops) + { + this.outboundStops = outboundStops; + } + + /** + * @return the returnStops + */ + public int getReturnStops() + { + return returnStops; + } + + /** + * @param returnStops + * the returnStops to set + */ + public void setReturnStops(int returnStops) + { + this.returnStops = returnStops; + } + + /** + * @return the firstTrip + */ + public int getFirstTrip() + { + return firstTrip; + } + + /** + * @param firstTrip + * the firstTrip to set + */ + public void setFirstTrip(int firstTrip) + { + this.firstTrip = firstTrip; + } + + /** + * @return the lastTrip + */ + public int getLastTrip() + { + return lastTrip; + } + + /** + * @param lastTrip + * the lastTrip to set + */ + public void setLastTrip(int lastTrip) + { + this.lastTrip = lastTrip; + } + + /** + * @return the tourModeIsDA + */ + public int getTourModeIsDA() + { + return tourModeIsDA; + } + + /** + * @param tourModeIsDA + * the tourModeIsDA to set + */ + public void setTourModeIsDA(int tourModeIsDA) + { + this.tourModeIsDA = tourModeIsDA; + } + + /** + * @return the tourModeIsS2 + */ + public int getTourModeIsS2() + { + return tourModeIsS2; + } + + /** + * @param tourModeIsS2 + * the tourModeIsS2 to set + */ + public void setTourModeIsS2(int tourModeIsS2) + { + this.tourModeIsS2 = tourModeIsS2; + } + + /** + * @return the tourModeIsS3 + */ + public int getTourModeIsS3() + { + return tourModeIsS3; + } + + /** + * @param tourModeIsS3 + * the tourModeIsS3 to set + */ + public void setTourModeIsS3(int tourModeIsS3) + { + this.tourModeIsS3 = tourModeIsS3; + } + + /** + * @return the tourModeIsWalk + */ + public int getTourModeIsWalk() + { + return tourModeIsWalk; + } + + /** + * @param tourModeIsWalk + * the tourModeIsWalk to set + */ + public void setTourModeIsWalk(int tourModeIsWalk) + { + this.tourModeIsWalk = tourModeIsWalk; + } + + /** + * @return the tourModeIsSentri + */ + public int getTourCrossingIsSentri() + { + return tourCrossingIsSentri; + } + + /** + * @param tourModeIsSentri + * the tourModeIsSentri to set + */ + public void setTourCrossingIsSentri(int tourCrossingIsSentri) + { + this.tourCrossingIsSentri = tourCrossingIsSentri; + } + + /** + * @return the hourlyParkingCostTourDest + */ + public float getHourlyParkingCostTourDest() + { + return hourlyParkingCostTourDest; + } + + /** + * @param hourlyParkingCostTourDest + * the hourlyParkingCostTourDest to set + */ + public void setHourlyParkingCostTourDest(float hourlyParkingCostTourDest) + { + this.hourlyParkingCostTourDest = hourlyParkingCostTourDest; + } + + /** + * @return the dailyParkingCostTourDest + */ + public float getDailyParkingCostTourDest() + { + return dailyParkingCostTourDest; + } + + /** + * @param dailyParkingCostTourDest + * the dailyParkingCostTourDest to set + */ + public void setDailyParkingCostTourDest(float dailyParkingCostTourDest) + { + this.dailyParkingCostTourDest = dailyParkingCostTourDest; + } + + /** + * @return the monthlyParkingCostTourDest + */ + public float getMonthlyParkingCostTourDest() + { + return monthlyParkingCostTourDest; + } + + /** + * @param monthlyParkingCostTourDest + * the monthlyParkingCostTourDest to set + */ + public void setMonthlyParkingCostTourDest(float monthlyParkingCostTourDest) + { + this.monthlyParkingCostTourDest = monthlyParkingCostTourDest; + } + + /** + * @return the tripOrigIsTourDest + */ + public int getTripOrigIsTourDest() + { + return tripOrigIsTourDest; + } + + /** + * @param tripOrigIsTourDest + * the tripOrigIsTourDest to set + */ + public void setTripOrigIsTourDest(int tripOrigIsTourDest) + { + this.tripOrigIsTourDest = tripOrigIsTourDest; + } + + /** + * @return the tripDestIsTourDest + */ + public int getTripDestIsTourDest() + { + return tripDestIsTourDest; + } + + /** + * @param tripDestIsTourDest + * the tripDestIsTourDest to set + */ + public void setTripDestIsTourDest(int tripDestIsTourDest) + { + this.tripDestIsTourDest = tripDestIsTourDest; + } + + /** + * @return the hourlyParkingCostTripOrig + */ + public float getHourlyParkingCostTripOrig() + { + return hourlyParkingCostTripOrig; + } + + /** + * @param hourlyParkingCostTripOrig + * the hourlyParkingCostTripOrig to set + */ + public void setHourlyParkingCostTripOrig(float hourlyParkingCostTripOrig) + { + this.hourlyParkingCostTripOrig = hourlyParkingCostTripOrig; + } + + /** + * @return the hourlyParkingCostTripDest + */ + public float getHourlyParkingCostTripDest() + { + return hourlyParkingCostTripDest; + } + + /** + * @param hourlyParkingCostTripDest + * the hourlyParkingCostTripDest to set + */ + public void setHourlyParkingCostTripDest(float hourlyParkingCostTripDest) + { + this.hourlyParkingCostTripDest = hourlyParkingCostTripDest; + } + + /** + * @return the outboundHalfTourDirection + */ + public int getOutboundHalfTourDirection() + { + return outboundHalfTourDirection; + } + + /** + * @param outboundHalfTourDirection + * the outboundHalfTourDirection to set + */ + public void setOutboundHalfTourDirection(int outboundHalfTourDirection) + { + this.outboundHalfTourDirection = outboundHalfTourDirection; + } + + /** + * @return the tourDepartPeriod + */ + public int getTourDepartPeriod() + { + return tourDepartPeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(int tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(int tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + /** + * @return the tourArrivePeriod + */ + public int getTourArrivePeriod() + { + return tourArrivePeriod; + } + + public double getNm_walkTime() + { + return nmWalkTime; + } + + public void setNonMotorizedWalkTime(double nmWalkTime) + { + this.nmWalkTime = nmWalkTime; + } + + public void setNonMotorizedBikeTime(double nmBikeTime) + { + this.nmBikeTime = nmBikeTime; + } + + public double getNm_bikeTime() + { + return nmBikeTime; + } + + + public float getWorkTimeFactor() { + return workTimeFactor; + } + + public void setWorkTimeFactor(float workTimeFactor) { + this.workTimeFactor = workTimeFactor; + } + + public float getNonWorkTimeFactor() { + return nonWorkTimeFactor; + } + + public void setNonWorkTimeFactor(float nonWorkTimeFactor) { + this.nonWorkTimeFactor = nonWorkTimeFactor; + } + + public double getIvtCoeff() { + return ivtCoeff; + } + + public void setIvtCoeff(double ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + public double getCostCoeff() { + return costCoeff; + } + + public double getWalkTransitLogsum() { + return walkTransitLogsum; + } + + public void setWalkTransitLogsum(double walkTransitLogsum) { + this.walkTransitLogsum = walkTransitLogsum; + } + + public double getPnrTransitLogsum() { + return pnrTransitLogsum; + } + + public void setPnrTransitLogsum(double pnrTransitLogsum) { + this.pnrTransitLogsum = pnrTransitLogsum; + } + + public double getKnrTransitLogsum() { + return knrTransitLogsum; + } + + public void setKnrTransitLogsum(double knrTransitLogsum) { + this.knrTransitLogsum = knrTransitLogsum; + } + + + + + public int getAvAvailable() { + return avAvailable; + } + + public void setAvAvailable(int avAvailable) { + this.avAvailable = avAvailable; + } + + public float getWaitTimeTaxi() { + return waitTimeTaxi; + } + + public void setWaitTimeTaxi(float waitTimeTaxi) { + this.waitTimeTaxi = waitTimeTaxi; + } + + public float getWaitTimeSingleTNC() { + return waitTimeSingleTNC; + } + + public void setWaitTimeSingleTNC(float waitTimeSingleTNC) { + this.waitTimeSingleTNC = waitTimeSingleTNC; + } + + public float getWaitTimeSharedTNC() { + return waitTimeSharedTNC; + } + + public void setWaitTimeSharedTNC(float waitTimeSharedTNC) { + this.waitTimeSharedTNC = waitTimeSharedTNC; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTourDepartPeriod", 0); + methodIndexMap.put("getTourArrivePeriod", 1); + methodIndexMap.put("getTripPeriod", 2); + + methodIndexMap.put("getWorkTour", 4); + methodIndexMap.put("getOutboundStops", 5); + methodIndexMap.put("getReturnStops", 6); + methodIndexMap.put("getFirstTrip", 7); + methodIndexMap.put("getLastTrip", 8); + methodIndexMap.put("getTourModeIsDA", 9); + methodIndexMap.put("getTourModeIsS2", 10); + methodIndexMap.put("getTourModeIsS3", 11); + methodIndexMap.put("getTourModeIsWalk", 12); + methodIndexMap.put("getTourCrossingIsSentri", 13); + methodIndexMap.put("getHourlyParkingCostTourDest", 14); + methodIndexMap.put("getDailyParkingCostTourDest", 15); + methodIndexMap.put("getMonthlyParkingCostTourDest", 16); + methodIndexMap.put("getTripOrigIsTourDest", 17); + methodIndexMap.put("getTripDestIsTourDest", 18); + methodIndexMap.put("getHourlyParkingCostTripOrig", 19); + methodIndexMap.put("getHourlyParkingCostTripDest", 20); + + methodIndexMap.put("getWorkTimeFactor", 50); + methodIndexMap.put("getNonWorkTimeFactor", 51); + + methodIndexMap.put("getIvtCoeff", 60); + methodIndexMap.put("getCostCoeff", 61); + + methodIndexMap.put("getWalkSetLogSum", 62); + methodIndexMap.put("getPnrSetLogSum", 63); + methodIndexMap.put("getKnrSetLogSum", 64); + + methodIndexMap.put("getWaitTimeTaxi", 70); + methodIndexMap.put("getWaitTimeSingleTNC", 71); + methodIndexMap.put("getWaitTimeSharedTNC", 72); + + methodIndexMap.put("getNm_walkTime", 90); + methodIndexMap.put("getNm_bikeTime", 91); + + methodIndexMap.put("getAvAvailable", 95); + + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + case 0: + returnValue = getTourDepartPeriod(); + break; + case 1: + returnValue = getTourArrivePeriod(); + break; + case 2: + returnValue = getTripPeriod(); + break; + case 4: + returnValue = getWorkTour(); + break; + case 5: + returnValue = getOutboundStops(); + break; + case 6: + returnValue = getReturnStops(); + break; + case 7: + returnValue = getFirstTrip(); + break; + case 8: + returnValue = getLastTrip(); + break; + case 9: + returnValue = getTourModeIsDA(); + break; + case 10: + returnValue = getTourModeIsS2(); + break; + case 11: + returnValue = getTourModeIsS3(); + break; + case 12: + returnValue = getTourModeIsWalk(); + break; + case 13: + returnValue = getTourCrossingIsSentri(); + break; + case 14: + returnValue = getHourlyParkingCostTourDest(); + break; + case 15: + returnValue = getDailyParkingCostTourDest(); + break; + case 16: + returnValue = getMonthlyParkingCostTourDest(); + break; + case 17: + returnValue = getTripOrigIsTourDest(); + break; + case 18: + returnValue = getTripDestIsTourDest(); + break; + case 19: + returnValue = getHourlyParkingCostTripOrig(); + break; + case 20: + returnValue = getHourlyParkingCostTripDest(); + break; + case 50: + returnValue = getWorkTimeFactor(); + break; + case 51: + returnValue = getNonWorkTimeFactor(); + break; + case 60: + returnValue = getIvtCoeff(); + break; + case 61: + returnValue = getCostCoeff(); + break; + case 62: + returnValue = getWalkTransitLogsum(); + break; + case 63: + returnValue = getPnrTransitLogsum(); + break; + case 64: + returnValue = getKnrTransitLogsum(); + break; + case 70: return getWaitTimeTaxi(); + case 71: return getWaitTimeSingleTNC(); + case 72: return getWaitTimeSharedTNC(); + + case 90: + returnValue = getNm_walkTime(); + break; + case 91: + returnValue = getNm_bikeTime(); + break; + case 95: + returnValue = getAvAvailable(); + break; + + default: + logger.error( "method number = " + variableIndex + " not found" ); + throw new RuntimeException( "method number = " + variableIndex + " not found" ); + } + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripModeChoiceModel.java new file mode 100644 index 0000000..1d40c89 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripModeChoiceModel.java @@ -0,0 +1,369 @@ +package org.sandag.abm.crossborder; + +import java.util.HashMap; +import java.util.Random; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.TNCAndTaxiWaitTimeCalculator; +import org.sandag.abm.ctramp.TripModeChoiceDMU; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class CrossBorderTripModeChoiceModel +{ + + private transient Logger logger = Logger.getLogger("crossBorderModel"); + + private AutoAndNonMotorizedSkimsCalculator anm; + private McLogsumsCalculator logsumHelper; + private CrossBorderModelStructure modelStructure; + private SandagModelStructure sandagModelStructure; + private TazDataManager tazs; + private MgraDataManager mgraManager; + private double[] lsWgtAvgCostM; + private double[] lsWgtAvgCostD; + private double[] lsWgtAvgCostH; + private CrossBorderTripModeChoiceDMU dmu; + private ChoiceModelApplication tripModeChoiceModel; + double logsum = 0; + + private TripModeChoiceDMU mcDmuObject; + private AutoTazSkimsCalculator tazDistanceCalculator; + + + private static final String PROPERTIES_UEC_DATA_SHEET = "crossBorder.trip.mc.data.page"; + private static final String PROPERTIES_UEC_MODEL_SHEET = "crossBorder.trip.mc.model.page"; + private static final String PROPERTIES_UEC_FILE = "crossBorder.trip.mc.uec.file"; + + private TNCAndTaxiWaitTimeCalculator tncTaxiWaitTimeCalculator; + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public CrossBorderTripModeChoiceModel(HashMap propertyMap, + CrossBorderModelStructure myModelStructure, CrossBorderDmuFactoryIf dmuFactory, AutoTazSkimsCalculator tazDistanceCalculator) + { + tazs = TazDataManager.getInstance(propertyMap); + mgraManager = MgraDataManager.getInstance(propertyMap); + + lsWgtAvgCostM = mgraManager.getLsWgtAvgCostM(); + lsWgtAvgCostD = mgraManager.getLsWgtAvgCostD(); + lsWgtAvgCostH = mgraManager.getLsWgtAvgCostH(); + + modelStructure = myModelStructure; + sandagModelStructure = new SandagModelStructure(); + + this.tazDistanceCalculator = tazDistanceCalculator; + + setupTripModeChoiceModel(propertyMap, dmuFactory); + + } + + /** + * Read the UEC file and set up the trip mode choice model. + * + * @param propertyMap + * @param dmuFactory + */ + private void setupTripModeChoiceModel(HashMap propertyMap, + CrossBorderDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up cross border trip mode choice model.")); + + dmu = dmuFactory.getCrossBorderTripModeChoiceDMU(); + + int dataPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_DATA_SHEET)); + int modelPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_MODEL_SHEET)); + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String tripModeUecFile = propertyMap.get(PROPERTIES_UEC_FILE); + tripModeUecFile = uecPath + tripModeUecFile; + + tripModeChoiceModel = new ChoiceModelApplication(tripModeUecFile, modelPage, dataPage, + propertyMap, (VariableTable) dmu); + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + SandagModelStructure modelStructure = new SandagModelStructure(); + mcDmuObject = new TripModeChoiceDMU(modelStructure, logger); + + tncTaxiWaitTimeCalculator = new TNCAndTaxiWaitTimeCalculator(); + tncTaxiWaitTimeCalculator.createWaitTimeDistributions(propertyMap); + + } + + /** + * Calculate utilities and return logsum for the tour and stop. + * + * @param tour + * @param trip + */ + public double computeUtilities(CrossBorderTour tour, CrossBorderTrip trip) + { + + setDmuAttributes(tour, trip); + + tripModeChoiceModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + if (tour.getDebugChoiceModels()) + { + tour.logTourObject(logger, 100); + tripModeChoiceModel.logUECResults(logger, "Cross border trip mode choice model"); + + } + + logsum = tripModeChoiceModel.getLogsum(); + + if (tour.getDebugChoiceModels()) logger.info("Returning logsum " + logsum); + + return logsum; + + } + + /** + * Choose a mode and store in the trip object. + * + * @param tour + * CrossBorderTour + * @param trip + * CrossBorderTrip + * + */ + public void chooseMode(CrossBorderTour tour, CrossBorderTrip trip) + { + computeUtilities(tour, trip); + + double rand = tour.getRandom(); + int mode=0; + try{ + mode = tripModeChoiceModel.getChoiceResult(rand); + trip.setTripMode(mode); + float vot = getTripValueOfTime(mode); + trip.setValueOfTime(vot); + float parkingCost = getTripParkingCost(mode); + trip.setParkingCost(parkingCost); + + if(sandagModelStructure.getTripModeIsTransit(mode)){ + double[][] bestTapPairs = logsumHelper.getBestWtwTripTaps(); + //pick transit path from N-paths + double rn = tour.getRandom(); + int pathIndex = logsumHelper.chooseTripPath(rn, bestTapPairs, tour.getDebugChoiceModels(), logger); + int boardTap = (int) bestTapPairs[pathIndex][0]; + int alightTap = (int) bestTapPairs[pathIndex][1]; + int set = (int) bestTapPairs[pathIndex][2]; + trip.setBoardTap(boardTap); + trip.setAlightTap(alightTap); + trip.setSet(set); + } + }catch(Exception e){ + logger.info("rand="+rand); + tour.logTourObject(logger, 100); + logger.error(e.getMessage()); + } + + } + + /** + * Return parking cost from UEC if auto trip, else return 0. + * + * @param tripMode + * @return Parking cost if auto mode, else 0 + */ + public float getTripParkingCost(int tripMode) { + + float parkingCost=0; + + if(sandagModelStructure.getTripModeIsSovOrHov(tripMode)) { + UtilityExpressionCalculator uec = tripModeChoiceModel.getUEC(); + int parkingCostIndex = uec.lookupVariableIndex("parkingCost"); + parkingCost = (float) uec.getValueForIndex(parkingCostIndex); + return parkingCost; + } + return parkingCost; + } + + /** + * This method looks up the value of time from the last call to the UEC and returns + * it based on the occupancy of the mode passed in as an argument. this method ensures + * that the value of time at a tour level is the same for all trips on the tour (even + * though the actual trip level VOT might vary based on the trip occupancy). + * + * @param tourMode + * @return The value of time + */ + public float getTourValueOfTime(int tourMode){ + + //value of time; lookup vot, votS2, or votS3 from the UEC depending on chosen mode + UtilityExpressionCalculator uec = tripModeChoiceModel.getUEC(); + + double vot = 0.0; + + if(tourMode== modelStructure.SHARED2){ + int votIndex = uec.lookupVariableIndex("votS2"); + vot = uec.getValueForIndex(votIndex); + }else if (tourMode== modelStructure.SHARED3){ + int votIndex = uec.lookupVariableIndex("votS3"); + vot = uec.getValueForIndex(votIndex); + }else{ + int votIndex = uec.lookupVariableIndex("vot"); + vot = uec.getValueForIndex(votIndex); + } + return (float) (vot * 0.5); //take half the VOT (assumed for tours) + + + } + + /** + * This method looks up the value of time from the last call to the UEC and returns + * it based on the occupancy of the mode passed in as an argument. this method ensures + * that the value of time at a tour level is the same for all trips on the tour (even + * though the actual trip level VOT might vary based on the trip occupancy). + * + * @param tripMode + * @return The value of time + */ + public float getTripValueOfTime(int tripMode){ + + //value of time; lookup vot, votS2, or votS3 from the UEC depending on chosen mode + UtilityExpressionCalculator uec = tripModeChoiceModel.getUEC(); + + double vot = 0.0; + + if(modelStructure.getTripModeIsS2(tripMode)){ + int votIndex = uec.lookupVariableIndex("votS2"); + vot = uec.getValueForIndex(votIndex); + }else if (modelStructure.getTripModeIsS3(tripMode)){ + int votIndex = uec.lookupVariableIndex("votS3"); + vot = uec.getValueForIndex(votIndex); + }else{ + int votIndex = uec.lookupVariableIndex("vot"); + vot = uec.getValueForIndex(votIndex); + } + return (float) vot; + + + } + + /** + * Set DMU attributes. + * + * @param tour + * @param trip + */ + public void setDmuAttributes(CrossBorderTour tour, CrossBorderTrip trip) + { + + int tourDestinationMgra = tour.getDestinationMGRA(); + int tripOriginMgra = trip.getOriginMgra(); + int tripDestinationMgra = trip.getDestinationMgra(); + + int tripOriginTaz = trip.getOriginTAZ(); + int tripDestinationTaz = trip.getDestinationTAZ(); + + dmu.setDmuIndexValues(tripOriginTaz, tripDestinationTaz, tripOriginTaz, tripDestinationTaz, + tour.getDebugChoiceModels()); + + dmu.setTourDepartPeriod(tour.getDepartTime()); + dmu.setTourArrivePeriod(tour.getArriveTime()); + dmu.setTripPeriod(trip.getPeriod()); + + dmu.setWorkTimeFactor((float)tour.getWorkTimeFactor()); + dmu.setNonWorkTimeFactor((float)tour.getNonWorkTimeFactor()); + + // set trip mc dmu values for transit logsum (gets replaced below by uec values) + double c_ivt = -0.03; + double c_cost = - 0.0003; + + // Solve trip mode level utilities + mcDmuObject.setIvtCoeff(c_ivt); + mcDmuObject.setCostCoeff(c_cost); + double walkTransitLogsum = -999.0; + + logsumHelper.setNmTripMcDmuAttributes(mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + dmu.setNonMotorizedWalkTime(mcDmuObject.getNm_walkTime()); + dmu.setNonMotorizedBikeTime(mcDmuObject.getNm_bikeTime()); + + logsumHelper.setWtwTripMcDmuAttributes( mcDmuObject, tripOriginMgra, tripDestinationMgra, trip.getPeriod(), tour.getDebugChoiceModels()); + walkTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTW); + + dmu.setWalkTransitLogsum(walkTransitLogsum); + + if (tour.getPurpose() == modelStructure.WORK) dmu.setWorkTour(1); + else dmu.setWorkTour(0); + + dmu.setOutboundStops(tour.getNumberInboundStops()); + dmu.setReturnStops(tour.getNumberInboundStops()); + + if (trip.isFirstTrip()) dmu.setFirstTrip(1); + else dmu.setFirstTrip(0); + + if (trip.isLastTrip()) dmu.setLastTrip(1); + else dmu.setLastTrip(0); + + if (tour.getTourMode() == modelStructure.DRIVEALONE) dmu.setTourModeIsDA(1); + else dmu.setTourModeIsDA(0); + + if (tour.getTourMode() == modelStructure.SHARED2) dmu.setTourModeIsS2(1); + else dmu.setTourModeIsS2(0); + + if (tour.getTourMode() == modelStructure.SHARED3) dmu.setTourModeIsS3(1); + else dmu.setTourModeIsS3(0); + + if (tour.getTourMode() == modelStructure.WALK) dmu.setTourModeIsWalk(1); + else dmu.setTourModeIsWalk(0); + + if (tour.isSentriAvailable()) dmu.setTourCrossingIsSentri(1); + else dmu.setTourCrossingIsSentri(0); + + if (trip.isOriginIsTourDestination()) dmu.setTripOrigIsTourDest(1); + else dmu.setTripOrigIsTourDest(0); + + if (trip.isDestinationIsTourDestination()) dmu.setTripDestIsTourDest(1); + else dmu.setTripDestIsTourDest(0); + + dmu.setHourlyParkingCostTourDest((float) lsWgtAvgCostH[tourDestinationMgra]); + dmu.setDailyParkingCostTourDest((float) lsWgtAvgCostD[tourDestinationMgra]); + dmu.setMonthlyParkingCostTourDest((float) lsWgtAvgCostM[tourDestinationMgra]); + dmu.setHourlyParkingCostTripOrig((float) lsWgtAvgCostH[tripOriginMgra]); + dmu.setHourlyParkingCostTripDest((float) lsWgtAvgCostH[tripDestinationMgra]); + + float popEmpDenOrig = (float) mgraManager.getPopEmpPerSqMi(trip.getOriginMgra()); + + double rnum = tour.getRandom(); + float waitTimeSingleTNC = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenOrig); + float waitTimeSharedTNC = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenOrig); + float waitTimeTaxi = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenOrig); + dmu.setWaitTimeSingleTNC(waitTimeSingleTNC); + dmu.setWaitTimeSharedTNC(waitTimeSharedTNC); + dmu.setWaitTimeTaxi(waitTimeTaxi); + + + } + + public McLogsumsCalculator getMcLogsumsCalculator(){ + return logsumHelper; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripTables.java b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripTables.java new file mode 100644 index 0000000..3aca0c5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/crossborder/CrossBorderTripTables.java @@ -0,0 +1,704 @@ +package org.sandag.abm.crossborder; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.util.ResourceUtil; + +public class CrossBorderTripTables +{ + + private static Logger logger = Logger.getLogger("tripTables"); + public static final int MATRIX_DATA_SERVER_PORT = 1171; + + private TableDataSet tripData; + + // Some parameters + private int[] modeIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // total + // modes, + // returns + // 0=auto + // modes, + // 1=non-motor, + // 2=transit, + // 3= + // other + private int[] matrixIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // modes, + // returns + // the + // element + // of + // the + // matrix + // array + // to + // store + // value + + // array modes: AUTO, NON-MOTORIZED, TRANSIT, OTHER + private int autoModes = 0; + private int tranModes = 0; + private int nmotModes = 0; + private int othrModes = 0; + + // one file per time period + private int numberOfPeriods; + + private HashMap rbMap; + + // matrices are indexed by modes, vot bins, submodes + private Matrix[][][] matrix; + + private ResourceBundle rb; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private TapDataManager tapManager; + private SandagModelStructure modelStructure; + + private float averageOcc3Plus = 3.5f; + private float sampleRate = 1; + private static final String VOT_THRESHOLD_LOW = "valueOfTime.threshold.low"; + private static final String VOT_THRESHOLD_MED = "valueOfTime.threshold.med"; + private float valueOfTimeThresholdLow = 0; + private float valueOfTimeThresholdMed = 0; + //value of time bins by mode group + int[] votBins = {3,1,1,1}; + + public int numSkimSets; + + + /** + * @return the sampleRate + */ + public float getSampleRate() + { + return sampleRate; + } + + /** + * @param sampleRate + * the sampleRate to set + */ + public void setSampleRate(float sampleRate) + { + this.sampleRate = sampleRate; + } + + private MatrixDataServerRmi ms; + + public CrossBorderTripTables(HashMap rbMap) + { + + this.rbMap = rbMap; + tazManager = TazDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + modelStructure = new SandagModelStructure(); + + // Time period limits + numberOfPeriods = modelStructure.getNumberModelPeriods(); + + numSkimSets = Util.getIntegerValueFromPropertyMap(rbMap,"utility.bestTransitPath.skim.sets"); + + + // number of modes + modeIndex = new int[modelStructure.MAXIMUM_TOUR_MODE_ALT_INDEX + 1]; + matrixIndex = new int[modeIndex.length]; + + // set the mode arrays + for (int i = 1; i < modeIndex.length; ++i) + { + if (modelStructure.getTripModeIsSovOrHov(i)) + { + modeIndex[i] = 0; + matrixIndex[i] = autoModes; + ++autoModes; + } else if (modelStructure.getTripModeIsNonMotorized(i)) + { + modeIndex[i] = 1; + matrixIndex[i] = nmotModes; + ++nmotModes; + } else if (modelStructure.getTripModeIsWalkTransit(i) + || modelStructure.getTripModeIsPnrTransit(i) + || modelStructure.getTripModeIsKnrTransit(i)) + { + modeIndex[i] = 2; + matrixIndex[i] = tranModes; + ++tranModes; + } else + { + modeIndex[i] = 3; + matrixIndex[i] = othrModes; + ++othrModes; + } + } + //value of time thresholds + valueOfTimeThresholdLow = new Float(rbMap.get(VOT_THRESHOLD_LOW)); + valueOfTimeThresholdMed = new Float(rbMap.get(VOT_THRESHOLD_MED)); + + } + + /** + * Initialize all the matrices for the given time period. + * + * @param periodName + * The name of the time period. + */ + public void initializeMatrices(String periodName) + { + + /* + * This won't work because external stations aren't listed in the MGRA + * file int[] tazIndex = tazManager.getTazsOneBased(); int tazs = + * tazIndex.length-1; + */ + // Instead, use maximum taz number + int maxTaz = tazManager.getMaxTaz(); + int[] tazIndex = new int[maxTaz + 1]; + + // assume zone numbers are sequential + for (int i = 1; i < tazIndex.length; ++i) + tazIndex[i] = i; + + // get the tap index + int[] tapIndex = tapManager.getTaps(); + int taps = tapIndex.length - 1; + + // Initialize matrices; one for each mode group (auto, non-mot, tran, + // other) + // All matrices will be dimensioned by TAZs except for transit, which is + // dimensioned by TAPs + int numberOfModes = 4; + matrix = new Matrix[numberOfModes][][]; + for (int i = 0; i < numberOfModes; ++i) + { + + String modeName; + + matrix[i] = new Matrix[votBins[i]][]; + + for(int j = 0; j< votBins[i];++j){ + if (i == 0) + { + matrix[i][j] = new Matrix[autoModes]; + for (int k = 0; k < autoModes; ++k) + { + modeName = modelStructure.getModeName(k + 1); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 1) + { + matrix[i][j] = new Matrix[nmotModes]; + for (int k = 0; k < nmotModes; ++k) + { + modeName = modelStructure.getModeName(k + 1 + autoModes); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 2) + { + matrix[i][j] = new Matrix[tranModes*numSkimSets]; + for (int k = 0; k < tranModes; ++k) + { + for(int l=0;l1) + votBin = getValueOfTimeBin(valueOfTime); + + if (mode == 0) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + vehicleTrips)); + } else if (mode == 1) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } else if (mode == 2) + { + + if (boardTap == 0 || alightTap == 0) continue; + + //store transit trips in matrices + mat = (matrixIndex[tripMode]*numSkimSets)+set; + float value = matrix[mode][votBin][mat].getValueAt(boardTap, alightTap); + matrix[mode][votBin][mat].setValueAt(boardTap, alightTap, (value + personTrips)); + + // Store PNR transit trips in SOV free mode skim (mode 0 mat 0) + if (modelStructure.getTourModeIsDriveTransit(tripMode)) + { + + boolean inbound = tripData.getBooleanValueAt(i, "inbound"); + + // add the tNCVehicle trip portion to the trip table + if (!inbound) + { // from origin to lot (boarding tap) + int PNRTAZ = tapManager.getTazForTap(boardTap); + value = matrix[0][votBin][0].getValueAt(originTAZ, PNRTAZ); + matrix[0][votBin][0].setValueAt(originTAZ, PNRTAZ, (value + vehicleTrips)); + + } else + { // from lot (alighting tap) to destination + int PNRTAZ = tapManager.getTazForTap(alightTap); + value = matrix[0][votBin][0].getValueAt(PNRTAZ, destinationTAZ); + matrix[0][votBin][0].setValueAt(PNRTAZ, destinationTAZ, (value + vehicleTrips)); + } + + } + } else + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } + + //logger.info("End creating trip tables for period " + timePeriod); + } + } + + /** + * Return the value of time bin 0 through 2 based on the thresholds provided in the property map + * @param valueOfTime + * @return value of time bin 0 through 2 + */ + public int getValueOfTimeBin(float valueOfTime){ + + if(valueOfTime1) + end[i][j] = "_" + per + "_"+ votBinName[j]+ ".omx"; + else + end[i][j] = "_" + per + ".omx"; + } + } + for (int i = 0; i < 4; ++i){ + for(int j = 0; j < votBins[i];++j){ + try + { + //Delete the file if it exists + File f = new File(fileName[i]+end[i][j]); + if(f.exists()){ + logger.info("Deleting existing trip file: "+fileName[i]+end[i][j]); + f.delete(); + } + + if (ms != null) ms.writeMatrixFile(fileName[i]+end[i][j], matrix[i][j], mt); + else writeMatrixFile(fileName[i]+end[i][j], matrix[i][j]); + } catch (Exception e) + { + logger.error("exception caught writing " + mt.toString() + " matrix file = " + + fileName[i] +end[i][j] + ", for mode index = " + i, e); + throw new RuntimeException(); + } + } + } + + } + + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + public void writeMatrixFile(String fileName, Matrix[] m) + { + + // auto trips + MatrixWriter writer = MatrixWriter.createWriter(fileName); + String[] names = new String[m.length]; + + for (int i = 0; i < m.length; i++) + { + names[i] = m[i].getName(); + logger.info(m[i].getName() + " has " + m[i].getRowCount() + " rows, " + + m[i].getColumnCount() + " cols, and a total of " + m[i].getSum()); + } + + writer.writeMatrices(names, m); + } + + /** + * Start matrix server + * + * @param serverAddress + * @param serverPort + * @param mt + * @return + */ + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * @param args + */ + public static void main(String[] args) + { + + HashMap pMap; + String propertiesFile = null; + + logger.info(String.format( + "SANDAG Cross-Border Model Trip Table Generation Program using CT-RAMP version %s", + CtrampApplication.VERSION)); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + CrossBorderTripTables tripTables = new CrossBorderTripTables(pMap); + float sampleRate = 1.0f; + int iteration = 1; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + + logger.info("Crossborder Model Trip Table:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + tripTables.setSampleRate(sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = tripTables.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + tripTables.ms = matrixServer; + } else + { + tripTables.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + tripTables.ms.testRemote("CrossBorderTripTables"); + + // mdm = MatrixDataManager.getInstance(); + // mdm.setMatrixDataServerObject(ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + tripTables.createTripTables(mt); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/AtWorkSubtourFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/AtWorkSubtourFrequencyDMU.java new file mode 100644 index 0000000..fa50023 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/AtWorkSubtourFrequencyDMU.java @@ -0,0 +1,204 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class AtWorkSubtourFrequencyDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(AtWorkSubtourFrequencyDMU.class); + + protected HashMap methodIndexMap; + + protected Household hh; + protected Person person; + protected Tour tour; + protected IndexValues dmuIndex; + + protected double nmEatOutAccessibillity; + + protected ModelStructure modelStructure; + + public AtWorkSubtourFrequencyDMU(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + dmuIndex = new IndexValues(); + } + + public Household getHouseholdObject() + { + return hh; + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + public void setPersonObject(Person persObject) + { + person = persObject; + } + + public void setTourObject(Tour tourObject) + { + tour = tourObject; + } + + // DMU methods - define one of these for every @var in the mode choice + // control + // file. + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug INMTF UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return household income category + */ + public int getIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + /** + * @return person type category index + */ + public int getPersonType() + { + return person.getPersonTypeNumber(); + } + + /** + * @return person type category index + */ + public int getFemale() + { + if (person.getPersonIsFemale() == 1) return 1; + else return 0; + } + + /** + * @return number of driving age people in household + */ + public int getDrivers() + { + return hh.getDrivers(); + } + + /** + * @return number of people of preschool person type in household + */ + public int getNumPreschoolChildren() + { + return hh.getNumPreschool(); + } + + /** + * @return number of individual non-mandatory eat-out tours for the person. + */ + public int getNumIndivEatOutTours() + { + int numTours = 0; + ArrayList tourList = person.getListOfIndividualNonMandatoryTours(); + if (tourList != null) + { + for (Tour t : tourList) + { + String tourPurpose = t.getTourPurpose(); + if (tourPurpose.equalsIgnoreCase(ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME)) + { + numTours++; + } + } + } + return numTours; + } + + /** + * @return total mandatory and non-mandatory tours for the person. + */ + public int getNumTotalTours() + { + int numTours = 0; + + ArrayList wTourList = person.getListOfWorkTours(); + if (wTourList != null) numTours += wTourList.size(); + + ArrayList sTourList = person.getListOfSchoolTours(); + if (sTourList != null) numTours += sTourList.size(); + + ArrayList nmTourList = person.getListOfIndividualNonMandatoryTours(); + if (nmTourList != null) numTours += nmTourList.size(); + + return numTours; + } + + public double getNmEatOutAccessibilityWorkplace() + { + return nmEatOutAccessibillity; + } + + /** + * set the value of the non-mandatory eat out accessibility for this + * decision maker + */ + public void setNmEatOutAccessibilityWorkplace(double nmEatOutAccessibillity) + { + this.nmEatOutAccessibillity = nmEatOutAccessibillity; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/AutoOwnershipChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/AutoOwnershipChoiceDMU.java new file mode 100644 index 0000000..1708b43 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/AutoOwnershipChoiceDMU.java @@ -0,0 +1,267 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class AutoOwnershipChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(AutoOwnershipChoiceDMU.class); + + protected HashMap methodIndexMap; + + private Household hh; + private IndexValues dmuIndex; + + private boolean useAccessibility = false; + + private double workAutoDependency = 0.0; + private double schoolAutoDependency = 0.0; + private double workAutoTime = 0.0; + + private double workersRailProportion = 0.0; + private double studentsRailProportion = 0.0; + + private double homeTazAutoAccessibility = 0.0; + private double homeTazTransitAccessibility = 0.0; + private double homeTazNonMotorizedAccessibility = 0.0; + private double homeTazMaasAccessibility = 0.0; + + public AutoOwnershipChoiceDMU() + { + dmuIndex = new IndexValues(); + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + // DMU methods - define one of these for every @var in the mode choice + // control + // file. + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug AO UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public Household getHouseholdObject() + { + return hh; + } + + public int getGq() + { + return hh.getIsGroupQuarters(); + } + + public int getDrivers() + { + return hh.getDrivers(); + } + + public int getNumFtWorkers() + { + return hh.getNumFtWorkers(); + } + + public int getNumPtWorkers() + { + return hh.getNumPtWorkers(); + } + + public int getNumPersons18to24() + { + return hh.getNumPersons18to24(); + } + + public int getNumPersons18to35(){ + return hh.getNumPersons18to35(); + } + + public int getNumPersons6to15() + { + return hh.getNumPersons6to15(); + } + + public int getNumPersons65Plus() + { + return (hh.getNumPersons65to79()+hh.getNumPersons80plus()); + } + + public int getNumPersons80plus() + { + return hh.getNumPersons80plus(); + } + + public int getNumPersons65to79() + { + return hh.getNumPersons65to79(); + } + + public int getHhIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + public int getNumHighSchoolGraduates() + { + return hh.getNumHighSchoolGraduates(); + } + + public int getDetachedDwellingType() + { + return hh.getHhBldgsz(); + } + + public double getUseAccessibilities() + { + return useAccessibility ? 1 : 0; + } + + public double getHomeTazAutoAccessibility() + { + return homeTazAutoAccessibility; + } + + public double getHomeTazTransitAccessibility() + { + return homeTazTransitAccessibility; + } + + public double getHomeTazMaasAccessibility() + { + return homeTazMaasAccessibility; + } + + public double getHomeTazNonMotorizedAccessibility() + { + return homeTazNonMotorizedAccessibility; + } + + public double getWorkAutoDependency() + { + return workAutoDependency; + } + + public double getSchoolAutoDependency() + { + return schoolAutoDependency; + } + + public double getWorkAutoTime() { + return workAutoTime; + } + + public void setWorkAutoTime(double workAutoTime) { + this.workAutoTime = workAutoTime; + } + + public double getWorkersRailProportion() + { + return workersRailProportion; + } + + public double getStudentsRailProportion() + { + return studentsRailProportion; + } + + public void setUseAccessibilities(boolean flag) + { + useAccessibility = flag; + } + + public void setHomeTazAutoAccessibility(double acc) + { + homeTazAutoAccessibility = acc; + } + + public void setHomeTazTransitAccessibility(double acc) + { + homeTazTransitAccessibility = acc; + } + + public void setHomeTazMaasAccessibility(double acc) + { + homeTazMaasAccessibility = acc; + } + + public void setHomeTazNonMotorizedAccessibility(double acc) + { + homeTazNonMotorizedAccessibility = acc; + } + + public void setWorkAutoDependency(double value) + { + workAutoDependency = value; + } + + public void setSchoolAutoDependency(double value) + { + schoolAutoDependency = value; + } + + public void setWorkersRailProportion(double proportion) + { + workersRailProportion = proportion; + } + + public void setStudentsRailProportion(double proportion) + { + studentsRailProportion = proportion; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/BikeLogsum.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/BikeLogsum.java new file mode 100644 index 0000000..7105499 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/BikeLogsum.java @@ -0,0 +1,259 @@ +package org.sandag.abm.ctramp; + +import java.io.BufferedReader; +import java.io.FileReader; +import java.io.IOException; +import java.io.ObjectStreamException; +import java.io.Serializable; +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; + +import org.apache.log4j.Level; +import org.apache.log4j.LogManager; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.util.ResourceUtil; + +/** + * The {@code BikeLogsum} class holds bike logsums for use in the SANDAG model. This class is intended to be used as a singleton, and so the only way to + * access it is via the {@code getBikeLogsum} static method. It is constructed on demand and safe for concurrent access. + *

+ * Internally, the logsums are held in a mapping using node-pairs as keys. The taz and mgra pairs are held in the same mapping, with the tazs multiplied + * by -1 to avoid conflicts. To ensure good performance when building the object, a good guess as to the number of node pairs (maz pairs plus taz pairs) + * can be provided (a default value of 26 million will be used otherwise) via the {@code BIKE_LOGSUM_NODE_PAIR_COUNT_PROPERTY} property. + */ +public class BikeLogsum implements SegmentedSparseMatrix,Serializable { + private static final long serialVersionUID = 660793106399818667L; + private static Logger logger = Logger.getLogger(BikeLogsum.class); + + public static final String BIKE_LOGSUM_OUTPUT_PROPERTY = "active.output.bike"; + public static final String BIKE_LOGSUM_MGRA_FILE_PROPERTY = "active.logsum.matrix.file.bike.mgra"; + public static final String BIKE_LOGSUM_TAZ_FILE_PROPERTY = "active.logsum.matrix.file.bike.taz"; + public static final String BIKE_LOGSUM_NODE_PAIR_COUNT_PROPERTY = "active.logsum.matrix.node.pair.count"; + /** + * The default logsum node pair count. + */ + public static final int DEFAULT_BIKE_LOGSUM_NODE_PAIR_COUNT = 26_000_000; //testing found 18_880_631, so this should be good enough to start + + + private Map logsum; + private int[] mgraIndex; + + private static volatile BikeLogsum instance = null; + + /** + * Get the {@code BikeLogsum} instance. + * + * @param rbMap + * The model property mapping. + * + * @return the {@code BikeLogsum} instance. + */ + public static BikeLogsum getBikeLogsum(Map rbMap) { + if (instance == null) { + synchronized (BikeLogsum.class) { + if (instance == null) { //check again to see if we waited for another thread to do the initialization already + int nodePairCount = rbMap.containsKey(BIKE_LOGSUM_NODE_PAIR_COUNT_PROPERTY) ? + Integer.parseInt(rbMap.get(BIKE_LOGSUM_NODE_PAIR_COUNT_PROPERTY)) : DEFAULT_BIKE_LOGSUM_NODE_PAIR_COUNT; + String mgraFile = Paths.get(rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY),rbMap.get(MgraDataManager.PROPERTIES_MGRA_DATA_FILE)).toString(); + String tazLogsumFile = Paths.get(rbMap.get(BIKE_LOGSUM_OUTPUT_PROPERTY),rbMap.get(BIKE_LOGSUM_TAZ_FILE_PROPERTY)).toString(); + String mgraLogsumFile = Paths.get(rbMap.get(BIKE_LOGSUM_OUTPUT_PROPERTY),rbMap.get(BIKE_LOGSUM_MGRA_FILE_PROPERTY)).toString(); + instance = new BikeLogsum(tazLogsumFile,mgraLogsumFile,nodePairCount,mgraFile); + } + } + } + return instance; + } + + private BikeLogsum(String tazLogsumFile, String mgraLogsumFile, int nodePairCount, String mgraFile) { + logsum = new HashMap(nodePairCount,1.01f); //capacity of nodepairs, plus a little buffer just in case + Map> tazMgraMapping = loadTazMgraMapping(mgraFile); + mgraIndex = buildMgraIndex(tazMgraMapping); + loadLogsum(tazLogsumFile,true); + loadLogsum(mgraLogsumFile,false); + } + + private int[] buildMgraIndex(Map> tazMgraMapping) { + int maxMgra = 0; + for (Set mgras : tazMgraMapping.values()) + for (int mgra : mgras) + if (maxMgra < mgra) + maxMgra = mgra; + + int[] mgraIndex = new int[maxMgra+1]; + for (int taz : tazMgraMapping.keySet()) + for (int mgra : tazMgraMapping.get(taz)) + mgraIndex[mgra] = -1*taz; + + return mgraIndex; + } + + private Map> loadTazMgraMapping(String mgraFile) { + Map> tazMgraMapping = new HashMap<>(); + boolean first = true; + String mgraColumnName = MgraDataManager.MGRA_FIELD_NAME.toLowerCase(); + String tazColumnName = MgraDataManager.MGRA_TAZ_FIELD_NAME.toLowerCase(); + int mgraColumn = -1; + int tazColumn = -1; + try (BufferedReader reader = new BufferedReader(new FileReader(mgraFile))) { + String line; + while ((line = reader.readLine()) != null) { + String[] lineData = line.trim().split(","); + if (first) { + for (int i = 0; i < lineData.length; i++) { + String column = lineData[i].toLowerCase(); + if (column.equals(mgraColumnName)) + mgraColumn = i; + if (column.equals(tazColumnName)) + tazColumn = i; + } + first = false; + continue; + } + if (lineData.length < 2) + continue; + int mgra = Integer.parseInt(lineData[mgraColumn]); + int taz = Integer.parseInt(lineData[tazColumn]); + if (!tazMgraMapping.containsKey(taz)) + tazMgraMapping.put(taz,new HashSet()); + tazMgraMapping.get(taz).add(mgra); + } + + } catch (IOException e) { + throw new RuntimeException(e); + } + return tazMgraMapping; + } + + private void loadLogsum(String logsumFile, boolean taz) { + logger.info("Processing bike logsum from " + logsumFile); + int counter = 0; + long startTime = System.currentTimeMillis(); + + int segmentWidth = BikeLogsumSegment.segmentWidth(); + try (BufferedReader reader = new BufferedReader(new FileReader(logsumFile))) { + int logsumIndex = -1; + int timeIndex = -1; + boolean first = true; + + String line; + while ((line = reader.readLine()) != null) { + String[] lineData = line.trim().split(","); + for (int i = 0; i < lineData.length; i++) + lineData[i] = lineData[i].trim(); + if (first) { + for (int i = 2; i < lineData.length; i++) { //first two are for row and column + String columnName = lineData[i].toLowerCase(); + if (columnName.contains("logsum")) + logsumIndex = i; + if (columnName.contains("time")) + timeIndex = i; + } + first = false; + continue; + } + if (++counter % 100_000 == 0) + logger.debug("Finished processing " + counter + " node pairs (logsum lookup size: " + logsum.size() + ")"); + //if we ever bring back segmented logsums, then this will be a bit more complicated + // the basic idea is all logsums first, then times (in same order) so lookups are straightforward + // without having to replicate the hashmap, which is a big data structure + double[] data = new double[] {Double.parseDouble(lineData[logsumIndex]),Double.parseDouble(lineData[timeIndex])}; + + int fromZone = Integer.parseInt(lineData[0]); + int toZone = Integer.parseInt(lineData[1]); + int indexFactor = taz ? -1 : 1; + MatrixLookup ml = new MatrixLookup(indexFactor*fromZone,indexFactor*toZone); + logsum.put(ml,data); + + } + } catch (IOException e) { + throw new RuntimeException(e); + } + logger.info("Finished processing " + counter + " node pairs (logsum lookup size: " + logsum.size() + ") in " + ((System.currentTimeMillis() - startTime) / 60000.0) + " minutes"); + } + + private double[] getLogsums(int rowId, int columnId) { + double[] logsums = logsum.get(new MatrixLookup(rowId,columnId)); + if (logsums == null) + logsums = logsum.get(new MatrixLookup(mgraIndex[rowId],mgraIndex[columnId])); + return logsums; + } + + @Override + public double getValue(BikeLogsumSegment segment, int rowId, int columnId) { + double[] logsums = getLogsums(rowId,columnId); + return logsums == null ? -999 : logsums[segment.getSegmentId()]; + } + + public double getLogsum(BikeLogsumSegment segment, int rowId, int columnId) { + return getValue(segment,rowId,columnId); + } + + public double getTime(BikeLogsumSegment segment, int rowId, int columnId) { + double[] logsums = getLogsums(rowId,columnId); + return logsums == null ? Double.POSITIVE_INFINITY : logsums[segment.getSegmentId()+BikeLogsumSegment.segmentWidth()]; + } + + private static class MatrixLookup implements Serializable { + private static final long serialVersionUID = -5048040835197200584L; + private final int row; + private final int column; + + private MatrixLookup(int row, int column) { + this.row = row; + this.column = column; + } + + public boolean equals(Object o) { + if ((o == null) || (!(o instanceof MatrixLookup))) + return false; + MatrixLookup ml = (MatrixLookup) o; + return (row == ml.row) && (column == ml.column); + } + + public int hashCode() { + return row + 37*column; + } + } + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + out.writeObject(logsum); + out.writeObject(mgraIndex); + } + + @SuppressWarnings("unchecked") + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + logsum = (Map) in.readObject(); + mgraIndex = (int[]) in.readObject(); + synchronized (BikeLogsum.class) { + //ensures singleton - readResolve will ensure all get this single value + //we need to allow the above reading of fields, though, so that deserialization is aligned correctly + if (instance == null) + instance = this; + } + } + + private Object readResolve() throws ObjectStreamException { + return instance; //ensures singelton + } + + public static void main(String ... args) { + org.apache.log4j.BasicConfigurator.configure(); + LogManager.getRootLogger().setLevel(Level.INFO); + logger.info("usage: org.sandag.abm.ctramp.BikeLogsum properties origin_mgra dest_mgra"); + Map properties = ResourceUtil.getResourceBundleAsHashMap(args[0]); + int originMgra = Integer.parseInt(args[1]); + int destMgra = Integer.parseInt(args[2]); + BikeLogsum bls = BikeLogsum.getBikeLogsum(properties); + + BikeLogsumSegment defaultSegment = new BikeLogsumSegment(true,true,true); + double logsum = bls.getLogsum(new BikeLogsumSegment(true,true,true),originMgra,destMgra); + double time = bls.getTime(new BikeLogsumSegment(true,true,true),originMgra,destMgra); + logger.info(String.format("omgra: %s, dmgra: %s, logsum: %s, time: %s",originMgra,destMgra,logsum,time)); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/BikeLogsumSegment.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/BikeLogsumSegment.java new file mode 100644 index 0000000..9c2efc0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/BikeLogsumSegment.java @@ -0,0 +1,117 @@ +package org.sandag.abm.ctramp; + +import java.io.IOException; +import java.io.Serializable; + +/** + * The {@code BikeLogsumSegment} class provides a segmentation for bicycle logsums used in the SANDAG model. The segmentation is currently + * based on three variables: + *

+ *

    + *
  • sex (male/female)
  • + *
  • tour type (mandatory/non-mandatory)
  • + *
  • trip direction (outbound/inbound) - only used if tour type is mandatory
  • + *
+ *

+ * This segmentation maps the 6 possible unique combinations into the integer indices 0 through 5, which can then be used as a lookup to a + * zero-based array or list data structure. + */ +public class BikeLogsumSegment implements Serializable { + private static final long serialVersionUID = -8429882786837391491L; + + private int segmentId; + + /** + * Constructor specifying the segment parameters. + * + * @param isFemale + * {@code true} if the sex is female. + * + * @param mandatory + * {@code true} if the tour type is mandatory. + * + * @param inbound + * {@code true} if the trip direction is inbound. + */ + public BikeLogsumSegment(boolean isFemale, boolean mandatory, boolean inbound) { + segmentId = formSegmentId(isFemale,mandatory,inbound); + } + + private int formSegmentId(boolean isFemale, boolean mandatory, boolean inbound) { + return 0; //only one segment now, but leaving in this structure in case it is needed in the future + } + + /** + * Get the segment index (0-5) for this segment. + * + * @return return this segment's index id. + */ + public int getSegmentId() { + return segmentId; + } + + /** + * Get the total number of segments available from this class. All segment index ids will be less than this value. + * + * @return the number of unique segments provided by this class. + */ + public static int segmentWidth() { + return 1; + } + + /** + * Get the segments corresponding to the tour-specific segment values. This will give all permutations which can then be combined to form a + * tour-level (as opposed to trip-level) composite logsum. + * + * @param isFemale + * {@code true} if the sex is female. + * + * @param mandatory + * {@code true} if the tour type is mandatory. + * + * @return an array of all possible segments with {@code isFemale} and {@code mandatory}. + */ + public static BikeLogsumSegment[] getTourSegments(boolean isFemale, boolean mandatory) { + return new BikeLogsumSegment[] {new BikeLogsumSegment(isFemale,mandatory,true), + new BikeLogsumSegment(isFemale,mandatory,false)}; + } + + /** + * Get the segments corresponding to the tour-specific, person-inspecific segment values. This will give all permutations which can then be + * combined to form a tour- and household-level (as opposed to trip-level) composite logsum. + * + * @param mandatory + * {@code true} if the tour type is mandatory. + * + * @return an array of all possible segments with {@code mandatory}. + */ + public static BikeLogsumSegment[] getTourSegments(boolean mandatory) { + return new BikeLogsumSegment[] {new BikeLogsumSegment(true,mandatory,true), + new BikeLogsumSegment(true,mandatory,false), + new BikeLogsumSegment(false,mandatory,true), + new BikeLogsumSegment(false,mandatory,false)}; + } + + @Override + public String toString() { + StringBuilder sb = new StringBuilder(" 0; + boolean isMandatory = (segmentId & 2) > 0; + boolean inbound = (segmentId & 4) > 0; + sb.append(isFemale ? "female" : "male"); + sb.append(",").append(isMandatory ? "mandatory" : "non-mandatory"); + if (isMandatory) + sb.append(",").append(inbound ? "inbound" : "outbound"); + sb.append(">"); + return sb.toString(); + } + + private void writeObject(java.io.ObjectOutputStream out) throws IOException { + out.writeInt(segmentId); + } + + private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { + segmentId = in.readInt(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/ConnectionHelper.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ConnectionHelper.java new file mode 100644 index 0000000..7084678 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ConnectionHelper.java @@ -0,0 +1,55 @@ +package org.sandag.abm.ctramp; + +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.SQLException; + +public final class ConnectionHelper +{ + + private String url; + private static ConnectionHelper instance; + + private ConnectionHelper(String fileName) + { + try + { + Class.forName("org.sqlite.JDBC"); + // url = "jdbc:sqlite:/c:/jim/projects/baylanta/data/status.db"; + url = "jdbc:sqlite:/" + fileName; + } catch (Exception e) + { + e.printStackTrace(); + } + } + + public static Connection getConnection(String fileName) throws SQLException + { + if (instance == null) + { + instance = new ConnectionHelper(fileName); + } + try + { + return DriverManager.getConnection(instance.url); + } catch (SQLException e) + { + throw e; + } + } + + public static void close(Connection connection) + { + try + { + if (connection != null) + { + connection.close(); + } + } catch (SQLException e) + { + e.printStackTrace(); + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/CoordinatedDailyActivityPatternDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/CoordinatedDailyActivityPatternDMU.java new file mode 100644 index 0000000..93d988c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/CoordinatedDailyActivityPatternDMU.java @@ -0,0 +1,442 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + * Decision making unit object for the Coordinated Daily Activity Pattern Model. + * This DMU contains all the getters specified in the UEC, i.e. all the "@" + * variables. + * + * @author D. Ory + * + */ +public class CoordinatedDailyActivityPatternDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(CoordinatedDailyActivityPatternDMU.class); + + protected HashMap methodIndexMap; + + protected IndexValues dmuIndex; + + protected Household householdObject; + protected Person personA, personB, personC; + protected double workModeChoiceLogsumA; + protected double schoolModeChoiceLogsumA; + protected double retailAccessibility; + + protected double workAccessForMandatoryDap; + + protected int numAdultsWithNonMandatoryDap; + protected int numAdultsWithMandatoryDap; + protected int numKidsWithNonMandatoryDap; + protected int numKidsWithMandatoryDap; + protected int allAdultsAtHome; + + public CoordinatedDailyActivityPatternDMU() + { + dmuIndex = new IndexValues(); + } + + public void setDmuIndexValues(int zoneId) + { + dmuIndex.setZoneIndex(zoneId); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (householdObject.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug CDAP UEC"); + } + + } + + public IndexValues getIndexValues() + { + return dmuIndex; + } + + public void setHousehold(Household passedInHouseholdObject) + { + + householdObject = passedInHouseholdObject; + + // set the household index + dmuIndex.setHHIndex(passedInHouseholdObject.getHhId()); + + // set the home zone as the zone index + dmuIndex.setZoneIndex(passedInHouseholdObject.getHhMgra()); + } + + public void setPersonA(Person passedInPersonA) + { + this.personA = passedInPersonA; + } + + public void setPersonB(Person passedInPersonB) + { + this.personB = passedInPersonB; + } + + public void setPersonC(Person passedInPersonC) + { + this.personC = passedInPersonC; + } + + // full-time worker + public int getFullTimeWorkerA() + { + return (personA.getPersonTypeIsFullTimeWorker()); + } + + public int getFullTimeWorkerB() + { + return (personB.getPersonTypeIsFullTimeWorker()); + } + + public int getFullTimeWorkerC() + { + return (personC.getPersonTypeIsFullTimeWorker()); + } + + // part-time worker + public int getPartTimeWorkerA() + { + return (personA.getPersonTypeIsPartTimeWorker()); + } + + public int getPartTimeWorkerB() + { + return (personB.getPersonTypeIsPartTimeWorker()); + } + + public int getPartTimeWorkerC() + { + return (personC.getPersonTypeIsPartTimeWorker()); + } + + // university student + public int getUniversityStudentA() + { + return (personA.getPersonIsUniversityStudent()); + } + + public int getUniversityStudentB() + { + return (personB.getPersonIsUniversityStudent()); + } + + public int getUniversityStudentC() + { + return (personC.getPersonIsUniversityStudent()); + } + + // non-working adult + public int getNonWorkingAdultA() + { + return (personA.getPersonIsNonWorkingAdultUnder65()); + } + + public int getNonWorkingAdultB() + { + return (personB.getPersonIsNonWorkingAdultUnder65()); + } + + public int getNonWorkingAdultC() + { + return (personC.getPersonIsNonWorkingAdultUnder65()); + } + + // retired + public int getRetiredA() + { + return (personA.getPersonIsNonWorkingAdultOver65()); + } + + public int getRetiredB() + { + return (personB.getPersonIsNonWorkingAdultOver65()); + } + + public int getRetiredC() + { + return (personC.getPersonIsNonWorkingAdultOver65()); + } + + // driving age school child + public int getDrivingAgeSchoolChildA() + { + return (personA.getPersonIsStudentDriving()); + } + + public int getDrivingAgeSchoolChildB() + { + return (personB.getPersonIsStudentDriving()); + } + + public int getDrivingAgeSchoolChildC() + { + return (personC.getPersonIsStudentDriving()); + } + + // non-driving school-age child + public int getPreDrivingAgeSchoolChildA() + { + return (personA.getPersonIsStudentNonDriving()); + } + + public int getPreDrivingAgeSchoolChildB() + { + return (personB.getPersonIsStudentNonDriving()); + } + + public int getPreDrivingAgeSchoolChildC() + { + return (personC.getPersonIsStudentNonDriving()); + } + + // pre-school child + public int getPreSchoolChildA() + { + return (personA.getPersonIsPreschoolChild()); + } + + public int getPreSchoolChildB() + { + return (personB.getPersonIsPreschoolChild()); + } + + public int getPreSchoolChildC() + { + return (personC.getPersonIsPreschoolChild()); + } + + // age + public int getAgeA() + { + return (personA.getAge()); + } + + // female + public int getFemaleA() + { + return (personA.getPersonIsFemale()); + } + + // household more cars than workers + public int getMoreCarsThanWorkers() + { + + int workers = householdObject.getWorkers(); + int autos = householdObject.getAutosOwned(); + + if (autos > workers) return 1; + return 0; + + } + + // household fewer cars than workers + public int getFewerCarsThanWorkers() + { + + int workers = householdObject.getWorkers(); + int autos = householdObject.getAutosOwned(); + + if (autos < workers) return 1; + return 0; + + } + + // household with zero cars + public int getZeroCars() + { + int autos = householdObject.getAutosOwned(); + if (autos == 0) return 1; + return 0; + + } + + // household income + public int getHHIncomeInDollars() + { + return householdObject.getIncomeInDollars(); + } + + public int getUsualWorkLocationIsHomeA() + { + if (personA.getWorkLocation() == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) return 1; + else return 0; + } + + public int getNoUsualWorkLocationA() + { + if (personA.getWorkLocation() > 0 + && personA.getWorkLocation() != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) return 0; + else return 1; + } + + // no usual school location is 1 if person is a student, location is home + // mgra, + // and distance to school is 0. + public int getNoUsualSchoolLocationA() + { + if (personA.getPersonIsStudent() == 1 + && personA.getUsualSchoolLocation() == personA.getHouseholdObject().getHhMgra() + && personA.getSchoolLocationDistance() == 0) return 0; + else return 1; + } + + public int getHhSize() + { + + int hhSize = Math.min(HouseholdCoordinatedDailyActivityPatternModel.MAX_MODEL_HH_SIZE, + householdObject.getSize()); + + return (hhSize); + } + + public int getHhDetach() + { + return householdObject.getHhBldgsz(); + } + + public int getNumAdultsWithNonMandatoryDap() + { + return numAdultsWithNonMandatoryDap; + } + + public int getNumAdultsWithMandatoryDap() + { + return numAdultsWithMandatoryDap; + } + + public int getNumKidsWithNonMandatoryDap() + { + return numKidsWithNonMandatoryDap; + } + + public int getNumKidsWithMandatoryDap() + { + return numKidsWithMandatoryDap; + } + + public void setNumAdultsWithNonMandatoryDap(int value) + { + numAdultsWithNonMandatoryDap = value; + } + + public void setNumAdultsWithMandatoryDap(int value) + { + numAdultsWithMandatoryDap = value; + } + + public void setNumKidsWithNonMandatoryDap(int value) + { + numKidsWithNonMandatoryDap = value; + } + + public void setNumKidsWithMandatoryDap(int value) + { + numKidsWithMandatoryDap = value; + } + + public int getAllAdultsAtHome() + { + return allAdultsAtHome; + } + + public void setAllAdultsAtHome(int value) + { + allAdultsAtHome = value; + } + + public void setWorkAccessForMandatoryDap(double logsum) + { + workAccessForMandatoryDap = logsum; + } + + public double getWorkAccessForMandatoryDap() + { + return workAccessForMandatoryDap; + } + + public void setWorkLocationModeChoiceLogsumA(double logsum) + { + workModeChoiceLogsumA = logsum; + } + + public double getWorkLocationModeChoiceLogsumA() + { + return workModeChoiceLogsumA; + } + + public void setSchoolLocationModeChoiceLogsumA(double logsum) + { + schoolModeChoiceLogsumA = logsum; + } + + public double getSchoolLocationModeChoiceLogsumA() + { + return schoolModeChoiceLogsumA; + } + + public void setRetailAccessibility(double logsum) + { + retailAccessibility = logsum; + } + + public double getRetailAccessibility() + { + return retailAccessibility; + } + + public int getTelecommuteFrequencyA() { + return personA.getTelecommuteChoice(); + } + + public int getTelecommuteFrequencyB() { + return personB.getTelecommuteChoice(); + } + + public int getTelecommuteFrequencyC() { + return personC.getTelecommuteChoice(); + } + + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/CtrampApplication.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/CtrampApplication.java new file mode 100644 index 0000000..bfb4032 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/CtrampApplication.java @@ -0,0 +1,2481 @@ +package org.sandag.abm.ctramp; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.NotSerializableException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.TreeMap; +import org.apache.log4j.Logger; +import org.jppf.client.JPPFClient; +import org.sandag.abm.accessibilities.BestTransitPathCalculator; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.accessibilities.StoredUtilityData; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.DataFile; +import com.pb.common.datafile.DataReader; +import com.pb.common.datafile.DataWriter; +import com.pb.common.matrix.MatrixIO32BitJvm; +import com.pb.common.matrix.MatrixType; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; +// import org.sandag.abm.accessibilities.BuildAccessibilities; +// import +// org.sandag.abm.ctramp.HouseholdDataWriter; +// import org.sandag.abm.ctramp.IndividualMandatoryTourFrequencyModel; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +// 1.0.1 - 09/21/09 - starting point for SANDAG AB model implementation - AO +// model + +public class CtrampApplication + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(CtrampApplication.class); + + public static final String VERSION = "2.0.0"; + + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + + public static final String PROPERTIES_BASE_NAME = "ctramp"; + public static final String PROPERTIES_PROJECT_DIRECTORY = "Project.Directory"; + + public static final String PROPERTIES_UEC_PATH = "uec.path"; + public static final String SQLITE_DATABASE_FILENAME = "Sqlite.DatabaseFileName"; + + public static final String PROPERTIES_RUN_POPSYN = "RunModel.PopulationSynthesizer"; + public static final String PROPERTIES_RUN_PRE_AUTO_OWNERSHIP = "RunModel.PreAutoOwnership"; + public static final String PROPERTIES_RUN_WORKSCHOOL_CHOICE = "RunModel.UsualWorkAndSchoolLocationChoice"; + public static final String PROPERTIES_RUN_AUTO_OWNERSHIP = "RunModel.AutoOwnership"; + public static final String PROPERTIES_RUN_TRANSPONDER_CHOICE = "RunModel.TransponderChoice"; + public static final String PROPERTIES_RUN_FREE_PARKING_AVAILABLE = "RunModel.FreeParking"; + public static final String PROPERTIES_RUN_INTERNAL_EXTERNAL_TRIP = "RunModel.InternalExternal"; + public static final String PROPERTIES_RUN_DAILY_ACTIVITY_PATTERN = "RunModel.CoordinatedDailyActivityPattern"; + public static final String PROPERTIES_RUN_INDIV_MANDATORY_TOUR_FREQ = "RunModel.IndividualMandatoryTourFrequency"; + public static final String PROPERTIES_RUN_MAND_TOUR_DEP_TIME_AND_DUR = "RunModel.MandatoryTourDepartureTimeAndDuration"; + public static final String PROPERTIES_RUN_SCHOOL_ESCORT_MODEL = "RunModel.SchoolEscortModel"; + public static final String PROPERTIES_RUN_MAND_TOUR_MODE_CHOICE = "RunModel.MandatoryTourModeChoice"; + public static final String PROPERTIES_RUN_AT_WORK_SUBTOUR_FREQ = "RunModel.AtWorkSubTourFrequency"; + public static final String PROPERTIES_RUN_AT_WORK_SUBTOUR_LOCATION_CHOICE = "RunModel.AtWorkSubTourLocationChoice"; + public static final String PROPERTIES_RUN_AT_WORK_SUBTOUR_MODE_CHOICE = "RunModel.AtWorkSubTourModeChoice"; + public static final String PROPERTIES_RUN_AT_WORK_SUBTOUR_DEP_TIME_AND_DUR = "RunModel.AtWorkSubTourDepartureTimeAndDuration"; + public static final String PROPERTIES_RUN_JOINT_TOUR_FREQ = "RunModel.JointTourFrequency"; + public static final String PROPERTIES_RUN_JOINT_LOCATION_CHOICE = "RunModel.JointTourLocationChoice"; + public static final String PROPERTIES_RUN_JOINT_TOUR_MODE_CHOICE = "RunModel.JointTourModeChoice"; + public static final String PROPERTIES_RUN_JOINT_TOUR_DEP_TIME_AND_DUR = "RunModel.JointTourDepartureTimeAndDuration"; + public static final String PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_FREQ = "RunModel.IndividualNonMandatoryTourFrequency"; + public static final String PROPERTIES_RUN_INDIV_NON_MANDATORY_LOCATION_CHOICE = "RunModel.IndividualNonMandatoryTourLocationChoice"; + public static final String PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_MODE_CHOICE = "RunModel.IndividualNonMandatoryTourModeChoice"; + public static final String PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_DEP_TIME_AND_DUR = "RunModel.IndividualNonMandatoryTourDepartureTimeAndDuration"; + public static final String PROPERTIES_RUN_STOP_FREQUENCY = "RunModel.StopFrequency"; + public static final String PROPERTIES_RUN_STOP_LOCATION = "RunModel.StopLocation"; + + public static final String PROPERTIES_RUN_WORK_LOC_CHOICE_KEY = "uwsl.run.workLocChoice"; + public static final String PROPERTIES_RUN_SCHOOL_LOC_CHOICE_KEY = "uwsl.run.schoolLocChoice"; + public static final String PROPERTIES_WRITE_WORK_SCHOOL_LOC_RESULTS_KEY = "uwsl.write.results"; + + public static final String PROPERTIES_UEC_AUTO_OWNERSHIP = "UecFile.AutoOwnership"; + public static final String PROPERTIES_UEC_DAILY_ACTIVITY_PATTERN = "UecFile.CoordinatedDailyActivityPattern"; + public static final String PROPERTIES_UEC_INDIV_MANDATORY_TOUR_FREQ = "UecFile.IndividualMandatoryTourFrequency"; + public static final String PROPERTIES_UEC_MAND_TOUR_DEP_TIME_AND_DUR = "UecFile.TourDepartureTimeAndDuration"; + public static final String PROPERTIES_UEC_INDIV_NON_MANDATORY_TOUR_FREQ = "UecFile.IndividualNonMandatoryTourFrequency"; + + public static final String PROPERTIES_CLEAR_MATRIX_MANAGER_ON_START = "RunModel.Clear.MatrixMgr.At.Start"; + + public static final String READ_ACCESSIBILITIES = "acc.read.input.file"; + + // TODO eventually move to model-specific structure object + public static final int TOUR_MODE_CHOICE_WORK_MODEL_UEC_PAGE = 1; + public static final int TOUR_MODE_CHOICE_UNIVERSITY_MODEL_UEC_PAGE = 2; + public static final int TOUR_MODE_CHOICE_HIGH_SCHOOL_MODEL_UEC_PAGE = 3; + public static final int TOUR_MODE_CHOICE_GRADE_SCHOOL_MODEL_UEC_PAGE = 4; + + // TODO eventually move to model-specific model structure object + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_WORK_MODEL_UEC_PAGE = 1; + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_WORK_DEPARTURE_UEC_PAGE = 2; + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_WORK_DURATION_UEC_PAGE = 3; + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_WORK_ARRIVAL_UEC_PAGE = 4; + + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_SCHOOL_MODEL_UEC_PAGE = 5; + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_SCHOOL_DEPARTURE_UEC_PAGE = 6; + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_SCHOOL_DURATION_UEC_PAGE = 7; + public static final int MANDATORY_TOUR_DEP_TIME_AND_DUR_SCHOOL_ARRIVAL_UEC_PAGE = 8; + + public static final String PROPERTIES_SCHEDULING_NUMBER_OF_TIME_PERIODS = "Scheduling.NumberOfTimePeriods"; + public static final String PROPERTIES_SCHEDULING_FIRST_TIME_PERIOD = "Scheduling.FirstTimePeriod"; + + static final String PROPERTIES_RESTART_WITH_HOUSEHOLD_SERVER = "RunModel.RestartWithHhServer"; + + static final String PROPERTIES_HOUSEHOLD_DISK_OBJECT_FILE_NAME = "Households.disk.object.base.name"; + static final String PROPERTIES_HOUSEHOLD_DISK_OBJECT_KEY = "Read.HouseholdDiskObjectFile"; + + public static final String PROPERTIES_RESULTS_AUTO_OWNERSHIP = "Results.AutoOwnership"; + public static final String PROPERTIES_RESULTS_CDAP = "Results.CoordinatedDailyActivityPattern"; + + public static final String PROPERTIES_OUTPUT_WRITE_SWITCH = "CTRAMP.Output.WriteToDiskSwitch"; + public static final String PROPERTIES_OUTPUT_HOUSEHOLD_FILE = "CTRAMP.Output.HouseholdFile"; + public static final String PROPERTIES_OUTPUT_PERSON_FILE = "CTRAMP.Output.PersonFile"; + + public static final String PROPERTIES_WRITE_DATA_TO_FILE = "Results.WriteDataToFiles"; + public static final String PROPERTIES_WRITE_DATA_TO_DATABASE = "Results.WriteDataToDatabase"; + + public static final String PROPERTIES_SAVE_TOUR_MODE_CHOICE_UTILS = "TourModeChoice.Save.UtilsAndProbs"; + + public static final String PROPERTIES_WORK_LOCATION_CHOICE_SHADOW_PRICE_INPUT_FILE = "UsualWorkLocationChoice.ShadowPrice.Input.File"; + public static final String PROPERTIES_SCHOOL_LOCATION_CHOICE_SHADOW_PRICE_INPUT_FILE = "UsualSchoolLocationChoice.ShadowPrice.Input.File"; + + public static final String PROPERTIES_NUMBER_OF_GLOBAL_ITERATIONS = "Global.iterations"; + + public static final String ALT_FIELD_NAME = "a"; + public static final String START_FIELD_NAME = "depart"; + public static final String END_FIELD_NAME = "arrive"; + + private static final int NUM_WRITE_PACKETS = 1000; + + private ResourceBundle resourceBundle; + private HashMap propertyMap; + + private MatrixDataServerIf ms; + private MatrixDataManager mdm; + + private ModelStructure modelStructure; + protected String projectDirectory; + + private HashMap> cdapByHhSizeAndPattern; + private HashMap> cdapByPersonTypeAndActivity; + + private BuildAccessibilities aggAcc; + private boolean calculateLandUseAccessibilities; + + public CtrampApplication(ResourceBundle rb, HashMap rbMap, + boolean calculateLandUseAccessibilities) + { + resourceBundle = rb; + propertyMap = rbMap; + this.calculateLandUseAccessibilities = calculateLandUseAccessibilities; + } + + public void setupModels(ModelStructure modelStructure) + { + + this.modelStructure = modelStructure; + + } + + // public void runPopulationSynthesizer( SANDAGPopSyn populationSynthesizer + // ){ + // + // // run population synthesizer + // boolean runModelPopulationSynthesizer = + // ResourceUtil.getBooleanProperty(resourceBundle, PROPERTIES_RUN_POPSYN); + // if(runModelPopulationSynthesizer){ + // populationSynthesizer.run(); + // } + // + // } + + public void runModels(HouseholdDataManagerIf householdDataManager, + CtrampDmuFactoryIf dmuFactory, int globalIterationNumber, float iterationSampleRate) + { + + logger.info("Running JPPF CtrampApplication.runModels() for " + + householdDataManager.getNumHouseholds() + " households."); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(propertyMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(propertyMap, + "RunModel.MatrixServerPort"); + } catch (RuntimeException e) + { + // if no matrix server address entry is found, leave undefined -- + // it's eithe not needed or show could create an error. + } + } catch (RuntimeException e) + { + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServer matrixServer = null; + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = startMatrixServerProcess(matrixServerAddress, serverPort); + ms = matrixServer; + } else + { + ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + + mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + } + + } + + } catch (Exception e) + { + + logger.error(String + .format("exception caught running ctramp model components -- exiting."), e); + throw new RuntimeException(e); + + } + + // get the property that indicates if the MatrixDataServer should be + // cleared. + // default is to clear the manager + boolean clearMatrixMgr = true; + try + { + clearMatrixMgr = Util.getBooleanValueFromPropertyMap(propertyMap, + PROPERTIES_CLEAR_MATRIX_MANAGER_ON_START); + } catch (RuntimeException e) + { + // catch the RuntimeExcption that's thrown if the property key + // is not found in the properties file. + // no need to anything - the boolean clearMatrixMgr was + // initialized to the default action. + } + + // if the property to clear matrices is true and a remote + // MatrixDataServer is being used, clear the matrices. + // if matrices are being read directly into the current process, no + // need to clear. + if (clearMatrixMgr && !matrixServerAddress.equalsIgnoreCase("localhost")) ms.clear(); + + // run core activity based model for the specified iteration + runModelSequence(globalIterationNumber, householdDataManager, dmuFactory); + + } + + /** + * This method maintains the sequencing of the various AB Model choice model + * components + * + * @param iteration + * is the global iteration number in the sequence of AB Model + * runs during feedback + * @param householdDataManager + * is the handle to the household object data manager + * @param dmuFactory + * is the factory object for creating DMU objects used in choice + * models + */ + private void runModelSequence(int iteration, HouseholdDataManagerIf householdDataManager, + CtrampDmuFactoryIf dmuFactory) + { + + String restartModel = ResourceUtil.getProperty(resourceBundle, + PROPERTIES_RESTART_WITH_HOUSEHOLD_SERVER); + boolean logResults = Util.getStringValueFromPropertyMap(propertyMap, "RunModel.LogResults") + .equalsIgnoreCase("true"); + if (restartModel == null) restartModel = "none"; + if (!restartModel.equalsIgnoreCase("none")) restartModels(householdDataManager); + + JPPFClient jppfClient = null; + + boolean runPreAutoOwnershipChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_PRE_AUTO_OWNERSHIP); + if (runPreAutoOwnershipChoiceModel) + { + + logger.info("creating Accessibilities Object for Pre-AO."); + buildNonMandatoryAccessibilities(calculateLandUseAccessibilities); + + logger.info("starting Pre-Auto Ownership Model."); + HashMap propertyMap = ResourceUtil + .changeResourceBundleIntoHashMap(resourceBundle); + + householdDataManager.resetPreAoRandom(); + + HouseholdAutoOwnershipModel aoModel = new HouseholdAutoOwnershipModel(propertyMap, + dmuFactory, aggAcc.getAccessibilitiesTableObject(), null); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + for (int i = 0; i < householdArray.length; ++i) + { + + try + { + aoModel.applyModel(householdArray[i], true); + } catch (RuntimeException e) + { + logger.fatal(String + .format("exception caught running pre-AO for i=%d, startIndex=%d, endIndex=%d, hhId=%d.", + i, startIndex, endIndex, householdArray[i].getHhId())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + householdDataManager.setHhArray(householdArray, startIndex); + + } + + saveAoResults(householdDataManager, projectDirectory, true); + + // clear the zonal data used in the AO UEC so a different zonal data + // file + // (MGRA data) can be used later by other UECs. + // TableDataSetManager tableDataManager = + // TableDataSetManager.getInstance(); + // tableDataManager.clearData(); + } + logger.info("flag to run pre-AO was set to: " + runPreAutoOwnershipChoiceModel); + logAoResults(householdDataManager, true); + + boolean runUsualWorkSchoolChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_WORKSCHOOL_CHOICE); + if (runUsualWorkSchoolChoiceModel) + { + + boolean runWorkLocationChoice = false; + try + { + String stringValue = resourceBundle.getString(PROPERTIES_RUN_WORK_LOC_CHOICE_KEY); + runWorkLocationChoice = stringValue.equalsIgnoreCase("true"); + } catch (MissingResourceException e) + { + // default value is true if property was not defined + runWorkLocationChoice = true; + } + logger.info("flag to run work location choice was set to: " + runWorkLocationChoice); + + boolean runSchoolLocationChoice = false; + try + { + String stringValue = resourceBundle.getString(PROPERTIES_RUN_SCHOOL_LOC_CHOICE_KEY); + runSchoolLocationChoice = stringValue.equalsIgnoreCase("true"); + } catch (MissingResourceException e) + { + // default value is true if property was not defined + runSchoolLocationChoice = true; + } + logger.info("flag to run school location choice was set to: " + runSchoolLocationChoice); + + boolean writeLocationChoiceResultsFile = false; + try + { + String stringValue = resourceBundle + .getString(PROPERTIES_WRITE_WORK_SCHOOL_LOC_RESULTS_KEY); + writeLocationChoiceResultsFile = stringValue.equalsIgnoreCase("true"); + } catch (MissingResourceException e) + { + // default value is true if property was not defined + writeLocationChoiceResultsFile = true; + } + logger.info("flag to write uwsl result was set to: " + writeLocationChoiceResultsFile); + + if (aggAcc == null) + { + logger.info("creating Accessibilities Object for UWSL."); + buildNonMandatoryAccessibilities(calculateLandUseAccessibilities); + } + + // new the usual school and location choice model object + jppfClient = new JPPFClient(); + UsualWorkSchoolLocationChoiceModel usualWorkSchoolLocationChoiceModel = new UsualWorkSchoolLocationChoiceModel( + resourceBundle, restartModel, jppfClient, modelStructure, ms, dmuFactory, + aggAcc); + + if (runWorkLocationChoice) + { + // calculate and get the array of worker size terms table - + // MGRAs by + // occupations + aggAcc.createWorkSegmentNameIndices(); + aggAcc.calculateWorkerSizeTerms(); + double[][] workerSizeTerms = aggAcc.getWorkerSizeTerms(); + + // run the model + logger.info("starting usual work location choice."); + usualWorkSchoolLocationChoiceModel.runWorkLocationChoiceModel(householdDataManager, + workerSizeTerms); + logger.info("finished with usual work location choice."); + } + + if (runSchoolLocationChoice) + { + aggAcc.createSchoolSegmentNameIndices(); + aggAcc.calculateSchoolSizeTerms(); + double[][] schoolFactors = aggAcc.calculateSchoolSegmentFactors(); + double[][] schoolSizeTerms = aggAcc.getSchoolSizeTerms(); + + logger.info("starting usual school location choice."); + usualWorkSchoolLocationChoiceModel.runSchoolLocationChoiceModel( + householdDataManager, schoolSizeTerms, schoolFactors); + logger.info("finished with usual school location choice."); + } + + if (writeLocationChoiceResultsFile) + { + logger.info("writing work/school location choice results file; may take a few minutes ..."); + usualWorkSchoolLocationChoiceModel.saveResults(householdDataManager, + projectDirectory, iteration); + logger.info(String + .format("finished writing work/school location choice results file.")); + } + + usualWorkSchoolLocationChoiceModel = null; + + } + logger.info("flag to run UWSL was set to: " + runUsualWorkSchoolChoiceModel); + + boolean runAutoOwnershipChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_AUTO_OWNERSHIP); + boolean runTransponderChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_TRANSPONDER_CHOICE); + boolean runFreeParkingChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_FREE_PARKING_AVAILABLE); + boolean runInternalExternalTripChoiceModel = ResourceUtil.getBooleanProperty( + resourceBundle, PROPERTIES_RUN_INTERNAL_EXTERNAL_TRIP); + boolean runCoordinatedDailyActivityPatternChoiceModel = ResourceUtil.getBooleanProperty( + resourceBundle, PROPERTIES_RUN_DAILY_ACTIVITY_PATTERN); + boolean runMandatoryTourFreqChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_INDIV_MANDATORY_TOUR_FREQ); + boolean runJointTourFreqChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_JOINT_TOUR_FREQ); + boolean runIndivNonManTourFrequencyModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_FREQ); + boolean runAtWorkSubTourFrequencyModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_AT_WORK_SUBTOUR_FREQ); + boolean runStopFrequencyModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_STOP_FREQUENCY); + + if (runAutoOwnershipChoiceModel || runTransponderChoiceModel || runFreeParkingChoiceModel + || runInternalExternalTripChoiceModel + || runCoordinatedDailyActivityPatternChoiceModel || runMandatoryTourFreqChoiceModel + || runIndivNonManTourFrequencyModel || runAtWorkSubTourFrequencyModel + || runStopFrequencyModel) + { + + // We're resetting the random number sequence used by pre-AO for the + // primary AO + if (runAutoOwnershipChoiceModel) householdDataManager.resetPreAoRandom(); + + if (runTransponderChoiceModel) + householdDataManager.computeTransponderChoiceTazPercentArrays(); + + logger.info("starting HouseholdChoiceModelRunner."); + HashMap propertyMap = ResourceUtil + .changeResourceBundleIntoHashMap(resourceBundle); + HouseholdChoiceModelRunner runner = new HouseholdChoiceModelRunner(propertyMap, + jppfClient, restartModel, householdDataManager, ms, modelStructure, dmuFactory); + runner.runHouseholdChoiceModels(); + + if (runAutoOwnershipChoiceModel) + { + saveAoResults(householdDataManager, projectDirectory, false); + if (logResults) logAoResults(householdDataManager, false); + } + + if (runTransponderChoiceModel) + { + if (logResults) logTpResults(householdDataManager); + } + + if (runFreeParkingChoiceModel) + { + if (logResults) logFpResults(householdDataManager); + } + + if (runInternalExternalTripChoiceModel) + { + if (logResults) logIeResults(householdDataManager); + } + + if (runCoordinatedDailyActivityPatternChoiceModel) + { + saveCdapResults(householdDataManager, projectDirectory); + if (logResults) logCdapResults(householdDataManager); + } + + if (runMandatoryTourFreqChoiceModel) + { + if (logResults) logImtfResults(householdDataManager); + } + + if (runJointTourFreqChoiceModel) + { + if (logResults) logJointModelResults(householdDataManager, dmuFactory); + } + + if (runAtWorkSubTourFrequencyModel) + { + if (logResults) logAtWorkSubtourFreqResults(householdDataManager); + } + + if (runStopFrequencyModel) + { + if (logResults) logIndivStfResults(householdDataManager); + } + + } + + jppfClient.close(); + + boolean writeTextFileFlag = false; + boolean writeSqliteFlag = false; + try + { + writeTextFileFlag = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_WRITE_DATA_TO_FILE); + } catch (MissingResourceException e) + { + // if exception is caught while getting property file value, then + // boolean + // flag remains false + } + try + { + writeSqliteFlag = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_WRITE_DATA_TO_DATABASE); + } catch (MissingResourceException e) + { + // if exception is caught while getting property file value, then + // boolean + // flag remains false + } + + HouseholdDataWriter dataWriter = null; + if (writeTextFileFlag || writeSqliteFlag) + { + dataWriter = new HouseholdDataWriter(propertyMap, modelStructure, iteration); + + if (writeTextFileFlag) dataWriter.writeDataToFiles(householdDataManager); + + if (writeSqliteFlag) + { + String dbFilename = ""; + try + { + String baseDir = resourceBundle.getString(PROPERTIES_PROJECT_DIRECTORY); + dbFilename = baseDir + resourceBundle.getString(SQLITE_DATABASE_FILENAME) + "_" + + iteration; + dataWriter.writeDataToDatabase(householdDataManager, dbFilename); + } catch (MissingResourceException e) + { + // if exception is caught while getting property file value, + // then + // boolean flag remains false + } + } + } + + } + + /** + * Build the mandatory accessibilities object used by the usual work and + * school location choice models + * + * @return BuildAccessibilities object containing mandatory size term and + * logsum information private void buildMandatoryAccessibilities() { + * + * HashMap propertyMap = + * ResourceUtil.changeResourceBundleIntoHashMap(resourceBundle); + * + * if ( aggAcc == null ) aggAcc = new BuildAccessibilities( + * propertyMap ); + * + * MatrixDataManager mdm = MatrixDataManager.getInstance(); + * mdm.setMatrixDataServerObject( ms ); + * + * aggAcc.setupBuildAccessibilities( propertyMap ); + * aggAcc.calculateConstants(); + * + * // do this in dest choice model + * //aggAcc.buildAccessibilityComponents( propertyMap ); + * + * } + */ + + /** + * Build the non-mandatory accessibilities object used by the auto ownership + * model + * + * @return BuildAccessibilities object containing non-mandatory size term + * and logsum information + */ + private void buildNonMandatoryAccessibilities(boolean calculateLandUseAccessibilities) + { + + HashMap propertyMap = ResourceUtil + .changeResourceBundleIntoHashMap(resourceBundle); + + aggAcc = BuildAccessibilities.getInstance(); + aggAcc.setupBuildAccessibilities(propertyMap, calculateLandUseAccessibilities); + + + if(calculateLandUseAccessibilities) + aggAcc.setCalculatedLandUseAccessibilities(); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateWorkerSizeTerms(); + aggAcc.createSchoolSegmentNameIndices(); + aggAcc.calculateSchoolSizeTerms(); + aggAcc.calculateConstants(); + // aggAcc.buildAccessibilityComponents(propertyMap); + + boolean readAccessibilities = ResourceUtil.getBooleanProperty(resourceBundle, + READ_ACCESSIBILITIES); + if (readAccessibilities) + { + + // output data + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file"); + + aggAcc.readAccessibilityTableFromFile(accFileName); + + } else + { + + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + if (isJppfRunningDistributed()) { + // release the memory used to store the access-tap, tap-egress, and + // tap-tap utilities while calculating accessibilities for the + // client program + // don't do this if we are running jppf in local mode + HashMap rbMap = ResourceUtil + .changeResourceBundleIntoHashMap(resourceBundle); + StoredUtilityData.getInstance(MgraDataManager.getInstance(rbMap).getMaxMgra(), + MgraDataManager.getInstance(rbMap).getMaxTap(), + TazDataManager.getInstance(rbMap).getMaxTaz(), + BestTransitPathCalculator.ACC_EGR, ModelStructure.PERIODCODES) + .deallocateArrays(); + + MatrixDataManager.getInstance().clearData(); + } + } + + } + + private boolean isJppfRunningDistributed() { + //note: this assumes that the jppf config file is being entered in through a system property, and that it is a property file + String jppfConfigFile = System.getProperty("jppf.config"); + ResourceBundle jppfConfig = ResourceUtil.getResourceBundle(jppfConfigFile.replace(".properties","")); + try { + return !jppfConfig.getString("jppf.local.execution.enabled").equalsIgnoreCase("true"); + } catch (MissingResourceException e) { + return false; + } + } + + /* + * method used in original ARC implementation private void runIteration( int + * iteration, HouseholdDataManagerIf householdDataManager, + * CtrampDmuFactoryIf dmuFactory ) { String restartModel = ""; if ( + * hhDiskObjectKey != null && ! hhDiskObjectKey.equalsIgnoreCase("none") ) { + * String doFileName = hhDiskObjectFile + "_" + hhDiskObjectKey; + * householdDataManager.createHhArrayFromSerializedObjectInFile( doFileName, + * hhDiskObjectKey ); restartModel = hhDiskObjectKey; restartModels ( + * householdDataManager ); } else { restartModel = ResourceUtil.getProperty( + * resourceBundle, PROPERTIES_RESTART_WITH_HOUSEHOLD_SERVER ); if ( + * restartModel == null ) restartModel = "none"; if ( ! + * restartModel.equalsIgnoreCase("none") ) restartModels ( + * householdDataManager ); } JPPFClient jppfClient = new JPPFClient(); + * boolean runUsualWorkSchoolChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_WORKSCHOOL_CHOICE); if(runUsualWorkSchoolChoiceModel){ // + * create an object for calculating destination choice attraction size terms + * and managing shadow price calculations. DestChoiceSize dcSizeObj = new + * DestChoiceSize( modelStructure, tazDataManager ); // new the usual school + * and location choice model object UsualWorkSchoolLocationChoiceModel + * usualWorkSchoolLocationChoiceModel = new + * UsualWorkSchoolLocationChoiceModel(resourceBundle, restartModel, + * jppfClient, modelStructure, ms, tazDataManager, dcSizeObj, dmuFactory ); + * // run the model logger.info ( + * "starting usual work and school location choice."); + * usualWorkSchoolLocationChoiceModel + * .runSchoolAndLocationChoiceModel(householdDataManager); logger.info ( + * "finished with usual work and school location choice."); logger.info ( + * "writing work/school location choice results file; may take a few minutes ..." + * ); usualWorkSchoolLocationChoiceModel.saveResults( householdDataManager, + * projectDirectory, iteration ); logger.info ( + * String.format("finished writing results file.") ); + * usualWorkSchoolLocationChoiceModel = null; dcSizeObj = null; System.gc(); + * // write a disk object fle for the householdDataManager, in case we want + * to restart from the next step. if ( hhDiskObjectFile != null ) { + * logger.info ( + * "writing household disk object file after work/school location choice; may take a long time ..." + * ); String hhFileName = String.format( "%s_%d_ao", hhDiskObjectFile, + * iteration ); + * householdDataManager.createSerializedHhArrayInFileFromObject( hhFileName, + * "ao" ); logger.info (String.format( + * "finished writing household disk object file = %s after uwsl; continuing to household choice models ..." + * , hhFileName) ); } } boolean runAutoOwnershipChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_AUTO_OWNERSHIP ); boolean runFreeParkingChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_FREE_PARKING_AVAILABLE ); boolean + * runCoordinatedDailyActivityPatternChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_DAILY_ACTIVITY_PATTERN ); boolean + * runMandatoryTourFreqChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_INDIV_MANDATORY_TOUR_FREQ ); boolean + * runMandatoryTourTimeOfDayChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_MAND_TOUR_DEP_TIME_AND_DUR ); boolean + * runMandatoryTourModeChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_MAND_TOUR_MODE_CHOICE ); boolean + * runJointTourFrequencyModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_JOINT_TOUR_FREQ ); boolean runJointTourLocationChoiceModel + * = ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_JOINT_LOCATION_CHOICE ); boolean + * runJointTourModeChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_JOINT_TOUR_MODE_CHOICE ); boolean + * runJointTourDepartureTimeAndDurationModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_JOINT_TOUR_DEP_TIME_AND_DUR ); boolean + * runIndivNonManTourFrequencyModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_FREQ ); boolean + * runIndivNonManTourLocationChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_INDIV_NON_MANDATORY_LOCATION_CHOICE ); boolean + * runIndivNonManTourModeChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_MODE_CHOICE ); boolean + * runIndivNonManTourDepartureTimeAndDurationModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_DEP_TIME_AND_DUR ); boolean + * runAtWorkSubTourFrequencyModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_AT_WORK_SUBTOUR_FREQ ); boolean + * runAtWorkSubtourLocationChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_AT_WORK_SUBTOUR_LOCATION_CHOICE ); boolean + * runAtWorkSubtourModeChoiceModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_AT_WORK_SUBTOUR_MODE_CHOICE ); boolean + * runAtWorkSubtourDepartureTimeAndDurationModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_AT_WORK_SUBTOUR_DEP_TIME_AND_DUR ); boolean + * runStopFrequencyModel = ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_STOP_FREQUENCY ); boolean runStopLocationModel = + * ResourceUtil.getBooleanProperty(resourceBundle, + * PROPERTIES_RUN_STOP_LOCATION ); boolean runHouseholdModels = false; if ( + * runAutoOwnershipChoiceModel || runFreeParkingChoiceModel || + * runCoordinatedDailyActivityPatternChoiceModel || + * runMandatoryTourFreqChoiceModel || runMandatoryTourModeChoiceModel || + * runMandatoryTourTimeOfDayChoiceModel || runJointTourFrequencyModel || + * runJointTourLocationChoiceModel || runJointTourModeChoiceModel || + * runJointTourDepartureTimeAndDurationModel || + * runIndivNonManTourFrequencyModel || runIndivNonManTourLocationChoiceModel + * || runIndivNonManTourModeChoiceModel || + * runIndivNonManTourDepartureTimeAndDurationModel || + * runAtWorkSubTourFrequencyModel || runAtWorkSubtourLocationChoiceModel || + * runAtWorkSubtourModeChoiceModel || + * runAtWorkSubtourDepartureTimeAndDurationModel || runStopFrequencyModel || + * runStopLocationModel ) runHouseholdModels = true; // disk object file is + * labeled with the next component eligible to be run if model restarted + * String lastComponent = "uwsl"; String nextComponent = "ao"; if( + * runHouseholdModels ) { logger.info ( + * "starting HouseholdChoiceModelRunner." ); HashMap + * propertyMap = + * ResourceUtil.changeResourceBundleIntoHashMap(resourceBundle); + * HouseholdChoiceModelRunner runner = new HouseholdChoiceModelRunner( + * propertyMap, jppfClient, restartModel, householdDataManager, ms, + * modelStructure, tazDataManager, dmuFactory ); + * runner.runHouseholdChoiceModels(); if( runAutoOwnershipChoiceModel ){ + * saveAoResults( householdDataManager, projectDirectory ); logAoResults( + * householdDataManager ); lastComponent = "ao"; nextComponent = "fp"; } if( + * runFreeParkingChoiceModel ){ logFpResults( householdDataManager ); + * lastComponent = "fp"; nextComponent = "cdap"; } if( + * runCoordinatedDailyActivityPatternChoiceModel ){ saveCdapResults( + * householdDataManager, projectDirectory ); logCdapResults( + * householdDataManager ); lastComponent = "cdap"; nextComponent = "imtf"; } + * if( runMandatoryTourFreqChoiceModel ){ logImtfResults( + * householdDataManager ); lastComponent = "imtf"; nextComponent = "imtod"; + * } if( runMandatoryTourTimeOfDayChoiceModel || + * runMandatoryTourModeChoiceModel ){ lastComponent = "imtod"; nextComponent + * = "jtf"; } if( runJointTourFrequencyModel ){ logJointModelResults( + * householdDataManager ); lastComponent = "jtf"; nextComponent = "jtl"; } + * if( runJointTourLocationChoiceModel ){ lastComponent = "jtl"; + * nextComponent = "jtod"; } if( runJointTourDepartureTimeAndDurationModel + * || runJointTourModeChoiceModel ){ lastComponent = "jtod"; nextComponent = + * "inmtf"; } if( runIndivNonManTourFrequencyModel ){ lastComponent = + * "inmtf"; nextComponent = "inmtl"; } if( + * runIndivNonManTourLocationChoiceModel ){ lastComponent = "inmtl"; + * nextComponent = "inmtod"; } if( + * runIndivNonManTourDepartureTimeAndDurationModel || + * runIndivNonManTourModeChoiceModel ){ lastComponent = "inmtod"; + * nextComponent = "awf"; } if( runAtWorkSubTourFrequencyModel ){ + * logAtWorkSubtourFreqResults( householdDataManager ); lastComponent = + * "awf"; nextComponent = "awl"; } if( runAtWorkSubtourLocationChoiceModel + * ){ lastComponent = "awl"; nextComponent = "awtod"; } if( + * runAtWorkSubtourDepartureTimeAndDurationModel || + * runAtWorkSubtourModeChoiceModel ){ lastComponent = "awtod"; nextComponent + * = "stf"; } if( runStopFrequencyModel ){ lastComponent = "stf"; + * nextComponent = "stl"; } if( runStopLocationModel ){ lastComponent = + * "stl"; nextComponent = "done"; } // write a disk object fle for the + * householdDataManager, in case we want to restart from the next step. if ( + * hhDiskObjectFile != null && ! lastComponent.equalsIgnoreCase("uwsl") ) { + * logger.info (String.format( + * "writing household disk object file after %s choice model; may take a long time ..." + * , lastComponent) ); String hhFileName = hhDiskObjectFile + "_" + + * nextComponent; + * householdDataManager.createSerializedHhArrayInFileFromObject( hhFileName, + * nextComponent ); logger.info ( + * String.format("finished writing household disk object file = %s.", + * hhFileName) ); } logger.info ( + * "finished with HouseholdChoiceModelRunner." ); } + */ + + public String getProjectDirectoryName() + { + return projectDirectory; + } + + private MatrixDataServer startMatrixServerProcess(String serverAddress, int serverPort) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServer matrixServer = new MatrixDataServer(); + + // bind this concrete object with the cajo library objects for managing RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + public void restartModels(HouseholdDataManagerIf householdDataManager) + { + + // if no filename was specified for the previous shadow price info, + // restartIter == -1, and random counts will be reset to 0. + int restartIter = -1; + String fileName = ResourceUtil.getProperty(resourceBundle, + PROPERTIES_WORK_LOCATION_CHOICE_SHADOW_PRICE_INPUT_FILE); + if (fileName != null) + { + fileName = projectDirectory + fileName; + int underScoreIndex = fileName.lastIndexOf('_'); + int dotIndex = fileName.lastIndexOf('.'); + restartIter = Integer.parseInt(fileName.substring(underScoreIndex + 1, dotIndex)); + } + + boolean runPreAutoOwnershipModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_PRE_AUTO_OWNERSHIP); + if (runPreAutoOwnershipModel) + { + householdDataManager.resetPreAoRandom(); + } else + { + boolean runUsualWorkSchoolChoiceModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_WORKSCHOOL_CHOICE); + if (runUsualWorkSchoolChoiceModel) + { + householdDataManager.resetUwslRandom(restartIter + 1); + } else + { + boolean runAutoOwnershipModel = ResourceUtil.getBooleanProperty(resourceBundle, + PROPERTIES_RUN_AUTO_OWNERSHIP); + if (runAutoOwnershipModel) + { + // We're resetting the random number sequence used by pre-AO + // for + // the primary AO + householdDataManager.resetPreAoRandom(); + // householdDataManager.resetAoRandom( restartIter+1 ); + } else + { + // boolean runFreeParkingAvailableModel = + // ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_FREE_PARKING_AVAILABLE); + // if ( runFreeParkingAvailableModel ) { + // householdDataManager.resetFpRandom(); + // } + // else { + boolean runCoordinatedDailyActivityPatternModel = ResourceUtil + .getBooleanProperty(resourceBundle, + PROPERTIES_RUN_DAILY_ACTIVITY_PATTERN); + if (runCoordinatedDailyActivityPatternModel) + { + householdDataManager.resetCdapRandom(); + } else + { + boolean runIndividualMandatoryTourFrequencyModel = ResourceUtil + .getBooleanProperty(resourceBundle, + PROPERTIES_RUN_INDIV_MANDATORY_TOUR_FREQ); + if (runIndividualMandatoryTourFrequencyModel) + { + householdDataManager.resetImtfRandom(); + } else + { + // boolean + // runIndividualMandatoryTourDepartureAndDurationModel + // = + // ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_MAND_TOUR_DEP_TIME_AND_DUR); + // if ( + // runIndividualMandatoryTourDepartureAndDurationModel + // ) + // { + // householdDataManager.resetImtodRandom(); + // } + // else { + // boolean runJointTourFrequencyModel = + // ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_JOINT_TOUR_FREQ); + // if ( runJointTourFrequencyModel ) { + // householdDataManager.resetJtfRandom(); + // } + // else { + // boolean runJointTourLocationModel = + // ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_JOINT_LOCATION_CHOICE); + // if ( runJointTourLocationModel ) { + // householdDataManager.resetJtlRandom(); + // } + // else { + // boolean runJointTourDepartureAndDurationModel = + // ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_JOINT_TOUR_DEP_TIME_AND_DUR); + // if ( runJointTourDepartureAndDurationModel ) { + // householdDataManager.resetJtodRandom(); + // } + // else { + boolean runIndividualNonMandatoryTourFrequencyModel = ResourceUtil + .getBooleanProperty(resourceBundle, + PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_FREQ); + if (runIndividualNonMandatoryTourFrequencyModel) + { + householdDataManager.resetInmtfRandom(); + } + // else { + // boolean + // runIndividualNonMandatoryTourLocationModel = + // ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_INDIV_NON_MANDATORY_LOCATION_CHOICE); + // if ( runIndividualNonMandatoryTourLocationModel ) + // { + // householdDataManager.resetInmtlRandom(); + // } + // else { + // boolean + // runIndividualNonMandatoryTourDepartureAndDurationModel + // = ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_DEP_TIME_AND_DUR); + // if ( + // runIndividualNonMandatoryTourDepartureAndDurationModel + // ) { + // householdDataManager.resetInmtodRandom(); + // } + // else { + boolean runAtWorkSubTourFrequencyModel = ResourceUtil + .getBooleanProperty(resourceBundle, + PROPERTIES_RUN_AT_WORK_SUBTOUR_FREQ); + if (runAtWorkSubTourFrequencyModel) + { + householdDataManager.resetAwfRandom(); + } + // else { + // boolean runAtWorkSubtourLocationChoiceModel = + // ResourceUtil.getBooleanProperty( resourceBundle, + // PROPERTIES_RUN_AT_WORK_SUBTOUR_LOCATION_CHOICE ); + // if ( runAtWorkSubtourLocationChoiceModel ) { + // householdDataManager.resetAwlRandom(); + // } + // else { + // boolean + // runAtWorkSubtourDepartureTimeAndDurationModel + // = ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_AT_WORK_SUBTOUR_DEP_TIME_AND_DUR); + // if ( + // runAtWorkSubtourDepartureTimeAndDurationModel ) { + // householdDataManager.resetAwtodRandom(); + // } + // else { + boolean runStopFrequencyModel = ResourceUtil.getBooleanProperty( + resourceBundle, PROPERTIES_RUN_STOP_FREQUENCY); + if (runStopFrequencyModel) + { + householdDataManager.resetStfRandom(); + } + // else { + // boolean runStopLocationModel = + // ResourceUtil.getBooleanProperty(resourceBundle, + // PROPERTIES_RUN_STOP_LOCATION); + // if ( runStopLocationModel ) { + // householdDataManager.resetStlRandom(); + // } + // } + // } + // } + // } + // } + // } + // } + // } + // } + // } + // } + // } + } + } + } + } + } + } + + /** + * private void createSerializedObjectInFileFromObject( Object + * objectToSerialize, String serializedObjectFileName, String + * serializedObjectKey ){ try{ DataFile dataFile = new DataFile( + * serializedObjectFileName, 1 ); DataWriter dw = new DataWriter( + * serializedObjectKey ); dw.writeObject( objectToSerialize ); + * dataFile.insertRecord( dw ); dataFile.close(); } + * catch(NotSerializableException e) { logger.error( String.format( + * "NotSerializableException for %s. Trying to create serialized object with key=%s, in filename=%s." + * , objectToSerialize.getClass().getName(), serializedObjectKey, + * serializedObjectFileName ), e ); throw new RuntimeException(); } + * catch(IOException e) { logger.error( String.format( + * "IOException trying to write disk object file=%s, with key=%s for writing." + * , serializedObjectFileName, serializedObjectKey ), e ); throw new + * RuntimeException(); } } + * + * + * private Object createObjectFromSerializedObjectInFile( Object newObject, + * String serializedObjectFileName, String serializedObjectKey ){ try{ + * DataFile dataFile = new DataFile( serializedObjectFileName, "r" ); + * DataReader dr = dataFile.readRecord( serializedObjectKey ); newObject = + * dr.readObject(); dataFile.close(); return newObject; } catch(IOException + * e) { logger.error( String.format( + * "IOException trying to read disk object file=%s, with key=%s.", + * serializedObjectFileName, serializedObjectKey ), e ); throw new + * RuntimeException(); } catch(ClassNotFoundException e) { logger.error( + * String.format + * ("could not instantiate %s object, with key=%s from filename=%s.", + * newObject.getClass().getName(), serializedObjectFileName, + * serializedObjectKey ), e ); throw new RuntimeException(); } } + **/ + /** + * Loops through the households in the HouseholdDataManager, gets the auto + * ownership result for each household, and writes a text file with hhid and + * auto ownership. + * + * @param householdDataManager + * is the object from which the array of household objects can be + * retrieved. + * @param projectDirectory + * is the root directory for the output file named + */ + private void saveAoResults(HouseholdDataManagerIf householdDataManager, + String projectDirectory, boolean preModel) + { + + String aoResultsFileName; + try + { + + aoResultsFileName = resourceBundle.getString(PROPERTIES_RESULTS_AUTO_OWNERSHIP); + + // change the filename property value to include "_pre" at the end + // of the + // name before the extension, if this is a pre-auto ownership run + if (preModel) + { + int dotIndex = aoResultsFileName.indexOf('.'); + if (dotIndex > 0) + { + String beforeDot = aoResultsFileName.substring(0, dotIndex); + String afterDot = aoResultsFileName.substring(dotIndex); + aoResultsFileName = beforeDot + "_pre" + afterDot; + } else + { + aoResultsFileName += "_pre"; + } + } + + } catch (MissingResourceException e) + { + // if filename not specified in properties file, don't need to write + // it. + return; + } + + FileWriter writer; + PrintWriter outStream = null; + if (aoResultsFileName != null) + { + + aoResultsFileName = projectDirectory + aoResultsFileName; + + try + { + writer = new FileWriter(new File(aoResultsFileName)); + outStream = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening AO results file: %s.", + aoResultsFileName)); + throw new RuntimeException(e); + } + + outStream.println("HHID,AO"); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Household household = householdArray[i]; + int hhid = household.getHhId(); + int ao = household.getAutosOwned(); + + outStream.println(String.format("%d,%d", hhid, ao)); + + } + + } + + outStream.close(); + + } + + } + + private void logAoResults(HouseholdDataManagerIf householdDataManager, boolean preModel) + { + + String[] aoRowCategoryLabel = {"0 autos", "1 auto", "2 autos", "3 autos", "4 or more autos"}; + String[] aoColCategoryLabel = {"Non-GQ HHs", "GQ HHs",}; + + logger.info(""); + logger.info(""); + logger.info((preModel ? "Pre-" : "") + "Auto Ownership Model Results"); + String header = String.format("%-16s", "Category"); + for (String label : aoColCategoryLabel) + header += String.format("%15s", label); + header += String.format("%15s", "Total HHs"); + logger.info(header); + + // track the results + int[][] hhsByAutoOwnership = new int[aoRowCategoryLabel.length][aoColCategoryLabel.length]; + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Household household = householdArray[i]; + int ao = household.getAutosOwned(); + if (ao > hhsByAutoOwnership.length - 1) ao = hhsByAutoOwnership.length - 1; + + int gq = household.getIsGroupQuarters(); + hhsByAutoOwnership[ao][gq]++; + + } + + } + + int[] colTotals = new int[aoColCategoryLabel.length]; + for (int i = 0; i < hhsByAutoOwnership.length; i++) + { + + int rowTotal = 0; + String logString = String.format("%-16s", aoRowCategoryLabel[i]); + for (int j = 0; j < hhsByAutoOwnership[i].length; j++) + { + int value = hhsByAutoOwnership[i][j]; + logString += String.format("%15d", value); + rowTotal += value; + colTotals[j] += value; + } + logString += String.format("%15d", rowTotal); + logger.info(logString); + + } + + int total = 0; + String colTotalsString = String.format("%-16s", "Total"); + for (int j = 0; j < colTotals.length; j++) + { + colTotalsString += String.format("%15d", colTotals[j]); + total += colTotals[j]; + } + colTotalsString += String.format("%15d", total); + logger.info(colTotalsString); + + } + + private void logTpResults(HouseholdDataManagerIf householdDataManager) + { + + logger.info(""); + logger.info(""); + logger.info("Transponder Choice Model Results"); + logger.info(String.format("%-16s %20s", "Category", "Num Households")); + logger.info(String.format("%-16s %20s", "----------", "------------------")); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + int numYes = 0; + int numNo = 0; + int numOther = 0; + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Household household = householdArray[i]; + if (household.getTpChoice() + 1 == TransponderChoiceModel.TP_MODEL_NO_ALT) numNo++; + else if (household.getTpChoice() + 1 == TransponderChoiceModel.TP_MODEL_YES_ALT) numYes++; + else numOther++; + + } + + } + + logger.info(String.format("%-16s %20d", "No", numNo)); + logger.info(String.format("%-16s %20d", "Yes", numYes)); + logger.info(String.format("%-16s %20d", "Other", numOther)); + + logger.info(String.format("%-16s %20s", "----------", "------------------")); + logger.info(String.format("%-16s %20d", "Total", (numNo + numYes + numOther))); + + } + + private void logFpResults(HouseholdDataManagerIf householdDataManager) + { + + String[] fpCategoryLabel = {"No Choice Made", "Free Available", "Must Pay", "Reimbursed"}; + + logger.info(""); + logger.info(""); + logger.info("Free Parking Choice Model Results"); + logger.info(String.format("%-16s %20s %20s %20s %20s", "Category", "Workers in area 1", + "Workers in area 2", "Workers in area 3", "Workers in area 4")); + logger.info(String.format("%-16s %20s %20s %20s %20s", "----------", + "------------------", "------------------", "------------------", + "------------------")); + + // track the results by 4 work areas - only workers in area 1 should + // have made choices + int numParkAreas = 4; + int[][] workLocationsByFreeParking; + workLocationsByFreeParking = new int[fpCategoryLabel.length][numParkAreas]; + + // get the correspndence between mgra and park area to associate work + // locations with areas + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + int[] parkAreas = mgraManager.getMgraParkAreas(); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Household household = householdArray[i]; + Person[] persons = household.getPersons(); + for (int p = 1; p < persons.length; p++) + { + int workLocation = persons[p].getWorkLocation(); + if (workLocation > 0 + && workLocation != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + int area = parkAreas[workLocation]; + int areaIndex = area - 1; + + int fp = persons[p].getFreeParkingAvailableResult(); + int freqIndex = 0; + if (fp > 0) freqIndex = fp; + + workLocationsByFreeParking[freqIndex][areaIndex]++; + } + } + + } + + } + + int[] total = new int[numParkAreas]; + for (int i = 0; i < workLocationsByFreeParking.length; i++) + { + logger.info(String.format("%-16s %20d %20d %20d %20d", fpCategoryLabel[i], + workLocationsByFreeParking[i][0], workLocationsByFreeParking[i][1], + workLocationsByFreeParking[i][2], workLocationsByFreeParking[i][3])); + for (int j = 0; j < numParkAreas; j++) + total[j] += workLocationsByFreeParking[i][j]; + } + logger.info(String.format("%-16s %20s %20s %20s %20s", "----------", + "------------------", "------------------", "------------------", + "------------------")); + logger.info(String.format("%-16s %20d %20d %20d %20d", "Totals", total[0], total[1], + total[2], total[3])); + + } + + private void logIeResults(HouseholdDataManagerIf householdDataManager) + { + + String[] ieCategoryLabel = {"No IE Trip", "Yes IE Trip"}; + + logger.info(""); + logger.info(""); + logger.info("Internal-External Trip Choice Model Results"); + logger.info(String.format("%-30s %20s %20s %20s", "Person Type", ieCategoryLabel[0], + ieCategoryLabel[1], "Total")); + logger.info(String.format("%-30s %20s %20s %20s", "-------------", "-------------", + "-------------", "---------")); + + // summarize yes/no choice by person type + int[][] personTypeByIeChoice; + personTypeByIeChoice = new int[Person.PERSON_TYPE_NAME_ARRAY.length][2]; + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Household household = householdArray[i]; + Person[] persons = household.getPersons(); + for (int p = 1; p < persons.length; p++) + { + + int ie = persons[p].getInternalExternalTripChoiceResult(); + + // ie = 1 means no, 2 means yes. Get index by subtracting 1. + // person typ indices are 1 based, so subtract 1 for array + // index + try + { + personTypeByIeChoice[persons[p].getPersonTypeNumber() - 1][ie - 1]++; + } catch (ArrayIndexOutOfBoundsException e) + { + logger.error("array index error"); + logger.error("hhid=" + household.getHhId() + ", p=" + p + ", ie=" + ie + + ", personType=" + persons[p].getPersonTypeNumber(), e); + } + } + + } + + } + + int[] totals = new int[2]; + for (int i = 0; i < personTypeByIeChoice.length; i++) + { + int total = personTypeByIeChoice[i][0] + personTypeByIeChoice[i][1]; + logger.info(String.format("%-30s %20d %20d %20d", Person.PERSON_TYPE_NAME_ARRAY[i], + personTypeByIeChoice[i][0], personTypeByIeChoice[i][1], total)); + totals[0] += personTypeByIeChoice[i][0]; + totals[1] += personTypeByIeChoice[i][1]; + } + logger.info(String.format("%-30s %20s %20s %20s", "-------------", "-------------", + "-------------", "---------")); + logger.info(String.format("%-30s %20d %20d %20d", "Totals", totals[0], totals[1], + (totals[0] + totals[1]))); + + } + + /** + * Records the coordinated daily activity pattern model results to the + * logger. A household-level summary simply records each pattern type and a + * person-level summary summarizes the activity choice by person type + * (full-time worker, university student, etc). + * + */ + public void logCdapResults(HouseholdDataManagerIf householdDataManager) + { + + String[] activityNameArray = {Definitions.MANDATORY_PATTERN, + Definitions.NONMANDATORY_PATTERN, Definitions.HOME_PATTERN}; + + getLogReportSummaries(householdDataManager); + + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info("Coordinated Daily Activity Pattern Model Results"); + + // count of activities by person type + logger.info(" "); + logger.info("CDAP Results: Count of activities by person type"); + String firstHeader = "Person type "; + String secondHeader = "----------------------------- "; + for (int i = 0; i < activityNameArray.length; ++i) + { + firstHeader += " " + activityNameArray[i] + " "; + secondHeader += "--------- "; + } + + firstHeader += " Total"; + secondHeader += "---------"; + + logger.info(firstHeader); + logger.info(secondHeader); + + int[] columnTotals = new int[activityNameArray.length]; + + for (int i = 0; i < Person.PERSON_TYPE_NAME_ARRAY.length; ++i) + { + String personType = Person.PERSON_TYPE_NAME_ARRAY[i]; + String stringToLog = String.format("%-30s", personType); + int lineTotal = 0; + + if (cdapByPersonTypeAndActivity.containsKey(personType)) + { + + for (int j = 0; j < activityNameArray.length; ++j) + { + int count = 0; + if (cdapByPersonTypeAndActivity.get(personType).containsKey( + activityNameArray[j])) + { + count = cdapByPersonTypeAndActivity.get(personType).get( + activityNameArray[j]); + } + stringToLog += String.format("%10d", count); + + lineTotal += count; + columnTotals[j] += count; + } // j + + } // if key + + stringToLog += String.format("%10d", lineTotal); + logger.info(stringToLog); + + } // i + + logger.info(secondHeader); + + String stringToLog = String.format("%-30s", "Total"); + int lineTotal = 0; + for (int j = 0; j < activityNameArray.length; ++j) + { + stringToLog += String.format("%10d", columnTotals[j]); + lineTotal += columnTotals[j]; + } // j + + stringToLog += String.format("%10d", lineTotal); + logger.info(stringToLog); + + // count of patterns + logger.info(" "); + logger.info(" "); + logger.info("CDAP Results: Count of patterns"); + logger.info("Pattern Count"); + logger.info("------------------ ---------"); + + // sort the map by hh size first + Set hhSizeKeySet = cdapByHhSizeAndPattern.keySet(); + Integer[] hhSizeKeyArray = new Integer[hhSizeKeySet.size()]; + hhSizeKeySet.toArray(hhSizeKeyArray); + Arrays.sort(hhSizeKeyArray); + + int total = 0; + for (int i = 0; i < hhSizeKeyArray.length; ++i) + { + + // sort the patterns alphabetically + HashMap patternMap = cdapByHhSizeAndPattern.get(hhSizeKeyArray[i]); + Set patternKeySet = patternMap.keySet(); + String[] patternKeyArray = new String[patternKeySet.size()]; + patternKeySet.toArray(patternKeyArray); + Arrays.sort(patternKeyArray); + for (int j = 0; j < patternKeyArray.length; ++j) + { + int count = patternMap.get(patternKeyArray[j]); + total += count; + logger.info(String.format("%-18s%10d", patternKeyArray[j], count)); + } + + } + + logger.info("------------------ ---------"); + logger.info(String.format("%-18s%10d", "Total", total)); + logger.info(" "); + + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info(" "); + logger.info(" "); + + } + + /** + * Logs the results of the individual mandatory tour frequency model. + * + */ + public void logImtfResults(HouseholdDataManagerIf householdDataManager) + { + + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info("Individual Mandatory Tour Frequency Model Results"); + + // count of model results + logger.info(" "); + String firstHeader = "Person type "; + String secondHeader = "----------------------------- "; + + String[] choiceResults = HouseholdIndividualMandatoryTourFrequencyModel.CHOICE_RESULTS; + + // summarize results + HashMap countByPersonType = new HashMap(); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Person[] personArray = householdArray[i].getPersons(); + for (int j = 1; j < personArray.length; j++) + { + + // only summarize persons with mandatory pattern + String personActivity = personArray[j].getCdapActivity(); + if (personActivity != null + && personArray[j].getCdapActivity().equalsIgnoreCase("M")) + { + + String personTypeString = personArray[j].getPersonType(); + int choice = personArray[j].getImtfChoice(); + + if (choice == 0) + { + + // there are 5 IMTF alts, so it's the offset for the + // extra at home categories + if (personArray[j].getPersonEmploymentCategoryIndex() < Person.EmployStatus.NOT_EMPLOYED + .ordinal() + && personArray[j].getWorkLocation() == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) choice = 5 + 1; + else if (personArray[j].getPersonEmploymentCategoryIndex() < Person.EmployStatus.NOT_EMPLOYED + .ordinal() + && personArray[j].getPersonSchoolLocationZone() == ModelStructure.NOT_ENROLLED_SEGMENT_INDEX) choice = 5 + 2; + else if (personArray[j].getPersonIsStudent() < Person.EmployStatus.NOT_EMPLOYED + .ordinal() + && personArray[j].getWorkLocation() == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) choice = 5 + 3; + else if (personArray[j].getPersonIsStudent() < Person.EmployStatus.NOT_EMPLOYED + .ordinal() + && personArray[j].getPersonSchoolLocationZone() == ModelStructure.NOT_ENROLLED_SEGMENT_INDEX) + choice = 5 + 4; + + } + + // count the results + if (countByPersonType.containsKey(personTypeString)) + { + + int[] counterArray = countByPersonType.get(personTypeString); + counterArray[choice - 1]++; + countByPersonType.put(personTypeString, counterArray); + + } else + { + + int[] counterArray = new int[choiceResults.length]; + counterArray[choice - 1]++; + countByPersonType.put(personTypeString, counterArray); + + } + } + + } + + } + + } + + for (int i = 0; i < choiceResults.length; ++i) + { + firstHeader += String.format("%12s", choiceResults[i]); + secondHeader += "----------- "; + } + + firstHeader += String.format("%12s", "Total"); + secondHeader += "-----------"; + + logger.info(firstHeader); + logger.info(secondHeader); + + int[] columnTotals = new int[choiceResults.length]; + + int lineTotal = 0; + for (int i = 0; i < Person.PERSON_TYPE_NAME_ARRAY.length; ++i) + { + String personTypeString = Person.PERSON_TYPE_NAME_ARRAY[i]; + String stringToLog = String.format("%-30s", personTypeString); + + if (countByPersonType.containsKey(personTypeString)) + { + + lineTotal = 0; + int[] countArray = countByPersonType.get(personTypeString); + for (int j = 0; j < choiceResults.length; ++j) + { + stringToLog += String.format("%12d", countArray[j]); + columnTotals[j] += countArray[j]; + lineTotal += countArray[j]; + } // j + } else + { + // if key + // log zeros + lineTotal = 0; + for (int j = 0; j < choiceResults.length; ++j) + { + stringToLog += String.format("%12d", 0); + } + } + + stringToLog += String.format("%12d", lineTotal); + + logger.info(stringToLog); + + } // i + + String stringToLog = String.format("%-30s", "Total"); + lineTotal = 0; + for (int j = 0; j < choiceResults.length; ++j) + { + stringToLog += String.format("%12d", columnTotals[j]); + lineTotal += columnTotals[j]; + } // j + + logger.info(secondHeader); + stringToLog += String.format("%12d", lineTotal); + logger.info(stringToLog); + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info(" "); + logger.info(" "); + + } + + private void logJointModelResults(HouseholdDataManagerIf householdDataManager, + CtrampDmuFactoryIf dmuFactory) + { + + String uecFileDirectory = ResourceUtil.getProperty(resourceBundle, PROPERTIES_UEC_PATH); + String uecFileName = ResourceUtil.getProperty(resourceBundle, + JointTourModels.UEC_FILE_PROPERTIES_TARGET); + uecFileName = uecFileDirectory + uecFileName; + + int dataSheet = ResourceUtil.getIntegerProperty(resourceBundle, + JointTourModels.UEC_DATA_PAGE_TARGET); + int freqCompSheet = ResourceUtil.getIntegerProperty(resourceBundle, + JointTourModels.UEC_JOINT_TOUR_FREQ_COMP_MODEL_PAGE); + + // get the alternative names + JointTourModelsDMU dmuObject = dmuFactory.getJointTourModelsDMU(); + ChoiceModelApplication jointTourFrequencyModel = new ChoiceModelApplication(uecFileName, + freqCompSheet, dataSheet, + ResourceUtil.changeResourceBundleIntoHashMap(resourceBundle), + (VariableTable) dmuObject); + String[] altLabels = jointTourFrequencyModel.getAlternativeNames(); + + // this is the first index in the summary array for choices made by + // eligible households + int[] jointTourChoiceFreq = new int[altLabels.length + 1]; + + TreeMap partySizeFreq = new TreeMap(); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Tour[] jt = householdArray[i].getJointTourArray(); + int jtfAlt = householdArray[i].getJointTourFreqChosenAlt(); + + if (jt == null) + { + + if (jtfAlt > 0) + { + logger.error(String + .format("HHID=%d, joint tour array is null, but a valid alternative=%d is recorded for the household.", + householdArray[i].getHhId(), jtfAlt)); + throw new RuntimeException(); + } + + jointTourChoiceFreq[0]++; + + } else + { + + if (jtfAlt < 1) + { + logger.error(String + .format("HHID=%d, joint tour array is not null, but an invalid alternative=%d is recorded for the household.", + householdArray[i].getHhId(), jtfAlt)); + throw new RuntimeException(); + } + + jointTourChoiceFreq[jtfAlt]++; + + // determine party size frequency for joint tours generated + Person[] persons = householdArray[i].getPersons(); + for (int j = 0; j < jt.length; j++) + { + + int compAlt = jt[j].getJointTourComposition(); + + // determine number of children and adults in tour + int adults = 0; + int children = 0; + int[] participants = jt[j].getPersonNumArray(); + for (int k = 0; k < participants.length; k++) + { + int index = participants[k]; + Person person = persons[index]; + if (person.getPersonIsAdult() == 1) adults++; + else children++; + } + + // create a key to use for a frequency map for + // "JointTourPurpose_Composition_NumAdults_NumChildren" + String key = String.format("%s_%d_%d_%d", jt[j].getTourPurpose(), compAlt, + adults, children); + + int value = 0; + if (partySizeFreq.containsKey(key)) value = partySizeFreq.get(key); + partySizeFreq.put(key, ++value); + + } + + } + + } + + } + + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info("Joint Tour Frequency and Joint Tour Composition Model Results"); + + logger.info(" "); + logger.info("Frequency Table of Households by Joint Tour Frequency Choice"); + logger.info(String.format("%-5s %-26s %12s", "Alt", "Alt Name", "Households")); + + int rowTotal = jointTourChoiceFreq[0]; + logger.info(String.format("%-5d %-26s %12d", 0, "None", jointTourChoiceFreq[0])); + for (int i = 1; i <= altLabels.length; i++) + { + logger.info(String.format("%-5d %-26s %12d", i, altLabels[i - 1], + jointTourChoiceFreq[i])); + rowTotal += jointTourChoiceFreq[i]; + } + logger.info(String.format("%-34s %12d", "Total Households", rowTotal)); + + logger.info(" "); + logger.info(" "); + logger.info(" "); + + logger.info("Frequency Table of Joint Tours by All Parties Generated"); + logger.info(String.format("%-5s %-20s %-15s %10s %10s %10s", "N", "Purpose", + "Type", "Adults", "Children", "Freq")); + + int count = 1; + for (String key : partySizeFreq.keySet()) + { + + int start = 0; + int end = 0; + int compIndex = 0; + int adults = 0; + int children = 0; + String indexString = ""; + String purpose = ""; + + start = 0; + end = key.indexOf('_', start); + purpose = key.substring(start, end); + + start = end + 1; + end = key.indexOf('_', start); + indexString = key.substring(start, end); + compIndex = Integer.parseInt(indexString); + + start = end + 1; + end = key.indexOf('_', start); + indexString = key.substring(start, end); + adults = Integer.parseInt(indexString); + + start = end + 1; + indexString = key.substring(start); + children = Integer.parseInt(indexString); + + logger.info(String.format("%-5d %-20s %-15s %10d %10d %10d", count++, + purpose, JointTourModels.JOINT_TOUR_COMPOSITION_NAMES[compIndex], adults, + children, partySizeFreq.get(key))); + } + + logger.info(" "); + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info(" "); + + } + + private void getLogReportSummaries(HouseholdDataManagerIf householdDataManager) + { + + // summary collections + cdapByHhSizeAndPattern = new HashMap>(); + cdapByPersonTypeAndActivity = new HashMap>(); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] partialHhArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (Household hhObject : partialHhArray) + { + + // get the household's activity pattern choice + String pattern = hhObject.getCoordinatedDailyActivityPattern(); + if (pattern == null) continue; + + Person[] personArray = hhObject.getPersons(); + for (int j = 1; j < personArray.length; j++) + { + + // get person's activity string + String activityString = personArray[j].getCdapActivity(); + + // get the person type to simmarize results by + String personTypeString = personArray[j].getPersonType(); + + // check if the person type is in the map + if (cdapByPersonTypeAndActivity.containsKey(personTypeString)) + { + + HashMap activityCountMap = cdapByPersonTypeAndActivity + .get(personTypeString); + + // check if the activity is in the activity map + int currentCount = 1; + if (activityCountMap.containsKey(activityString)) + currentCount = activityCountMap.get(activityString) + 1; + + activityCountMap.put(activityString, currentCount); + cdapByPersonTypeAndActivity.put(personTypeString, activityCountMap); + + } else + { + + HashMap activityCountMap = new HashMap(); + activityCountMap.put(activityString, 1); + cdapByPersonTypeAndActivity.put(personTypeString, activityCountMap); + + } // is personType in map if + + } // j (person loop) + + // count each type of pattern string by hhSize + if ((!cdapByHhSizeAndPattern.isEmpty()) + && cdapByHhSizeAndPattern.containsKey(pattern.length())) + { + + HashMap patternCountMap = cdapByHhSizeAndPattern.get(pattern + .length()); + + int currentCount = 1; + if (patternCountMap.containsKey(pattern)) + currentCount = patternCountMap.get(pattern) + 1; + patternCountMap.put(pattern, currentCount); + cdapByHhSizeAndPattern.put(pattern.length(), patternCountMap); + + } else + { + + HashMap patternCountMap = new HashMap(); + patternCountMap.put(pattern, 1); + cdapByHhSizeAndPattern.put(pattern.length(), patternCountMap); + + } // is personType in map if + + } + + } + + } + + /** + * Loops through the households in the HouseholdDataManager, gets the + * coordinated daily activity pattern for each person in the household, and + * writes a text file with hhid, personid, persnum, and activity pattern. + * + * @param householdDataManager + */ + public void saveCdapResults(HouseholdDataManagerIf householdDataManager, String projectDirectory) + { + + String cdapResultsFileName; + try + { + cdapResultsFileName = resourceBundle.getString(PROPERTIES_RESULTS_CDAP); + } catch (MissingResourceException e) + { + // if filename not specified in properties file, don't need to write + // it. + return; + } + + FileWriter writer; + PrintWriter outStream = null; + if (cdapResultsFileName != null) + { + + cdapResultsFileName = projectDirectory + cdapResultsFileName; + + try + { + writer = new FileWriter(new File(cdapResultsFileName)); + outStream = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening CDAP results file: %s.", + cdapResultsFileName)); + throw new RuntimeException(e); + } + + outStream.println("HHID,PersonID,PersonNum,PersonType,ActivityString"); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Household household = householdArray[i]; + int hhid = household.getHhId(); + + // get the pattern for each person + Person[] personArray = household.getPersons(); + for (int j = 1; j < personArray.length; j++) + { + + Person person = personArray[j]; + + int persId = person.getPersonId(); + int persNum = person.getPersonNum(); + int persType = person.getPersonTypeNumber(); + String activityString = person.getCdapActivity(); + + outStream.println(String.format("%d,%d,%d,%d,%s", hhid, persId, persNum, + persType, activityString)); + + } // j (person loop) + + } + + } + + outStream.close(); + + } + + } + + /** + * Logs the results of the model. + * + */ + public void logAtWorkSubtourFreqResults(HouseholdDataManagerIf householdDataManager) + { + + String[] alternativeNames = modelStructure.getAwfAltLabels(); + HashMap awfByPersonType = new HashMap(); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + for (int i = 0; i < householdArray.length; ++i) + { + + // get this household's person array + Person[] personArray = householdArray[i].getPersons(); + + // loop through the person array (1-based) + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + + // loop through the work tours for this person + ArrayList tourList = person.getListOfWorkTours(); + if (tourList == null || tourList.size() == 0) continue; + + // count the results by person type + String personTypeString = person.getPersonType(); + + for (Tour workTour : tourList) + { + + int choice = 0; + if (person.getListOfAtWorkSubtours().size() == 0) choice = 1; + else + { + choice = workTour.getSubtourFreqChoice(); + if (choice == 0) choice++; + } + + int dummy = 0; + if (person.getPersonTypeNumber() == 7) + { + dummy = 1; + } + + // count the results by person type + if (awfByPersonType.containsKey(personTypeString)) + { + int[] counterArray = awfByPersonType.get(personTypeString); + counterArray[choice - 1]++; + awfByPersonType.put(personTypeString, counterArray); + + } else + { + int[] counterArray = new int[alternativeNames.length]; + counterArray[choice - 1]++; + awfByPersonType.put(personTypeString, counterArray); + } + + } + + } + + } + + } + + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info("At-Work Subtour Frequency Model Results"); + + // count of model results + logger.info(" "); + String firstHeader = "Person type "; + String secondHeader = "--------------------------- "; + + for (int i = 0; i < alternativeNames.length; ++i) + { + firstHeader += String.format("%16s", alternativeNames[i]); + secondHeader += "------------ "; + } + + firstHeader += String.format("%16s", "Total"); + secondHeader += "------------"; + + logger.info(firstHeader); + logger.info(secondHeader); + + int[] columnTotals = new int[alternativeNames.length]; + + int lineTotal = 0; + for (int i = 0; i < Person.PERSON_TYPE_NAME_ARRAY.length; ++i) + { + String personTypeString = Person.PERSON_TYPE_NAME_ARRAY[i]; + String stringToLog = String.format("%-28s", personTypeString); + + if (awfByPersonType.containsKey(personTypeString)) + { + + lineTotal = 0; + int[] countArray = awfByPersonType.get(personTypeString); + for (int j = 0; j < alternativeNames.length; ++j) + { + stringToLog += String.format("%16d", countArray[j]); + columnTotals[j] += countArray[j]; + lineTotal += countArray[j]; + } // j + + } else + { + // if key + // log zeros + lineTotal = 0; + for (int j = 0; j < alternativeNames.length; ++j) + { + stringToLog += String.format("%16d", 0); + } + } + + stringToLog += String.format("%16d", lineTotal); + + logger.info(stringToLog); + + } // i + + String stringToLog = String.format("%-28s", "Total"); + lineTotal = 0; + for (int j = 0; j < alternativeNames.length; ++j) + { + stringToLog += String.format("%16d", columnTotals[j]); + lineTotal += columnTotals[j]; + } // j + + logger.info(secondHeader); + stringToLog += String.format("%16d", lineTotal); + logger.info(stringToLog); + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info(" "); + logger.info(" "); + + } + + /** + * Logs the results of the individual tour stop frequency model. + * + */ + public void logIndivStfResults(HouseholdDataManagerIf householdDataManager) + { + + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info("Individual Tour Stop Frequency Model Results"); + + // count of model results + logger.info(" "); + String firstHeader = "Tour Purpose "; + String secondHeader = "--------------- "; + + int[] obStopsAlt = StopFrequencyDMU.NUM_OB_STOPS_FOR_ALT; + int[] ibStopsAlt = StopFrequencyDMU.NUM_IB_STOPS_FOR_ALT; + + // 10 purposes + int[][] chosen = new int[obStopsAlt.length][11]; + HashMap indexPurposeMap = modelStructure.getIndexPrimaryPurposeNameMap(); + HashMap purposeIndexMap = modelStructure.getPrimaryPurposeNameIndexMap(); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Person[] personArray = householdArray[i].getPersons(); + for (int j = 1; j < personArray.length; j++) + { + + List tourList = new ArrayList(); + + // apply stop frequency for all person tours + tourList.addAll(personArray[j].getListOfWorkTours()); + tourList.addAll(personArray[j].getListOfSchoolTours()); + tourList.addAll(personArray[j].getListOfIndividualNonMandatoryTours()); + tourList.addAll(personArray[j].getListOfAtWorkSubtours()); + + for (Tour t : tourList) + { + + int index = t.getTourPrimaryPurposeIndex(); + int choice = t.getStopFreqChoice(); + chosen[choice][index]++; + + } + + } + + } + + } + + for (int i = 1; i < chosen[1].length; ++i) + { + firstHeader += String.format("%18s", indexPurposeMap.get(i)); + secondHeader += " --------------- "; + } + + firstHeader += String.format("%18s", "Total"); + secondHeader += " --------------- "; + + logger.info(firstHeader); + logger.info(secondHeader); + + int[] columnTotals = new int[chosen[1].length]; + + int lineTotal = 0; + for (int i = 1; i < chosen.length; ++i) + { + String stringToLog = String.format("%d out, %d in ", obStopsAlt[i], ibStopsAlt[i]); + + lineTotal = 0; + int[] countArray = chosen[i]; + for (int j = 1; j < countArray.length; ++j) + { + stringToLog += String.format("%18d", countArray[j]); + columnTotals[j] += countArray[j]; + lineTotal += countArray[j]; + } // j + + stringToLog += String.format("%18d", lineTotal); + + logger.info(stringToLog); + + } // i + + String stringToLog = String.format("%-17s", "Total"); + lineTotal = 0; + for (int j = 1; j < chosen[1].length; ++j) + { + stringToLog += String.format("%18d", columnTotals[j]); + lineTotal += columnTotals[j]; + } // j + + logger.info(secondHeader); + stringToLog += String.format("%18d", lineTotal); + logger.info(stringToLog); + logger.info(" "); + logger.info("~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~"); + logger.info(" "); + logger.info(" "); + + } + + private void createSerializedObjectInFileFromObject(Object objectToSerialize, + String serializedObjectFileName, String serializedObjectKey) + { + try + { + DataFile dataFile = new DataFile(serializedObjectFileName, 1); + DataWriter dw = new DataWriter(serializedObjectKey); + dw.writeObject(objectToSerialize); + dataFile.insertRecord(dw); + dataFile.close(); + } catch (NotSerializableException e) + { + logger.error( + String.format( + "NotSerializableException for %s. Trying to create serialized object with key=%s, in filename=%s.", + objectToSerialize.getClass().getName(), serializedObjectKey, + serializedObjectFileName), e); + throw new RuntimeException(); + } catch (IOException e) + { + logger.error(String.format( + "IOException trying to write disk object file=%s, with key=%s for writing.", + serializedObjectFileName, serializedObjectKey), e); + throw new RuntimeException(); + } + } + + private Object createObjectFromSerializedObjectInFile(Object newObject, + String serializedObjectFileName, String serializedObjectKey) + { + try + { + DataFile dataFile = new DataFile(serializedObjectFileName, "r"); + DataReader dr = dataFile.readRecord(serializedObjectKey); + newObject = dr.readObject(); + dataFile.close(); + return newObject; + } catch (IOException e) + { + logger.error(String.format( + "IOException trying to read disk object file=%s, with key=%s.", + serializedObjectFileName, serializedObjectKey), e); + throw new RuntimeException(); + } catch (ClassNotFoundException e) + { + logger.error(String.format( + "could not instantiate %s object, with key=%s from filename=%s.", newObject + .getClass().getName(), serializedObjectFileName, serializedObjectKey), + e); + throw new RuntimeException(); + } + } + + private ArrayList getWriteHouseholdRanges(int numberOfHouseholds) + { + + ArrayList startEndIndexList = new ArrayList(); + + int startIndex = 0; + int endIndex = 0; + + while (endIndex < numberOfHouseholds - 1) + { + endIndex = startIndex + NUM_WRITE_PACKETS - 1; + if (endIndex + NUM_WRITE_PACKETS > numberOfHouseholds) + endIndex = numberOfHouseholds - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += NUM_WRITE_PACKETS; + } + + return startEndIndexList; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/CtrampDmuFactoryIf.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/CtrampDmuFactoryIf.java new file mode 100644 index 0000000..95f7801 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/CtrampDmuFactoryIf.java @@ -0,0 +1,52 @@ +package org.sandag.abm.ctramp; + +/** + * Created by IntelliJ IDEA. User: Jim Date: Jul 9, 2008 Time: 3:13:17 PM To + * change this template use File | Settings | File Templates. + */ +public interface CtrampDmuFactoryIf +{ + + AutoOwnershipChoiceDMU getAutoOwnershipDMU(); + + ParkingProvisionChoiceDMU getFreeParkingChoiceDMU(); + + TelecommuteDMU getTelecommuteDMU(); + + TransponderChoiceDMU getTransponderChoiceDMU(); + + InternalExternalTripChoiceDMU getInternalExternalTripChoiceDMU(); + + CoordinatedDailyActivityPatternDMU getCoordinatedDailyActivityPatternDMU(); + + DcSoaDMU getDcSoaDMU(); + + DestChoiceDMU getDestChoiceDMU(); + + DestChoiceTwoStageModelDMU getDestChoiceSoaTwoStageDMU(); + + DestChoiceTwoStageSoaTazDistanceUtilityDMU getDestChoiceSoaTwoStageTazDistUtilityDMU(); + + TourModeChoiceDMU getModeChoiceDMU(); + + IndividualMandatoryTourFrequencyDMU getIndividualMandatoryTourFrequencyDMU(); + + TourDepartureTimeAndDurationDMU getTourDepartureTimeAndDurationDMU(); + + AtWorkSubtourFrequencyDMU getAtWorkSubtourFrequencyDMU(); + + JointTourModelsDMU getJointTourModelsDMU(); + + IndividualNonMandatoryTourFrequencyDMU getIndividualNonMandatoryTourFrequencyDMU(); + + StopFrequencyDMU getStopFrequencyDMU(); + + StopLocationDMU getStopLocationDMU(); + + TripModeChoiceDMU getTripModeChoiceDMU(); + + ParkingChoiceDMU getParkingChoiceDMU(); + + MicromobilityChoiceDMU getMicromobilityChoiceDMU(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DAOException.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DAOException.java new file mode 100644 index 0000000..d2fc746 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DAOException.java @@ -0,0 +1,23 @@ +package org.sandag.abm.ctramp; + +public class DAOException + extends RuntimeException +{ + static final long serialVersionUID = -1881205326938716446L; + + public DAOException(String message) + { + super(message); + } + + public DAOException(Throwable cause) + { + super(cause); + } + + public DAOException(String message, Throwable cause) + { + super(message, cause); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DcSoaDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DcSoaDMU.java new file mode 100644 index 0000000..769f85d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DcSoaDMU.java @@ -0,0 +1,215 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class DcSoaDMU + implements SoaDMU, Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(DcSoaDMU.class); + + protected HashMap methodIndexMap; + + protected Household hh; + protected Person person; + protected Tour tour; + + protected IndexValues dmuIndex = null; + protected String dmuLabel = "Origin Location"; + + protected double[] dcSize; + protected double[] distance; + + protected BuildAccessibilities aggAcc; + + public DcSoaDMU() + { + dmuIndex = new IndexValues(); + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug DC SOA UEC"); + } + + } + + public void setAggAcc(BuildAccessibilities myAggAcc) + { + aggAcc = myAggAcc; + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + public void setPersonObject(Person personObject) + { + person = personObject; + } + + public void setTourObject(Tour tourObject) + { + tour = tourObject; + } + + public void setDestChoiceSize(double[] dcSize) + { + this.dcSize = dcSize; + } + + public void setDestDistance(double[] distance) + { + this.distance = distance; + } + + public double[] getDestDistance() + { + return distance; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public Household getHouseholdObject() + { + return hh; + } + + public int getTourPurposeIsEscort() + { + return tour.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME) ? 1 : 0; + } + + public int getNumPreschool() + { + return hh.getNumPreschool(); + } + + public int getNumGradeSchoolStudents() + { + return hh.getNumGradeSchoolStudents(); + } + + public int getNumHighSchoolStudents() + { + return hh.getNumHighSchoolStudents(); + } + + protected double getLnDcSize(int alt) + { + + double size = dcSize[alt]; + + double logSize = 0.0; + logSize = Math.log(size + 1); + + return logSize; + + } + + protected double getDcSizeAlt(int alt) + { + return dcSize[alt]; + } + + protected double getHouseholdsDestAlt(int mgra) + { + return aggAcc.getMgraHouseholds(mgra); + } + + protected double getGradeSchoolEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraGradeSchoolEnrollment(mgra); + } + + protected double getHighSchoolEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraHighSchoolEnrollment(mgra); + } + + public int getGradeSchoolDistrictDestAlt(int mgra) + { + return aggAcc.getMgraGradeSchoolDistrict(mgra); + } + + public int getHomeMgraGradeSchoolDistrict() + { + return aggAcc.getMgraGradeSchoolDistrict(hh.getHhMgra()); + } + + public double getHighSchoolDistrictDestAlt(int mgra) + { + return aggAcc.getMgraHighSchoolDistrict(mgra); + } + + public double getHomeMgraHighSchoolDistrict() + { + return aggAcc.getMgraHighSchoolDistrict(hh.getHhMgra()); + } + + public double getOriginToMgraDistanceAlt(int alt) + { + return distance[alt]; + } + + public double getUniversityEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraUniversityEnrollment(mgra); + } + + public String getDmuLabel() + { + return dmuLabel; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/Definitions.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Definitions.java new file mode 100644 index 0000000..496426e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Definitions.java @@ -0,0 +1,22 @@ +package org.sandag.abm.ctramp; + +/** + * This class holds definitions that are inherant in CT-RAMP based models + * including: person types tour category types purposes activity types + * + * @author Jim + * + */ +public final class Definitions +{ + + // Coordinated daily activity pattern type definitions + public static final String MANDATORY_PATTERN = "M"; + public static final String NONMANDATORY_PATTERN = "N"; + public static final String HOME_PATTERN = "H"; + + private Definitions() + { + // Not implemented in utility classes + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceDMU.java new file mode 100644 index 0000000..be69e84 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceDMU.java @@ -0,0 +1,394 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public abstract class DestChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(DestChoiceDMU.class); + + protected HashMap methodIndexMap; + + protected Household hh; + protected Person person; + protected Tour tour; + protected IndexValues dmuIndex = null; + + protected double workAccessibility; + protected double nonMandatoryAccessibility; + + protected double[] homeMgraNonMandatoryAccessibilityArray; + protected double[] homeMgraTotalEmploymentAccessibilityArray; + protected double[] homeMgraSizeArray; + protected double[] homeMgraDistanceArray; + protected double[] modeChoiceLogsums; + protected double[] dcSoaCorrections; + + protected int toursLeftCount; + + protected ModelStructure modelStructure; + protected MgraDataManager mgraManager; + protected BuildAccessibilities aggAcc; + protected AccessibilitiesTable accTable; + + public DestChoiceDMU(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + initDmuObject(); + } + + public abstract void setMcLogsum(int mgra, double logsum); + + private void initDmuObject() + { + + dmuIndex = new IndexValues(); + + // create default objects - some choice models use these as place + // holders for values + person = new Person(null, -1, modelStructure); + hh = new Household(modelStructure); + + mgraManager = MgraDataManager.getInstance(); + + int maxMgra = mgraManager.getMaxMgra(); + + modeChoiceLogsums = new double[maxMgra + 1]; + dcSoaCorrections = new double[maxMgra + 1]; + + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + public void setPersonObject(Person personObject) + { + person = personObject; + } + + public void setTourObject(Tour tour) + { + this.tour = tour; + } + + public void setAggAcc(BuildAccessibilities aggAcc) + { + this.aggAcc = aggAcc; + } + + public void setAccTable(AccessibilitiesTable myAccTable) + { + accTable = myAccTable; + } + + public void setDestChoiceSize(double[] homeMgraSizeArray) + { + this.homeMgraSizeArray = homeMgraSizeArray; + } + + public void setDestChoiceDistance(double[] homeMgraDistanceArray) + { + this.homeMgraDistanceArray = homeMgraDistanceArray; + } + + public void setDcSoaCorrections(int mgra, double correction) + { + dcSoaCorrections[mgra] = correction; + } + + public void setNonMandatoryAccessibility(double nonMandatoryAccessibility) + { + this.nonMandatoryAccessibility = nonMandatoryAccessibility; + } + + public void setToursLeftCount(int count) + { + toursLeftCount = count; + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug DC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public Household getHouseholdObject() + { + return hh; + } + + public Person getPersonObject() + { + return person; + } + + // DMU methods - define one of these for every @var in the mode choice + // control + // file. + + protected int getToursLeftCount() + { + return toursLeftCount; + } + + protected int getMaxContinuousAvailableWindow() + { + + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) return hh + .getMaxJointTimeWindow(tour); + else return person.getMaximumContinuousAvailableWindow(); + } + + protected double getDcSoaCorrectionsAlt(int alt) + { + return dcSoaCorrections[alt]; + } + + protected double getMcLogsumDestAlt(int mgra) + { + return modeChoiceLogsums[mgra]; + } + + protected double getPopulationDestAlt(int mgra) + { + return aggAcc.getMgraPopulation(mgra); + } + + protected double getHouseholdsDestAlt(int mgra) + { + return aggAcc.getMgraHouseholds(mgra); + } + + protected double getGradeSchoolEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraGradeSchoolEnrollment(mgra); + } + + protected double getHighSchoolEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraHighSchoolEnrollment(mgra); + } + + protected double getUniversityEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraUniversityEnrollment(mgra); + } + + protected double getOtherCollegeEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraOtherCollegeEnrollment(mgra); + } + + protected double getAdultSchoolEnrollmentDestAlt(int mgra) + { + return aggAcc.getMgraAdultSchoolEnrollment(mgra); + } + + protected int getIncome() + { + return hh.getIncomeCategory(); + } + + protected int getIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + protected int getAutos() + { + return hh.getAutosOwned(); + } + + protected int getWorkers() + { + return hh.getWorkers(); + } + + protected int getNumberOfNonWorkingAdults() + { + return hh.getNumberOfNonWorkingAdults(); + } + + protected int getNumPreschool() + { + return hh.getNumPreschool(); + } + + public int getNumGradeSchoolStudents() + { + return hh.getNumGradeSchoolStudents(); + } + + public int getNumHighSchoolStudents() + { + return hh.getNumHighSchoolStudents(); + } + + protected int getNumChildrenUnder16() + { + return hh.getNumChildrenUnder16(); + } + + protected int getNumChildrenUnder19() + { + return hh.getNumChildrenUnder19(); + } + + protected int getAge() + { + return person.getAge(); + } + + protected int getFemaleWorker() + { + if (person.getPersonIsFemale() == 1) return 1; + else return 0; + } + + protected int getFemale() + { + if (person.getPersonIsFemale() == 1) return 1; + else return 0; + } + + protected int getFullTimeWorker() + { + if (person.getPersonIsFullTimeWorker() == 1) return 1; + else return 0; + } + + protected int getTypicalUniversityStudent() + { + return person.getPersonIsTypicalUniversityStudent(); + } + + protected int getPersonType() + { + return person.getPersonTypeNumber(); + } + + protected int getPersonHasBachelors() + { + return person.getHasBachelors(); + } + + protected int getPersonIsWorker() + { + return person.getPersonIsWorker(); + } + + protected int getWorkTaz() + { + return person.getWorkLocation(); + } + + protected int getWorkTourModeIsSOV() + { + boolean tourModeIsSov = modelStructure.getTourModeIsSov(tour.getTourModeChoice()); + if (tourModeIsSov) return 1; + else return 0; + } + + protected int getTourIsJoint() + { + return tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY) ? 1 + : 0; + } + + protected double getTotEmpAccessibilityAlt(int alt) + { + return homeMgraTotalEmploymentAccessibilityArray[alt]; + } + + protected double getNonMandatoryAccessibilityAlt(int alt) + { + return accTable.getAggregateAccessibility("nonmotor", alt); + } + + protected double getOpSovDistanceAlt(int alt) + { + return homeMgraDistanceArray[alt]; + } + + protected double getLnDcSizeAlt(int alt) + { + return Math.log(homeMgraSizeArray[alt] + 1); + } + + protected double getDcSizeAlt(int alt) + { + return homeMgraSizeArray[alt]; + } + + protected void setWorkAccessibility(double accessibility) + { + workAccessibility = accessibility; + } + + protected double getWorkAccessibility() + { + return workAccessibility; + } + + protected double getNonMandatoryAccessibility() + { + return nonMandatoryAccessibility; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceModelManager.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceModelManager.java new file mode 100644 index 0000000..bd4c33f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceModelManager.java @@ -0,0 +1,1082 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.Serializable; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; + +public class DestChoiceModelManager + implements Serializable +{ + + private static String PROPERTIES_WORK_DC_SOA_UEC_FILE = "work.soa.uec.file"; + private static String PROPERTIES_WORK_DC_SOA_UEC_MODEL_PAGE = "work.soa.uec.model"; + private static String PROPERTIES_WORK_DC_SOA_UEC_DATA_PAGE = "work.soa.uec.data"; + + private static String PROPERTIES_UNIV_DC_SOA_UEC_FILE = "univ.soa.uec.file"; + private static String PROPERTIES_UNIV_DC_SOA_UEC_MODEL_PAGE = "univ.soa.uec.model"; + private static String PROPERTIES_UNIV_DC_SOA_UEC_DATA_PAGE = "univ.soa.uec.data"; + + private static String PROPERTIES_HS_DC_SOA_UEC_FILE = "hs.soa.uec.file"; + private static String PROPERTIES_HS_DC_SOA_UEC_MODEL_PAGE = "hs.soa.uec.model"; + private static String PROPERTIES_HS_DC_SOA_UEC_DATA_PAGE = "hs.soa.uec.data"; + + private static String PROPERTIES_GS_DC_SOA_UEC_FILE = "gs.soa.uec.file"; + private static String PROPERTIES_GS_DC_SOA_UEC_MODEL_PAGE = "gs.soa.uec.model"; + private static String PROPERTIES_GS_DC_SOA_UEC_DATA_PAGE = "gs.soa.uec.data"; + + private static String PROPERTIES_PS_DC_SOA_UEC_FILE = "ps.soa.uec.file"; + private static String PROPERTIES_PS_DC_SOA_UEC_MODEL_PAGE = "ps.soa.uec.model"; + private static String PROPERTIES_PS_DC_SOA_UEC_DATA_PAGE = "ps.soa.uec.data"; + + private static final int PRESCHOOL_ALT_INDEX = BuildAccessibilities.PRESCHOOL_ALT_INDEX; + private static final int GRADE_SCHOOL_ALT_INDEX = BuildAccessibilities.GRADE_SCHOOL_ALT_INDEX; + private static final int HIGH_SCHOOL_ALT_INDEX = BuildAccessibilities.HIGH_SCHOOL_ALT_INDEX; + private static final int UNIV_TYPICAL_ALT_INDEX = BuildAccessibilities.UNIV_TYPICAL_ALT_INDEX; + private static final int UNIV_NONTYPICAL_ALT_INDEX = BuildAccessibilities.UNIV_NONTYPICAL_ALT_INDEX; + private static final int NUMBER_OF_SCHOOL_SEGMENT_TYPES = 5; + + private static transient Logger logger = Logger.getLogger(DestChoiceModelManager.class); + + private static DestChoiceModelManager objInstance = null; + + private LinkedList modelQueueWorkLoc = null; + private LinkedList modelQueueSchoolLoc = null; + private LinkedList modelQueueWork = null; + private LinkedList modelQueueSchool = null; + + private MgraDataManager mgraManager; + private TazDataManager tdm; + + private int maxTaz; + + private BuildAccessibilities aggAcc; + + private HashMap propertyMap; + private String dcUecFileName; + private String soaUecFileName; + private int soaSampleSize; + private String modeChoiceUecFileName; + private CtrampDmuFactoryIf dmuFactory; + + private int modelIndexWork; + private int modelIndexSchool; + private int currentIteration; + + private DestChoiceTwoStageSoaTazDistanceUtilityDMU locChoiceDistSoaDmu; + private DestChoiceTwoStageSoaProbabilitiesCalculator workLocSoaDistProbsObject; + private DestChoiceTwoStageSoaProbabilitiesCalculator psLocSoaDistProbsObject; + private DestChoiceTwoStageSoaProbabilitiesCalculator gsLocSoaDistProbsObject; + private DestChoiceTwoStageSoaProbabilitiesCalculator hsLocSoaDistProbsObject; + private DestChoiceTwoStageSoaProbabilitiesCalculator univLocSoaDistProbsObject; + + // the first dimension on these arrays is work location segments (worker + // occupations) + private double[][][] workSizeProbs; + private double[][][] workTazDistProbs; + + // the first dimension on these arrays is school location segment type (ps, + // gs, hs, univTypical, univNonTypical) + private double[][][] schoolSizeProbs; + private double[][][] schoolTazDistProbs; + + private AutoTazSkimsCalculator tazDistanceCalculator; + + private boolean managerIsSetup = false; + + private int completedHouseholdsWork; + private int completedHouseholdsSchool; + private boolean logResults=false; + + private DestChoiceModelManager() + { + } + + public static synchronized DestChoiceModelManager getInstance() + { + // logger.info( + // "beginning of DestChoiceModelManager.getInstance() - objInstance address = " + // + objInstance ); + if (objInstance == null) + { + objInstance = new DestChoiceModelManager(); + // logger.info( + // "after new DestChoiceModelManager() - objInstance address = " + + // objInstance ); + return objInstance; + } else + { + // logger.info( + // "returning current DestChoiceModelManager() - objInstance address = " + // + objInstance ); + return objInstance; + } + } + + // the task instances should call needToInitialize() first, then this method + // if necessary. + public synchronized void managerSetup(HashMap propertyMap, + ModelStructure modelStructure, MatrixDataServerIf ms, String dcUecFileName, + String soaUecFileName, int soaSampleSize, CtrampDmuFactoryIf dmuFactory, + String restartModelString) + { + + if (managerIsSetup) return; + + // get the HouseholdChoiceModelsManager instance and clear the objects + // that hold large memory references + HouseholdChoiceModelsManager.getInstance().clearHhModels(); + + modelIndexWork = 0; + modelIndexSchool = 0; + completedHouseholdsWork = 0; + completedHouseholdsSchool = 0; + + System.out.println(String.format("initializing DC ModelManager: thread=%s.", Thread + .currentThread().getName())); + + this.propertyMap = propertyMap; + this.dcUecFileName = dcUecFileName; + this.soaUecFileName = soaUecFileName; + this.soaSampleSize = soaSampleSize; + this.dmuFactory = dmuFactory; + + logResults = Util.getStringValueFromPropertyMap(propertyMap, "RunModel.LogResults") + .equalsIgnoreCase("true"); + + mgraManager = MgraDataManager.getInstance(propertyMap); + tdm = TazDataManager.getInstance(propertyMap); + maxTaz = tdm.getMaxTaz(); + + modelQueueWorkLoc = new LinkedList(); + modelQueueSchoolLoc = new LinkedList(); + modelQueueWork = new LinkedList(); + modelQueueSchool = new LinkedList(); + + // Initialize the MatrixDataManager to use the MatrixDataServer instance + // passed in, unless ms is null. + if (ms == null) + { + + logger.info(Thread.currentThread().getName() + + ": No remote MatrixServer being used, MatrixDataManager will get created when needed by DestChoiceModelManager."); + } else + { + + String testString = ms.testRemote(Thread.currentThread().getName()); + logger.info(String.format(Thread.currentThread().getName() + + ": DestChoiceModelManager connecting to remote MatrixDataServer.")); + logger.info(String.format("MatrixDataServer connection test: %s", testString)); + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + + } + + aggAcc = BuildAccessibilities.getInstance(); + + // assume that if the filename exists, at was created previously, either + // in another model run, or by the main client + // if the filename doesn't exist, then calculate the accessibilities + String projectDirectory = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file"); + boolean accFileReadFlag = Util.getBooleanValueFromPropertyMap(propertyMap, + CtrampApplication.READ_ACCESSIBILITIES); + + if ((new File(accFileName)).canRead()) + { + + logger.info("filling Accessibilities Object in DestChoiceModelManager by reading file: " + + accFileName + "."); + aggAcc.readAccessibilityTableFromFile(accFileName); + + aggAcc.setupBuildAccessibilities(propertyMap, false); + aggAcc.createSchoolSegmentNameIndices(); + + aggAcc.calculateSizeTerms(); + + } else + { + + aggAcc.setupBuildAccessibilities(propertyMap, false); + aggAcc.createSchoolSegmentNameIndices(); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateConstants(); + + logger.info("filling Accessibilities Object in DestChoiceModelManager by calculating them."); + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + } + + // compute the array of cumulative taz distance based SOA probabilities + // for each origin taz. + locChoiceDistSoaDmu = dmuFactory.getDestChoiceSoaTwoStageTazDistUtilityDMU(); + + tazDistanceCalculator = new AutoTazSkimsCalculator(propertyMap); + tazDistanceCalculator.computeTazDistanceArrays(); + + managerIsSetup = true; + + } + + public synchronized void returnWorkLocModelObject(WorkLocationChoiceModel dcModel, + int taskIndex, int startIndex, int endIndex) + { + modelQueueWorkLoc.add(dcModel); + completedHouseholdsWork += (endIndex - startIndex + 1); + if(logResults){ + logger.info(String + .format("returned workLocationChoice[%d,%d] to workQueueLoc, task=%d, thread=%s, completedHouseholds=%d.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread + .currentThread().getName(), completedHouseholdsWork)); + } + } + + public synchronized void returnDcWorkModelObject(MandatoryDestChoiceModel dcModel, + int taskIndex, int startIndex, int endIndex) + { + modelQueueWork.add(dcModel); + completedHouseholdsWork += (endIndex - startIndex + 1); + if(logResults){ + logger.info(String + .format("returned dcModelWork[%d,%d] to workQueue, task=%d, thread=%s, completedHouseholds=%d.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread + .currentThread().getName(), completedHouseholdsWork)); + } + } + + public synchronized void returnSchoolLocModelObject(SchoolLocationChoiceModel dcModel, + int taskIndex, int startIndex, int endIndex) + { + modelQueueSchoolLoc.add(dcModel); + completedHouseholdsSchool += (endIndex - startIndex + 1); + if(logResults){ + logger.info(String + .format("returned schoolLocationChoice[%d,%d] to schoolQueueLoc, task=%d, thread=%s, completedHouseholds=%d.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread + .currentThread().getName(), completedHouseholdsSchool)); + } + } + + public synchronized void returnDcSchoolModelObject(MandatoryDestChoiceModel dcModel, + int taskIndex, int startIndex, int endIndex) + { + modelQueueSchool.add(dcModel); + completedHouseholdsSchool += (endIndex - startIndex + 1); + if(logResults){ + logger.info(String + .format("returned dcModelSchool[%d,%d] to schoolQueue, task=%d, thread=%s, completedHouseholds=%d.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread + .currentThread().getName(), completedHouseholdsSchool)); + } + } + + public synchronized WorkLocationChoiceModel getWorkLocModelObject(int taskIndex, int iteration, + DestChoiceSize dcSizeObj, int[] uecIndices, int[] soaUecIndices) + { + + // can release memory for the school location choice probabilities + // before running school location choice + clearSchoolProbabilitiesArrys(); + + WorkLocationChoiceModel dcModel = null; + + if (!modelQueueWorkLoc.isEmpty()) + { + + // the first task processed with an iteration parameter greater than + // the manager's + // current iteration updates the manager's SOA size and dist + // probabilities arrays and + // updates the iteration count. + if (iteration > currentIteration) + { + + // update the arrays of cumulative probabilities based on mgra + // size for mgras within each origin taz. + double[][] dcSizeArray = dcSizeObj.getDcSizeArray(); + updateWorkSoaProbabilities(workLocSoaDistProbsObject, dcSizeObj, workSizeProbs, + workTazDistProbs, dcSizeArray); + + currentIteration = iteration; + completedHouseholdsWork = 0; + } + + dcModel = modelQueueWorkLoc.remove(); + dcModel.setDcSizeObject(dcSizeObj); + + if(logResults){ + logger.info(String.format( + "removed workLocationChoice[%d,%d] from workQueueLoc, task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + } + + } else + { + + if (modelIndexWork == 0 && iteration == 0) + { + + // compute the arrays of cumulative probabilities based on mgra + // size for mgras within each origin taz. + logger.info("pre-computing work SOA Distance and Size probabilities."); + workLocSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_WORK_DC_SOA_UEC_FILE, + PROPERTIES_WORK_DC_SOA_UEC_MODEL_PAGE, PROPERTIES_WORK_DC_SOA_UEC_DATA_PAGE); + double[][] dcSizeArray = dcSizeObj.getDcSizeArray(); + workSizeProbs = new double[dcSizeArray.length][maxTaz][]; + workTazDistProbs = new double[dcSizeArray.length][][]; + updateWorkSoaProbabilities(workLocSoaDistProbsObject, dcSizeObj, workSizeProbs, + workTazDistProbs, dcSizeArray); + + currentIteration = 0; + completedHouseholdsWork = 0; + } + + modelIndexWork++; + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + // pass null in instead if modelStructure, since it's not available + // and won't be needed for logsum calculation. + TourModeChoiceModel immcModel = new TourModeChoiceModel(propertyMap, null, + TourModeChoiceModel.MANDATORY_MODEL_INDICATOR, dmuFactory, logsumHelper); + + dcModel = new WorkLocationChoiceModel(modelIndexWork, propertyMap, dcSizeObj, aggAcc, + dcUecFileName, soaUecFileName, soaSampleSize, modeChoiceUecFileName, + dmuFactory, immcModel, workSizeProbs, workTazDistProbs); + + dcModel.setupWorkSegments(uecIndices, soaUecIndices); + dcModel.setupDestChoiceModelArrays(propertyMap, dcUecFileName, soaUecFileName, + soaSampleSize); + + logger.info(String.format("created workLocationChoice[%d,%d], task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + + } + + return dcModel; + + } + + public synchronized MandatoryDestChoiceModel getDcWorkModelObject(int taskIndex, int iteration, + DestChoiceSize dcSizeObj, int[] uecIndices, int[] soaUecIndices) + { + + MandatoryDestChoiceModel dcModel = null; + + if (!modelQueueWork.isEmpty()) + { + + // the first task processed with an iteration parameter greater than + // the manager's + // current iteration updates the manager's SOA size and dist + // probabilities arrays and + // updates the iteration count. + if (iteration > currentIteration) + { + + currentIteration = iteration; + completedHouseholdsWork = 0; + } + + dcModel = modelQueueWork.remove(); + dcModel.setDcSizeObject(dcSizeObj); + + if(logResults){ + logger.info(String.format( + "removed dcModelWork[%d,%d] from workQueue, task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + } + + } else + { + + if (modelIndexWork == 0 && iteration == 0) + { + + currentIteration = 0; + completedHouseholdsWork = 0; + } + + modelIndexWork++; + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + // pass null in instead if modelStructure, since it's not available + // and won't be needed for logsum calculation. + TourModeChoiceModel immcModel = new TourModeChoiceModel(propertyMap, null, + TourModeChoiceModel.MANDATORY_MODEL_INDICATOR, dmuFactory, logsumHelper); + + dcModel = new MandatoryDestChoiceModel(modelIndexWork, propertyMap, dcSizeObj, aggAcc, + mgraManager, dcUecFileName, soaUecFileName, soaSampleSize, + modeChoiceUecFileName, dmuFactory, immcModel); + + dcModel.setupWorkSegments(uecIndices, soaUecIndices); + dcModel.setupDestChoiceModelArrays(propertyMap, dcUecFileName, soaUecFileName, + soaSampleSize); + + logger.info(String.format("created dcModelWork[%d,%d], task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + + } + + return dcModel; + + } + + public synchronized SchoolLocationChoiceModel getSchoolLocModelObject(int taskIndex, + int iteration, DestChoiceSize dcSizeObj) + { + // can release memory for the work location choice probabilities before + // running school location choice + clearWorkProbabilitiesArrys(); + clearWorkLocModels(); + + SchoolLocationChoiceModel dcModel = null; + + int[] gsDistrict = new int[maxTaz + 1]; + int[] hsDistrict = new int[maxTaz + 1]; + double[] univEnrollment = new double[maxTaz + 1]; + + if (!modelQueueSchoolLoc.isEmpty()) + { + + // the first task processed with an iteration parameter greater than + // the + // manager's current iteration count clears the dcModel cache and + // updates the iteration count. + if (iteration > currentIteration) + { + + // compute the exponentiated distance utilities that all + // segments of this tour purpose will share + double[][] tazDistExpUtils = null; + + logger.info("updating pre-school SOA Distance and Size probabilities."); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(psLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getPsSegmentNameIndexMap(), dcSizeObj, + tazDistExpUtils, schoolSizeProbs[PRESCHOOL_ALT_INDEX], + schoolTazDistProbs[PRESCHOOL_ALT_INDEX]); + + logger.info("updating grade school SOA Distance and Size probabilities."); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(gsLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getGsSegmentNameIndexMap(), dcSizeObj, + tazDistExpUtils, schoolSizeProbs[GRADE_SCHOOL_ALT_INDEX], + schoolTazDistProbs[GRADE_SCHOOL_ALT_INDEX]); + + logger.info("updating high school SOA Distance and Size probabilities."); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(hsLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getHsSegmentNameIndexMap(), dcSizeObj, + tazDistExpUtils, schoolSizeProbs[HIGH_SCHOOL_ALT_INDEX], + schoolTazDistProbs[HIGH_SCHOOL_ALT_INDEX]); + + logger.info("updating university-typical school SOA Distance and Size probabilities."); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(univLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getUnivTypicalSegmentNameIndexMap(), dcSizeObj, + tazDistExpUtils, schoolSizeProbs[UNIV_TYPICAL_ALT_INDEX], + schoolTazDistProbs[UNIV_TYPICAL_ALT_INDEX]); + + logger.info("updating university-non-typical school SOA Distance and Size probabilities."); + updateSchoolSoaProbabilities(aggAcc.getUnivNonTypicalSegmentNameIndexMap(), + dcSizeObj, tazDistExpUtils, schoolSizeProbs[UNIV_NONTYPICAL_ALT_INDEX], + schoolTazDistProbs[UNIV_NONTYPICAL_ALT_INDEX]); + + currentIteration = iteration; + completedHouseholdsSchool = 0; + + } + + dcModel = modelQueueSchoolLoc.remove(); + dcModel.setDcSizeObject(dcSizeObj); + if(logResults){ + logger.info(String.format( + "removed schoolLocationChoice[%d,%d] from schoolQueueLoc, task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + } + + } else + { + + if (modelIndexSchool == 0 && iteration == 0) + { + + // if the schoolSizeProbs array is null, no task has yet + // initialized the probabilities arrays, so enter the block. + // if not null, the arrays have been computed, so it's ok to + // skip. + if (schoolSizeProbs == null) + { + + // compute the exponentiated distance utilities that all + // segments of this tour purpose will share + double[][] tazDistExpUtils = null; + + int[] gsDistrictByMgra = aggAcc.getMgraGsDistrict(); + int[] hsDistrictByMgra = aggAcc.getMgraHsDistrict(); + + // determine university enrollment by TAZs + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + int[] mgraArray = tdm.getMgraArray(taz); + if (mgraArray != null) + { + for (int mgra : mgraArray) + { + univEnrollment[taz] = aggAcc.getMgraUniversityEnrollment(mgra); + } + } + } + locChoiceDistSoaDmu.setTazUnivEnrollment(univEnrollment); + + // determine grade school and high school districts by TAZs + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + int[] mgraArray = tdm.getMgraArray(taz); + if (mgraArray != null) + { + for (int mgra : mgraArray) + { + gsDistrict[taz] = gsDistrictByMgra[mgra]; + hsDistrict[taz] = hsDistrictByMgra[mgra]; + break; + } + } + } + locChoiceDistSoaDmu.setTazGsDistricts(gsDistrict); + locChoiceDistSoaDmu.setTazHsDistricts(hsDistrict); + + schoolSizeProbs = new double[NUMBER_OF_SCHOOL_SEGMENT_TYPES][maxTaz][]; + schoolTazDistProbs = new double[NUMBER_OF_SCHOOL_SEGMENT_TYPES][maxTaz][maxTaz]; + + // compute the arrays of cumulative probabilities based on + // mgra size for mgras within each origin taz. + try + { + logger.info("pre-computing pre-school SOA Distance and Size probabilities."); + psLocSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_PS_DC_SOA_UEC_FILE, + PROPERTIES_PS_DC_SOA_UEC_MODEL_PAGE, + PROPERTIES_PS_DC_SOA_UEC_DATA_PAGE); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(psLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getPsSegmentNameIndexMap(), dcSizeObj, + tazDistExpUtils, schoolSizeProbs[PRESCHOOL_ALT_INDEX], + schoolTazDistProbs[PRESCHOOL_ALT_INDEX]); + } catch (Exception e) + { + logger.error("exception caught updating pre-school SOA probabilities", e); + System.exit(-1); + } + + try + { + logger.info("pre-computing grade school SOA Distance and Size probabilities."); + gsLocSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_GS_DC_SOA_UEC_FILE, + PROPERTIES_GS_DC_SOA_UEC_MODEL_PAGE, + PROPERTIES_GS_DC_SOA_UEC_DATA_PAGE); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(gsLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getGsSegmentNameIndexMap(), dcSizeObj, + tazDistExpUtils, schoolSizeProbs[GRADE_SCHOOL_ALT_INDEX], + schoolTazDistProbs[GRADE_SCHOOL_ALT_INDEX]); + } catch (Exception e) + { + logger.error("exception caught updating grade school SOA probabilities", e); + System.exit(-1); + } + + try + { + logger.info("pre-computing high school SOA Distance and Size probabilities."); + hsLocSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_HS_DC_SOA_UEC_FILE, + PROPERTIES_HS_DC_SOA_UEC_MODEL_PAGE, + PROPERTIES_HS_DC_SOA_UEC_DATA_PAGE); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(hsLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getHsSegmentNameIndexMap(), dcSizeObj, + tazDistExpUtils, schoolSizeProbs[HIGH_SCHOOL_ALT_INDEX], + schoolTazDistProbs[HIGH_SCHOOL_ALT_INDEX]); + } catch (Exception e) + { + logger.error("exception caught updating high school SOA probabilities", e); + System.exit(-1); + } + + try + { + logger.info("pre-computing university-typical SOA Distance and Size probabilities."); + univLocSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_UNIV_DC_SOA_UEC_FILE, + PROPERTIES_UNIV_DC_SOA_UEC_MODEL_PAGE, + PROPERTIES_UNIV_DC_SOA_UEC_DATA_PAGE); + tazDistExpUtils = computeTazDistanceExponentiatedUtilities(univLocSoaDistProbsObject); + updateSchoolSoaProbabilities(aggAcc.getUnivTypicalSegmentNameIndexMap(), + dcSizeObj, tazDistExpUtils, + schoolSizeProbs[UNIV_TYPICAL_ALT_INDEX], + schoolTazDistProbs[UNIV_TYPICAL_ALT_INDEX]); + } catch (Exception e) + { + logger.error("exception caught updating university SOA probabilities", e); + System.exit(-1); + } + + try + { + logger.info("pre-computing university-non-typical SOA Distance and Size probabilities."); + univLocSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_UNIV_DC_SOA_UEC_FILE, + PROPERTIES_UNIV_DC_SOA_UEC_MODEL_PAGE, + PROPERTIES_UNIV_DC_SOA_UEC_DATA_PAGE); + updateSchoolSoaProbabilities(aggAcc.getUnivNonTypicalSegmentNameIndexMap(), + dcSizeObj, tazDistExpUtils, + schoolSizeProbs[UNIV_NONTYPICAL_ALT_INDEX], + schoolTazDistProbs[UNIV_NONTYPICAL_ALT_INDEX]); + } catch (Exception e) + { + logger.error("exception caught updating university SOA probabilities", e); + System.exit(-1); + } + + currentIteration = 0; + completedHouseholdsSchool = 0; + + } + + } + + modelIndexSchool++; + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + // pass null in instead if modelStructure, since it's not available + // and won't be needed for logsum calculation. + TourModeChoiceModel immcModel = new TourModeChoiceModel(propertyMap, null, + TourModeChoiceModel.MANDATORY_MODEL_INDICATOR, dmuFactory, logsumHelper); + + dcModel = new SchoolLocationChoiceModel(modelIndexSchool, propertyMap, dcSizeObj, + aggAcc, dcUecFileName, soaUecFileName, soaSampleSize, modeChoiceUecFileName, + dmuFactory, immcModel, schoolSizeProbs, schoolTazDistProbs); + + dcModel.setupSchoolSegments(); + dcModel.setupDestChoiceModelArrays(propertyMap, dcUecFileName, soaUecFileName, + soaSampleSize); + + logger.info(String.format("created schoolLocationChoice[%d,%d], task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + + } + + return dcModel; + + } + + public synchronized MandatoryDestChoiceModel getDcSchoolModelObject(int taskIndex, + int iteration, DestChoiceSize dcSizeObj) + { + + MandatoryDestChoiceModel dcModel = null; + if (!modelQueueSchool.isEmpty()) + { + + // the first task processed with an iteration parameter greater than + // the + // manager's current iteration count clears the dcModel cache and + // updates the iteration count. + if (iteration > currentIteration) + { + + currentIteration = iteration; + completedHouseholdsSchool = 0; + + } + + dcModel = modelQueueSchool.remove(); + dcModel.setDcSizeObject(dcSizeObj); + if(logResults){ + logger.info(String.format( + "removed dcModelSchool[%d,%d] from schoolQueue, task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + } + + } else + { + + if (modelIndexSchool == 0 && iteration == 0) + { + currentIteration = 0; + completedHouseholdsSchool = 0; + } + + modelIndexSchool++; + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + // pass null in instead if modelStructure, since it's not available + // and won't be needed for logsum calculation. + TourModeChoiceModel immcModel = new TourModeChoiceModel(propertyMap, null, + TourModeChoiceModel.MANDATORY_MODEL_INDICATOR, dmuFactory, logsumHelper); + + dcModel = new MandatoryDestChoiceModel(modelIndexSchool, propertyMap, dcSizeObj, + aggAcc, mgraManager, dcUecFileName, soaUecFileName, soaSampleSize, + modeChoiceUecFileName, dmuFactory, immcModel); + + dcModel.setupSchoolSegments(); + dcModel.setupDestChoiceModelArrays(propertyMap, dcUecFileName, soaUecFileName, + soaSampleSize); + + logger.info(String.format("created dcModelSchool[%d,%d], task=%d, thread=%s.", + currentIteration, dcModel.getModelIndex(), taskIndex, Thread.currentThread() + .getName())); + + } + + return dcModel; + + } + + public synchronized void clearDcModels() + { + + clearWorkLocModels(); + clearSchoolLocModels(); + clearWorkProbabilitiesArrys(); + clearSchoolProbabilitiesArrys(); + + if (tazDistanceCalculator != null) + { + tazDistanceCalculator.clearStoredTazsDistanceSkims(); + tazDistanceCalculator = null; + } + + logger.info("DestChoiceModelManager elements cleared."); + + } + + private void clearWorkLocModels() + { + + if (modelQueueWorkLoc != null && !modelQueueWorkLoc.isEmpty()) + { + + logger.info(String.format( + "%s: clearing dc choice models modelQueueWorkLoc, thread=%s.", new Date(), + Thread.currentThread().getName())); + + while (!modelQueueWorkLoc.isEmpty()) + modelQueueWorkLoc.remove(); + modelIndexWork = 0; + completedHouseholdsWork = 0; + + } + + if (modelQueueWork != null && !modelQueueWork.isEmpty()) + { + + logger.info(String.format("%s: clearing dc choice models modelQueueWork, thread=%s.", + new Date(), Thread.currentThread().getName())); + while (!modelQueueWork.isEmpty()) + modelQueueWork.remove(); + + modelIndexWork = 0; + completedHouseholdsWork = 0; + + } + + } + + private void clearSchoolLocModels() + { + + if (modelQueueSchoolLoc != null && !modelQueueSchoolLoc.isEmpty()) + { + + logger.info(String.format( + "%s: clearing dc choice models modelQueueSchoolLoc, thread=%s.", new Date(), + Thread.currentThread().getName())); + while (!modelQueueSchoolLoc.isEmpty()) + modelQueueSchoolLoc.remove(); + + modelIndexSchool = 0; + completedHouseholdsSchool = 0; + + } + + if (modelQueueSchool != null && !modelQueueSchool.isEmpty()) + { + + logger.info(String.format( + "%s: clearing dc choice models modelQueueSchool, thread=%s.", new Date(), + Thread.currentThread().getName())); + while (!modelQueueSchool.isEmpty()) + modelQueueSchool.remove(); + + modelIndexSchool = 0; + completedHouseholdsSchool = 0; + + } + + } + + private void clearWorkProbabilitiesArrys() + { + + // null out the cache of probabilities arrays for work location choice + if (workSizeProbs != null) + { + for (int i = 0; i < workSizeProbs.length; i++) + { + if (workSizeProbs[i] != null) + { + for (int j = 0; j < workSizeProbs[i].length; j++) + workSizeProbs[i][j] = null; + } + workSizeProbs[i] = null; + } + workSizeProbs = null; + } + + if (workTazDistProbs != null) + { + for (int i = 0; i < workTazDistProbs.length; i++) + { + if (workTazDistProbs[i] != null) + { + for (int j = 0; j < workTazDistProbs[i].length; j++) + workTazDistProbs[i][j] = null; + } + workTazDistProbs[i] = null; + } + workTazDistProbs = null; + } + + } + + private void clearSchoolProbabilitiesArrys() + { + + // null out the cache of probabilities arrays for work location choice + if (schoolSizeProbs != null) + { + for (int i = 0; i < schoolSizeProbs.length; i++) + { + if (schoolSizeProbs[i] != null) + { + for (int j = 0; j < schoolSizeProbs[i].length; j++) + schoolSizeProbs[i][j] = null; + } + schoolSizeProbs[i] = null; + } + schoolSizeProbs = null; + } + + if (schoolTazDistProbs != null) + { + for (int i = 0; i < schoolTazDistProbs.length; i++) + { + if (schoolTazDistProbs[i] != null) + { + for (int j = 0; j < schoolTazDistProbs[i].length; j++) + schoolTazDistProbs[i][j] = null; + } + schoolTazDistProbs[i] = null; + } + schoolTazDistProbs = null; + } + + } + + private void updateWorkSoaProbabilities( + DestChoiceTwoStageSoaProbabilitiesCalculator locChoiceSoaDistProbsObject, + DestChoiceSize dcSizeObj, double[][][] sizeProbs, double[][][] tazDistProbs, + double[][] dcSizeArray) + { + + HashMap segmentNameIndexMap = dcSizeObj.getSegmentNameIndexMap(); + + for (String segmentName : segmentNameIndexMap.keySet()) + { + + int segmentIndex = segmentNameIndexMap.get(segmentName); + + // compute the TAZ size values from the mgra values and the + // correspondence between mgras and tazs. + double[] tazSize = computeTazSize(dcSizeArray[segmentIndex]); + locChoiceDistSoaDmu.setDestChoiceTazSize(tazSize); + + // tazDistProbs[segmentIndex] = + // locChoiceSoaDistProbsObject.computeDistanceProbabilities( 3737, + // locChoiceDistSoaDmu ); + tazDistProbs[segmentIndex] = locChoiceSoaDistProbsObject + .computeDistanceProbabilities(locChoiceDistSoaDmu); + + computeSizeSegmentProbabilities(sizeProbs[segmentIndex], dcSizeArray[segmentIndex]); + + } + + } + + private void updateSchoolSoaProbabilities(HashMap segmentNameIndexMap, + DestChoiceSize dcSizeObj, double[][] tazDistExpUtils, double[][] sizeProbs, + double[][] tazDistProbs) + { + + double[][] dcSizeArray = dcSizeObj.getDcSizeArray(); + + double[] tempExpUtils = new double[tazDistExpUtils.length]; + + // compute an array of SOA probabilities for each segment + for (String segmentName : segmentNameIndexMap.keySet()) + { + + // compute the TAZ size values from the mgra values and the + // correspondence between mgras and tazs. + int segmentIndex = segmentNameIndexMap.get(segmentName); + double[] tazSize = computeTazSize(dcSizeArray[segmentIndex]); + + // compute the taz dist probabilities from the exponentiated + // utilities for this segmnet and the taz size terms + for (int i = 0; i < tazDistExpUtils.length; i++) + { + + // compute the final exponentiated utilities by multiplying with + // taz size, and accumulate total exponentiated utility. + double totalExpUtil = 0; + for (int j = 0; j < tempExpUtils.length; j++) + { + tempExpUtils[j] = tazDistExpUtils[i][j] * tazSize[j + 1]; + totalExpUtil += tempExpUtils[j]; + } + + if (totalExpUtil > 0) + { + + // compute the SOA cumulative probabilities + tazDistProbs[i][0] = tempExpUtils[0] / totalExpUtil; + for (int j = 1; j < tempExpUtils.length - 1; j++) + { + double prob = tempExpUtils[j] / totalExpUtil; + tazDistProbs[i][j] = tazDistProbs[i][j - 1] + prob; + } + tazDistProbs[i][tempExpUtils.length - 1] = 1.0; + + } + + } + + computeSizeSegmentProbabilities(sizeProbs, dcSizeArray[segmentIndex]); + + } + + } + + private double[][] computeTazDistanceExponentiatedUtilities( + DestChoiceTwoStageSoaProbabilitiesCalculator locChoiceSoaDistProbsObject) + { + + double[][] tazDistExpUtils = locChoiceSoaDistProbsObject + .computeDistanceUtilities(locChoiceDistSoaDmu); + for (int i = 0; i < tazDistExpUtils.length; i++) + for (int j = 0; j < tazDistExpUtils[i].length; j++) + { + if (tazDistExpUtils[i][j] < -500) tazDistExpUtils[i][j] = 0; + else tazDistExpUtils[i][j] = Math.exp(tazDistExpUtils[i][j]); + } + + return tazDistExpUtils; + + } + + private double[] computeTazSize(double[] size) + { + + double[] tazSize = new double[maxTaz + 1]; + + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + + int[] mgraArray = tdm.getMgraArray(taz); + if (mgraArray != null) + { + for (int mgra : mgraArray) + { + tazSize[taz] += size[mgra] + (size[mgra] > 0 ? 1 : 0); + } + } + + } + + return tazSize; + + } + + private void computeSizeSegmentProbabilities(double[][] sizeProbs, double[] size) + { + + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + + int[] mgraArray = tdm.getMgraArray(taz); + + if (mgraArray == null) + { + sizeProbs[taz - 1] = new double[0]; + } else + { + double totalSize = 0; + for (int mgra : mgraArray) + totalSize += size[mgra] + (size[mgra] > 0 ? 1 : 0); + + if (totalSize > 0) + { + sizeProbs[taz - 1] = new double[mgraArray.length]; + for (int i = 0; i < mgraArray.length; i++) + { + double mgraSize = size[mgraArray[i]]; + if (mgraSize > 0) mgraSize += 1; + sizeProbs[taz - 1][i] = mgraSize / totalSize; + } + } else if (sizeProbs[taz - 1] == null) + { + sizeProbs[taz - 1] = new double[0]; + } + } + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceSize.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceSize.java new file mode 100644 index 0000000..695b2fc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceSize.java @@ -0,0 +1,965 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.datafile.CSVFileWriter; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * Handles building and storing destination choice size variables + * + */ + +public class DestChoiceSize + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(DestChoiceSize.class); + private transient Logger convergeLogger = Logger.getLogger("converge"); + + public static final String PROPERTIES_DC_SHADOW_OUTPUT = "uwsl.ShadowPricing.OutputFile"; + public static final String PROPERTIES_WORK_DC_SHADOW_NITER = "uwsl.ShadowPricing.Work.MaximumIterations"; + public static final String PROPERTIES_SCHOOL_DC_SHADOW_NITER = "uwsl.ShadowPricing.School.MaximumIterations"; + + private int numSegments; + private double[][] segmentSizeTerms; + private HashMap segmentIndexNameMap; + private HashMap segmentNameIndexMap; + private HashSet noShadowPriceSchoolSegmentIndices; + private MgraDataManager mgraManager; + + // 1st dimension is an index for the set of DC Size variables used in Sample + // of + // Alternative choice and destination choice, + // 2nd dimension is zone number (1,...,numZones), 3rd dimension walk subzone + // index is 0: no walk %, 1: shrt %, 2: long %. + protected double[][] dcSize; + protected double[][] originalSize; + protected double[][] originalAdjSize; + protected double[][] scaledSize; + protected double[][] balanceSize; + protected double[][] previousSize; + protected double[][] shadowPrice; + + protected double[][] externalFactors; + + protected int maxShadowPriceIterations; + + protected String dcShadowOutputFileName; + + protected boolean dcSizeCalculated = false; + + /** + * + * @param propertyMap + * is the model properties file key:value pairs + * @param segmentNameIndexMap + * is a map from segment name to size term array index. + * @param segmentIndexNameMap + * is a map from size term array index to segment name. + * @param segmentSizeTerms + * is an array by segment index and MGRA index + */ + public DestChoiceSize(HashMap propertyMap, + HashMap segmentIndexNameMap, + HashMap segmentNameIndexMap, double[][] segmentSizeTerms, + int maxIterations) + { + + this.segmentIndexNameMap = segmentIndexNameMap; + this.segmentNameIndexMap = segmentNameIndexMap; + this.segmentSizeTerms = segmentSizeTerms; + + // get the number of segments from the segmentIndexNameMap + numSegments = segmentIndexNameMap.size(); + + maxShadowPriceIterations = maxIterations; + + String projectDirectory = Util.getStringValueFromPropertyMap(propertyMap, + CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + dcShadowOutputFileName = projectDirectory + propertyMap.get(PROPERTIES_DC_SHADOW_OUTPUT); + + mgraManager = MgraDataManager.getInstance(); + + // set default external factors array (all 1.0s) + // an object creating a destChoice object can override these valuse by + // calling setExternalFactors(). + externalFactors = new double[numSegments][mgraManager.getMaxMgra() + 1]; + for (int i = 0; i < numSegments; i++) + Arrays.fill(externalFactors[i], 1.0); + + } + + /** + * @return a boolean for whether or not the size terms in this object have + * been calculated + */ + public boolean getDcSizeCalculated() + { + return dcSizeCalculated; + } + + public HashMap getSegmentIndexNameMap() + { + return segmentIndexNameMap; + } + + public HashMap getSegmentNameIndexMap() + { + return segmentNameIndexMap; + } + + /** + * @return the maximum number of shadow price iterations set in the + * properties file + */ + public int getMaxShadowPriceIterations() + { + return maxShadowPriceIterations; + } + + public void setExternalFactors(double[][] factors) + { + externalFactors = factors; + } + + public void setNoShadowPriceSchoolSegmentIndices(HashSet indexSet) + { + noShadowPriceSchoolSegmentIndices = indexSet; + } + + /** + * Scale the destination choice size values so that the total modeled + * destinations by segment match the total origins. total Origin/Destination + * constraining usuallu done for home oriented mandatory tours, e.g. work + * university, school. This method also has the capability to read a file of + * destination size adjustments and apply them during the balancing + * procedure. This capability was used in the Morpc model and was + * transferred to the Baylanta project, but may or may not be used. + * + * @param originsByHomeZone + * - total long term choice origin locations (i.e. number of + * workers, university students, or school age students) in + * residence zone, subzone, by segment. + * + */ + public void balanceSizeVariables(int[][] originsByHomeMgra) + { + + // store the original size variable values. + // set the initial sizeBalance values to the original size variable + // values. + originalSize = duplicateDouble2DArray(segmentSizeTerms); + balanceSize = duplicateDouble2DArray(segmentSizeTerms); + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + // create the shadow price array - num + shadowPrice = new double[numSegments][maxMgra + 1]; + + // create the total origin locations array to store total tours by + // segment + double[] totalOriginLocations = new double[numSegments]; + + // create the total destination choice size array to store total tours + // by + // segment + double[] totalDestSize = new double[numSegments]; + + // initialize shadow prices with 1.0 + // accumulate total tours and size by segment. + for (int i = 0; i < numSegments; i++) + { + for (int j = 1; j <= maxMgra; j++) + { + shadowPrice[i][j] = 1.0; + totalOriginLocations[i] += originsByHomeMgra[i][j]; + totalDestSize[i] += (segmentSizeTerms[i][j] * externalFactors[i][j]); + } // j (mgra) + } // i (segment) + + // log a report of total origin locations by segment + logger.info(""); + logger.info("total origin locations by segment before any balancing, destination size adjustments, or shadow price scaling:"); + double segmentSum = 0.0; + for (int i = 0; i < numSegments; i++) + { + String segmentString = segmentIndexNameMap.get(i); + segmentSum += totalOriginLocations[i]; + logger.info(String.format(" %-6d %-55s: %10.1f", i, segmentString, + totalOriginLocations[i])); + } // i + logger.info(String.format(" %-6s %-55s: %10.1f", " ", "Total", segmentSum)); + logger.info(""); + + // log a report of total destination choice size calculated by segment + logger.info(""); + logger.info("total destination choice size by segment before any balancing, destination choice size adjustments, or shadow price scaling:"); + segmentSum = 0.0; + for (int i = 0; i < numSegments; i++) + { + String segmentString = segmentIndexNameMap.get(i); + segmentSum += totalDestSize[i]; + logger.info(String.format(" %-6d %-55s: %10.1f", i, segmentString, + totalDestSize[i])); + } + logger.info(String.format(" %-6s %-55s: %10.1f", " ", "Total", segmentSum)); + logger.info(""); + + // save original adjusted size variable arrays prior to balancing - used + // in + // reporting size variable calculations to output files. + originalAdjSize = duplicateDouble2DArray(balanceSize); + + // Balance destination choice size variables to equal total origin + // locations by segment. + // The scaledSize calculated is what is adjusted by shadow pricing + // adjustments, and dcSize, the array referenced + // by UEC DMUs is a duplicate copy of this array after the shadow + // pricing + // calculations are made. + scaledSize = new double[balanceSize.length][maxMgra + 1]; + double tot = 0.0; + for (int i = 0; i < numSegments; i++) + { + + tot = 0.0; + for (int j = 1; j <= maxMgra; j++) + { + + if (totalDestSize[i] > 0.0) scaledSize[i][j] = (balanceSize[i][j] + * externalFactors[i][j] * totalOriginLocations[i]) + / totalDestSize[i]; + else scaledSize[i][j] = 0.0f; + + tot += scaledSize[i][j]; + + } + + } + + // set destination choice size variables for the first iteration of + // shadow + // pricing to calculated scaled values + dcSize = duplicateDouble2DArray(scaledSize); + + // sum scaled destination size values by segment for reporting + double[] sumScaled = new double[numSegments]; + for (int i = 0; i < numSegments; i++) + { + for (int j = 1; j <= maxMgra; j++) + sumScaled[i] += scaledSize[i][j]; + } + + // log a report of total destination locations by segment + logger.info(""); + logger.info("total destination choice size by segment after destination choice size adjustments, after shadow price scaling:"); + segmentSum = 0.0; + for (int i = 0; i < numSegments; i++) + { + String segmentString = segmentIndexNameMap.get(i); + segmentSum += sumScaled[i]; + logger.info(String.format(" %-6d %-55s: %10.1f", i, segmentString, sumScaled[i])); + } + logger.info(String.format(" %-6s %-55s: %10.1f", " ", "Total", segmentSum)); + logger.info(""); + + // save scaled size variables used in shadow price adjustmnents for + // reporting + // to output file + previousSize = new double[numSegments][]; + for (int i = 0; i < numSegments; i++) + previousSize[i] = duplicateDouble1DArray(scaledSize[i]); + + } + + public double getDcSize(int segmentIndex, int mgra) + { + return dcSize[segmentIndex][mgra]; + } + + public double getDcSize(String segmentName, int mgra) + { + int segmentIndex = segmentNameIndexMap.get(segmentName); + return dcSize[segmentIndex][mgra]; + } + + public double[][] getDcSizeArray() + { + return dcSize; + } + + public int getNumberOfSegments() + { + return dcSize.length; + } + + public void updateSizeVariables() + { + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + for (int i = 0; i < numSegments; i++) + { + for (int j = 1; j <= maxMgra; j++) + { + dcSize[i][j] = scaledSize[i][j] * shadowPrice[i][j]; + if (dcSize[i][j] < 0.0f) dcSize[i][j] = 0.0f; + } + } + + } + + public void updateShadowPrices(int[][] modeledDestinationLocationsByDestMgra) + { + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + for (int i = 0; i < numSegments; i++) + { + if (noShadowPriceSchoolSegmentIndices != null + && noShadowPriceSchoolSegmentIndices.contains(i)) continue; + + for (int j = 1; j <= maxMgra; j++) + { + if (modeledDestinationLocationsByDestMgra[i][j] > 0) + shadowPrice[i][j] *= (scaledSize[i][j] / modeledDestinationLocationsByDestMgra[i][j]); + // else + // shadowPrice[i][j] *= scaledSize[i][j]; + } + } + + } + + public void reportMaxDiff(int iteration, int[][] modeledDestinationLocationsByDestMgra) + { + + double[] maxSize = {10, 100, 1000, Double.MAX_VALUE}; + double[] maxDeltas = {0.05, 0.10, 0.25, 0.50, 1.0, Double.MAX_VALUE}; + + int[] nObs = new int[maxSize.length]; + double[] sse = new double[maxSize.length]; + double[] sumObs = new double[maxSize.length]; + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + logger.info("Shadow Price Iteration " + iteration); + + double minRange = 0.0; + for (int r = 0; r < maxSize.length; r++) + { + + logger.info(String + .format("Frequency of chosen mgra locations with non-zero DC Size < %s by range of relative error", + (maxSize[r] < 1000000 ? String.format("%.1f", maxSize[r]) : "+Inf"))); + logger.info(String.format("%-6s %-55s %15s %15s %15s %15s %15s %15s %15s %8s", + "index", "segment", "0 DCs", "< 5%", "< 10%", "< 25%", "< 50%", "< 100%", + "100% +", "Total")); + + int tot = 0; + int[] tots = new int[maxDeltas.length + 1]; + String logRecord = ""; + for (int i = 0; i < numSegments; i++) + { + + tot = 0; + int[] freqs = new int[maxDeltas.length + 1]; + int nonZeroSizeLocs = 0; + for (int j = 1; j <= maxMgra; j++) + { + + if (scaledSize[i][j] > minRange && scaledSize[i][j] <= maxSize[r]) + { + + nonZeroSizeLocs++; + + if (modeledDestinationLocationsByDestMgra[i][j] == 0.0) + { + // store the number of DC alternatives where DC Size + // > 0, + // but alternative was not chosen. + // relative error measure is not meaningful for this + // case, so report number of cases separately. + freqs[0]++; + + // calculations for %RMSE + sse[r] += scaledSize[i][j] * scaledSize[i][j]; + } else + { + + double relDiff = Math.abs(scaledSize[i][j] + - modeledDestinationLocationsByDestMgra[i][j]) + / scaledSize[i][j]; + for (int k = 0; k < maxDeltas.length; k++) + { + if (relDiff < maxDeltas[k]) + { + // store number of DC alternatives chosen + // where + // DC Size > 0, by relative error range. + freqs[k + 1]++; + break; + } + } + + // calculations for %RMSE + sse[r] += relDiff * relDiff; + } + + // calculations for %RMSE + sumObs[r] += scaledSize[i][j]; + nObs[r]++; + + } + + } + + for (int k = 0; k < freqs.length; k++) + { + tots[k] += freqs[k]; + tot += freqs[k]; + } + + String segmentString = segmentIndexNameMap.get(i); + logRecord = String.format("%-6d %-55s", i, segmentString); + + for (int k = 0; k < freqs.length; k++) + { + float pct = 0.0f; + if (tot > 0) pct = (float) (100.0 * freqs[k] / tot); + logRecord += String.format(" %6d (%5.1f%%)", freqs[k], pct); + } + + logRecord += String.format(" %8d", tot); + logger.info(logRecord); + + } + + tot = 0; + for (int k = 0; k < tots.length; k++) + { + tot += tots[k]; + } + + logRecord = String.format("%-6s %-55s", " ", "Total"); + String underline = String.format("------------------------"); + + for (int k = 0; k < tots.length; k++) + { + float pct = 0.0f; + if (tot > 0) pct = (float) (100.0 * tots[k] / tot); + logRecord += String.format(" %6d (%5.1f%%)", tots[k], pct); + underline += String.format("----------------"); + } + + logRecord += String.format(" %8d", tot); + underline += String.format("---------"); + + logger.info(underline); + logger.info(logRecord); + + double rmse = -1.0; + if (nObs[r] > 1) + rmse = 100.0 * (Math.sqrt(sse[r] / (nObs[r] - 1)) / (sumObs[r] / nObs[r])); + + logger.info("%RMSE = " + + (rmse < 0 ? "N/A, no observations" : String.format( + "%.1f, with mean %.1f, for %d observations.", rmse, + (sumObs[r] / nObs[r]), nObs[r]))); + + logger.info(""); + + minRange = maxSize[r]; + + } + + logger.info(""); + logger.info(""); + + } + + public void saveSchoolMaxDiffValues(int iteration, int[][] modeledDestinationLocationsByDestMgra) + { + + // define labels for the schoolsegment categories + String[] segmentRangelabels = {"Pre-School", "K-8", "9-12", "Univ"}; + + // define the highest index value for the range of segments for the + // school segment category + int[] segmentRange = {0, 36, 54, 56}; + + double[] maxSize = {10, 100, 1000, Double.MAX_VALUE}; + double[] maxDeltas = {0.05, 0.10, 0.25, 0.50, 1.0, 999.9}; + + int[][][] freqs = new int[segmentRangelabels.length][maxSize.length][maxDeltas.length]; + + int[][] nObs = new int[segmentRangelabels.length][maxSize.length]; + double[][] sse = new double[segmentRangelabels.length][maxSize.length]; + double[][] sumObs = new double[segmentRangelabels.length][maxSize.length]; + + double[][] rmse = new double[segmentRangelabels.length][maxSize.length]; + double[][] meanSize = new double[segmentRangelabels.length][maxSize.length]; + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + convergeLogger.info("School Shadow Price Iteration " + iteration); + + double[] minRange = new double[segmentRangelabels.length]; + + int minS = 0; + for (int s = 0; s < segmentRangelabels.length; s++) + { + + convergeLogger.info(""); + convergeLogger.info(""); + convergeLogger.info(segmentRangelabels[s] + " convergence statistics"); + + if (s > 0) minS = segmentRange[s - 1] + 1; + + for (int r = 0; r < maxSize.length; r++) + { + + for (int i = minS; i <= segmentRange[s]; i++) + { + + for (int j = 1; j <= maxMgra; j++) + { + + if (scaledSize[i][j] > minRange[s] && scaledSize[i][j] <= maxSize[r]) + { + + if (modeledDestinationLocationsByDestMgra[i][j] > 0.0) + { + + int delta = maxDeltas.length - 1; + double diff = Math.abs(scaledSize[i][j] + - modeledDestinationLocationsByDestMgra[i][j]); + double relDiff = diff / scaledSize[i][j]; + for (int k = 0; k < maxDeltas.length; k++) + { + if (relDiff < maxDeltas[k]) + { + delta = k; + break; + } + } + + freqs[s][r][delta]++; + + // calculations for %RMSE + sse[s][r] += (diff * diff); + + } + + // calculations for %RMSE + sumObs[s][r] += scaledSize[i][j]; + nObs[s][r]++; + + } + + } + + } + + rmse[s][r] = -1.0; + if (nObs[s][r] > 1) + { + meanSize[s][r] = sumObs[s][r] / nObs[s][r]; + rmse[s][r] = 100.0 * (Math.sqrt((sse[s][r] / (nObs[s][r] - 1))) / meanSize[s][r]); + } + + minRange[s] = maxSize[r]; + + } + + convergeLogger.info("%RMSE by DC Size Range Category"); + for (int i = 0; i < maxSize.length - 1; i++) + convergeLogger.info(String.format("< %-8.2f %12.2f", maxSize[i], rmse[s][i])); + convergeLogger.info(String + .format("%-8s %14.2f", " 1000+", rmse[s][maxSize.length - 1])); + + convergeLogger.info(""); + + convergeLogger.info("%Mean DC Size by DC Size Range Category"); + for (int i = 0; i < maxSize.length - 1; i++) + convergeLogger.info(String.format("< %-8.2f %12.2f", maxSize[i], meanSize[s][i])); + convergeLogger.info(String.format("%-8s %14.2f", " 1000+", + meanSize[s][maxSize.length - 1])); + + convergeLogger.info(""); + + convergeLogger.info("Freq of MGRAs by DC Size Range Category and Relative Error"); + for (int r = 0; r < maxSize.length - 1; r++) + { + + convergeLogger.info(String.format("Size < %-8.0f", maxSize[r])); + for (int i = 0; i < maxDeltas.length - 1; i++) + convergeLogger.info(String + .format("< %-8.2f %12d", maxDeltas[i], freqs[s][r][i])); + convergeLogger.info(String.format("%-8s %14d", " 1.0+", + freqs[s][r][maxDeltas.length - 1])); + + convergeLogger.info(""); + } + + convergeLogger.info(String.format("Size >= 1000")); + for (int i = 0; i < maxDeltas.length - 1; i++) + convergeLogger.info(String.format("< %-8.2f %12d", maxDeltas[i], + freqs[s][maxSize.length - 1][i])); + convergeLogger.info(String.format("%-8s %14d", " 1.0+", + freqs[s][maxSize.length - 1][maxDeltas.length - 1])); + + convergeLogger.info(""); + + } + + convergeLogger.info(""); + convergeLogger.info(""); + convergeLogger.info(""); + convergeLogger.info(""); + + } + + public void saveWorkMaxDiffValues(int iteration, int[][] modeledDestinationLocationsByDestMgra) + { + + // define labels for the schoolsegment categories + String[] segmentRangelabels = {"White Collar", "Services", "Health", "Retail and Food", + "Blue Collar", "Military"}; + + // define the highest index value for the range of segments for the + // school segment category + int[] segmentRange = {0, 1, 2, 3, 4, 5}; + + double[] maxSize = {10, 100, 1000, Double.MAX_VALUE}; + double[] maxDeltas = {0.05, 0.10, 0.25, 0.50, 1.0, 999.9}; + + int[][][] freqs = new int[segmentRangelabels.length][maxSize.length][maxDeltas.length]; + + int[][] nObs = new int[segmentRangelabels.length][maxSize.length]; + double[][] sse = new double[segmentRangelabels.length][maxSize.length]; + double[][] sumObs = new double[segmentRangelabels.length][maxSize.length]; + + double[][] rmse = new double[segmentRangelabels.length][maxSize.length]; + double[][] meanSize = new double[segmentRangelabels.length][maxSize.length]; + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + convergeLogger.info("Work Shadow Price Iteration " + iteration); + + double[] minRange = new double[segmentRangelabels.length]; + + int minS = 0; + for (int s = 0; s < segmentRangelabels.length; s++) + { + + convergeLogger.info(""); + convergeLogger.info(""); + convergeLogger.info(segmentRangelabels[s] + " convergence statistics"); + + if (s > 0) minS = segmentRange[s - 1] + 1; + + for (int r = 0; r < maxSize.length; r++) + { + + for (int i = minS; i <= segmentRange[s]; i++) + { + + for (int j = 1; j <= maxMgra; j++) + { + + if (scaledSize[i][j] > minRange[s] && scaledSize[i][j] <= maxSize[r]) + { + + if (modeledDestinationLocationsByDestMgra[i][j] > 0.0) + { + + int delta = maxDeltas.length - 1; + double diff = Math.abs(scaledSize[i][j] + - modeledDestinationLocationsByDestMgra[i][j]); + double relDiff = diff / scaledSize[i][j]; + for (int k = 0; k < maxDeltas.length; k++) + { + if (relDiff < maxDeltas[k]) + { + delta = k; + break; + } + } + + freqs[s][r][delta]++; + + // calculations for %RMSE + sse[s][r] += (diff * diff); + + } + + // calculations for %RMSE + sumObs[s][r] += scaledSize[i][j]; + nObs[s][r]++; + + } + + } + + } + + rmse[s][r] = -1.0; + if (nObs[s][r] > 1) + { + meanSize[s][r] = sumObs[s][r] / nObs[s][r]; + rmse[s][r] = 100.0 * (Math.sqrt((sse[s][r] / (nObs[s][r] - 1))) / meanSize[s][r]); + } + + minRange[s] = maxSize[r]; + + } + + convergeLogger.info("%RMSE by DC Size Range Category"); + for (int i = 0; i < maxSize.length - 1; i++) + convergeLogger.info(String.format("< %-8.2f %12.2f", maxSize[i], rmse[s][i])); + convergeLogger.info(String + .format("%-8s %14.2f", " 1000+", rmse[s][maxSize.length - 1])); + + convergeLogger.info(""); + + convergeLogger.info("%Mean DC Size by DC Size Range Category"); + for (int i = 0; i < maxSize.length - 1; i++) + convergeLogger.info(String.format("< %-8.2f %12.2f", maxSize[i], meanSize[s][i])); + convergeLogger.info(String.format("%-8s %14.2f", " 1000+", + meanSize[s][maxSize.length - 1])); + + convergeLogger.info(""); + + convergeLogger.info("Freq of MGRAs by DC Size Range Category and Relative Error"); + for (int r = 0; r < maxSize.length - 1; r++) + { + + convergeLogger.info(String.format("Size < %-8.0f", maxSize[r])); + for (int i = 0; i < maxDeltas.length - 1; i++) + convergeLogger.info(String + .format("< %-8.2f %12d", maxDeltas[i], freqs[s][r][i])); + convergeLogger.info(String.format("%-8s %14d", " 1.0+", + freqs[s][r][maxDeltas.length - 1])); + + convergeLogger.info(""); + } + + convergeLogger.info(String.format("Size >= 1000")); + for (int i = 0; i < maxDeltas.length - 1; i++) + convergeLogger.info(String.format("< %-8.2f %12d", maxDeltas[i], + freqs[s][maxSize.length - 1][i])); + convergeLogger.info(String.format("%-8s %14d", " 1.0+", + freqs[s][maxSize.length - 1][maxDeltas.length - 1])); + + convergeLogger.info(""); + } + + convergeLogger.info(""); + convergeLogger.info(""); + convergeLogger.info(""); + convergeLogger.info(""); + + } + + public boolean getSegmentIsInSkipSegmentSet(int segment) + { + return noShadowPriceSchoolSegmentIndices.contains(segment); + } + + public void updateShadowPricingInfo(int iteration, int[][] originsByHomeMgra, + int[][] modeledDestinationLocationsByDestMgra, String mandatoryType) + { + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + ArrayList tableHeadings = new ArrayList(); + tableHeadings.add("alt"); + tableHeadings.add("mgra"); + + for (int i = 0; i < numSegments; i++) + { + + String segmentString = segmentIndexNameMap.get(i); + + tableHeadings.add(String.format("%s_origins", segmentString)); + tableHeadings.add(String.format("%s_sizeOriginal", segmentString)); + tableHeadings.add(String.format("%s_sizeAdjOriginal", segmentString)); + tableHeadings.add(String.format("%s_sizeScaled", segmentString)); + tableHeadings.add(String.format("%s_sizePrevious", segmentString)); + tableHeadings.add(String.format("%s_modeledDests", segmentString)); + tableHeadings.add(String.format("%s_sizeFinal", segmentString)); + tableHeadings.add(String.format("%s_shadowPrices", segmentString)); + + } + + // define a TableDataSet for use in writing output file + float[][] tableData = new float[maxMgra + 1][tableHeadings.size()]; + + int alt = 0; + for (int i = 1; i <= maxMgra; i++) + { + + tableData[alt][0] = alt + 1; + tableData[alt][1] = i; + + int index = 2; + + for (int p = 0; p < numSegments; p++) + { + tableData[alt][index++] = (float) originsByHomeMgra[p][i]; + tableData[alt][index++] = (float) originalSize[p][i]; + tableData[alt][index++] = (float) originalAdjSize[p][i]; + tableData[alt][index++] = (float) scaledSize[p][i]; + tableData[alt][index++] = (float) previousSize[p][i]; + tableData[alt][index++] = (float) modeledDestinationLocationsByDestMgra[p][i]; + tableData[alt][index++] = (float) dcSize[p][i]; + tableData[alt][index++] = (float) shadowPrice[p][i]; + } + alt++; + + } + + TableDataSet outputTable = TableDataSet.create(tableData, tableHeadings); + + // write outputTable to new output file + try + { + String newFilename = this.dcShadowOutputFileName.replaceFirst(".csv", "_" + + mandatoryType + "_" + iteration + ".csv"); + CSVFileWriter writer = new CSVFileWriter(); + writer.writeFile(outputTable, new File(newFilename), + new DecimalFormat("#.000000000000")); + // writer.writeFile( outputTable, new File(newFilename) ); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + // save scaled size variables used in shadow price adjustmnents for + // reporting + // to output file + for (int i = 0; i < numSegments; i++) + previousSize[i] = duplicateDouble1DArray(dcSize[i]); + + } + + public void restoreShadowPricingInfo(String fileName) + { + + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + + TableDataSet tds = null; + try + { + tds = reader.readFileAsDouble(new File(fileName)); + } catch (IOException e) + { + logger.error("exception reading saved shadow price file: " + fileName + + " from previous model run.", e); + } + + // the following are based on format used to write the shadow pricing + // file + // first three columns are indices: ALT, ZONE, SUBZONE. + int columnIndex = 2; + int numberOfColumnsPerPurpose = 8; + int scaledSizeColumnOffset = 3; + int previousSizeColumnOffset = 4; + int finalSizeColumnOffset = 6; + int finalShadowPriceOffset = 7; + + // get the number of MGRAs + int maxMgra = mgraManager.getMaxMgra(); + + for (int i = 0; i < numSegments; i++) + { + + // first restore the scaled size values; getColumnAsFloat(column) + // takes a + // 1s based column value, returns a 0s based array of values + int column = columnIndex + i * numberOfColumnsPerPurpose + scaledSizeColumnOffset + 1; + double[] columnData = tds.getColumnAsDoubleFromDouble(column); + for (int z = 1; z <= maxMgra; z++) + scaledSize[i][z] = columnData[z - 1]; + + // next restore the final size values + column = columnIndex + i * numberOfColumnsPerPurpose + finalSizeColumnOffset + 1; + columnData = tds.getColumnAsDoubleFromDouble(column); + for (int z = 1; z <= maxMgra; z++) + dcSize[i][z] = columnData[z - 1]; + + // next restore the previous size values from the final size of the + // previous iteration + column = columnIndex + i * numberOfColumnsPerPurpose + finalSizeColumnOffset + 1; + columnData = tds.getColumnAsDoubleFromDouble(column); + for (int z = 1; z <= maxMgra; z++) + previousSize[i][z] = columnData[z - 1]; + + // finally restore the final shadow price values + column = columnIndex + i * numberOfColumnsPerPurpose + finalShadowPriceOffset + 1; + columnData = tds.getColumnAsDoubleFromDouble(column); + for (int z = 1; z <= maxMgra; z++) + shadowPrice[i][z] = columnData[z - 1]; + + } + + } + + /** + * Create a new double[], dimension it exactly as the argument array, and + * copy the element values from the argument array to the new one. + * + * @param in + * a 1-dimension double array to be duplicated + * @return an exact duplicate of the argument array + */ + private double[] duplicateDouble1DArray(double[] in) + { + double[] out = new double[in.length]; + for (int i = 0; i < in.length; i++) + { + out[i] = in[i]; + } + return out; + } + + /** + * Create a new double[][], dimension it exactly as the argument array, and + * copy the element values from the argument array to the new one. + * + * @param in + * a 2-dimensional double array to be duplicated + * @return an exact duplicate of the argument array + */ + private double[][] duplicateDouble2DArray(double[][] in) + { + double[][] out = new double[in.length][]; + for (int i = 0; i < in.length; i++) + { + out[i] = new double[in[i].length]; + for (int j = 0; j < in[i].length; j++) + { + out[i][j] = in[i][j]; + } + } + return out; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageModel.java new file mode 100644 index 0000000..afb76d0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageModel.java @@ -0,0 +1,625 @@ +package org.sandag.abm.ctramp; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +public class DestChoiceTwoStageModel +{ + + private transient Logger logger = Logger.getLogger(DestChoiceTwoStageModel.class); + + // dimensioned for maxMgra, holds the number of times a specific mgra was + // selected to be in the the sample + private int[] mgraSampleFreq; + + // these arrays are dimesnioned to the maxSampleSize and hold values mgra + // selected for the sample. + private int[] sampleMgras; + private double[] sampleProbabilities; + + // these arrays are dimesnioned to the maxSampleSize, but hold values up to + // the number of unique mgras selected for the sample. + // array values after the number of unique selected mgras are default array + // values. + private int[] uniqueMgraSample; + private double[] uniqueCorrectionFactors; + + // this array holds the sampleIndex associated with a unique mgra, and is + // used to lookup the sample probability for the unique mgra. + private int[] uniqueSampleIndices; + + // use this variable to keep track of the number of unique sampled mgras + // while choosing the sample + private int uniqueIndex; + + private TazDataManager tdm; + private MgraDataManager mgraManager; + + // for each purpose index, the 2D array is 0-based on origTaz and is 0-based + // on destTaz, giving cumulative taz distance probabilities. + private double[][][] tazDistCumProbs; + + // for each purpose index, the 2D array is 0-based on TAZ and is 0-based on + // MGRAs in the taz, giving size probabilities for MGRAs in the TAZ. + private double[][][] mgraSizeProbs; + + private double[][][] slcSizeProbs; + private double[][] slcTazSize; + private double[][] slcTazDistExpUtils; + + // create an array to re-use to hold cumulative probabilities for selecting + // an MGRA from a TAZ. + private double[] tempMgraCumProbs = new double[200]; + + private double[] slcTazProbs; + private double[] slcTazCumProbs; + private int maxTaz; + + private long soaRunTime; + + public DestChoiceTwoStageModel(HashMap propertyMap, int soaMaxSampleSize) + { + + mgraManager = MgraDataManager.getInstance(propertyMap); + int maxMgra = mgraManager.getMaxMgra(); + + tdm = TazDataManager.getInstance(propertyMap); + maxTaz = tdm.getMaxTaz(); + + slcTazProbs = new double[maxTaz]; + slcTazCumProbs = new double[maxTaz]; + + mgraSampleFreq = new int[maxMgra + 1]; + + sampleMgras = new int[soaMaxSampleSize]; + sampleProbabilities = new double[soaMaxSampleSize]; + + uniqueMgraSample = new int[soaMaxSampleSize]; + uniqueCorrectionFactors = new double[soaMaxSampleSize]; + + uniqueSampleIndices = new int[soaMaxSampleSize]; + } + + private void resetSampleArrays() + { + Arrays.fill(mgraSampleFreq, 0); + Arrays.fill(sampleMgras, 0); + Arrays.fill(sampleProbabilities, 0); + Arrays.fill(uniqueMgraSample, 0); + Arrays.fill(uniqueSampleIndices, -1); + Arrays.fill(uniqueCorrectionFactors, 0); + uniqueIndex = 0; + } + + /** + * get the array of unique mgras selected in the sample. The number of + * unique mgras may be fewer than the number selected for the sample - the + * overall sample size. If so, values in this array from + * 0,...,numUniqueMgras-1 will be the selected unique mgras, and values from + * numUniqueMgras,...,maxSampleSize-1 will be 0. + * + * @return uniqueMgraSample array. + */ + public int[] getUniqueSampleMgras() + { + return uniqueMgraSample; + } + + /** + * get the number of unique mgra values in the sample. It gives the + * upperbound of unique values in uniqueMgraSample[0,...,numUniqueMgras-1]. + * + * @return number of unique mgra values in the sample + */ + public int getNumberofUniqueMgrasInSample() + { + return uniqueIndex; + } + + public double[] getUniqueSampleMgraCorrectionFactors() + { + + for (int i = 0; i < uniqueIndex; i++) + { + int chosenMgra = uniqueMgraSample[i]; + int freq = mgraSampleFreq[chosenMgra]; + + int sampleIndex = uniqueSampleIndices[i]; + double prob = sampleProbabilities[sampleIndex]; + + uniqueCorrectionFactors[i] = (float) Math.log((double) freq / prob); + } + + return uniqueCorrectionFactors; + } + + public void computeSoaProbabilities(int origTaz, int segmentTypeIndex) + { + + double[][] sizeProbs = mgraSizeProbs[segmentTypeIndex]; + double[] probs = new double[mgraManager.getMaxMgra() + 1]; + + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + + int[] mgraArray = tdm.getMgraArray(taz); + if (mgraArray == null) continue; + + if (sizeProbs[taz - 1].length == 0) continue; + + double tazProb = 0; + if (taz > 1) tazProb = tazDistCumProbs[segmentTypeIndex][origTaz - 1][taz - 1] + - tazDistCumProbs[segmentTypeIndex][origTaz - 1][taz - 2]; + else tazProb = tazDistCumProbs[segmentTypeIndex][origTaz - 1][0]; + + for (int mgraIndex = 0; mgraIndex < mgraArray.length; mgraIndex++) + { + double mgraProb = sizeProbs[taz - 1][mgraIndex]; + probs[mgraArray[mgraIndex]] = tazProb * mgraProb; + } + + } + + PrintWriter out = null; + try + { + out = new PrintWriter(new BufferedWriter(new FileWriter(new File("distSoaProbs.csv")))); + + for (int i = 1; i < probs.length; i++) + { + out.println(i + "," + probs[i]); + } + } catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + out.close(); + + } + + public void chooseSampleMgra(int sampleIndex, int origTaz, int sizePurposeIndex, + int segmentTypeIndex, double rn, boolean debug) + { + + // get the chosen TAZ array index for the 0-based cumulative TAZ + // distance probabilities array + int chosenTazIndex = Util.binarySearchDouble( + tazDistCumProbs[segmentTypeIndex][origTaz - 1], rn); + + if (mgraSizeProbs[segmentTypeIndex][chosenTazIndex].length == 0) + { + logger.error("The MGRA size probabilities array for chosen TAZ index = " + + chosenTazIndex + " has 0 length."); + logger.error("This should not be the case. If a TAZ was chosen, its TAZ Size > 0, so there should be at least one MGRA with size > 0 in the TAZ."); + logger.error("Likely cause is an indexing bug. sampleIndex=" + sampleIndex + + ", origTaz=" + origTaz + ", sizePurposeIndex=" + sizePurposeIndex + + ", segmentTypeIndex=" + segmentTypeIndex); + throw new RuntimeException(); + } + + // get the chosen TAZ distance probability from the taz distance + // cumulative probabilities array + // also initialize the 0 index cumulative MGRA probability to the + // cumulative taz distance propbaility + double tazProb = 0; + double cumProbabilityLowerBound = 0; + if (chosenTazIndex > 0) + { + tazProb = tazDistCumProbs[segmentTypeIndex][origTaz - 1][chosenTazIndex] + - tazDistCumProbs[segmentTypeIndex][origTaz - 1][chosenTazIndex - 1]; + cumProbabilityLowerBound = tazDistCumProbs[segmentTypeIndex][origTaz - 1][chosenTazIndex - 1]; + } else + { + tazProb = tazDistCumProbs[segmentTypeIndex][origTaz - 1][0]; + cumProbabilityLowerBound = 0; + } + + // get the array of MGRAs for the chosen TAZ (the chosen index + 1) + int[] mgraArray = tdm.getMgraArray(chosenTazIndex + 1); + + // get the unscaled MGRA size probability, scale by the TAZ distance + // probability, and accumulate cumulative probabilities + tempMgraCumProbs[0] = cumProbabilityLowerBound + + (mgraSizeProbs[segmentTypeIndex][chosenTazIndex][0] * tazProb); + for (int i = 1; i < mgraArray.length; i++) + tempMgraCumProbs[i] = tempMgraCumProbs[i - 1] + + (mgraSizeProbs[segmentTypeIndex][chosenTazIndex][i] * tazProb); + + // get the chosen array index for the 0-based cumulative probabilities + // array + int chosenMgraIndex = Util.binarySearchDouble(cumProbabilityLowerBound, tempMgraCumProbs, + mgraArray.length, rn); + + // use the chosen mgra index to get the chosenMgra value from the + // 0-based array of MGRAs associated with the chosen TAZ + int chosenMgra = mgraArray[chosenMgraIndex]; + + // store the sampled mgra and its selection probability + sampleMgras[sampleIndex] = chosenMgra; + sampleProbabilities[sampleIndex] = (mgraSizeProbs[segmentTypeIndex][chosenTazIndex][chosenMgraIndex] * tazProb); + + // if the sample freq is 0, this mgra has not been selected yet, so add + // it to the array of unique sampled mgras. + if (mgraSampleFreq[chosenMgra] == 0) + { + uniqueMgraSample[uniqueIndex] = chosenMgra; + uniqueSampleIndices[uniqueIndex] = sampleIndex; + uniqueIndex++; + } + + // increment the frequency of times this mgra was selected for the + // sample + mgraSampleFreq[chosenMgra]++; + + if (debug) + { + + double cumDistProb = 0; + double prevDistCumProb = 0; + if (chosenTazIndex > 1) + { + cumDistProb = tazDistCumProbs[segmentTypeIndex][origTaz - 1][chosenTazIndex]; + prevDistCumProb = tazDistCumProbs[segmentTypeIndex][origTaz - 1][chosenTazIndex - 1]; + } else + { + cumDistProb = tazDistCumProbs[segmentTypeIndex][origTaz - 1][0]; + prevDistCumProb = 0; + } + + double cumSizeProb = 0; + double prevSizeCumProb = 0; + if (chosenMgraIndex > 0) + { + cumSizeProb = tempMgraCumProbs[chosenMgraIndex]; + prevSizeCumProb = tempMgraCumProbs[chosenMgraIndex - 1]; + } else + { + cumSizeProb = tempMgraCumProbs[0]; + prevSizeCumProb = 0; + } + + logger.info(String.format( + "%-12d %10d %10.6f %16.8f %16.8f %18d %18.8f %18.8f %12d %18.8f", sampleIndex, + chosenTazIndex, rn, prevDistCumProb, cumDistProb, chosenMgraIndex, + prevSizeCumProb, cumSizeProb, chosenMgra, + ((cumSizeProb - prevSizeCumProb) * (cumDistProb - prevDistCumProb)))); + } + + } + + private void chooseSlcSampleMgraBinarySearch(int sampleIndex, int slcOrigTaz, int slcDestTaz, + int slcSizeSegmentIndex, double rn, boolean debug) + { + + // compute stop location sample probabilities from the pre-computed + // sample exponentiated utilities and taz size terms. + // first compute exponentiated utilites for each alternative from the + // pre-computed component exponentiated utilities + double totalExponentiatedUtility = 0; + for (int k = 0; k < maxTaz; k++) + { + slcTazProbs[k] = (slcTazDistExpUtils[slcOrigTaz - 1][k] + * slcTazDistExpUtils[k][slcDestTaz - 1] / slcTazDistExpUtils[slcOrigTaz - 1][slcDestTaz - 1]) + * slcTazSize[slcSizeSegmentIndex][k + 1]; + totalExponentiatedUtility += slcTazProbs[k]; + } + + // now compute alterantive probabilities and determine selected + // alternative + slcTazCumProbs[0] = slcTazProbs[0] / totalExponentiatedUtility; + for (int k = 1; k < maxTaz - 1; k++) + slcTazCumProbs[k] = slcTazCumProbs[k - 1] + + (slcTazProbs[k] / totalExponentiatedUtility); + slcTazCumProbs[maxTaz - 1] = 1.0; + + // get the chosen TAZ array index for the 0-based cumulative TAZ + // distance probabilities array + int chosenTazIndex = Util.binarySearchDouble(slcTazCumProbs, rn); + + /* + * // now compute alterantive probabilities and determine selected + * alternative int chosenTazIndex0 = -1; double sum = slcTazProbs[0] / + * totalExponentiatedUtility; if ( rn < sum ) { chosenTazIndex0 = 0; } + * else { for ( int k=1; k < maxTaz; k++ ) { slcTazProbs[k] /= + * totalExponentiatedUtility; sum += slcTazProbs[k]; if ( rn < sum ) { + * chosenTazIndex0 = k; break; } } } + * + * + * if ( chosenTazIndex0 != chosenTazIndex ) { logger.error ( + * "error - inconsistent choices made by two alternative monte carlo methods. " + * ); System.exit(-1); } + */ + + if (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex].length == 0) + { + logger.error("The MGRA size probabilities array for chosen stop location TAZ index = " + + chosenTazIndex + " has 0 length."); + logger.error("This should not be the case. If a TAZ was chosen, its TAZ Size > 0, so there should be at least one MGRA with size > 0 in the TAZ."); + logger.error("Likely cause is an indexing bug. sampleIndex=" + sampleIndex + + ", slcOrigTaz=" + slcOrigTaz + ", slcDestTaz=" + slcDestTaz + + ", slcSizeSegmentIndex=" + slcSizeSegmentIndex); + throw new RuntimeException(); + } + + // get the chosen SLC TAZ distance probability from the taz distance + // cumulative probabilities array + // also initialize the 0 index cumulative MGRA probability to the + // cumulative taz distance propbaility + double tazProb = 0; + double cumProbabilityLowerBound = 0; + if (chosenTazIndex > 0) + { + tazProb = slcTazCumProbs[chosenTazIndex] - slcTazCumProbs[chosenTazIndex - 1]; + cumProbabilityLowerBound = slcTazCumProbs[chosenTazIndex - 1]; + } else + { + tazProb = slcTazCumProbs[0]; + cumProbabilityLowerBound = 0; + } + + // get the array of MGRAs for the chosen TAZ (the chosen index + 1) + int[] mgraArray = tdm.getMgraArray(chosenTazIndex + 1); + + // get the unscaled MGRA size probability, scale by the TAZ distance + // probability, and accumulate cumulative probabilities + tempMgraCumProbs[0] = cumProbabilityLowerBound + + (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][0] * tazProb); + for (int i = 1; i < mgraArray.length; i++) + tempMgraCumProbs[i] = tempMgraCumProbs[i - 1] + + (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][i] * tazProb); + + // get the chosen array index for the 0-based cumulative probabilities + // array + int chosenMgraIndex = Util.binarySearchDouble(cumProbabilityLowerBound, tempMgraCumProbs, + mgraArray.length, rn); + + // use the chosen mgra index to get the chosenMgra value from the + // 0-based array of MGRAs associated with the chosen TAZ + int chosenMgra = mgraArray[chosenMgraIndex]; + + // store the sampled mgra and its selection probability + sampleMgras[sampleIndex] = chosenMgra; + sampleProbabilities[sampleIndex] = (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][chosenMgraIndex] * tazProb); + + // if the sample freq is 0, this mgra has not been selected yet, so add + // it to the array of unique sampled mgras. + if (mgraSampleFreq[chosenMgra] == 0) + { + uniqueMgraSample[uniqueIndex] = chosenMgra; + uniqueSampleIndices[uniqueIndex] = sampleIndex; + uniqueIndex++; + } + + // increment the frequency of times this mgra was selected for the + // sample + mgraSampleFreq[chosenMgra]++; + + } + + private void chooseSlcSampleMgraLinearWalk(int sampleIndex, int slcOrigTaz, int slcDestTaz, + int slcSizeSegmentIndex, double rn, boolean debug) + { + + // compute stop location sample probabilities from the pre-computed + // sample exponentiated utilities and taz size terms. + // first compute exponentiated utilites for each alternative from the + // pre-computed component exponentiated utilities + double totalExponentiatedUtility = 0; + for (int k = 0; k < maxTaz; k++) + { + slcTazProbs[k] = (slcTazDistExpUtils[slcOrigTaz - 1][k] + * slcTazDistExpUtils[k][slcDestTaz - 1] / slcTazDistExpUtils[slcOrigTaz - 1][slcDestTaz - 1]) + * slcTazSize[slcSizeSegmentIndex][k + 1]; + totalExponentiatedUtility += slcTazProbs[k]; + } + + /* + * // now compute alterantive probabilities and determine selected + * alternative slcTazCumProbs[0] = slcTazProbs[0] / + * totalExponentiatedUtility; for ( int k=1; k < maxTaz - 1; k++ ) + * slcTazCumProbs[k] = slcTazCumProbs[k-1] + (slcTazProbs[k] / + * totalExponentiatedUtility); slcTazCumProbs[maxTaz - 1] = 1.0; + * + * + * /* // get the chosen TAZ array index for the 0-based cumulative TAZ + * distance probabilities array int chosenTazIndex0 = + * Util.binarySearchDouble( slcTazCumProbs, rn ); + */ + + // now compute alterantive probabilities and determine selected + // alternative + int chosenTazIndex = -1; + double sum = slcTazProbs[0] / totalExponentiatedUtility; + double cumProbabilityLowerBound = 0; + double tazProb = 0; + if (rn < sum) + { + chosenTazIndex = 0; + tazProb = sum; + } else + { + for (int k = 1; k < maxTaz; k++) + { + tazProb = slcTazProbs[k] / totalExponentiatedUtility; + cumProbabilityLowerBound = sum; + sum += tazProb; + if (rn < sum) + { + chosenTazIndex = k; + break; + } + } + } + + /* + * if ( chosenTazIndex0 != chosenTazIndex ) { logger.error ( + * "error - inconsistent choices made by two alternative monte carlo methods. " + * ); System.exit(-1); } + */ + + if (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex].length == 0) + { + logger.error("The MGRA size probabilities array for chosen stop location TAZ index = " + + chosenTazIndex + " has 0 length."); + logger.error("This should not be the case. If a TAZ was chosen, its TAZ Size > 0, so there should be at least one MGRA with size > 0 in the TAZ."); + logger.error("Likely cause is an indexing bug. sampleIndex=" + sampleIndex + + ", slcOrigTaz=" + slcOrigTaz + ", slcDestTaz=" + slcDestTaz + + ", slcSizeSegmentIndex=" + slcSizeSegmentIndex); + throw new RuntimeException(); + } + + /* + * // get the chosen SLC TAZ distance probability from the taz distance + * cumulative probabilities array // also initialize the 0 index + * cumulative MGRA probability to the cumulative taz distance + * propbaility double tazProb = 0; double cumProbabilityLowerBound = 0; + * if ( chosenTazIndex > 0 ) { tazProb = slcTazCumProbs[chosenTazIndex] + * - slcTazCumProbs[chosenTazIndex-1]; cumProbabilityLowerBound = + * slcTazCumProbs[chosenTazIndex-1]; } else { tazProb = + * slcTazCumProbs[0]; cumProbabilityLowerBound = 0; } + */ + + // get the array of MGRAs for the chosen TAZ (the chosen index + 1) + int[] mgraArray = tdm.getMgraArray(chosenTazIndex + 1); + + /* + * // get the unscaled MGRA size probability, scale by the TAZ distance + * probability, and accumulate cumulative probabilities + * tempMgraCumProbs[0] = cumProbabilityLowerBound + ( + * slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][0] * tazProb ); for + * ( int i=1; i < mgraArray.length; i++ ) tempMgraCumProbs[i] = + * tempMgraCumProbs[i-1] + ( + * slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][i] * tazProb ); + */ + + // now compute alterantive probabilities and determine selected + // alternative + int chosenMgraIndex = -1; + sum = cumProbabilityLowerBound + + (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][0] * tazProb); + if (rn < sum) + { + chosenMgraIndex = 0; + } else + { + for (int k = 1; k < mgraArray.length; k++) + { + sum += (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][k] * tazProb); + if (rn < sum) + { + chosenMgraIndex = k; + break; + } + } + } + + /* + * // get the chosen array index for the 0-based cumulative + * probabilities array int chosenMgraIndex = Util.binarySearchDouble( + * cumProbabilityLowerBound, tempMgraCumProbs, mgraArray.length, rn ); + */ + + // use the chosen mgra index to get the chosenMgra value from the + // 0-based array of MGRAs associated with the chosen TAZ + int chosenMgra = mgraArray[chosenMgraIndex]; + + // store the sampled mgra and its selection probability + sampleMgras[sampleIndex] = chosenMgra; + sampleProbabilities[sampleIndex] = (slcSizeProbs[slcSizeSegmentIndex][chosenTazIndex][chosenMgraIndex] * tazProb); + + // if the sample freq is 0, this mgra has not been selected yet, so add + // it to the array of unique sampled mgras. + if (mgraSampleFreq[chosenMgra] == 0) + { + uniqueMgraSample[uniqueIndex] = chosenMgra; + uniqueSampleIndices[uniqueIndex] = sampleIndex; + uniqueIndex++; + } + + // increment the frequency of times this mgra was selected for the + // sample + mgraSampleFreq[chosenMgra]++; + + } + + public void chooseSample(int origTaz, int sizeSegmentIndex, int segmentTypeIndex, + int numInSample, Random rand, boolean debug) + { + + long timeCheck = System.nanoTime(); + + if (debug) + { + computeSoaProbabilities(origTaz, segmentTypeIndex); + } + + resetSampleArrays(); + for (int i = 0; i < numInSample; i++) + { + chooseSampleMgra(i, origTaz, sizeSegmentIndex, segmentTypeIndex, rand.nextDouble(), + debug); + } + + soaRunTime += (System.nanoTime() - timeCheck); + + } + + public void chooseSlcSample(int origTaz, int destTaz, int sizeSegmentIndex, int numInSample, + Random rand, boolean debug) + { + + long timeCheck = System.nanoTime(); + + resetSampleArrays(); + for (int i = 0; i < numInSample; i++) + { + // chooseSlcSampleMgraBinarySearch( i, origTaz, destTaz, + // sizeSegmentIndex, rand.nextDouble(), debug ); + chooseSlcSampleMgraLinearWalk(i, origTaz, destTaz, sizeSegmentIndex, rand.nextDouble(), + debug); + } + + soaRunTime += (System.nanoTime() - timeCheck); + + } + + public void setSlcSoaProbsAndUtils(double[][] slcTazDistExpUtils, double[][][] slcSizeProbs, + double[][] slcTazSize) + { + this.slcSizeProbs = slcSizeProbs; + this.slcTazSize = slcTazSize; + this.slcTazDistExpUtils = slcTazDistExpUtils; + } + + public void setMgraSizeProbs(double[][][] probs) + { + mgraSizeProbs = probs; + } + + public void setTazDistProbs(double[][][] probs) + { + tazDistCumProbs = probs; + } + + public long getSoaRunTime() + { + return soaRunTime; + } + + public void resetSoaRunTime() + { + soaRunTime = 0; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageModelDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageModelDMU.java new file mode 100644 index 0000000..a23453c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageModelDMU.java @@ -0,0 +1,408 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public abstract class DestChoiceTwoStageModelDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(DestChoiceTwoStageModelDMU.class); + + protected HashMap methodIndexMap; + + protected Household hh; + protected Person person; + protected Tour tour; + protected IndexValues dmuIndex = null; + + protected double workAccessibility; + protected double nonMandatoryAccessibility; + + protected double[] homeMgraNonMandatoryAccessibilityArray; + protected double[] homeMgraTotalEmploymentAccessibilityArray; + + protected int[] sampleMgras; + protected double[] modeChoiceLogsums; + protected double[] dcSoaCorrections; + + protected double[] mgraSizeArray; + protected double[] mgraDistanceArray; + + protected int toursLeftCount; + + protected ModelStructure modelStructure; + protected MgraDataManager mgraManager; + protected BuildAccessibilities aggAcc; + protected AccessibilitiesTable accTable; + + public DestChoiceTwoStageModelDMU(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + initDmuObject(); + } + + public abstract void setMcLogsum(int mgra, double logsum); + + private void initDmuObject() + { + + dmuIndex = new IndexValues(); + + // create default objects - some choice models use these as place + // holders for values + person = new Person(null, -1, modelStructure); + hh = new Household(modelStructure); + + mgraManager = MgraDataManager.getInstance(); + + int maxMgra = mgraManager.getMaxMgra(); + + modeChoiceLogsums = new double[maxMgra + 1]; + dcSoaCorrections = new double[maxMgra + 1]; + + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + public void setPersonObject(Person personObject) + { + person = personObject; + } + + public void setTourObject(Tour tour) + { + this.tour = tour; + } + + public void setAggAcc(BuildAccessibilities aggAcc) + { + this.aggAcc = aggAcc; + } + + public void setAccTable(AccessibilitiesTable myAccTable) + { + accTable = myAccTable; + } + + public void setMgraSizeArray(double[] mgraSizeArray) + { + this.mgraSizeArray = mgraSizeArray; + } + + public void setMgraDistanceArray(double[] mgraDistanceArray) + { + this.mgraDistanceArray = mgraDistanceArray; + } + + public void setSampleArray(int[] sampleArray) + { + sampleMgras = sampleArray; + } + + public void setDcSoaCorrections(double[] sampleCorrections) + { + dcSoaCorrections = sampleCorrections; + } + + public void setNonMandatoryAccessibility(double nonMandatoryAccessibility) + { + this.nonMandatoryAccessibility = nonMandatoryAccessibility; + } + + public void setToursLeftCount(int count) + { + toursLeftCount = count; + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug DC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public Household getHouseholdObject() + { + return hh; + } + + public Person getPersonObject() + { + return person; + } + + // DMU methods - define one of these for every @var in the mode choice + // control + // file. + + protected int getToursLeftCount() + { + return toursLeftCount; + } + + protected int getMaxContinuousAvailableWindow() + { + + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) return hh + .getMaxJointTimeWindow(tour); + else return person.getMaximumContinuousAvailableWindow(); + } + + protected double getDcSoaCorrectionsAlt(int alt) + { + return dcSoaCorrections[alt - 1]; + } + + protected double getMcLogsumDestAlt(int alt) + { + return modeChoiceLogsums[alt - 1]; + } + + protected double getPopulationDestAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return aggAcc.getMgraPopulation(mgra); + } + + protected double getHouseholdsDestAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return aggAcc.getMgraHouseholds(mgra); + } + + protected double getGradeSchoolEnrollmentDestAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return aggAcc.getMgraGradeSchoolEnrollment(mgra); + } + + protected double getHighSchoolEnrollmentDestAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return aggAcc.getMgraHighSchoolEnrollment(mgra); + } + + protected double getUniversityEnrollmentDestAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return aggAcc.getMgraUniversityEnrollment(mgra); + } + + protected double getOtherCollegeEnrollmentDestAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return aggAcc.getMgraOtherCollegeEnrollment(mgra); + } + + protected double getAdultSchoolEnrollmentDestAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return aggAcc.getMgraAdultSchoolEnrollment(mgra); + } + + protected int getIncome() + { + return hh.getIncomeCategory(); + } + + protected int getIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + protected int getAutos() + { + return hh.getAutosOwned(); + } + + protected int getWorkers() + { + return hh.getWorkers(); + } + + protected int getNumberOfNonWorkingAdults() + { + return hh.getNumberOfNonWorkingAdults(); + } + + protected int getNumPreschool() + { + return hh.getNumPreschool(); + } + + public int getNumGradeSchoolStudents() + { + return hh.getNumGradeSchoolStudents(); + } + + public int getNumHighSchoolStudents() + { + return hh.getNumHighSchoolStudents(); + } + + protected int getNumChildrenUnder16() + { + return hh.getNumChildrenUnder16(); + } + + protected int getNumChildrenUnder19() + { + return hh.getNumChildrenUnder19(); + } + + protected int getAge() + { + return person.getAge(); + } + + protected int getFemaleWorker() + { + if (person.getPersonIsFemale() == 1) return 1; + else return 0; + } + + protected int getFemale() + { + if (person.getPersonIsFemale() == 1) return 1; + else return 0; + } + + protected int getFullTimeWorker() + { + if (person.getPersonIsFullTimeWorker() == 1) return 1; + else return 0; + } + + protected int getTypicalUniversityStudent() + { + return person.getPersonIsTypicalUniversityStudent(); + } + + protected int getPersonType() + { + return person.getPersonTypeNumber(); + } + + protected int getPersonHasBachelors() + { + return person.getHasBachelors(); + } + + protected int getPersonIsWorker() + { + return person.getPersonIsWorker(); + } + + protected int getWorkTaz() + { + return person.getWorkLocation(); + } + + protected int getWorkTourModeIsSOV() + { + boolean tourModeIsSov = modelStructure.getTourModeIsSov(tour.getTourModeChoice()); + if (tourModeIsSov) return 1; + else return 0; + } + + protected int getTourIsJoint() + { + return tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY) ? 1 + : 0; + } + + protected double getTotEmpAccessibilityAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return homeMgraTotalEmploymentAccessibilityArray[mgra]; + } + + protected double getNonMandatoryAccessibilityAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return accTable.getAggregateAccessibility("nonmotor", mgra); + } + + protected double getOpSovDistanceAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return mgraDistanceArray[mgra]; + } + + protected double getLnDcSizeAlt(int alt) + { + int mgra = sampleMgras[alt - 1]; + return Math.log(mgraSizeArray[mgra] + 1); + } + + protected void setWorkAccessibility(double accessibility) + { + workAccessibility = accessibility; + } + + protected double getWorkAccessibility() + { + return workAccessibility; + } + + protected double getNonMandatoryAccessibility() + { + return nonMandatoryAccessibility; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageSoaProbabilitiesCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageSoaProbabilitiesCalculator.java new file mode 100644 index 0000000..c04c83e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageSoaProbabilitiesCalculator.java @@ -0,0 +1,159 @@ +package org.sandag.abm.ctramp; + +import java.util.Arrays; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class DestChoiceTwoStageSoaProbabilitiesCalculator +{ + + private transient Logger soaTwoStageProbsLogger = Logger.getLogger("soaTwoStageProbsLogger"); + + private TazDataManager tdm; + private int maxTaz; + + private ChoiceModelApplication cm; + + public DestChoiceTwoStageSoaProbabilitiesCalculator(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory, String soaDistUECPropertyKey, + String soaDistUECModelSheetPropertyKey, String soaDistUECDataSheetPropertyKey) + { + + tdm = TazDataManager.getInstance(propertyMap); + maxTaz = tdm.getMaxTaz(); + + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String soaDistUecFileName = propertyMap.get(soaDistUECPropertyKey); + soaDistUecFileName = uecFileDirectory + soaDistUecFileName; + int soaModelPage = Integer.parseInt(propertyMap.get(soaDistUECModelSheetPropertyKey)); + int soaDataPage = Integer.parseInt(propertyMap.get(soaDistUECDataSheetPropertyKey)); + + DestChoiceTwoStageSoaTazDistanceUtilityDMU tazDistUtilityDmu = dmuFactory + .getDestChoiceSoaTwoStageTazDistUtilityDMU(); + + // create a ChoiceModelApplication object for the filename, model page + // and data page. + cm = new ChoiceModelApplication(soaDistUecFileName, soaModelPage, soaDataPage, propertyMap, + (VariableTable) tazDistUtilityDmu); + + } + + /** + * @param dmuObject + * is the distance utility DMU object + */ + public double[][] computeDistanceUtilities(DestChoiceTwoStageSoaTazDistanceUtilityDMU dmuObject) + { + + double[][] tazDistUtils = new double[maxTaz][maxTaz]; + IndexValues iv = new IndexValues(); + dmuObject.setIndexValuesObject(iv); + + // Loop through combinations of orig/dest TAZs and compute OD utilities + for (int i = 0; i < tazDistUtils.length; i++) + { + iv.setOriginZone(i + 1); + iv.setZoneIndex(i + 1); + cm.computeUtilities(dmuObject, iv); + tazDistUtils[i] = Arrays.copyOf(cm.getUtilities(), tazDistUtils.length); + } + + return tazDistUtils; + } + + /** + * @param dmuObject + * is the distance utility DMU object + * @param distUtilityIndex + * is the distance utility segment index This method signature is + * the default, assuming that no distance probabilities logging + * is required + */ + public double[][] computeDistanceProbabilities( + DestChoiceTwoStageSoaTazDistanceUtilityDMU dmuObject) + { + + double[][] tazDistProbs = new double[maxTaz][maxTaz]; + IndexValues iv = new IndexValues(); + dmuObject.setIndexValuesObject(iv); + + // Loop through combinations of orig/dest TAZs and compute OD utilities + for (int i = 0; i < tazDistProbs.length; i++) + { + iv.setOriginZone(i + 1); + iv.setZoneIndex(i + 1); + cm.computeUtilities(dmuObject, iv); + double[] tempArray = Arrays + .copyOf(cm.getCumulativeProbabilities(), tazDistProbs.length); + tazDistProbs[i] = tempArray; + } + + return tazDistProbs; + } + + /** + * @param dmuObject + * is the distance utility DMU object + * @param distUtilityIndex + * is the distance utility segment index This alternative method + * signature allows distance probabilities logging to be written + */ + public double[][] computeDistanceProbabilities(int traceOrig, + DestChoiceTwoStageSoaTazDistanceUtilityDMU dmuObject) + { + + double[][] tazDistProbs = new double[maxTaz][maxTaz]; + IndexValues iv = new IndexValues(); + dmuObject.setIndexValuesObject(iv); + + // Loop through combinations of orig/dest TAZs and compute OD utilities + for (int i = 0; i < tazDistProbs.length; i++) + { + + iv.setOriginZone(i + 1); + iv.setZoneIndex(i + 1); + cm.computeUtilities(dmuObject, iv); + + if (i == traceOrig - 1) + { + int[] altsToLog = {0, 500, 1000, 2000, 2500, 3736, 3737, 3738, 3739, 3500, 4000}; + cm.logUECResultsSpecificAlts(soaTwoStageProbsLogger, + "Two stage SOA Dist Utilities from TAZ = " + (i + 1), altsToLog); + + double[] probs = cm.getProbabilities(); + double[] utils = cm.getUtilities(); + double total = 0; + for (int k = 0; k < probs.length; k++) + total += Math.exp(utils[k]); + + soaTwoStageProbsLogger.info(""); + for (int k = 1; k < altsToLog.length; k++) + soaTwoStageProbsLogger.info("alt=" + (altsToLog[k] - 1) + ", util=" + + utils[altsToLog[k] - 1] + ", prob=" + probs[altsToLog[k] - 1]); + + soaTwoStageProbsLogger.info("total exponentiated utility = " + total); + soaTwoStageProbsLogger.info(""); + soaTwoStageProbsLogger.info(""); + + } + + tazDistProbs[i] = Arrays.copyOf(cm.getCumulativeProbabilities(), tazDistProbs.length); + + } + + for (int i = 0; i < tazDistProbs.length; i++) + { + soaTwoStageProbsLogger.info("orig=" + (i + 1) + ", dest=3738, cumProb[3737]=" + + tazDistProbs[i][3736] + ", cumProb[3738]=" + tazDistProbs[i][3737] + + ", prob[3738]=" + (tazDistProbs[i][3737] - tazDistProbs[i][3736])); + } + + return tazDistProbs; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageSoaTazDistanceUtilityDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageSoaTazDistanceUtilityDMU.java new file mode 100644 index 0000000..24299ac --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestChoiceTwoStageSoaTazDistanceUtilityDMU.java @@ -0,0 +1,156 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class DestChoiceTwoStageSoaTazDistanceUtilityDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(DestChoiceTwoStageSoaTazDistanceUtilityDMU.class); + + protected HashMap methodIndexMap; + + protected IndexValues dmuIndex = null; + + protected double[] dcSize; + protected double[] univEnrollment; + protected double[] gsEnrollment; + protected double[] hsEnrollment; + protected double[] numHhs; + protected int[] gsDistricts; + protected int[] hsDistricts; + + public DestChoiceTwoStageSoaTazDistanceUtilityDMU() + { + } + + public void setIndexValuesObject(IndexValues index) + { + dmuIndex = index; + } + + public void setDestChoiceTazSize(double[] size) + { + dcSize = size; + } + + public void setTazUnivEnrollment(double[] enrollment) + { + univEnrollment = enrollment; + } + + public void setTazGsEnrollment(double[] enrollment) + { + gsEnrollment = enrollment; + } + + public void setTazHsEnrollment(double[] enrollment) + { + hsEnrollment = enrollment; + } + + public void setNumHhs(double[] hhs) + { + numHhs = hhs; + } + + public void setTazGsDistricts(int[] districts) + { + gsDistricts = districts; + } + + public void setTazHsDistricts(int[] districts) + { + hsDistricts = districts; + } + + public double getLnDestChoiceSizeTazAlt(int taz) + { + return dcSize[taz] == 0 ? -999 : Math.log(dcSize[taz]); + } + + public double getSizeTazAlt(int taz) + { + return dcSize[taz]; + } + + public double getUniversityEnrollmentTazAlt(int taz) + { + return univEnrollment[taz]; + } + + public double getGradeSchoolEnrollmentTazAlt(int taz) + { + return gsEnrollment[taz]; + } + + public double getHighSchoolEnrollmentTazAlt(int taz) + { + return hsEnrollment[taz]; + } + + public double getHouseholdsTazAlt(int taz) + { + return numHhs[taz]; + } + + public int getHomeTazGradeSchoolDistrict() + { + return gsDistricts[dmuIndex.getZoneIndex()]; + } + + public int getGradeSchoolDistrictTazAlt(int taz) + { + return gsDistricts[taz]; + } + + public int getHomeTazHighSchoolDistrict() + { + return hsDistricts[dmuIndex.getZoneIndex()]; + } + + public int getHighSchoolDistrictTazAlt(int taz) + { + return hsDistricts[taz]; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestinationSampleOfAlternativesModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestinationSampleOfAlternativesModel.java new file mode 100644 index 0000000..9bb1941 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/DestinationSampleOfAlternativesModel.java @@ -0,0 +1,612 @@ +package org.sandag.abm.ctramp; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class DestinationSampleOfAlternativesModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(DestinationSampleOfAlternativesModel.class); + private transient Logger dcSoaLogger = Logger.getLogger("tourDcSoa"); + + // set to false to store probabilities in cache for re-use; true to disable + // probabilities cache. + private static final boolean ALWAYS_COMPUTE_PROBABILITIES = false; + private static final boolean ALLOW_DEBUG = true; + + private static final int DC_SOA_DATA_SHEET = 0; + private String dcSoaUecFileName; + private int sampleSize; + + private MgraDataManager mgraManager; + + private int currentOrigMgra; + private double[][] probabilitiesCache; + private double[][] cumProbabilitiesCache; + private int currentWorkMgra; + private double[][] subtourProbabilitiesCache; + private double[][] subtourCumProbabilitiesCache; + + // destsSample[] and destsAvailable[] are indexed by purpose and alternative + private boolean[] escortAvailable; + private int[] escortSample; + private boolean[][] destsAvailable; + private int[][] destsSample; + + private int[] sample; + private float[] corrections; + + private int[] dcSoaModelIndices; + private ChoiceModelApplication[] choiceModel; + + private int numberOfSoaChoiceAlternatives; + private int[] numberOfSoaChoiceAlternativesAvailable; + + private int soaProbabilitiesCalculationCount = 0; + private long soaRunTime = 0; + + public DestinationSampleOfAlternativesModel(String soaUecFile, int sampleSize, + HashMap propertyMap, MgraDataManager mgraManager, + double[][] dcSizeArray, DcSoaDMU dcSoaDmuObject, int[] soaUecIndices) + { + + this.sampleSize = sampleSize; + this.dcSoaUecFileName = soaUecFile; + this.mgraManager = mgraManager; + + // create an array of sample of alternative ChoiceModelApplication + // objects + // for each purpose + setupSampleOfAlternativesChoiceModelArrays(propertyMap, dcSizeArray, dcSoaDmuObject, + soaUecIndices); + + } + + private void setupSampleOfAlternativesChoiceModelArrays(HashMap propertyMap, + double[][] dcSizeArray, DcSoaDMU dcSoaDmuObject, int[] soaUecIndices) + { + + // create a HashMap to map purpose index to model index + dcSoaModelIndices = new int[soaUecIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int soaModelIndex = 0; + int sizeSegmentIndex = 0; + for (int uecIndex : soaUecIndices) + { + // if the uec sheet for the size segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, soaModelIndex); + dcSoaModelIndices[sizeSegmentIndex] = soaModelIndex++; + } else + { + dcSoaModelIndices[sizeSegmentIndex] = modelIndexMap.get(uecIndex); + } + + sizeSegmentIndex++; + } + // the value of soaModelIndex is the number of ChoiceModelApplication + // objects to create + // the modelIndexMap keys are the uec sheets to use in building + // ChoiceModelApplication objects + + choiceModel = new ChoiceModelApplication[modelIndexMap.size()]; + probabilitiesCache = new double[sizeSegmentIndex][]; + cumProbabilitiesCache = new double[sizeSegmentIndex][]; + subtourProbabilitiesCache = new double[sizeSegmentIndex][]; + subtourCumProbabilitiesCache = new double[sizeSegmentIndex][]; + + int i = 0; + for (int uecIndex : modelIndexMap.keySet()) + { + int modelIndex = -1; + try + { + modelIndex = modelIndexMap.get(uecIndex); + choiceModel[modelIndex] = new ChoiceModelApplication(dcSoaUecFileName, uecIndex, + DC_SOA_DATA_SHEET, propertyMap, (VariableTable) dcSoaDmuObject); + i++; + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught setting up DC SOA ChoiceModelApplication[%d] for modelIndex=%d of %d models", + i, modelIndex, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + + setAvailabilityForSampleOfAlternatives(dcSizeArray); + + } + + /** + * This method is called initially when the SOA choice models array is + * created. It would be called subsequently if a shadow pricing methodology + * is applied to reset the scaled size terms and corresponding + * availabilities and sample arrays. + */ + public void setAvailabilityForSampleOfAlternatives(double[][] dcSizeArray) + { + + int maxMgra = mgraManager.getMaxMgra(); + + // declare dimensions for the alternative availability array by purpose + // and + // number of alternaives + escortAvailable = new boolean[maxMgra + 1]; + escortSample = new int[maxMgra + 1]; + destsAvailable = new boolean[dcSizeArray.length][maxMgra + 1]; + destsSample = new int[dcSizeArray.length][maxMgra + 1]; + + numberOfSoaChoiceAlternativesAvailable = new int[dcSizeArray.length]; + + for (int i = 0; i < dcSizeArray.length; i++) + { + for (int k = 1; k <= maxMgra; k++) + { + if (dcSizeArray[i][k] > 0.0) + { + destsAvailable[i][k] = true; + destsSample[i][k] = 1; + numberOfSoaChoiceAlternativesAvailable[i]++; + } + } // k + } + + Arrays.fill(escortAvailable, true); + Arrays.fill(escortSample, 1); + + numberOfSoaChoiceAlternatives = maxMgra; + } + + public int getNumberOfAlternatives() + { + return numberOfSoaChoiceAlternatives; + } + + public void computeDestinationSampleOfAlternatives(DcSoaDMU dcSoaDmuObject, Tour tour, + Person person, String segmentName, int segmentIndex, int origMgra) + { + + long timeCheck = System.nanoTime(); + + // these will be dimensioned with the number of unique alternatives + // determined for the decision makers + int[] altList; + int[] altListFreq; + HashMap altFreqMap = new HashMap(); + + int modelIndex = dcSoaModelIndices[segmentIndex]; + + // if the flag is set to compute sample of alternative probabilities for + // every work/school location choice, + // or the tour's origin taz is different from the currentOrigTaz, reset + // the currentOrigTaz and clear the stored probabilities. + if (tour != null && tour.getTourCategory().equals(ModelStructure.AT_WORK_CATEGORY)) + { + + if (ALWAYS_COMPUTE_PROBABILITIES || origMgra != currentWorkMgra) + { + + // clear the probabilities stored for the current origin mgra, + // for each DC segment + for (int i = 0; i < subtourProbabilitiesCache.length; i++) + { + subtourProbabilitiesCache[i] = null; + subtourCumProbabilitiesCache[i] = null; + } + currentWorkMgra = origMgra; + + } + + // If the sample of alternatives choice probabilities have not been + // computed for the current origin mgra + // and segment specified, compute them. + if (subtourProbabilitiesCache[segmentIndex] == null) + { + computeSampleOfAlternativesChoiceProbabilities(dcSoaDmuObject, tour, person, + segmentName, segmentIndex, origMgra); + soaProbabilitiesCalculationCount++; + } + + } else if (tour != null + && tour.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME)) + { + + // always update probabilities for Escort tours + // clear the probabilities stored for the current origin mgra, for + // the Escort DC segment + probabilitiesCache[segmentIndex] = null; + cumProbabilitiesCache[segmentIndex] = null; + + destsAvailable[segmentIndex] = escortAvailable; + destsSample[segmentIndex] = escortSample; + + currentOrigMgra = origMgra; + + computeSampleOfAlternativesChoiceProbabilities(dcSoaDmuObject, tour, person, + segmentName, segmentIndex, origMgra); + soaProbabilitiesCalculationCount++; + + } else + { + + if (ALWAYS_COMPUTE_PROBABILITIES || origMgra != currentOrigMgra) + { + + // clear the probabilities stored for the current origin mgra, + // for each DC segment + for (int i = 0; i < probabilitiesCache.length; i++) + { + probabilitiesCache[i] = null; + cumProbabilitiesCache[i] = null; + } + currentOrigMgra = origMgra; + + } + + // If the sample of alternatives choice probabilities have not been + // computed for the current origin taz + // and purpose specified, compute them. + if (probabilitiesCache[segmentIndex] == null) + { + computeSampleOfAlternativesChoiceProbabilities(dcSoaDmuObject, tour, person, + segmentName, segmentIndex, origMgra); + soaProbabilitiesCalculationCount++; + } + + } + + Household hhObj = person.getHouseholdObject(); + Random hhRandom = hhObj.getHhRandom(); + int rnCount = hhObj.getHhRandomCount(); + // when household.getHhRandom() was applied, the random count was + // incremented, assuming a random number would be drawn right away. + // so let's decrement by 1, then increment the count each time a random + // number is actually drawn in this method. + rnCount--; + + // select sampleSize alternatives based on probabilitiesList[origTaz], + // and + // count frequency of alternatives chosen. + // final sample may include duplicate alternative selections. + for (int i = 0; i < sampleSize; i++) + { + + double rn = hhRandom.nextDouble(); + rnCount++; + + int chosenAlt = -1; + if (tour != null && tour.getTourCategory().equals(ModelStructure.AT_WORK_CATEGORY)) chosenAlt = Util + .binarySearchDouble(subtourCumProbabilitiesCache[segmentIndex], rn) + 1; + else chosenAlt = Util.binarySearchDouble(cumProbabilitiesCache[segmentIndex], rn) + 1; + + // write choice model alternative info to log file + if (hhObj.getDebugChoiceModels()) + { + choiceModel[modelIndex] + .logSelectionInfo( + String.format( + "Sample Of Alternatives Choice for segmentName=%s, segmentIndex=%d, modelIndex=%d, origMgra=%d", + segmentName, segmentIndex, modelIndex, origMgra), String + .format("HHID=%d, rn=%.8f, rnCount=%d", hhObj.getHhId(), + rn, (rnCount + i)), rn, chosenAlt); + } + + int freq = 0; + if (altFreqMap.containsKey(chosenAlt)) freq = altFreqMap.get(chosenAlt); + altFreqMap.put(chosenAlt, (freq + 1)); + + } + + // sampleSize random number draws were made from the Random object for + // the + // current household, + // so update the count in the hh's Random. + hhObj.setHhRandomCount(rnCount); + + // create arrays of the unique chosen alternatives and the frequency + // with + // which those alternatives were chosen. + int numUniqueAlts = altFreqMap.keySet().size(); + altList = new int[numUniqueAlts]; + altListFreq = new int[numUniqueAlts]; + Iterator it = altFreqMap.keySet().iterator(); + int k = 0; + while (it.hasNext()) + { + int key = (Integer) it.next(); + int value = (Integer) altFreqMap.get(key); + altList[k] = key; + altListFreq[k] = value; + k++; + } + + // loop through these arrays, construct final sample[] and + // corrections[]. + sample = new int[numUniqueAlts + 1]; + corrections = new float[numUniqueAlts + 1]; + for (k = 0; k < numUniqueAlts; k++) + { + int alt = altList[k]; + int freq = altListFreq[k]; + + double prob = 0; + if (tour != null && tour.getTourCategory().equals(ModelStructure.AT_WORK_CATEGORY)) prob = subtourProbabilitiesCache[segmentIndex][alt - 1]; + else prob = probabilitiesCache[segmentIndex][alt - 1]; + + sample[k + 1] = alt; + corrections[k + 1] = (float) Math.log((double) freq / prob); + } + + soaRunTime += (System.nanoTime() - timeCheck); + + } + + /** + * This method is used if the tour/person decision maker is the first one + * encountered for the purpose and origin taz. Once the sample of + * alternatives choice probabilities for a purpose and origin taz are + * computed, they are stored in an array and used by other decision makers + * with the same purpose and origin taz. + * + * @param probabilitiesList + * is the probabilities array for the given purpose in which + * choice probabilities will be saved for the origin of the + * tour/place to be selected. + * @param cumProbabilitiesList + * is the probabilities array for the given purpose in which + * choice cumulative probabilities will be saved for the origin + * of the tour/place to be selected. + * @param choiceModel + * the ChoiceModelApplication object for the purpose + * @param tour + * the tour object for whic destination choice is required, or + * null if a usual work/school location is being chosen + * @param person + * the person object for whom the choice is being made + * @param segmentName + * the name of the segment the choice is being made for - for + * logging + * @param segmentindex + * the index associated with the segment + * @param origMgra + * the index associated with the segment + * @param distances + * array frpm origin MGRA to all MGRAs + */ + private void computeSampleOfAlternativesChoiceProbabilities(DcSoaDMU dcSoaDmuObject, Tour tour, + Person person, String segmentName, int segmentIndex, int origMgra) + { + + Household hhObj = person.getHouseholdObject(); + + // set the hh, person, and tour objects for this DMU object + dcSoaDmuObject.setHouseholdObject(hhObj); + dcSoaDmuObject.setPersonObject(person); + dcSoaDmuObject.setTourObject(tour); + + // set sample of alternatives choice DMU attributes + dcSoaDmuObject.setDmuIndexValues(hhObj.getHhId(), hhObj.getHhMgra(), origMgra, 0); + + // prepare a trace log header that the choiceModel object will write + // prior to + // UEC trace logging + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + + int choiceModelIndex = dcSoaModelIndices[segmentIndex]; + + // If the person making the choice is from a household requesting trace + // information, + // create a trace logger header and write prior to the choiceModel + // computing + // utilities + if (hhObj.getDebugChoiceModels()) + { + + if (tour == null) + { + // null tour means the SOA choice is for a mandatory usual + // location choice + choiceModelDescription = String.format( + "Usual Location Sample of Alternatives Choice Model for: Segment=%s", + segmentName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", person + .getHouseholdObject().getHhId(), person.getPersonNum(), person + .getPersonType()); + } else + { + choiceModelDescription = String.format( + "Destination Choice Model for: Segment=%s, TourId=%d", segmentName, + tour.getTourId()); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", person + .getHouseholdObject().getHhId(), person.getPersonNum(), person + .getPersonType()); + } + + // log headers to traceLogger if the person making the choice is + // from a + // household requesting trace information + choiceModel[choiceModelIndex].choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + } + + try + { + choiceModel[choiceModelIndex].computeUtilities(dcSoaDmuObject, + dcSoaDmuObject.getDmuIndexValues(), destsAvailable[segmentIndex], + destsSample[segmentIndex]); + } catch (Exception e) + { + logger.error("exception caught in DC SOA model for:"); + choiceModelDescription = String.format( + "Destination Choice Model for: Segment=%s, TourId=%d", segmentName, + tour.getTourId()); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", person + .getHouseholdObject().getHhId(), person.getPersonNum(), person.getPersonType()); + logger.error("choiceModelDescription:" + choiceModelDescription); + logger.error("decisionMakerLabel:" + decisionMakerLabel); + throw new RuntimeException(e); + } + + // TODO: debug + if (choiceModel[choiceModelIndex].getAvailabilityCount() == 0) + { + + int j = 0; + int[] debugAlts = new int[5]; + for (int i = 0; i < destsSample[segmentIndex].length; i++) + { + if (destsSample[segmentIndex][i] == 1) + { + debugAlts[j++] = i; + if (j == 5) break; + } + } + + choiceModel[choiceModelIndex].logUECResultsSpecificAlts(dcSoaLogger, "debugging", + debugAlts); + } + + // the following order of assignment is important in mult-threaded + // context. + // probabilitiesCache[][] is a trigger variable - if it is not null for + // any thread, the cumProbabilitiesCache[][] values + // are used immediately, so the cumProbabilitiesCache values must be + // assigned before the probabilitiesCache + // are assigned, which indicates cumProbabilitiesCache[][] values are + // ready to be used. + if (tour != null && tour.getTourCategory().equals(ModelStructure.AT_WORK_CATEGORY)) + { + + subtourCumProbabilitiesCache[segmentIndex] = Arrays.copyOf( + choiceModel[choiceModelIndex].getCumulativeProbabilities(), + choiceModel[choiceModelIndex].getNumberOfAlternatives()); + subtourProbabilitiesCache[segmentIndex] = Arrays.copyOf( + choiceModel[choiceModelIndex].getProbabilities(), + choiceModel[choiceModelIndex].getNumberOfAlternatives()); + } else + { + + cumProbabilitiesCache[segmentIndex] = Arrays.copyOf( + choiceModel[choiceModelIndex].getCumulativeProbabilities(), + choiceModel[choiceModelIndex].getNumberOfAlternatives()); + probabilitiesCache[segmentIndex] = Arrays.copyOf( + choiceModel[choiceModelIndex].getProbabilities(), + choiceModel[choiceModelIndex].getNumberOfAlternatives()); + + if (hhObj.getDebugChoiceModels()) + { + PrintWriter out = null; + try + { + out = new PrintWriter(new BufferedWriter(new FileWriter( + new File("soaProbs.csv")))); + + out.println("choiceModelDescription:" + choiceModelDescription); + out.println("decisionMakerLabel:" + decisionMakerLabel); + + for (int i = 0; i < probabilitiesCache[segmentIndex].length; i++) + { + out.println((i + 1) + "," + probabilitiesCache[segmentIndex][i]); + } + } catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + out.close(); + + } + + } + + // If the person making the choice is from a household requesting trace + // information, + // write choice model alternative info to the debug log file + if (hhObj.getDebugChoiceModels() && ALLOW_DEBUG) + { + // if ( dcSoaLogger.isDebugEnabled() ){ + int[] altsToLog = {0, 77, 78, 79, 80}; + choiceModel[choiceModelIndex].logAlternativesInfo(String.format( + "%s Sample Of Alternatives Choice for origTaz=%d", segmentName, origMgra), + String.format("HHID=%d", hhObj.getHhId()), dcSoaLogger); + choiceModel[choiceModelIndex].logUECResultsSpecificAlts(dcSoaLogger, + choiceModelDescription + ", " + decisionMakerLabel, altsToLog); + + double[] probs = choiceModel[choiceModelIndex].getProbabilities(); + double[] utils = choiceModel[choiceModelIndex].getUtilities(); + double total = 0; + for (int i = 0; i < probs.length; i++) + total += Math.exp(utils[i]); + + dcSoaLogger.info(""); + for (int i = 1; i < altsToLog.length; i++) + dcSoaLogger.info("alt=" + (altsToLog[i] + 1) + ", util=" + utils[altsToLog[i]] + + ", prob=" + probs[altsToLog[i]]); + + dcSoaLogger.info("total exponentiated utility = " + total); + dcSoaLogger.info(""); + dcSoaLogger.info(""); + // } + } + + } + + public int getSoaProbabilitiesCalculationCount() + { + return soaProbabilitiesCalculationCount; + } + + public long getSoaRunTime() + { + return soaRunTime; + } + + public void resetSoaRunTime() + { + soaRunTime = 0; + } + + public int getCurrentOrigMgra() + { + return currentOrigMgra; + } + + public int[] getSampleOfAlternatives() + { + return sample; + } + + public float[] getSampleOfAlternativesCorrections() + { + return corrections; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/Household.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Household.java new file mode 100644 index 0000000..ba5b011 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Household.java @@ -0,0 +1,1847 @@ +package org.sandag.abm.ctramp; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +import org.apache.log4j.Logger; + +public class Household + implements java.io.Serializable +{ + + private boolean debugChoiceModels; + + private int hhId; + private short hhIncomeCategory; + private int hhIncomeInDollars; + private short hhSize; + private short hhType; + private short unitType; + private short hhBldgsz; + private short hhWorkers; + + private int homeTaz; + private int homeMgra; + private int homeWalkSubzone; + + //added for BCA tool + private float autoOwnershipLogsum; + private float transponderLogsum; + private float cdapLogsum; + private float jtfLogsum; + + private Person[] persons; + + private Tour[] jointTours; + + private short aoModelAutos; + private short automatedVehicles; + private short conventionalVehicles; + private String cdapModelPattern; + private short imtfModelPattern; + private String jtfModelPattern; + private short tpChoice; + private short outboundEscortChoice; + private short inboundEscortChoice; + + + private Random hhRandom; + private int randomCount = 0; + private HashMap uwslRandomCountList; + private int preAoRandomCount; + private int aoRandomCount; + private int tpRandomCount; + private int fpRandomCount; + private int ieRandomCount; + private int cdapRandomCount; + private int imtfRandomCount; + private int imtodRandomCount; + private int awfRandomCount; + private int awlRandomCount; + private int awtodRandomCount; + private int jtfRandomCount; + private int jtlRandomCount; + private int jtodRandomCount; + private int inmtfRandomCount; + private int inmtlRandomCount; + private int inmtodRandomCount; + private int stfRandomCount; + private int stlRandomCount; + + private int maxAdultOverlaps; + private int maxChildOverlaps; + private int maxMixedOverlaps; + + private ModelStructure modelStructure; + + private long seed; + public Household(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + hhRandom = new Random(); + uwslRandomCountList = new HashMap(); + } + + /** + * Returns a 1-based array of persons in the household + * @return Person array + */ + public Person[] getPersons() + { + return persons; + } + + public void initializeWindows() + { + + // loop through the person array (1-based) + for (int i = 1; i < persons.length; ++i) + { + persons[i].initializeWindows(); + } + + } + + public void setDebugChoiceModels(boolean value) + { + debugChoiceModels = value; + } + + public void setHhId(int id, int baseSeed) + { + hhId = id; + randomCount = 0; + hhRandom.setSeed(baseSeed + hhId); + } + + public void setRandomObject(Random r) + { + hhRandom = r; + } + + public void setHhRandomCount(int count) + { + randomCount = count; + } + + // work/school location choice uses shadow pricing, so save randomCount per + // iteration + public void setUwslRandomCount(int iter, int count) + { + uwslRandomCountList.put(iter, count); + } + + public void setPreAoRandomCount(int count) + { + preAoRandomCount = count; + } + + public void setAoRandomCount(int count) + { + aoRandomCount = count; + } + + public void setTpRandomCount(int count) + { + tpRandomCount = count; + } + + public void setFpRandomCount(int count) + { + fpRandomCount = count; + } + + public void setIeRandomCount(int count) + { + ieRandomCount = count; + } + + public void setCdapRandomCount(int count) + { + cdapRandomCount = count; + } + + public void setImtfRandomCount(int count) + { + imtfRandomCount = count; + } + + public void setImtodRandomCount(int count) + { + imtodRandomCount = count; + } + + public void setAwfRandomCount(int count) + { + awfRandomCount = count; + } + + public void setAwlRandomCount(int count) + { + awlRandomCount = count; + } + + public void setAwtodRandomCount(int count) + { + awtodRandomCount = count; + } + + public void setJtfRandomCount(int count) + { + jtfRandomCount = count; + } + + public void setJtlRandomCount(int count) + { + jtlRandomCount = count; + } + + public void setJtodRandomCount(int count) + { + jtodRandomCount = count; + } + + public void setInmtfRandomCount(int count) + { + inmtfRandomCount = count; + } + + public void setInmtlRandomCount(int count) + { + inmtlRandomCount = count; + } + + public void setInmtodRandomCount(int count) + { + inmtodRandomCount = count; + } + + public void setStfRandomCount(int count) + { + stfRandomCount = count; + } + + public void setStlRandomCount(int count) + { + stlRandomCount = count; + } + + public void setHhTaz(int taz) + { + homeTaz = taz; + } + + public void setHhMgra(int mgra) + { + homeMgra = mgra; + } + + public void setHhWalkSubzone(int subzone) + { + homeWalkSubzone = (short) subzone; + } + + public void setHhAutos(int autos) + { + // this sets the variable that will be used in work/school location + // choice. + // after auto ownership runs, this variable gets updated with number of + // autos + // for result. + aoModelAutos = (short) autos; + } + + public void setTpChoice(int value) + { + tpChoice = (short) value; + } + + /** + * auto sufficiency: 1 if cars < workers, 2 if cars equal workers, 3 if cars + * > workers + * + * @return auto sufficiency value + */ + public int getAutoSufficiency() + { + if (aoModelAutos < hhWorkers) return 1; + else if (aoModelAutos == hhWorkers) return 2; + else return 3; + } + + public int getAutosOwned() + { + return (int) aoModelAutos; + } + + public int getAutomatedVehicles() { + return (int) automatedVehicles; + } + + public void setAutomatedVehicles(int automatedVehicles) { + this.automatedVehicles = (short) automatedVehicles; + } + + public int getConventionalVehicles() { + return (int) conventionalVehicles; + } + + public void setConventionalVehicles(int conventionalVehicles) { + this.conventionalVehicles = (short) conventionalVehicles; + } + + public int getTpChoice() + { + return (int) tpChoice; + } + + public void setCoordinatedDailyActivityPatternResult(String pattern) + { + cdapModelPattern = pattern; + } + + public String getCoordinatedDailyActivityPattern() + { + return cdapModelPattern; + } + + public void setJointTourFreqResult(int altIndex, String altName) + { + jtfModelPattern = String.format("%d_%s", altIndex, altName); + } + + public int getJointTourFreqChosenAlt() + { + int returnValue = 0; + if (jtfModelPattern == null) + { + returnValue = 0; + } else + { + int endIndex = jtfModelPattern.indexOf('_'); + returnValue = Integer.parseInt(jtfModelPattern.substring(0, endIndex)); + } + return returnValue; + } + + public String getJointTourFreqChosenAltName() + { + String returnValue = "none"; + if (jtfModelPattern != null) + { + int startIndex = jtfModelPattern.indexOf('_') + 1; + returnValue = jtfModelPattern.substring(startIndex); + } + return returnValue; + } + + public void setHhBldgsz(int code) + { + hhBldgsz = (short) code; + } + + public int getHhBldgsz() + { + return (int) hhBldgsz; + } + + public void setHhSize(int numPersons) + { + hhSize = (short) numPersons; + persons = new Person[numPersons + 1]; + for (int i = 1; i <= numPersons; i++) + persons[i] = new Person(this, i, modelStructure); + + } + + public void setHhIncomeCategory(int category) + { + hhIncomeCategory = (short) category; + } + + public void setHhIncomeInDollars(int dollars) + { + hhIncomeInDollars = dollars; + } + + public void setHhWorkers(int numWorkers) + { + hhWorkers = (short) numWorkers; + } + + public void setHhType(int type) + { + hhType = (short) type; + } + + // 0=Housing unit, 1=Institutional group quarters, 2=Noninstitutional group + // quarters + public void setUnitType(int type) + { + unitType = (short) type; + } + + public boolean getDebugChoiceModels() + { + return debugChoiceModels; + } + + public int getHhSize() + { + return (int) hhSize; + } + + public int getNumTotalIndivTours() + { + int count = 0; + for (int i = 1; i < persons.length; i++) + count += persons[i].getNumTotalIndivTours(); + return count; + } + + public int getNumberOfNonWorkingAdults() + { + int count = 0; + for (int i = 1; i < persons.length; i++) + count += persons[i].getPersonIsNonWorkingAdultUnder65() + + persons[i].getPersonIsNonWorkingAdultOver65(); + return count; + } + + public int getIsNonFamilyHousehold() + { + + if (hhType == HouseholdType.NON_FAMILY_MALE_ALONE.ordinal()) return (1); + if (hhType == HouseholdType.NON_FAMILY_MALE_NOT_ALONE.ordinal()) return (1); + if (hhType == HouseholdType.NON_FAMILY_FEMALE_ALONE.ordinal()) return (1); + if (hhType == HouseholdType.NON_FAMILY_FEMALE_NOT_ALONE.ordinal()) return (1); + + return (0); + } + + /** + * unitType: 0=Housing unit, 1=Institutional group quarters, + * 2=Noninstitutional group quarters + * + * @return 1 if household is group quarters, 0 for non-group quarters + */ + public int getIsGroupQuarters() + { + if (unitType == 0) return 0; + else return 1; + } + + public int getNumStudents() + { + int count = 0; + for (int i = 1; i < persons.length; ++i) + { + count += persons[i].getPersonIsStudent(); + } + return (count); + } + + public int getNumGradeSchoolStudents() + { + int count = 0; + for (int i = 1; i < persons.length; ++i) + { + count += persons[i].getPersonIsGradeSchool(); + } + return (count); + } + + public int getNumHighSchoolStudents() + { + int count = 0; + for (int i = 1; i < persons.length; ++i) + { + count += persons[i].getPersonIsHighSchool(); + } + return (count); + } + + public int getNumberOfChildren6To18WithoutMandatoryActivity() + { + + int count = 0; + + for (int i = 1; i < persons.length; ++i) + { + count += persons[i].getPersonIsChild6To18WithoutMandatoryActivity(); + } + + return (count); + } + + public int getNumberOfPreDrivingWithNonHomeActivity() + { + + int count = 0; + for (int i = 1; i < persons.length; ++i) + { + // count only predrving kids + if (persons[i].getPersonIsStudentDriving() == 1) + { + // count only if CDAP is M or N (i.e. not H) + if (!persons[i].getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) + count++; + } + } + + return count; + } + + public int getNumberOfPreschoolWithNonHomeActivity() + { + + int count = 0; + for (int i = 1; i < persons.length; ++i) + { + // count only predrving kids + if (persons[i].getPersonIsPreschoolChild() == 1) + { + // count only if CDAP is M or N (i.e. not H) + if (!persons[i].getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) + count++; + } + } + + return count; + } + + /** + * return the number of school age students this household has for the + * purpose index. + * + * @param purposeIndex + * is the DC purpose index to be compared to the usual school + * location index saved for this person upon reading synthetic + * population file. + * @return num, a value of the number of school age students in the + * household for this purpose index. + */ + public int getNumberOfDrivingAgedStudentsWithDcPurposeIndex(int segmentIndex) + { + int num = 0; + for (int j = 1; j < persons.length; j++) + { + if (persons[j].getPersonIsStudentDriving() == 1 + && persons[j].getSchoolLocationSegmentIndex() == segmentIndex) num++; + } + return num; + } + + public int getNumberOfNonDrivingAgedStudentsWithDcPurposeIndex(int segmentIndex) + { + int num = 0; + for (int j = 1; j < persons.length; j++) + { + if (persons[j].getPersonIsStudentNonDriving() == 1 + || persons[j].getPersonIsPreschoolChild() == 1 + && persons[j].getSchoolLocationSegmentIndex() == segmentIndex) num++; + } + return num; + } + + public Person getPerson(int persNum) + { + if (persNum < 1 || persNum > hhSize) + { + throw new RuntimeException(String.format( + "persNum value = %d is out of range for hhSize = %d", persNum, hhSize)); + } + + return persons[persNum]; + } + + // methods DMU will use to get info from household object + + public int getHhId() + { + return hhId; + } + + public Random getHhRandom() + { + randomCount++; + return hhRandom; + } + + public int getHhRandomCount() + { + return randomCount; + } + + public int getUwslRandomCount(int iter) + { + return uwslRandomCountList.get(iter); + } + + public int getPreAoRandomCount() + { + return preAoRandomCount; + } + + public int getAoRandomCount() + { + return aoRandomCount; + } + + public int getTpRandomCount() + { + return tpRandomCount; + } + + public int getFpRandomCount() + { + return fpRandomCount; + } + + public int getIeRandomCount() + { + return ieRandomCount; + } + + public int getCdapRandomCount() + { + return cdapRandomCount; + } + + public int getImtfRandomCount() + { + return imtfRandomCount; + } + + public int getImtodRandomCount() + { + return imtodRandomCount; + } + + public int getJtfRandomCount() + { + return jtfRandomCount; + } + + public int getAwfRandomCount() + { + return awfRandomCount; + } + + public int getAwlRandomCount() + { + return awlRandomCount; + } + + public int getAwtodRandomCount() + { + return awtodRandomCount; + } + + public int getJtlRandomCount() + { + return jtlRandomCount; + } + + public int getJtodRandomCount() + { + return jtodRandomCount; + } + + public int getInmtfRandomCount() + { + return inmtfRandomCount; + } + + public int getInmtlRandomCount() + { + return inmtlRandomCount; + } + + public int getInmtodRandomCount() + { + return inmtodRandomCount; + } + + public int getStfRandomCount() + { + return stfRandomCount; + } + + public int getStlRandomCount() + { + return stlRandomCount; + } + + public int getHhTaz() + { + return homeTaz; + } + + public int getHhMgra() + { + return homeMgra; + } + + public int getHhWalkSubzone() + { + return homeWalkSubzone; + } + + public int getIncomeCategory() + { + return (int) hhIncomeCategory; + } + + public int getIncomeInDollars() + { + return hhIncomeInDollars; + } + + public int getWorkers() + { + return (int) hhWorkers; + } + + public int getDrivers() + { + return getNumPersons16plus(); + } + + public int getSize() + { + return (int) hhSize; + } + + public int getChildunder16() + { + if (getNumChildrenUnder16() > 0) return 1; + else return 0; + } + + public int getChild16plus() + { + if (getNumPersons16plus() > 0) return 1; + else return 0; + } + + public int getNumChildrenUnder16() + { + int numChildrenUnder16 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() < 16) numChildrenUnder16++; + } + return numChildrenUnder16; + } + + public int getNumChildrenUnder19() + { + int numChildrenUnder19 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() < 19) numChildrenUnder19++; + } + return numChildrenUnder19; + } + + public int getNumPersons0to4() + { + int numPersons0to4 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() < 5) numPersons0to4++; + } + return numPersons0to4; + } + + /** + * used in AO choice utility + * + * @return number of persons age 6 to 15, inclusive + */ + public int getNumPersons6to15() + { + int numPersons6to15 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 6 && persons[i].getAge() <= 15) numPersons6to15++; + } + return numPersons6to15; + } + + /** + * used in Stop Frequency choice utility + * + * @return number of persons age 5 to 15, inclusive + */ + public int getNumPersons5to15() + { + int numPersons5to15 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 5 && persons[i].getAge() <= 15) numPersons5to15++; + } + return numPersons5to15; + } + + public int getNumPersons16to17() + { + int numPersons16to17 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 16 && persons[i].getAge() <= 17) numPersons16to17++; + } + return numPersons16to17; + } + + public int getNumPersons18to35(){ + + int numPersons18to35 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 18 && persons[i].getAge() <= 35) numPersons18to35++; + } + return numPersons18to35; + } + + public int getNumPersons16plus() + { + int numPersons16plus = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 16) numPersons16plus++; + } + return numPersons16plus; + } + + public int getNumPersons18plus() + { + int numPersons18plus = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 18) numPersons18plus++; + } + return numPersons18plus; + } + + public int getNumPersons80plus() + { + int numPersons80plus = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 80) numPersons80plus++; + } + return numPersons80plus; + } + + public int getNumPersons18to24() + { + int numPersons18to24 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 18 && persons[i].getAge() <= 24) numPersons18to24++; + } + return numPersons18to24; + } + + public int getNumPersons65to79() + { + int numPersons65to79 = 0; + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getAge() >= 65 && persons[i].getAge() <= 79) numPersons65to79++; + } + return numPersons65to79; + } + + public int getNumFtWorkers() + { + int numFtWorkers = 0; + for (int i = 1; i < persons.length; i++) + numFtWorkers += persons[i].getPersonIsFullTimeWorker(); + return numFtWorkers; + } + + public int getNumPtWorkers() + { + int numPtWorkers = 0; + for (int i = 1; i < persons.length; i++) + numPtWorkers += persons[i].getPersonIsPartTimeWorker(); + return numPtWorkers; + } + + public int getNumUnivStudents() + { + int numUnivStudents = 0; + for (int i = 1; i < persons.length; i++) + numUnivStudents += persons[i].getPersonIsUniversityStudent(); + return numUnivStudents; + } + + public int getNumNonWorkAdults() + { + int numNonWorkAdults = 0; + for (int i = 1; i < persons.length; i++) + numNonWorkAdults += persons[i].getPersonIsNonWorkingAdultUnder65(); + return numNonWorkAdults; + } + + public int getNumAdults() + { + int numAdults = 0; + for (int i = 1; i < persons.length; i++) + numAdults += (persons[i].getPersonIsFullTimeWorker() + + persons[i].getPersonIsPartTimeWorker() + + persons[i].getPersonIsUniversityStudent() + + persons[i].getPersonIsNonWorkingAdultUnder65() + persons[i] + .getPersonIsNonWorkingAdultOver65()); + return numAdults; + } + + public int getNumRetired() + { + int numRetired = 0; + for (int i = 1; i < persons.length; i++) + numRetired += persons[i].getPersonIsNonWorkingAdultOver65(); + return numRetired; + } + + public int getNumDrivingStudents() + { + int numDrivingStudents = 0; + for (int i = 1; i < persons.length; i++) + numDrivingStudents += persons[i].getPersonIsStudentDriving(); + return numDrivingStudents; + } + + public int getNumNonDrivingStudents() + { + int numNonDrivingStudents = 0; + for (int i = 1; i < persons.length; i++) + numNonDrivingStudents += persons[i].getPersonIsStudentNonDriving(); + return numNonDrivingStudents; + } + + public int getNumPreschool() + { + int numPreschool = 0; + for (int i = 1; i < persons.length; i++) + numPreschool += persons[i].getPersonIsPreschoolChild(); + return numPreschool; + } + + public int getNumHighSchoolGraduates() + { + int numGrads = 0; + for (int i = 1; i < persons.length; i++) + numGrads += persons[i].getPersonIsHighSchoolGraduate(); + return numGrads; + } + + /** + * Iterates through person array, adds up and returns number of children with school tours for preschool children, non-driving age students, and driving age students + * @return Number of children with school tours. + */ + public int getNumChildrenWithSchoolTours(){ + + int numChildrenWithSchoolTours = 0; + + for(int i=1; i < persons.length;++i){ + Person p = persons[i]; + if((p.getPersonIsPreschoolChild() == 1) || (p.getPersonIsStudentNonDriving() == 1)|| (p.getPersonIsStudentDriving() == 1)){ + if(p.getNumSchoolTours()>0) + ++numChildrenWithSchoolTours; + } + } + + return numChildrenWithSchoolTours; + } + /** + * joint tour frequency choice is not applied to a household unless it has: + * 2 or more persons, each with at least one out-of home activity, and at + * least 1 of the persons not a pre-schooler. + * */ + public int getValidHouseholdForJointTourFrequencyModel() + { + + // return one of the following condition codes for this household + // producing + // joint tours: + // 1: household eligible for joint tour production + // 2: household ineligible due to 1 person hh. + // 3: household ineligible due to fewer than 2 persons traveling out of + // home + // 4: household ineligible due to fewer than 1 non-preschool person + // traveling + // out of home + + // no joint tours for single person household + if (hhSize == 1) return 2; + + int leavesHome = 0; + int nonPreSchoolerLeavesHome = 0; + for (int i = 1; i < persons.length; i++) + { + if (!persons[i].getCdapActivity().equalsIgnoreCase("H")) + { + leavesHome++; + if (persons[i].getPersonIsPreschoolChild() == 0) nonPreSchoolerLeavesHome++; + } + } + + // if the number of persons leaving home during the day is not at least + // 2, no + // joint tours + if (leavesHome < 2) return 3; + + // if the number of non-preschool persons leaving home during the day is + // not + // at least 1, no joint tours + if (nonPreSchoolerLeavesHome < 1) return 4; + + // if all conditions are met, we can apply joint tour frequency model to + // this + // household + return 1; + + } + + /** + * return maximum periods of overlap between this person and other adult + * persons in the household. + * + * @return the most number of periods mutually available between this person + * and other adult household members + */ + public int getMaxAdultOverlaps() + { + return maxAdultOverlaps; + } + + /** + * return maximum periods of overlap between this person and other children + * in the household. + * + * @return the most number of periods mutually available between this person + * and other child household members + */ + public int getMaxChildOverlaps() + { + return maxChildOverlaps; + } + + /** + * return maximum periods of overlap between this person(adult/child) and + * other persons(child/adult) in the household. + * + * @return the most number of periods mutually available between this person + * and other type household members + */ + public int getMaxMixedOverlaps() + { + return maxMixedOverlaps; + } + + public int getMaxJointTimeWindow(Tour t) + { + // get array of person array indices participating in joint tour + int[] participatingPersonIndices = t.getPersonNumArray(); + + // create an array to hold time window arrays for each participant + short[][] personWindows = new short[participatingPersonIndices.length][]; + + // get time window arrays for each participant + int k = 0; + for (int i : participatingPersonIndices) + personWindows[k++] = persons[i].getTimeWindows(); + + int count = 0; + + int maxCount = 0; + // loop over time window intervals + for (int w = 1; w < personWindows[0].length; w++) + { + + // loop over party; determine if interval is available for everyone + // in party; + boolean available = true; + for (k = 0; k < personWindows.length; k++) + { + if (personWindows[k][w] > 0) + { + available = false; + break; + } + } + + // if available for whole party, increment count; determine maximum + // continous time window available to whole party. + if (available) + { + count++; + if (count > maxCount) maxCount = count; + } else + { + count = 0; + } + + } + + return maxCount; + } + + /** + * @return number of adults in household with "M" or "N" activity pattern - + * that is, traveling adults. + */ + public int getTravelActiveAdults() + { + + int adultsStayingHome = 0; + int adults = 0; + for (int p = 1; p < persons.length; p++) + { + // person is an adult + if (persons[p].getPersonIsAdult() == 1) + { + adults++; + if (persons[p].getCdapActivity().equalsIgnoreCase("H")) adultsStayingHome++; + } + } + + // return the number of adults traveling = number of adults minus the + // number + // of adults staying home. + return adults - adultsStayingHome; + + } + + /** + * @return number of children in household with "M" or "N" activity pattern + * - that is, traveling children. + */ + public int getTravelActiveChildren() + { + + int childrenStayingHome = 0; + int children = 0; + for (int p = 1; p < persons.length; p++) + { + // person is not an adult + if (persons[p].getPersonIsAdult() == 0) + { + children++; + if (persons[p].getCdapActivity().equalsIgnoreCase("H")) childrenStayingHome++; + } + } + + // return the number of adults traveling = number of adults minus the + // number + // of adults staying home. + return children - childrenStayingHome; + + } + + public int getOutboundEscortChoice() { + return outboundEscortChoice; + } + public void setOutboundEscortChoice(int outboundEscortChoice) { + this.outboundEscortChoice = (short) outboundEscortChoice; + } + public int getInboundEscortChoice() { + return inboundEscortChoice; + } + public void setInboundEscortChoice(int inboundEscortChoice) { + this.inboundEscortChoice = (short) inboundEscortChoice; + } + public void calculateTimeWindowOverlaps() + { + + boolean pAdult; + boolean qAdult; + + maxAdultOverlaps = 0; + maxChildOverlaps = 0; + maxMixedOverlaps = 0; + + int[] maxAdultOverlapsP = new int[persons.length]; + int[] maxChildOverlapsP = new int[persons.length]; + + // loop over persons in the household and count available time windows + for (int p = 1; p < persons.length; p++) + { + + // determine if person p is an adult -- that is, person is not any + // of the + // three child types + pAdult = persons[p].getPersonIsPreschoolChild() == 0 + && persons[p].getPersonIsStudentNonDriving() == 0 + && persons[p].getPersonIsStudentDriving() == 0; + + // loop over person indices to compute length of pairwise available + // time windows. + for (int q = 1; q < persons.length; q++) + { + + if (p == q) continue; + + // determine if person q is an adult -- that is, person is not + // any of the three child types + qAdult = persons[q].getPersonIsPreschoolChild() == 0 + && persons[q].getPersonIsStudentNonDriving() == 0 + && persons[q].getPersonIsStudentDriving() == 0; + + // get the length of the maximum pairwise available time window + // between persons p and q. + int maxWindow = persons[p].getMaximumContinuousPairwiseAvailableWindow(persons[q] + .getTimeWindows()); + + // determine max time window overlap between adult pairs, + // children pairs, and mixed pairs in the household + // for max windows in all pairs in hh, don't need to check q,p + // once we'alread done p,q, so skip q <= p. + if (q > p) + { + if (pAdult && qAdult) + { + if (maxWindow > maxAdultOverlaps) maxAdultOverlaps = maxWindow; + } else if (!pAdult && !qAdult) + { + if (maxWindow > maxChildOverlaps) maxChildOverlaps = maxWindow; + } else + { + if (maxWindow > maxMixedOverlaps) maxMixedOverlaps = maxWindow; + } + } + + // determine the max time window overlap between this person and + // other household adults and children. + if (qAdult) + { + if (maxWindow > maxAdultOverlapsP[p]) maxAdultOverlapsP[p] = maxWindow; + } else + { + if (maxWindow > maxChildOverlapsP[p]) maxChildOverlapsP[p] = maxWindow; + } + + } // end of person q + + // set person attributes + persons[p].setMaxAdultOverlaps(maxAdultOverlapsP[p]); + persons[p].setMaxChildOverlaps(maxChildOverlapsP[p]); + + } // end of person p + + } + + public boolean[] getAvailableJointTourTimeWindows(Tour t, int[] altStarts, int[] altEnds) + { + int[] participatingPersonIndices = t.getPersonNumArray(); + + // availability array for each person + boolean[][] availability = new boolean[participatingPersonIndices.length][]; + + for (int i = 0; i < participatingPersonIndices.length; i++) + { + + int personNum = participatingPersonIndices[i]; + Person person = persons[personNum]; + + // availability array is 1-based indexing + availability[i] = new boolean[altStarts.length + 1]; + + for (int k = 1; k <= altStarts.length; k++) + { + int start = altStarts[k - 1]; + int end = altEnds[k - 1]; + availability[i][k] = person.isWindowAvailable(start, end); + } + + } + + boolean[] jointAvailability = new boolean[availability[0].length]; + + for (int k = 0; k < jointAvailability.length; k++) + { + jointAvailability[k] = true; + for (int i = 0; i < participatingPersonIndices.length; i++) + { + if (!availability[i][k]) + { + jointAvailability[k] = false; + break; + } + } + } + + return jointAvailability; + + } + + public void scheduleJointTourTimeWindows(Tour t, int start, int end) + { + int[] participatingPersonIndices = t.getPersonNumArray(); + for (int i : participatingPersonIndices) + { + Person person = persons[i]; + person.scheduleWindow(start, end); + } + } + + public void createJointTourArray() + { + jointTours = new Tour[0]; + } + + public void createJointTourArray(Tour tour1) + { + jointTours = new Tour[1]; + tour1.setTourOrigMgra(homeMgra); + tour1.setTourDestMgra(0); + jointTours[0] = tour1; + } + + public void createJointTourArray(Tour tour1, Tour tour2) + { + jointTours = new Tour[2]; + tour1.setTourOrigMgra(homeMgra); + tour1.setTourDestMgra(0); + tour1.setTourId(0); + tour2.setTourOrigMgra(homeMgra); + tour2.setTourDestMgra(0); + tour2.setTourId(1); + jointTours[0] = tour1; + jointTours[1] = tour2; + } + + public Tour[] getJointTourArray() + { + return jointTours; + } + + public void initializeForAoRestart() + { + jointTours = null; + + aoModelAutos = 0; + cdapModelPattern = null; + imtfModelPattern = 0; + jtfModelPattern = null; + + tpRandomCount = 0; + fpRandomCount = 0; + ieRandomCount = 0; + cdapRandomCount = 0; + imtfRandomCount = 0; + imtodRandomCount = 0; + awfRandomCount = 0; + awlRandomCount = 0; + awtodRandomCount = 0; + jtfRandomCount = 0; + jtlRandomCount = 0; + jtodRandomCount = 0; + inmtfRandomCount = 0; + inmtlRandomCount = 0; + inmtodRandomCount = 0; + stfRandomCount = 0; + stlRandomCount = 0; + + maxAdultOverlaps = 0; + maxChildOverlaps = 0; + maxMixedOverlaps = 0; + + for (int i = 1; i < persons.length; i++) + persons[i].initializeForAoRestart(); + + } + + public void initializeForImtfRestart() + { + jointTours = null; + + imtfModelPattern = 0; + jtfModelPattern = null; + + imtodRandomCount = 0; + jtfRandomCount = 0; + jtlRandomCount = 0; + jtodRandomCount = 0; + inmtfRandomCount = 0; + inmtlRandomCount = 0; + inmtodRandomCount = 0; + awfRandomCount = 0; + awlRandomCount = 0; + awtodRandomCount = 0; + stfRandomCount = 0; + stlRandomCount = 0; + + maxAdultOverlaps = 0; + maxChildOverlaps = 0; + maxMixedOverlaps = 0; + + for (int i = 1; i < persons.length; i++) + persons[i].initializeForImtfRestart(); + + } + + public void initializeForJtfRestart() + { + + jtfModelPattern = null; + + jtfRandomCount = 0; + jtlRandomCount = 0; + jtodRandomCount = 0; + inmtfRandomCount = 0; + inmtlRandomCount = 0; + inmtodRandomCount = 0; + awfRandomCount = 0; + awlRandomCount = 0; + awtodRandomCount = 0; + stfRandomCount = 0; + stlRandomCount = 0; + + initializeWindows(); + + if (jointTours != null) + { + for (Tour t : jointTours) + { + t.clearStopModelResults(); + } + } + + for (int i = 1; i < persons.length; i++) + persons[i].initializeForJtfRestart(); + + jointTours = null; + + } + + public void initializeForInmtfRestart() + { + + inmtfRandomCount = 0; + inmtlRandomCount = 0; + inmtodRandomCount = 0; + awfRandomCount = 0; + awlRandomCount = 0; + awtodRandomCount = 0; + stfRandomCount = 0; + stlRandomCount = 0; + + initializeWindows(); + + if (jointTours != null) + { + for (Tour t : jointTours) + { + for (int i : t.getPersonNumArray()) + persons[i].scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + } + + for (int i = 1; i < persons.length; i++) + persons[i].initializeForInmtfRestart(); + + } + + public void initializeForAwfRestart() + { + + awfRandomCount = 0; + awlRandomCount = 0; + awtodRandomCount = 0; + stfRandomCount = 0; + stlRandomCount = 0; + + initializeWindows(); + + if (jointTours != null) + { + for (Tour t : jointTours) + { + for (int i : t.getPersonNumArray()) + persons[i].scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + } + + for (int i = 1; i < persons.length; i++) + persons[i].initializeForAwfRestart(); + + } + + public void initializeForStfRestart() + { + + stfRandomCount = 0; + stlRandomCount = 0; + + for (int i = 1; i < persons.length; i++) + persons[i].initializeForStfRestart(); + + } + + public long getSeed() { + return seed; + } + public void setSeed(long seed) { + this.seed = seed; + } + + public float getAutoOwnershipLogsum() { + return autoOwnershipLogsum; + } + + public void setAutoOwnershipLogsum(float autoOwnershipLogsum) { + this.autoOwnershipLogsum = autoOwnershipLogsum; + } + + public float getTransponderLogsum() { + return transponderLogsum; + } + + public void setTransponderLogsum(float transponderLogsum) { + this.transponderLogsum = transponderLogsum; + } + + public float getCdapLogsum() { + return cdapLogsum; + } + + public void setCdapLogsum(float cdapLogsum) { + this.cdapLogsum = cdapLogsum; + } + + public float getJtfLogsum() { + return jtfLogsum; + } + + public void setJtfLogsum(float jtfLogsum) { + this.jtfLogsum = jtfLogsum; + } + + public void logHouseholdObject(String titleString, Logger logger) + { + + int totalChars = 72; + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "H"; + + logger.info(separater); + logger.info(titleString); + logger.info(separater); + + Household.logHelper(logger, "hhId: ", hhId, totalChars); + Household.logHelper(logger, "debugChoiceModels: ", debugChoiceModels ? "True" : "False", + totalChars); + Household.logHelper(logger, "hhIncome: ", hhIncomeCategory, totalChars); + Household.logHelper(logger, "hhIncomeInDollars: ", hhIncomeInDollars, totalChars); + Household.logHelper(logger, "hhSize: ", hhSize, totalChars); + Household.logHelper(logger, "hhType: ", hhType, totalChars); + Household.logHelper(logger, "hhWorkers: ", hhWorkers, totalChars); + Household.logHelper(logger, "homeTaz: ", homeTaz, totalChars); + Household.logHelper(logger, "homeMgra: ", homeMgra, totalChars); + Household.logHelper(logger, "homeWalkSubzone: ", homeWalkSubzone, totalChars); + Household.logHelper(logger, "aoModelAutos: ", aoModelAutos, totalChars); + Household.logHelper(logger, "cdapModelPattern: ", cdapModelPattern, totalChars); + Household.logHelper(logger, "imtfModelPattern: ", imtfModelPattern, totalChars); + Household.logHelper(logger, "outboundEscortChoice: ", outboundEscortChoice, totalChars); + Household.logHelper(logger, "inboundEscortChoice: ", inboundEscortChoice, totalChars); + Household.logHelper(logger, "jtfModelPattern: ", jtfModelPattern, totalChars); + Household.logHelper(logger, "randomCount: ", randomCount, totalChars); + if (uwslRandomCountList.size() > 0) + { + for (int i : uwslRandomCountList.keySet()) + Household.logHelper(logger, String.format("uwslRandomCount[%d]: ", i), + uwslRandomCountList.get(i), totalChars); + } else + { + Household.logHelper(logger, "uwslRandomCount[0]: ", 0, totalChars); + } + Household.logHelper(logger, "aoRandomCount: ", aoRandomCount, totalChars); + Household.logHelper(logger, "tpRandomCount: ", tpRandomCount, totalChars); + Household.logHelper(logger, "fpRandomCount: ", fpRandomCount, totalChars); + Household.logHelper(logger, "ieRandomCount: ", ieRandomCount, totalChars); + Household.logHelper(logger, "cdapRandomCount: ", cdapRandomCount, totalChars); + Household.logHelper(logger, "imtfRandomCount: ", imtfRandomCount, totalChars); + Household.logHelper(logger, "imtodRandomCount: ", imtodRandomCount, totalChars); + Household.logHelper(logger, "awfRandomCount: ", awfRandomCount, totalChars); + Household.logHelper(logger, "awlRandomCount: ", awlRandomCount, totalChars); + Household.logHelper(logger, "awtodRandomCount: ", awtodRandomCount, totalChars); + Household.logHelper(logger, "jtfRandomCount: ", jtfRandomCount, totalChars); + Household.logHelper(logger, "jtlRandomCount: ", jtlRandomCount, totalChars); + Household.logHelper(logger, "jtodRandomCount: ", jtodRandomCount, totalChars); + Household.logHelper(logger, "inmtfRandomCount: ", inmtfRandomCount, totalChars); + Household.logHelper(logger, "inmtlRandomCount: ", inmtlRandomCount, totalChars); + Household.logHelper(logger, "inmtodRandomCount: ", inmtodRandomCount, totalChars); + Household.logHelper(logger, "stfRandomCount: ", stfRandomCount, totalChars); + Household.logHelper(logger, "stlRandomCount: ", stlRandomCount, totalChars); + Household.logHelper(logger, "maxAdultOverlaps: ", maxAdultOverlaps, totalChars); + Household.logHelper(logger, "maxChildOverlaps: ", maxChildOverlaps, totalChars); + Household.logHelper(logger, "maxMixedOverlaps: ", maxMixedOverlaps, totalChars); + + String tempString = String.format("Joint Tours[%s]:", + jointTours == null ? "" : String.valueOf(jointTours.length)); + logger.info(tempString); + + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public void logPersonObject(String titleString, Logger logger, Person person) + { + + int totalChars = 114; + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "P"; + + logger.info(separater); + logger.info(titleString); + logger.info(separater); + + person.logPersonObject(logger, totalChars); + + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public void logTourObject(String titleString, Logger logger, Person person, Tour tour) + { + + int totalChars = 119; + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "T"; + + logger.info(separater); + logger.info(titleString); + logger.info(separater); + + person.logTourObject(logger, totalChars, tour); + + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public void logStopObject(String titleString, Logger logger, Stop stop, + ModelStructure modelStructure) + { + + int totalChars = 119; + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "S"; + + logger.info(separater); + logger.info(titleString); + logger.info(separater); + + stop.logStopObject(logger, totalChars); + + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public void logEntireHouseholdObject(String titleString, Logger logger) + { + + int totalChars = 60; + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "="; + + logger.info(separater); + logger.info(titleString); + logger.info(separater); + + separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "-"; + + Household.logHelper(logger, "hhId: ", hhId, totalChars); + Household.logHelper(logger, "debugChoiceModels: ", debugChoiceModels ? "True" : "False", + totalChars); + Household.logHelper(logger, "hhIncome: ", hhIncomeCategory, totalChars); + Household.logHelper(logger, "hhIncomeInDollars: ", hhIncomeInDollars, totalChars); + Household.logHelper(logger, "hhSize: ", hhSize, totalChars); + Household.logHelper(logger, "hhType: ", hhType, totalChars); + Household.logHelper(logger, "hhWorkers: ", hhWorkers, totalChars); + Household.logHelper(logger, "homeTaz: ", homeTaz, totalChars); + Household.logHelper(logger, "homeMgra: ", homeMgra, totalChars); + Household.logHelper(logger, "homeWalkSubzone: ", homeWalkSubzone, totalChars); + Household.logHelper(logger, "aoModelAutos: ", aoModelAutos, totalChars); + Household.logHelper(logger, "cdapModelPattern: ", cdapModelPattern, totalChars); + Household.logHelper(logger, "imtfModelPattern: ", imtfModelPattern, totalChars); + Household.logHelper(logger, "outboundEscortChoice: ", outboundEscortChoice, totalChars); + Household.logHelper(logger, "inboundEscortChoice: ", inboundEscortChoice, totalChars); + Household.logHelper(logger, "jtfModelPattern: ", jtfModelPattern, totalChars); + Household.logHelper(logger, "randomCount: ", randomCount, totalChars); + if (uwslRandomCountList.size() > 0) + { + for (int i : uwslRandomCountList.keySet()) + Household.logHelper(logger, String.format("uwslRandomCount[%d]: ", i), + uwslRandomCountList.get(i), totalChars); + } else + { + Household.logHelper(logger, "uwslRandomCount[0]: ", 0, totalChars); + } + Household.logHelper(logger, "aoRandomCount: ", aoRandomCount, totalChars); + Household.logHelper(logger, "tpRandomCount: ", tpRandomCount, totalChars); + Household.logHelper(logger, "fpRandomCount: ", fpRandomCount, totalChars); + Household.logHelper(logger, "ieRandomCount: ", ieRandomCount, totalChars); + Household.logHelper(logger, "cdapRandomCount: ", cdapRandomCount, totalChars); + Household.logHelper(logger, "imtfRandomCount: ", imtfRandomCount, totalChars); + Household.logHelper(logger, "imtodRandomCount: ", imtodRandomCount, totalChars); + Household.logHelper(logger, "awfRandomCount: ", awfRandomCount, totalChars); + Household.logHelper(logger, "awlRandomCount: ", awlRandomCount, totalChars); + Household.logHelper(logger, "awtodRandomCount: ", awtodRandomCount, totalChars); + Household.logHelper(logger, "jtfRandomCount: ", jtfRandomCount, totalChars); + Household.logHelper(logger, "jtlRandomCount: ", jtlRandomCount, totalChars); + Household.logHelper(logger, "jtodRandomCount: ", jtodRandomCount, totalChars); + Household.logHelper(logger, "inmtfRandomCount: ", inmtfRandomCount, totalChars); + Household.logHelper(logger, "inmtlRandomCount: ", inmtlRandomCount, totalChars); + Household.logHelper(logger, "inmtodRandomCount: ", inmtodRandomCount, totalChars); + Household.logHelper(logger, "stfRandomCount: ", stfRandomCount, totalChars); + Household.logHelper(logger, "stlRandomCount: ", stlRandomCount, totalChars); + Household.logHelper(logger, "maxAdultOverlaps: ", maxAdultOverlaps, totalChars); + Household.logHelper(logger, "maxChildOverlaps: ", maxChildOverlaps, totalChars); + Household.logHelper(logger, "maxMixedOverlaps: ", maxMixedOverlaps, totalChars); + + if (jointTours != null) + { + logger.info("Joint Tours:"); + if (jointTours.length > 0) + { + for (int i = 0; i < jointTours.length; i++) + jointTours[i].logEntireTourObject(logger); + } else logger.info(" No joint tours"); + } else logger.info(" No joint tours"); + + logger.info("Person Objects:"); + for (int i = 1; i < persons.length; i++) + persons[i].logEntirePersonObject(logger); + + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public static void logHelper(Logger logger, String label, int value, int totalChars) + { + int labelChars = label.length() + 2; + int remainingChars = totalChars - labelChars - 4; + String formatString = String.format(" %%%ds %%%dd", label.length(), remainingChars); + String logString = String.format(formatString, label, value); + logger.info(logString); + } + + public static void logHelper(Logger logger, String label, String value, int totalChars) + { + int labelChars = label.length() + 2; + int remainingChars = totalChars - labelChars - 4; + String formatString = String.format(" %%%ds %%%ds", label.length(), remainingChars); + String logString = String.format(formatString, label, value); + logger.info(logString); + } + + public static void logHelper(Logger logger, String label, float value, int totalChars) + { + int labelChars = label.length() + 2; + int remainingChars = totalChars - labelChars - 4; + String formatString = String.format(" %%%ds %%%df", label.length(), remainingChars); + String logString = String.format(formatString, label, value); + logger.info(logString); + } + public enum HouseholdType + { + nul, FAMILY_MARRIED, FAMILY_MALE_NO_WIFE, FAMILY_FEMALE_NO_HUSBAND, NON_FAMILY_MALE_ALONE, NON_FAMILY_MALE_NOT_ALONE, NON_FAMILY_FEMALE_ALONE, NON_FAMILY_FEMALE_NOT_ALONE + } + + /** + * Iterate through persons in household grab all adults and add them to an ArrayList of adults. Return the list. + * + * @return An ArrayList of adult household members. + */ + public List getAdultPersons() { + + List adultList = new ArrayList(); + + for(int i = 1; i < persons.length; ++i){ + Person p = persons[i]; + if((p.getPersonIsFullTimeWorker()==1)||(p.getPersonIsPartTimeWorker()==1)||(p.getPersonIsNonWorkingAdultUnder65()==1) + ||(p.getPersonIsUniversityStudent()==1)||(p.getPersonIsNonWorkingAdultOver65()==1)) + adultList.add(p); + + } + return adultList; + } + /** + * Iterate through persons in household grab all adults and add them to an ArrayList of adults. Return the list. + * + * @return An ArrayList of adult household members. + */ + public List getActiveAdultPersons() { + + List adultList = new ArrayList(); + + for(int i = 1; i < persons.length; ++i){ + Person p = persons[i]; + if(p.isActiveAdult()) + adultList.add(p); + + } + return adultList; + } + + /** + * Count and return the number of active adults in the household. + * + * @return The number of active adults. + */ + public int getNumberActiveAdults(){ + + int numberActiveAdults=0; + for(int i = 1; i < persons.length; ++i){ + if(persons[i].isActiveAdult()) + ++numberActiveAdults; + + } + return numberActiveAdults; + } + + + /** + * Iterate through persons in household grab all children and add them to an ArrayList of children. Return the list. + * + * @return An ArrayList of adult household members. + */ + public List getChildPersons() { + + List childList = new ArrayList(); + + for(int i = 1; i < persons.length; ++i){ + Person p = persons[i]; + if((p.getPersonIsPreschoolChild()==1)||(p.getPersonIsStudentNonDriving()==1)||(p.getPersonIsStudentDriving()==1)) + childList.add(p); + + } + return childList; + } + } diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdAtWorkSubtourFrequencyModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdAtWorkSubtourFrequencyModel.java new file mode 100644 index 0000000..11daef6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdAtWorkSubtourFrequencyModel.java @@ -0,0 +1,334 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +// + +public class HouseholdAtWorkSubtourFrequencyModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(HouseholdAtWorkSubtourFrequencyModel.class); + private transient Logger tourFreq = Logger.getLogger("tourFreq"); + + private static final String AWTF_CONTROL_FILE_TARGET = "awtf.uec.file"; + private static final String AWTF_DATA_SHEET_TARGET = "awtf.data.page"; + private static final String AWTF_MODEL_SHEET_TARGET = "awtf.model.page"; + + // model results + // private static final int NO_SUBTOURS = 1; + private static final int ONE_EAT = 2; + private static final int ONE_BUSINESS = 3; + private static final int ONE_OTHER = 4; + private static final int TWO_BUSINESS = 5; + private static final int TWO_OTHER = 6; + private static final int ONE_EAT_ONE_BUSINESS = 7; + + private AtWorkSubtourFrequencyDMU dmuObject; + private ChoiceModelApplication choiceModelApplication; + + private ModelStructure modelStructure; + private String[] alternativeNames; + + /** + * Constructor establishes the ChoiceModelApplication, which applies the + * logit model via the UEC spreadsheet. + * + * @param dmuObject + * is the UEC dmu object for this choice model + * @param uecFileName + * is the UEC control file name + * @param resourceBundle + * is the application ResourceBundle, from which a properties + * file HashMap will be created for the UEC + * @param tazDataManager + * is the object used to interact with the zonal data table + * @param modelStructure + * is the ModelStructure object that defines segmentation and + * other model structure relate atributes + */ + public HouseholdAtWorkSubtourFrequencyModel(HashMap propertyMap, + ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory) + { + + this.modelStructure = modelStructure; + setUpModels(propertyMap, dmuFactory); + + } + + private void setUpModels(HashMap propertyMap, CtrampDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up %s tour frequency choice model.", + ModelStructure.AT_WORK_CATEGORY)); + + // locate the individual mandatory tour frequency choice model UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String awtfUecFile = propertyMap.get(AWTF_CONTROL_FILE_TARGET); + awtfUecFile = uecPath + awtfUecFile; + + int dataPage = Util.getIntegerValueFromPropertyMap(propertyMap, AWTF_DATA_SHEET_TARGET); + int modelPage = Util.getIntegerValueFromPropertyMap(propertyMap, AWTF_MODEL_SHEET_TARGET); + + dmuObject = dmuFactory.getAtWorkSubtourFrequencyDMU(); + + // set up the model + choiceModelApplication = new ChoiceModelApplication(awtfUecFile, modelPage, dataPage, + propertyMap, (VariableTable) dmuObject); + + } + + /** + * Applies the model for the array of households that are stored in the + * HouseholdDataManager. The results are summarized by person type. + * + * @param householdDataManager + * is the object containg the Household objects for which this + * model is to be applied. + */ + public void applyModel(Household household) + { + + int choice = -1; + String personTypeString = ""; + + Logger modelLogger = tourFreq; + if (household.getDebugChoiceModels()) + household.logHouseholdObject( + "Pre AtWork Subtour Frequency Choice HHID=" + household.getHhId() + " Object", + modelLogger); + + // get this household's person array + Person[] personArray = household.getPersons(); + + // set the household id, origin taz, hh taz, and debugFlag=false in the + // dmu + dmuObject.setHouseholdObject(household); + + // loop through the person array (1-based) + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + + // count the results by person type + personTypeString = person.getPersonType(); + + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), personTypeString); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + // loop through the work tours for this person + ArrayList tourList = person.getListOfWorkTours(); + if (tourList == null) continue; + + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + int workTourIndex = 0; + for (Tour workTour : tourList) + { + + try + { + + // set the person and tour object + dmuObject.setPersonObject(person); + dmuObject.setTourObject(workTour); + + // write debug header + if (household.getDebugChoiceModels() || person.getPersonTypeNumber() == 7) + { + + choiceModelDescription = String + .format("At-work Subtour Frequency Choice Model:"); + decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, workTourId=%d", person + .getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), workTour.getTourId()); + choiceModelApplication.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = choiceModelDescription + " for " + decisionMakerLabel + + "."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + + } + + // set the availability array for the tour frequency model + alternativeNames = choiceModelApplication.getAlternativeNames(); + int numberOfAlternatives = alternativeNames.length; + boolean[] availabilityArray = new boolean[numberOfAlternatives + 1]; + Arrays.fill(availabilityArray, true); + + // create the sample array + int[] sampleArray = new int[availabilityArray.length]; + Arrays.fill(sampleArray, 1); + + // compute the utilities + IndexValues index = dmuObject.getDmuIndexValues(); + index.setHHIndex(household.getHhId()); + index.setZoneIndex(household.getHhTaz()); + index.setOriginZone(workTour.getTourOrigMgra()); + index.setDestZone(workTour.getTourDestMgra()); + index.setDebug(household.getDebugChoiceModels()); + + if (household.getDebugChoiceModels()) + { + household.logTourObject(loggingHeader, modelLogger, person, workTour); + } + + float logsum = (float) choiceModelApplication.computeUtilities(dmuObject, index, availabilityArray, + sampleArray); + + workTour.setSubtourFreqLogsum(logsum); + // get the random number from the household + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, + // make choice. + if (choiceModelApplication.getAvailabilityCount() > 0) choice = choiceModelApplication + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught for j=%d, tourNum=%d, HHID=%d, no available at-work frequency alternatives to choose from in choiceModelApplication.", + j, workTourIndex, person.getHouseholdObject().getHhId())); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = choiceModelApplication.getUtilities(); + double[] probabilities = choiceModelApplication.getProbabilities(); + + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + + personTypeString); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("-------------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < alternativeNames.length; k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %-16s", k + 1, + alternativeNames[k]); + modelLogger.info(String.format("%-20s%18.6e%18.6e%18.6e", altString, + utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %-16s", choice, + alternativeNames[choice - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + choiceModelApplication.logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + choiceModelApplication.logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, choice); + + // write UEC calculation results to separate model + // specific + // log file + choiceModelApplication.logUECResults(modelLogger, loggingHeader); + + } + + workTour.setSubtourFreqChoice(choice); + + // set the person choices + if (choice == ONE_EAT) + { + int id = workTourIndex * 10 + 1; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkEatPurposeName()); + } else if (choice == ONE_BUSINESS) + { + int id = workTourIndex * 10 + 1; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkBusinessPurposeName()); + } else if (choice == ONE_OTHER) + { + int id = workTourIndex * 10 + 1; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkMaintPurposeName()); + } else if (choice == TWO_BUSINESS) + { + int id = workTourIndex * 10 + 1; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkBusinessPurposeName()); + id = workTourIndex * 10 + 2; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkBusinessPurposeName()); + } else if (choice == TWO_OTHER) + { + int id = workTourIndex * 10 + 1; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkMaintPurposeName()); + id = workTourIndex * 10 + 2; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkMaintPurposeName()); + } else if (choice == ONE_EAT_ONE_BUSINESS) + { + int id = workTourIndex * 10 + 1; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkEatPurposeName()); + id = workTourIndex * 10 + 2; + person.createAtWorkSubtour(id, choice, workTour.getTourDestMgra(), + modelStructure.getAtWorkBusinessPurposeName()); + } + + } catch (Exception e) + { + logger.error(String.format("Exception caught for j=%d, tourNum=%d, HHID=%d.", + j, workTourIndex, household.getHhId())); + throw new RuntimeException(); + } + + workTourIndex++; + + } + + } // j (person loop) + + household.setAwfRandomCount(household.getHhRandomCount()); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdAutoOwnershipModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdAutoOwnershipModel.java new file mode 100644 index 0000000..cfa8483 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdAutoOwnershipModel.java @@ -0,0 +1,343 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import com.pb.common.calculator.VariableTable; +import com.pb.common.model.ModelException; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class HouseholdAutoOwnershipModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(HouseholdAutoOwnershipModel.class); + private transient Logger aoLogger = Logger.getLogger("ao"); + + private static final String AO_CONTROL_FILE_TARGET = "ao.uec.file"; + private static final String AO_MODEL_SHEET_TARGET = "ao.model.page"; + private static final String AO_DATA_SHEET_TARGET = "ao.data.page"; + + private static final int AUTO_SOV_TIME_INDEX = 10; + private static final int AUTO_LOGSUM_INDEX = 6; + private static final int TRANSIT_LOGSUM_INDEX = 8; + private static final int DT_RAIL_PROP_INDEX = 10; + + private AccessibilitiesTable accTable; + private MandatoryAccessibilitiesCalculator mandAcc; + private ChoiceModelApplication aoModel; + private AutoOwnershipChoiceDMU aoDmuObject; + + private int[] totalAutosByAlt; + private int[] automatedVehiclesByAlt; + private int[] conventionalVehiclesByAlt; + + public HouseholdAutoOwnershipModel(HashMap rbMap, + CtrampDmuFactoryIf dmuFactory, AccessibilitiesTable myAccTable, + MandatoryAccessibilitiesCalculator myMandAcc) + { + + logger.info("setting up AO choice model."); + + // set the aggAcc class variable, which will serve as a flag: null -> no + // accessibilities, !null -> set accessibilities. + // if the BuildAccessibilities object is null, the AO utility does not + // need + // to use the accessibilities components. + accTable = myAccTable; + mandAcc = myMandAcc; + + // locate the auto ownership UEC + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String autoOwnershipUecFile = rbMap.get(AO_CONTROL_FILE_TARGET); + autoOwnershipUecFile = uecPath + autoOwnershipUecFile; + + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, AO_DATA_SHEET_TARGET); + int modelPage = Util.getIntegerValueFromPropertyMap(rbMap, AO_MODEL_SHEET_TARGET); + + // create the auto ownership choice model DMU object. + aoDmuObject = dmuFactory.getAutoOwnershipDMU(); + + // create the auto ownership choice model object + aoModel = new ChoiceModelApplication(autoOwnershipUecFile, modelPage, dataPage, rbMap, + (VariableTable) aoDmuObject); + + String[] alternativeNames = aoModel.getAlternativeNames(); + calculateAlternativeArrays(alternativeNames); + + } + + /** + * Set the dmu attributes, compute the pre-AO or AO utilities, and select an + * alternative + * + * @param hhObj + * for which to apply thye model + * @param preAutoOwnership + * is true if running pre-auto ownership, or false to run primary + * auto ownership model. + */ + + public void applyModel(Household hhObj, boolean preAutoOwnership) + { + + // update the AO dmuObject for this hh + aoDmuObject.setHouseholdObject(hhObj); + aoDmuObject.setDmuIndexValues(hhObj.getHhId(), hhObj.getHhMgra(), hhObj.getHhMgra(), 0); + + // set the non-mandatory accessibility values for the home MGRA. + // values used by both pre-ao and ao models. + aoDmuObject.setHomeTazAutoAccessibility(accTable.getAggregateAccessibility("auto", + hhObj.getHhMgra())); + aoDmuObject.setHomeTazTransitAccessibility(accTable.getAggregateAccessibility("transit", + hhObj.getHhMgra())); + aoDmuObject.setHomeTazNonMotorizedAccessibility(accTable.getAggregateAccessibility( + "nonmotor", hhObj.getHhMgra())); + aoDmuObject.setHomeTazMaasAccessibility(accTable.getAggregateAccessibility("maas", + hhObj.getHhMgra())); + + + + if (preAutoOwnership) + { + + aoDmuObject.setUseAccessibilities(false); + + } else + { + + aoDmuObject.setUseAccessibilities(true); + + // compute the disaggregate accessibilities for the home MGRA to + // work and + // school MGRAs summed accross workers and students + double workAutoDependency = 0.0; + double schoolAutoDependency = 0.0; + double workRailProp = 0.0; + double schoolRailProp = 0.0; + double workAutoTime = 0.0; + Person[] persons = hhObj.getPersons(); + for (int i = 1; i < persons.length; i++) + { + + // sum over all workers (full time or part time) + if (persons[i].getPersonIsWorker() == 1) + { + + int workMgra = persons[i].getWorkLocation(); + if (workMgra != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + + // Non-Motorized Factor = 0.5*MIN(MAX(DIST,1),3)-0.5 + // if 0 <= dist < 1, nmFactor = 0 + // if 1 <= dist <= 3, nmFactor = [0.0, 1.0] + // if 3 <= dist, nmFactor = 1.0 + double nmFactor = 0.5 * (Math.min( + Math.max(persons[i].getWorkLocationDistance(), 1.0), 3.0)) - 0.5; + + // if auto logsum < transit logsum, do not accumulate + // auto + // dependency + double[] workerAccessibilities = mandAcc + .calculateWorkerMandatoryAccessibilities(hhObj.getHhMgra(), + workMgra); + workAutoTime += workerAccessibilities[AUTO_SOV_TIME_INDEX]; + if (workerAccessibilities[AUTO_LOGSUM_INDEX] >= workerAccessibilities[TRANSIT_LOGSUM_INDEX]) + { + double logsumDiff = workerAccessibilities[AUTO_LOGSUM_INDEX] + - workerAccessibilities[TRANSIT_LOGSUM_INDEX]; + + // need to scale and cap logsum difference + logsumDiff = Math.min(logsumDiff / 3.0, 1.0); + workAutoDependency += (logsumDiff * nmFactor); + } + + workRailProp += workerAccessibilities[DT_RAIL_PROP_INDEX]; + + } + + } + + // sum over all students of driving age + if (persons[i].getPersonIsUniversityStudent() == 1 + || persons[i].getPersonIsStudentDriving() == 1) + { + + int schoolMgra = persons[i].getUsualSchoolLocation(); + if (schoolMgra != ModelStructure.NOT_ENROLLED_SEGMENT_INDEX) + { + + // Non-Motorized Factor = 0.5*MIN(MAX(DIST,1),3)-0.5 + // if 0 <= dist < 1, nmFactor = 0 + // if 1 <= dist <= 3, nmFactor = [0.0, 1.0] + // if 3 <= dist, nmFactor = 1.0 + double nmFactor = 0.5 * (Math.min( + Math.max(persons[i].getWorkLocationDistance(), 1.0), 3.0)) - 0.5; + + // if auto logsum < transit logsum, do not accumulate + // auto + // dependency + double[] studentAccessibilities = mandAcc + .calculateStudentMandatoryAccessibilities(hhObj.getHhMgra(), + schoolMgra); + if (studentAccessibilities[AUTO_LOGSUM_INDEX] >= studentAccessibilities[TRANSIT_LOGSUM_INDEX]) + { + double logsumDiff = studentAccessibilities[AUTO_LOGSUM_INDEX] + - studentAccessibilities[TRANSIT_LOGSUM_INDEX]; + + // need to scale and cap logsum difference + logsumDiff = Math.min(logsumDiff / 3.0, 1.0); + schoolAutoDependency += (logsumDiff * nmFactor); + } + + schoolRailProp += studentAccessibilities[DT_RAIL_PROP_INDEX]; + + } + } + + } + + aoDmuObject.setWorkAutoDependency(workAutoDependency); + aoDmuObject.setSchoolAutoDependency(schoolAutoDependency); + + aoDmuObject.setWorkersRailProportion(workRailProp); + aoDmuObject.setStudentsRailProportion(schoolRailProp); + + aoDmuObject.setWorkAutoTime(workAutoTime); + + } + + // compute utilities and choose auto ownership alternative. + float logsum = (float) aoModel.computeUtilities(aoDmuObject, aoDmuObject.getDmuIndexValues()); + + hhObj.setAutoOwnershipLogsum(logsum); + Random hhRandom = hhObj.getHhRandom(); + int randomCount = hhObj.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt = -1; + if (aoModel.getAvailabilityCount() > 0) + { + try + { + chosenAlt = aoModel.getChoiceResult(rn); + } catch (ModelException e) + { + logger.error(String.format( + "exception caught for HHID=%d in choiceModelApplication.", hhObj.getHhId())); + } + } else + { + logger.error(String + .format("error: HHID=%d has no available auto ownership alternatives to choose from in choiceModelApplication.", + hhObj.getHhId())); + throw new RuntimeException(); + } + + // write choice model alternative info to log file + if (hhObj.getDebugChoiceModels() || chosenAlt < 0) + { + + String loggerString = (preAutoOwnership ? "Pre-AO without" : "AO with") + + " accessibilities, Household " + hhObj.getHhId() + " Object"; + hhObj.logHouseholdObject(loggerString, aoLogger); + + double[] utilities = aoModel.getUtilities(); + double[] probabilities = aoModel.getProbabilities(); + + aoLogger.info("Alternative Utility Probability CumProb"); + aoLogger.info("-------------------- --------------- ------------ ------------"); + + double cumProb = 0.0; + for (int k = 0; k < aoModel.getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + aoLogger.info(String.format("%-20s%18.6e%18.6e%18.6e", k + " autos", utilities[k], + probabilities[k], cumProb)); + } + + aoLogger.info(" "); + aoLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", chosenAlt, rn, + randomCount)); + + aoLogger.info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + aoLogger.info(""); + aoLogger.info(""); + + // write choice model alternative info to debug log file + aoModel.logAlternativesInfo("Household Auto Ownership Choice", + String.format("HH_%d", hhObj.getHhId())); + aoModel.logSelectionInfo("Household Auto Ownership Choice", + String.format("HH_%d", hhObj.getHhId()), rn, chosenAlt); + + // write UEC calculation results to separate model specific log file + aoModel.logUECResults(aoLogger, + String.format("Household Auto Ownership Choice, HH_%d", hhObj.getHhId())); + } + + if (preAutoOwnership) hhObj.setPreAoRandomCount(hhObj.getHhRandomCount()); + else hhObj.setAoRandomCount(hhObj.getHhRandomCount()); + + int autos = totalAutosByAlt[chosenAlt-1]; + int AVs = automatedVehiclesByAlt[chosenAlt-1]; + int CVs = conventionalVehiclesByAlt[chosenAlt-1]; + hhObj.setHhAutos(autos); + hhObj.setAutomatedVehicles(AVs); + hhObj.setConventionalVehicles(CVs); + + } + + + /** + * This is a helper method that iterates through the alternative names + * in the auto ownership UEC and searches through each name to collect + * the total number of autos (in the first position of the name character + * array), the number of AVs for the alternative (preceded by the "AV" substring) + * and the number of CVs for the alternative (preceded by the "CV" substring). The + * results are stored in the arrays: + * + * totalAutosByAlt + * automatedVehiclesByAlt + * conventionalVehiclesByAlt + * + * @param alternativeNames The array of alternative names. + */ + private void calculateAlternativeArrays(String[] alternativeNames){ + + totalAutosByAlt = new int[alternativeNames.length]; + automatedVehiclesByAlt = new int[alternativeNames.length]; + conventionalVehiclesByAlt = new int[alternativeNames.length]; + + + //iterate thru names + for(int i = 0; i < alternativeNames.length;++i){ + + String altName = alternativeNames[i]; + + //find the number of cars; first element of name (e.g. 0_CARS) + int autos = new Integer(altName.substring(0,1)).intValue(); + int AVs=0; + int HVs=0; + int AVPosition = altName.indexOf("AV"); + if(AVPosition>=0) + AVs = new Integer(altName.substring(AVPosition-1, AVPosition)).intValue(); + int HVPosition = altName.indexOf("HV"); + if(HVPosition>=0) + HVs = new Integer(altName.substring(HVPosition-1, HVPosition)).intValue(); + + totalAutosByAlt[i] = autos; + automatedVehiclesByAlt[i] = AVs; + conventionalVehiclesByAlt[i] = HVs; + + } + + } + + +} + diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelRunner.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelRunner.java new file mode 100644 index 0000000..3a5d92a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelRunner.java @@ -0,0 +1,254 @@ +package org.sandag.abm.ctramp; + +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; + +import org.apache.log4j.Logger; +import org.jppf.client.JPPFClient; +import org.jppf.client.JPPFJob; +import org.jppf.node.protocol.DataProvider; +import org.jppf.node.protocol.MemoryMapDataProvider; +import org.jppf.node.protocol.Task; + +import com.pb.common.calculator.MatrixDataServerIf; + +public class HouseholdChoiceModelRunner +{ + + private Logger logger = Logger.getLogger(HouseholdChoiceModelRunner.class); + + private static int PACKET_SIZE = 0; + + private static String PROPERTIES_NUM_INITIALIZATION_PACKETS = "number.initialization.packets"; + private static String PROPERTIES_INITIALIZATION_PACKET_SIZE = "initialization.packet.size"; + private static int NUM_INITIALIZATION_PACKETS = 0; + private static int INITIALIZATION_PACKET_SIZE = 0; + + private int ONE_HH_ID = -1; + + private static final String HOUSEHOLD_CHOICE_PACKET_SIZE = "distributed.task.packet.size"; + private static final String RUN_THIS_HOUSEHOLD_ONLY = "run.this.household.only"; + + private HashMap propertyMap; + private String restartModelString; + private MatrixDataServerIf ms; + private HouseholdDataManagerIf hhDataManager; + private ModelStructure modelStructure; + private CtrampDmuFactoryIf dmuFactory; + + private JPPFClient jppfClient; + private boolean logResults=false; + + // The number of initialization packets are the number of "small" packets + // submited at the beginning of a + // distributed task to minimize synchronization issues that significantly + // slow + // down model object setup. + // It is assumed that after theses small packets have run, all the model + // objects + // will have been setup, + // and the task objects can process much bigger chuncks of households. + + public HouseholdChoiceModelRunner(HashMap propertyMap, JPPFClient jppfClient, + String restartModelString, HouseholdDataManagerIf hhDataManager, MatrixDataServerIf ms, + ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory) + { + setupHouseholdChoiceModelRunner(propertyMap, jppfClient, restartModelString, hhDataManager, + ms, modelStructure, dmuFactory); + } + + private void setupHouseholdChoiceModelRunner(HashMap propertyMap, + JPPFClient jppfClient, String restartModelString, HouseholdDataManagerIf hhDataManager, + MatrixDataServerIf ms, ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory) + { + + this.propertyMap = propertyMap; + this.restartModelString = restartModelString; + this.hhDataManager = hhDataManager; + this.ms = ms; + this.modelStructure = modelStructure; + this.dmuFactory = dmuFactory; + this.jppfClient = jppfClient; + + String oneHhString = propertyMap.get(RUN_THIS_HOUSEHOLD_ONLY); + if (oneHhString != null) ONE_HH_ID = Integer.parseInt(oneHhString); + + String propertyValue = propertyMap.get(HOUSEHOLD_CHOICE_PACKET_SIZE); + if (propertyValue == null) PACKET_SIZE = 0; + else PACKET_SIZE = Integer.parseInt(propertyValue); + + propertyValue = propertyMap.get(PROPERTIES_NUM_INITIALIZATION_PACKETS); + if (propertyValue == null) NUM_INITIALIZATION_PACKETS = 0; + else NUM_INITIALIZATION_PACKETS = Integer.parseInt(propertyValue); + + propertyValue = propertyMap.get(PROPERTIES_INITIALIZATION_PACKET_SIZE); + if (propertyValue == null) INITIALIZATION_PACKET_SIZE = 0; + else INITIALIZATION_PACKET_SIZE = Integer.parseInt(propertyValue); + + logResults = Util.getStringValueFromPropertyMap(propertyMap, "RunModel.LogResults") + .equalsIgnoreCase("true"); + } + + /** + * + * JPPF framework based method + */ + public void runHouseholdChoiceModels() + { + + long initTime = System.currentTimeMillis(); + + submitTasks(); + + logger.info(String.format("household model runner finished %d households in %d minutes.", + hhDataManager.getNumHouseholds(), + ((System.currentTimeMillis() - initTime) / 1000) / 60)); + + } + + /** + * @param client + * is a JPPFClient object which is used to establish a connection + * to a computing node, submit tasks, and receive results. + */ + private void submitTasks() + { + + // if PACKET_SIZE was not specified, create a single task to use for all + // households + if (PACKET_SIZE == 0) PACKET_SIZE = hhDataManager.getNumHouseholds(); + + // Create a setup task object and submit it to the computing node. + // This setup task creates the HouseholdChoiceModelManager and causes it + // to + // create the necessary numuber + // of HouseholdChoiceModels objects which will operate in parallel on + // the + // computing node. + try + { + + JPPFJob job = new JPPFJob(); + job.setName("Household Choice Job"); + + DataProvider dataProvider = new MemoryMapDataProvider(); + dataProvider.setParameter("propertyMap", propertyMap); + dataProvider.setParameter("ms", ms); + dataProvider.setParameter("hhDataManager", hhDataManager); + dataProvider.setParameter("modelStructure", modelStructure); + dataProvider.setParameter("dmuFactory", dmuFactory); + dataProvider.setParameter("restartModelString", restartModelString); + job.setDataProvider(dataProvider); + + ArrayList startEndTaskIndicesList = getTaskHouseholdRanges(hhDataManager + .getNumHouseholds()); + + int startIndex = 0; + int endIndex = 0; + int taskIndex = 1; + for (int[] startEndIndices : startEndTaskIndicesList) + { + startIndex = startEndIndices[0]; + endIndex = startEndIndices[1]; + + HouseholdChoiceModelsTaskJppf task = new HouseholdChoiceModelsTaskJppf(taskIndex, + startIndex, endIndex); + job.add(task); + taskIndex++; + } + + List> results = jppfClient.submitJob(job); + for (Task task : results) + { + if (task.getThrowable() != null) throw new Exception(task.getThrowable()); + + try + { + if(logResults){ + logger.info(String.format("HH TASK: %s returned: %s, maxAlts: %d.", + task.getId(), (String) task.getResult(), + ((HouseholdChoiceModelsTaskJppf) task).getMaxAlts())); + } + } catch (Exception e) + { + logger.error( + "Exception returned by computing node caught in HouseholdChoiceModelsTaskJppf.", + e); + throw new RuntimeException(); + } + + } + + } catch (Exception e) + { + logger.error( + "Exception caught creating/submitting/receiving HouseholdChoiceModelsTaskJppf.", + e); + throw new RuntimeException(); + } + + } + + private ArrayList getTaskHouseholdRanges(int numberOfHouseholds) + { + + ArrayList startEndIndexList = new ArrayList(); + + if (ONE_HH_ID < 0) + { + + int numInitializationHouseholds = NUM_INITIALIZATION_PACKETS + * INITIALIZATION_PACKET_SIZE; + + int startIndex = 0; + int endIndex = 0; + if (numInitializationHouseholds < numberOfHouseholds) + { + + while (endIndex < numInitializationHouseholds) + { + endIndex = startIndex + INITIALIZATION_PACKET_SIZE - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += INITIALIZATION_PACKET_SIZE; + } + + } + + while (endIndex < numberOfHouseholds - 1) + { + endIndex = startIndex + PACKET_SIZE - 1; + if (endIndex + PACKET_SIZE > numberOfHouseholds) endIndex = numberOfHouseholds - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += PACKET_SIZE; + } + + return startEndIndexList; + + } else + { + + // create a single task packet high one household id + int[] startEndIndices = new int[2]; + int index = hhDataManager.getArrayIndex(ONE_HH_ID); + startEndIndices[0] = index; + startEndIndices[1] = index; + startEndIndexList.add(startEndIndices); + + return startEndIndexList; + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModels.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModels.java new file mode 100644 index 0000000..8bd78d8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModels.java @@ -0,0 +1,980 @@ +package org.sandag.abm.ctramp; + +import java.util.Arrays; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.util.ObjectUtil; + +public class HouseholdChoiceModels +{ + + private transient Logger logger = Logger.getLogger(HouseholdChoiceModels.class); + + private static final String GLOBAL_MODEL_SEED_PROPERTY = "Model.Random.Seed"; + private static final int AO_SEED_OFFSET = 0; + private static final int TP_SEED_OFFSET = 1; + private static final int PP_SEED_OFFSET = 2; + private static final int CDAP_SEED_OFFSET = 3; + private static final int IMTF_SEED_OFFSET = 4; + private static final int IMTOD_SEED_OFFSET = 5; + private static final int JTF_SEED_OFFSET = 6; + private static final int JTDC_SEED_OFFSET = 7; + private static final int JTOD_SEED_OFFSET = 8; + private static final int INMTF_SEED_OFFSET = 9; + private static final int INMDC_SEED_OFFSET = 10; + private static final int INMTOD_SEED_OFFSET = 11; + private static final int AWTF_SEED_OFFSET = 12; + private static final int AWDC_SEED_OFFSET = 13; + private static final int AWTOD_SEED_OFFSET = 14; + private static final int STF_SEED_OFFSET = 15; + private static final int SLC_SEED_OFFSET = 16; + private static final int IE_SEED_OFFSET = 17; + + private static final String USE_NEW_SLC_SOA_METHOD_PROPERTY_KEY = "slc.use.new.soa"; + + private boolean runAutoOwnershipModel; + private boolean runTransponderModel; + private boolean runInternalExternalModel; + private boolean runParkingProvisionModel; + private boolean runCoordinatedDailyActivityPatternModel; + private boolean runIndividualMandatoryTourFrequencyModel; + private boolean runMandatoryTourModeChoiceModel; + private boolean runMandatoryTourDepartureTimeAndDurationModel; + private boolean runEscortModel; + private boolean runAtWorkSubTourFrequencyModel; + private boolean runAtWorkSubtourLocationChoiceModel; + private boolean runAtWorkSubtourModeChoiceModel; + private boolean runAtWorkSubtourDepartureTimeAndDurationModel; + private boolean runJointTourFrequencyModel; + private boolean runJointTourLocationChoiceModel; + private boolean runJointTourDepartureTimeAndDurationModel; + private boolean runJointTourModeChoiceModel; + private boolean runIndividualNonMandatoryTourFrequencyModel; + private boolean runIndividualNonMandatoryTourLocationChoiceModel; + private boolean runIndividualNonMandatoryTourModeChoiceModel; + private boolean runIndividualNonMandatoryTourDepartureTimeAndDurationModel; + private boolean runStopFrequencyModel; + private boolean runStopLocationModel; + + private String restartModelString; + + private HouseholdAutoOwnershipModel aoModel; + private TourVehicleTypeChoiceModel tvtcModel; + private TransponderChoiceModel tcModel; + private InternalExternalTripChoiceModel ieModel; + private ParkingProvisionModel ppModel; + private TelecommuteModel teModel; + private HouseholdCoordinatedDailyActivityPatternModel cdapModel; + private HouseholdIndividualMandatoryTourFrequencyModel imtfModel; + private HouseholdIndividualNonMandatoryTourFrequencyModel inmtfModel; + private SchoolEscortingModel escortModel; + private HouseholdAtWorkSubtourFrequencyModel awfModel; + private StopFrequencyModel stfModel; + private TourModeChoiceModel immcModel; + private HouseholdIndividualMandatoryTourDepartureAndDurationTime imtodModel; + private JointTourModels jtfModel; + private TourModeChoiceModel nmmcModel; + private NonMandatoryDestChoiceModel nmlcModel; + private NonMandatoryTourDepartureAndDurationTime nmtodModel; + private TourModeChoiceModel awmcModel; + private SubtourDestChoiceModel awlcModel; + private SubtourDepartureAndDurationTime awtodModel; + private IntermediateStopChoiceModels stlmcModel; + private MicromobilityChoiceModel mmModel; + + private long aoTime; + private long fpTime; + private long ieTime; + private long cdapTime; + private long escortTime; + private long imtfTime; + private long imtodTime; + private long imtmcTime; + private long jtfTime; + private long jtdcTime; + private long jtodTime; + private long jtmcTime; + private long inmtfTime; + private long inmtdcTime; + private long inmtdcSoaTime; + private long inmtodTime; + private long inmtmcTime; + private long awtfTime; + private long awtdcTime; + private long awtdcSoaTime; + private long awtodTime; + private long awtmcTime; + private long stfTime; + private long stdtmTime; + private long[] returnPartialTimes = new long[IntermediateStopChoiceModels.NUM_CPU_TIME_VALUES]; + + private int maxAlts; + private int modelIndex; + + private int globalSeed; + + private boolean useNewSlcSoaMethod; + + private double[][][] slcSizeProbs; + private double[][] slcTazSize; + private double[][] slcTazDistExpUtils; + + private double[] distanceToCordonsLogsums; + + private MgraDataManager mgraManager; + private TazDataManager tdm; + + public HouseholdChoiceModels(int modelIndex, String restartModelString, + HashMap propertyMap, ModelStructure modelStructure, + CtrampDmuFactoryIf dmuFactory, BuildAccessibilities aggAcc, + McLogsumsCalculator logsumHelper, MandatoryAccessibilitiesCalculator mandAcc, + double[] pctHighIncome, double[] pctMultipleAutos, double[] avgtts, + double[] transpDist, double[] pctDetour, double[][][] nonManSoaDistProbs, + double[][][] nonManSoaSizeProbs, double[][][] subTourSoaDistProbs, + double[][][] subTourSoaSizeProbs, double[] distanceToCordonsLogsums,AutoTazSkimsCalculator tazDistanceCalculator) + { + + this.modelIndex = modelIndex; + this.restartModelString = restartModelString; + + this.distanceToCordonsLogsums = distanceToCordonsLogsums; + + globalSeed = Integer.parseInt(propertyMap.get(GLOBAL_MODEL_SEED_PROPERTY)); + + mgraManager = MgraDataManager.getInstance(propertyMap); + tdm = TazDataManager.getInstance(propertyMap); + + runAutoOwnershipModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_AUTO_OWNERSHIP)); + runTransponderModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_TRANSPONDER_CHOICE)); + runInternalExternalModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_INTERNAL_EXTERNAL_TRIP)); + runParkingProvisionModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_FREE_PARKING_AVAILABLE)); + runCoordinatedDailyActivityPatternModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_DAILY_ACTIVITY_PATTERN)); + runIndividualMandatoryTourFrequencyModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_INDIV_MANDATORY_TOUR_FREQ)); + runMandatoryTourModeChoiceModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_MAND_TOUR_MODE_CHOICE)); + runMandatoryTourDepartureTimeAndDurationModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_MAND_TOUR_DEP_TIME_AND_DUR)); + runEscortModel = Boolean.parseBoolean(propertyMap.get(CtrampApplication.PROPERTIES_RUN_SCHOOL_ESCORT_MODEL)); + runAtWorkSubTourFrequencyModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_AT_WORK_SUBTOUR_FREQ)); + runAtWorkSubtourLocationChoiceModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_AT_WORK_SUBTOUR_LOCATION_CHOICE)); + runAtWorkSubtourModeChoiceModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_AT_WORK_SUBTOUR_MODE_CHOICE)); + runAtWorkSubtourDepartureTimeAndDurationModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_AT_WORK_SUBTOUR_DEP_TIME_AND_DUR)); + runJointTourFrequencyModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_JOINT_TOUR_FREQ)); + runJointTourLocationChoiceModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_JOINT_LOCATION_CHOICE)); + runJointTourModeChoiceModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_JOINT_TOUR_MODE_CHOICE)); + runJointTourDepartureTimeAndDurationModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_JOINT_TOUR_DEP_TIME_AND_DUR)); + runIndividualNonMandatoryTourFrequencyModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_FREQ)); + runIndividualNonMandatoryTourLocationChoiceModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_INDIV_NON_MANDATORY_LOCATION_CHOICE)); + runIndividualNonMandatoryTourModeChoiceModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_MODE_CHOICE)); + runIndividualNonMandatoryTourDepartureTimeAndDurationModel = Boolean + .parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_INDIV_NON_MANDATORY_TOUR_DEP_TIME_AND_DUR)); + runStopFrequencyModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_STOP_FREQUENCY)); + runStopLocationModel = Boolean.parseBoolean(propertyMap + .get(CtrampApplication.PROPERTIES_RUN_STOP_LOCATION)); + + boolean measureObjectSizes = false; + + try + { + useNewSlcSoaMethod = Util.getBooleanValueFromPropertyMap(propertyMap, + USE_NEW_SLC_SOA_METHOD_PROPERTY_KEY); + + AccessibilitiesTable accTable = aggAcc.getAccessibilitiesTableObject(); + + // create the auto ownership choice model application object + if (runAutoOwnershipModel) + { + aoModel = new HouseholdAutoOwnershipModel(propertyMap, dmuFactory, accTable, + mandAcc); + tvtcModel = new TourVehicleTypeChoiceModel(propertyMap); + if ( measureObjectSizes ) logger.info ( "AO size: " + ObjectUtil.sizeOf( aoModel ) + ObjectUtil.sizeOf(tvtcModel)); + } + + if (runTransponderModel) + { + tcModel = new TransponderChoiceModel(propertyMap, dmuFactory, accTable, + pctHighIncome, pctMultipleAutos, avgtts, transpDist, pctDetour); + if (measureObjectSizes) + logger.info("TC size: " + ObjectUtil.sizeOf(tcModel)); + } + + if (runParkingProvisionModel) + { + ppModel = new ParkingProvisionModel(propertyMap, dmuFactory); + teModel = new TelecommuteModel(propertyMap, dmuFactory); + if (measureObjectSizes) { + logger.info("PP size: " + ObjectUtil.sizeOf(ppModel)); + logger.info("TE size: " + ObjectUtil.sizeOf(teModel)); + } + } + + if (runInternalExternalModel) + { + ieModel = new InternalExternalTripChoiceModel(propertyMap, modelStructure,dmuFactory); + if (measureObjectSizes) + logger.info("IE size: " + ObjectUtil.sizeOf(ieModel)); + } + + if (runCoordinatedDailyActivityPatternModel) + { + cdapModel = new HouseholdCoordinatedDailyActivityPatternModel(propertyMap, + modelStructure, dmuFactory, accTable); + if (measureObjectSizes) + logger.info("CDAP size: " + ObjectUtil.sizeOf(cdapModel)); + } + + if (runIndividualMandatoryTourFrequencyModel) + { + imtfModel = new HouseholdIndividualMandatoryTourFrequencyModel(propertyMap, + modelStructure, dmuFactory, accTable, mandAcc); + if (measureObjectSizes) + logger.info("IMTF size: " + ObjectUtil.sizeOf(imtfModel)); + } + + if (runMandatoryTourDepartureTimeAndDurationModel || runMandatoryTourModeChoiceModel) + { + immcModel = new TourModeChoiceModel(propertyMap, modelStructure, + TourModeChoiceModel.MANDATORY_MODEL_INDICATOR, dmuFactory, logsumHelper); + if (measureObjectSizes) + logger.info("IMMC size: " + ObjectUtil.sizeOf(immcModel)); + + imtodModel = new HouseholdIndividualMandatoryTourDepartureAndDurationTime( + propertyMap, modelStructure, aggAcc.getWorkSegmentNameList(), dmuFactory, + immcModel); + if (measureObjectSizes) + logger.info("IMTOD size: " + ObjectUtil.sizeOf(imtodModel)); + } + + if(runEscortModel){ + escortModel = new SchoolEscortingModel(propertyMap,mgraManager,tazDistanceCalculator); + if ( measureObjectSizes ) logger.info ( "SEM size: " + ObjectUtil.sizeOf( escortModel ) ); + + } + + if (runJointTourFrequencyModel) + { + jtfModel = new JointTourModels(propertyMap, accTable, modelStructure, dmuFactory); + if (measureObjectSizes) + logger.info("JTF size: " + ObjectUtil.sizeOf(jtfModel)); + } + + if (runIndividualNonMandatoryTourFrequencyModel) + { + inmtfModel = new HouseholdIndividualNonMandatoryTourFrequencyModel(propertyMap, + dmuFactory, accTable, mandAcc); + if (measureObjectSizes) + logger.info("INMTF size: " + ObjectUtil.sizeOf(inmtfModel)); + } + + if (runIndividualNonMandatoryTourLocationChoiceModel || runJointTourLocationChoiceModel + || runIndividualNonMandatoryTourDepartureTimeAndDurationModel + || runJointTourDepartureTimeAndDurationModel + || runIndividualNonMandatoryTourModeChoiceModel || runJointTourModeChoiceModel) + { + nmmcModel = new TourModeChoiceModel(propertyMap, modelStructure, + TourModeChoiceModel.NON_MANDATORY_MODEL_INDICATOR, dmuFactory, logsumHelper); + if (measureObjectSizes) + logger.info("INMMC size: " + ObjectUtil.sizeOf(nmmcModel)); + } + + if (runIndividualNonMandatoryTourLocationChoiceModel || runJointTourLocationChoiceModel) + { + nmlcModel = new NonMandatoryDestChoiceModel(propertyMap, modelStructure, aggAcc, + dmuFactory, nmmcModel); + nmlcModel.setNonMandatorySoaProbs(nonManSoaDistProbs, nonManSoaSizeProbs); + if (measureObjectSizes) + logger.info("INMLC size: " + ObjectUtil.sizeOf(nmlcModel)); + } + + if (runIndividualNonMandatoryTourDepartureTimeAndDurationModel + || runJointTourDepartureTimeAndDurationModel||runIndividualNonMandatoryTourModeChoiceModel) + { + nmtodModel = new NonMandatoryTourDepartureAndDurationTime(propertyMap, + modelStructure, dmuFactory, nmmcModel); + if (measureObjectSizes) + logger.info("INMTOD size: " + ObjectUtil.sizeOf(nmtodModel)); + } + + if (runAtWorkSubTourFrequencyModel) + { + awfModel = new HouseholdAtWorkSubtourFrequencyModel(propertyMap, modelStructure, + dmuFactory); + if (measureObjectSizes) + logger.info("AWTF size: " + ObjectUtil.sizeOf(awfModel)); + } + + if (runAtWorkSubtourLocationChoiceModel + || runAtWorkSubtourDepartureTimeAndDurationModel + || runAtWorkSubtourModeChoiceModel) + { + awmcModel = new TourModeChoiceModel(propertyMap, modelStructure, + TourModeChoiceModel.AT_WORK_SUBTOUR_MODEL_INDICATOR, dmuFactory, + logsumHelper); + if (measureObjectSizes) + logger.info("AWMC size: " + ObjectUtil.sizeOf(awmcModel)); + } + + if (runAtWorkSubtourLocationChoiceModel) + { + awlcModel = new SubtourDestChoiceModel(propertyMap, modelStructure, aggAcc, + dmuFactory, awmcModel); + awlcModel.setNonMandatorySoaProbs(subTourSoaDistProbs, subTourSoaSizeProbs); + if (measureObjectSizes) + logger.info("AWLC size: " + ObjectUtil.sizeOf(awlcModel)); + } + + if (runAtWorkSubtourDepartureTimeAndDurationModel) + { + awtodModel = new SubtourDepartureAndDurationTime(propertyMap, modelStructure, + dmuFactory, awmcModel); + if (measureObjectSizes) + logger.info("AWTOD size: " + ObjectUtil.sizeOf(awtodModel)); + } + + if (runStopFrequencyModel) + { + stfModel = new StopFrequencyModel(propertyMap, dmuFactory, modelStructure, accTable); + if (measureObjectSizes) + logger.info("STF size: " + ObjectUtil.sizeOf(stfModel)); + } + + if (runStopLocationModel) + { + stlmcModel = new IntermediateStopChoiceModels(propertyMap, modelStructure, + dmuFactory, logsumHelper); + + mmModel = new MicromobilityChoiceModel(propertyMap,modelStructure,dmuFactory); + + // if the slcTazDistProbs are not null, they have been already + // computed, and it is + // not necessary for the thread creating this + // HouseholdChoiceModels object to + // compute them also. If slcTazDistProbs is null, compute them. + if (useNewSlcSoaMethod && slcSizeProbs == null) + { + + // compute the array of cumulative taz distance based SOA + // probabilities for each origin taz. + DestChoiceTwoStageSoaTazDistanceUtilityDMU locChoiceDistSoaDmu = dmuFactory + .getDestChoiceSoaTwoStageTazDistUtilityDMU(); + + DestChoiceTwoStageSoaProbabilitiesCalculator slcSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, + dmuFactory, + IntermediateStopChoiceModels.PROPERTIES_UEC_SLC_SOA_DISTANCE_UTILITY, + IntermediateStopChoiceModels.PROPERTIES_UEC_SLC_SOA_DISTANCE_MODEL_PAGE, + IntermediateStopChoiceModels.PROPERTIES_UEC_SLC_SOA_DISTANCE_DATA_PAGE); + + computeSlcSoaProbabilities(slcSoaDistProbsObject, locChoiceDistSoaDmu, + stlmcModel.getSizeSegmentNameIndexMap(), + stlmcModel.getSizeSegmentArray()); + + stlmcModel.setupSlcDistanceBaseSoaModel(propertyMap, slcTazDistExpUtils, + slcSizeProbs, slcTazSize); + } + + if (measureObjectSizes) + logger.info("SLMT size: " + ObjectUtil.sizeOf(stlmcModel)); + } + + } catch (RuntimeException e) + { + + String lastModel = ""; + if (runAutoOwnershipModel && aoModel != null) lastModel += " ao"; + + if (runParkingProvisionModel && ppModel != null) lastModel += " fp"; + + if (runInternalExternalModel && ieModel != null) lastModel += " ie"; + + if (runCoordinatedDailyActivityPatternModel && cdapModel != null) lastModel += " cdap"; + + if (runIndividualMandatoryTourFrequencyModel && imtfModel != null) + lastModel += " imtf"; + + if (runMandatoryTourModeChoiceModel && immcModel != null) lastModel += " immc"; + + if (runMandatoryTourDepartureTimeAndDurationModel && imtodModel != null) + lastModel += " imtod"; + + if (runJointTourFrequencyModel && jtfModel != null) lastModel += " jtf"; + + if (runJointTourModeChoiceModel && nmmcModel != null) lastModel += " jmc"; + + if (runJointTourLocationChoiceModel && nmlcModel != null) lastModel += " jlc"; + + if (runJointTourDepartureTimeAndDurationModel && nmtodModel != null) + lastModel += " jtod"; + + if (runIndividualNonMandatoryTourFrequencyModel && inmtfModel != null) + lastModel += " inmtf"; + + if (runIndividualNonMandatoryTourModeChoiceModel && nmmcModel != null) + lastModel += " inmmc"; + + if (runIndividualNonMandatoryTourLocationChoiceModel && nmlcModel != null) + lastModel += " inmlc"; + + if (runIndividualNonMandatoryTourDepartureTimeAndDurationModel && nmtodModel != null) + lastModel += " inmtod"; + + if (runAtWorkSubTourFrequencyModel && awfModel != null) lastModel += " awf"; + + if (runAtWorkSubtourModeChoiceModel && awmcModel != null) lastModel += " awmc"; + + if (runAtWorkSubtourLocationChoiceModel && awlcModel != null) lastModel += " awlc"; + + if (runAtWorkSubtourDepartureTimeAndDurationModel && awtodModel != null) + lastModel += " awtod"; + + if (runStopFrequencyModel && stfModel != null) lastModel += " stf"; + + if (runStopLocationModel && stlmcModel != null) lastModel += " stlmc"; + + logger.error("RuntimeException setting up HouseholdChoiceModels."); + logger.error("Models setup = " + lastModel); + logger.error("", e); + + throw new RuntimeException(); + } + + } + + public void runModels(Household hhObject) + { + + // check to see if restartModel was set and reset random number sequence + // appropriately if so. + checkRestartModel(hhObject); + + if (runAutoOwnershipModel) aoModel.applyModel(hhObject, false); + + if (runTransponderModel) tcModel.applyModel(hhObject); + + if (runParkingProvisionModel) { + ppModel.applyModel(hhObject); + teModel.applyModel(hhObject); + } + + if (runInternalExternalModel) ieModel.applyModel(hhObject, distanceToCordonsLogsums); + + if (runCoordinatedDailyActivityPatternModel) cdapModel.applyModel(hhObject); + + if (runIndividualMandatoryTourFrequencyModel) { + imtfModel.applyModel(hhObject); + tvtcModel.applyModelToMandatoryTours(hhObject); + } + + if (runMandatoryTourDepartureTimeAndDurationModel||runMandatoryTourModeChoiceModel) + imtodModel.applyModel(hhObject, runMandatoryTourDepartureTimeAndDurationModel,runMandatoryTourModeChoiceModel); + + if(runEscortModel){ + try { + escortModel.applyModel(hhObject); + } catch (Exception e) { + logger.fatal("Error Attempting to run escort model for household "+hhObject.getHhId()); + throw new RuntimeException(e); + } + } + + if (runJointTourFrequencyModel) { + jtfModel.applyModel(hhObject); + tvtcModel.applyModelToJointTours(hhObject); + } + + if (runJointTourLocationChoiceModel) nmlcModel.applyJointModel(hhObject); + + if (runJointTourDepartureTimeAndDurationModel) + nmtodModel.applyJointModel(hhObject, runJointTourDepartureTimeAndDurationModel, runJointTourModeChoiceModel); + + if (runIndividualNonMandatoryTourFrequencyModel) { + inmtfModel.applyModel(hhObject); + tvtcModel.applyModelToNonMandatoryTours(hhObject); + } + + if (runIndividualNonMandatoryTourLocationChoiceModel) nmlcModel.applyIndivModel(hhObject); + + if (runIndividualNonMandatoryTourDepartureTimeAndDurationModel||runIndividualNonMandatoryTourModeChoiceModel) + nmtodModel.applyIndivModel(hhObject, runIndividualNonMandatoryTourDepartureTimeAndDurationModel, runIndividualNonMandatoryTourModeChoiceModel); + + if (runAtWorkSubTourFrequencyModel) { + awfModel.applyModel(hhObject); + tvtcModel.applyModelToAtWorkSubTours(hhObject); + } + + if (runAtWorkSubtourLocationChoiceModel) awlcModel.applyModel(hhObject); + + if (runAtWorkSubtourDepartureTimeAndDurationModel) + awtodModel.applyModel(hhObject, runAtWorkSubtourModeChoiceModel); + + if (runStopFrequencyModel) stfModel.applyModel(hhObject); + + if (runStopLocationModel) { + stlmcModel.applyModel(hhObject, false); + mmModel.applyModel(hhObject); + } + + } + + public void runModelsWithTiming(Household hhObject) + { + + // check to see if restartModel was set and reset random number sequence + // appropriately if so. + checkRestartModel(hhObject); + + if (runAutoOwnershipModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + AO_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + aoModel.applyModel(hhObject, false); + aoTime += (System.nanoTime() - check); + } + + if (runTransponderModel) + { + // long hhSeed = globalSeed + hhObject.getHhId() + TP_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + tcModel.applyModel(hhObject); + } + + if (runParkingProvisionModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + PP_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + ppModel.applyModel(hhObject); + teModel.applyModel(hhObject); + fpTime += (System.nanoTime() - check); + } + + if (runInternalExternalModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + PP_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + ieModel.applyModel(hhObject, distanceToCordonsLogsums); + ieTime += (System.nanoTime() - check); + } + + if (runCoordinatedDailyActivityPatternModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + CDAP_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + cdapModel.applyModel(hhObject); + cdapTime += (System.nanoTime() - check); + } + + if (runIndividualMandatoryTourFrequencyModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + IMTF_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + imtfModel.applyModel(hhObject); + tvtcModel.applyModelToMandatoryTours(hhObject); + imtfTime += (System.nanoTime() - check); + } + + if (runMandatoryTourDepartureTimeAndDurationModel||runMandatoryTourModeChoiceModel); + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + + // IMTOD_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + imtodModel.applyModel(hhObject, runMandatoryTourDepartureTimeAndDurationModel,runMandatoryTourModeChoiceModel); + long mcTime = imtodModel.getModeChoiceTime(); + imtodTime += (System.nanoTime() - check - mcTime); + imtmcTime += mcTime; + } + if(runEscortModel){ + long check = System.nanoTime(); + try { + escortModel.applyModel(hhObject); + } catch (Exception e) { + logger.fatal("Error Attempting to run escort model for household "+hhObject.getHhId()); + e.printStackTrace(); + } + escortTime += ( System.nanoTime() - check ); + } + + + if (runJointTourFrequencyModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + JTF_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + jtfModel.applyModel(hhObject); + tvtcModel.applyModelToJointTours(hhObject); + jtfTime += (System.nanoTime() - check); + } + + if (runJointTourLocationChoiceModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + JTDC_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + nmlcModel.applyJointModel(hhObject); + jtdcTime += (System.nanoTime() - check); + } + + if (runJointTourDepartureTimeAndDurationModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + JTOD_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + nmtodModel.applyJointModel(hhObject, runJointTourDepartureTimeAndDurationModel,runJointTourModeChoiceModel); + long mcTime = nmtodModel.getJointModeChoiceTime(); + jtodTime += (System.nanoTime() - check - mcTime); + jtmcTime += mcTime; + } + + if (runIndividualNonMandatoryTourFrequencyModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + + // INMTF_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + inmtfModel.applyModel(hhObject); + tvtcModel.applyModelToNonMandatoryTours(hhObject); + inmtfTime += (System.nanoTime() - check); + } + + if (runIndividualNonMandatoryTourLocationChoiceModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + + // INMDC_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + nmlcModel.resetSoaRunTime(); + nmlcModel.applyIndivModel(hhObject); + inmtdcSoaTime += nmlcModel.getSoaRunTime(); + inmtdcTime += (System.nanoTime() - check); + } + + if (runIndividualNonMandatoryTourDepartureTimeAndDurationModel||runIndividualNonMandatoryTourModeChoiceModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + + // INMTOD_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + nmtodModel.applyIndivModel(hhObject, runIndividualNonMandatoryTourDepartureTimeAndDurationModel,runIndividualNonMandatoryTourModeChoiceModel); + long mcTime = nmtodModel.getIndivModeChoiceTime(); + inmtodTime += (System.nanoTime() - check - mcTime); + inmtmcTime += mcTime; + } + + if (runAtWorkSubTourFrequencyModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + AWTF_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + awfModel.applyModel(hhObject); + tvtcModel.applyModelToAtWorkSubTours(hhObject); + awtfTime += (System.nanoTime() - check); + } + + if (runAtWorkSubtourLocationChoiceModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + AWDC_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + awlcModel.applyModel(hhObject); + awtdcSoaTime += awlcModel.getSoaRunTime(); + awtdcTime += (System.nanoTime() - check); + } + + if (runAtWorkSubtourDepartureTimeAndDurationModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + + // AWTOD_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + awtodModel.applyModel(hhObject, runAtWorkSubtourModeChoiceModel); + long mcTime = awtodModel.getModeChoiceTime(); + awtodTime += (System.nanoTime() - check - mcTime); + awtmcTime += mcTime; + } + + if (runStopFrequencyModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + STF_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + stfModel.applyModel(hhObject); + stfTime += (System.nanoTime() - check); + } + + if (runStopLocationModel) + { + long check = System.nanoTime(); + // long hhSeed = globalSeed + hhObject.getHhId() + SLC_SEED_OFFSET; + // hhObject.getHhRandom().setSeed( hhSeed ); + stlmcModel.applyModel(hhObject, true); + stdtmTime += (System.nanoTime() - check); + + long[] partials = stlmcModel.getStopTimes(); + for (int i = 0; i < returnPartialTimes.length; i++) + returnPartialTimes[i] += partials[i]; + + if (stlmcModel.getMaxAltsInSample() > maxAlts) + maxAlts = stlmcModel.getMaxAltsInSample(); + + mmModel.applyModel(hhObject); + } + + } + + private void checkRestartModel(Household hhObject) + { + + // none, ao, cdap, imtf, imtod, awf, awl, awtod, jtf, jtl, jtod, inmtf, + // inmtl, inmtod, stf, stl + // version 1.0.8.22 - changed model restart options - possible values + // for + // restart are now: none, uwsl, ao, imtf, jtf, inmtf, stf + + // if restartModel was specified, reset the random number sequence + // based on the cumulative count of random numbers drawn by the + // component + // preceding the one specified. + if (restartModelString.equalsIgnoreCase("") || restartModelString.equalsIgnoreCase("none")) return; + else if (restartModelString.equalsIgnoreCase("ao")) + { + hhObject.initializeForAoRestart(); + } else if (restartModelString.equalsIgnoreCase("imtf")) + { + hhObject.initializeForImtfRestart(); + } else if (restartModelString.equalsIgnoreCase("jtf")) + { + hhObject.initializeForJtfRestart(); + } else if (restartModelString.equalsIgnoreCase("inmtf")) + { + hhObject.initializeForInmtfRestart(); + } else if (restartModelString.equalsIgnoreCase("awf")) + { + hhObject.initializeForAwfRestart(); + } else if (restartModelString.equalsIgnoreCase("stf")) + { + hhObject.initializeForStfRestart(); + } + + } + + public int getModelIndex() + { + return modelIndex; + } + + public void zeroTimes() + { + aoTime = 0; + fpTime = 0; + ieTime = 0; + cdapTime = 0; + imtfTime = 0; + imtodTime = 0; + imtmcTime = 0; + jtfTime = 0; + jtdcTime = 0; + jtodTime = 0; + jtmcTime = 0; + inmtfTime = 0; + inmtdcTime = 0; + inmtdcSoaTime = 0; + inmtodTime = 0; + inmtmcTime = 0; + awtfTime = 0; + awtdcTime = 0; + awtdcSoaTime = 0; + awtodTime = 0; + awtmcTime = 0; + stfTime = 0; + stdtmTime = 0; + + Arrays.fill(returnPartialTimes, 0); + } + + public long[] getPartialStopTimes() + { + return returnPartialTimes; + } + + public long[] getTimes() + { + long[] returnTimes = new long[23]; + returnTimes[0] = aoTime; + returnTimes[1] = fpTime; + returnTimes[2] = ieTime; + returnTimes[3] = cdapTime; + returnTimes[4] = imtfTime; + returnTimes[5] = imtodTime; + returnTimes[6] = imtmcTime; + returnTimes[7] = jtfTime; + returnTimes[8] = jtdcTime; + returnTimes[9] = jtodTime; + returnTimes[10] = jtmcTime; + returnTimes[11] = inmtfTime; + returnTimes[12] = inmtdcSoaTime; + returnTimes[13] = inmtdcTime; + returnTimes[14] = inmtodTime; + returnTimes[15] = inmtmcTime; + returnTimes[16] = awtfTime; + returnTimes[17] = awtdcSoaTime; + returnTimes[18] = awtdcTime; + returnTimes[19] = awtodTime; + returnTimes[20] = awtmcTime; + returnTimes[21] = stfTime; + returnTimes[22] = stdtmTime; + return returnTimes; + } + + public int getMaxAlts() + { + return maxAlts; + } + + private void computeSlcSoaProbabilities( + DestChoiceTwoStageSoaProbabilitiesCalculator locChoiceSoaDistProbsObject, + DestChoiceTwoStageSoaTazDistanceUtilityDMU locChoiceDistSoaDmu, + HashMap segmentNameIndexMap, double[][] dcSizeArray) + { + + // compute the exponentiated distance utilities that all segments of + // this tour purpose will share + slcTazDistExpUtils = computeTazDistanceExponentiatedUtilities(locChoiceSoaDistProbsObject, + locChoiceDistSoaDmu); + + slcTazSize = new double[dcSizeArray.length][]; + slcSizeProbs = new double[dcSizeArray.length][][]; + + // compute an array of SOA size probabilities for each segment + for (String segmentName : segmentNameIndexMap.keySet()) + { + + // compute the TAZ size values from the mgra values and the + // correspondence between mgras and tazs. + int segmentIndex = segmentNameIndexMap.get(segmentName); + slcTazSize[segmentIndex] = computeTazSize(dcSizeArray[segmentIndex]); + + slcSizeProbs[segmentIndex] = computeSizeSegmentProbabilities(dcSizeArray[segmentIndex], + slcTazSize[segmentIndex]); + + } + + } + + private double[][] computeSizeSegmentProbabilities(double[] size, double[] totalTazSize) + { + + int maxTaz = tdm.getMaxTaz(); + + // this is a 0-based array of cumulative probabilities + double[][] sizeProbs = new double[maxTaz][]; + + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + + int[] mgraArray = tdm.getMgraArray(taz); + + if (mgraArray == null) + { + sizeProbs[taz - 1] = new double[0]; + } else + { + + if (totalTazSize[taz] > 0) + { + sizeProbs[taz - 1] = new double[mgraArray.length]; + for (int i = 0; i < mgraArray.length; i++) + { + double mgraSize = size[mgraArray[i]]; + if (mgraSize > 0) mgraSize += 1; + sizeProbs[taz - 1][i] = mgraSize / totalTazSize[taz]; + } + } else + { + sizeProbs[taz - 1] = new double[0]; + } + } + + } + + return sizeProbs; + + } + + private double[][] computeTazDistanceExponentiatedUtilities( + DestChoiceTwoStageSoaProbabilitiesCalculator locChoiceSoaDistProbsObject, + DestChoiceTwoStageSoaTazDistanceUtilityDMU locChoiceDistSoaDmu) + { + + // compute the TAZ x TAZ exponentiated utilities array for sample + // selection utilities. + double[][] tazDistExpUtils = locChoiceSoaDistProbsObject + .computeDistanceUtilities(locChoiceDistSoaDmu); + for (int i = 0; i < tazDistExpUtils.length; i++) + for (int j = 0; j < tazDistExpUtils[i].length; j++) + { + if (tazDistExpUtils[i][j] < -500) tazDistExpUtils[i][j] = 0; + else tazDistExpUtils[i][j] = Math.exp(tazDistExpUtils[i][j]); + } + + return tazDistExpUtils; + + } + + private double[] computeTazSize(double[] size) + { + + int maxTaz = tdm.getMaxTaz(); + + double[] tazSize = new double[maxTaz + 1]; + + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + + int[] mgraArray = tdm.getMgraArray(taz); + if (mgraArray != null) + { + for (int mgra : mgraArray) + { + tazSize[taz] += size[mgra] + (size[mgra] > 0 ? 1 : 0); + } + } + + } + + return tazSize; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelsManager.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelsManager.java new file mode 100644 index 0000000..ef4223d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelsManager.java @@ -0,0 +1,682 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Date; +import java.util.HashMap; +import java.util.LinkedList; +import java.util.StringTokenizer; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import org.sandag.abm.accessibilities.NonTransitUtilities; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MathUtil; + +public final class HouseholdChoiceModelsManager + implements Serializable +{ + + private static transient Logger logger = Logger.getLogger(HouseholdChoiceModelsManager.class); + + private static final String USE_NEW_SOA_METHOD_PROPERTY_KEY = "nmdc.use.new.soa"; + + private static final String TAZ_FIELD_NAME = "TAZ"; + private static final String TP_CHOICE_AVG_TTS_FILE = "tc.choice.avgtts.file"; + private static final String AVGTTS_COLUMN_NAME = "AVGTTS"; + private static final String TRANSP_DIST_COLUMN_NAME = "DIST"; + private static final String PCT_DETOUR_COLUMN_NAME = "PCTDETOUR"; + + private static final String IE_EXTERNAL_TAZS_KEY = "external.tazs"; + private static final String IE_DISTANCE_LOGSUM_COEFF_KEY = "ie.logsum.distance.coeff"; + + private static String PROPERTIES_NON_MANDATORY_DC_SOA_UEC_FILE = "nonSchool.soa.uec.file"; + private static String PROPERTIES_ESCORT_DC_SOA_UEC_MODEL_PAGE = "escort.soa.uec.model"; + private static String PROPERTIES_ESCORT_DC_SOA_UEC_DATA_PAGE = "escort.soa.uec.data"; + private static String PROPERTIES_NON_MANDATORY_DC_SOA_UEC_MODEL_PAGE = "other.nonman.soa.uec.model"; + private static String PROPERTIES_NON_MANDATORY_DC_SOA_UEC_DATA_PAGE = "other.nonman.soa.uec.data"; + private static String PROPERTIES_ATWORK_DC_SOA_UEC_MODEL_PAGE = "atwork.soa.uec.model"; + private static String PROPERTIES_ATWORK_DC_SOA_UEC_DATA_PAGE = "atwork.soa.uec.data"; + + private static HouseholdChoiceModelsManager objInstance = null; + + private LinkedList modelQueue = null; + + private HashMap propertyMap; + private String restartModelString; + private ModelStructure modelStructure; + private CtrampDmuFactoryIf dmuFactory; + + private MgraDataManager mgraManager; + private TazDataManager tdm; + + private int maxMgra; + private int maxTaz; + + private BuildAccessibilities aggAcc; + + private int completedHouseholds; + private int modelIndex; + + // store taz-taz exponentiated utilities (period, from taz, to taz) + private double[][][] sovExpUtilities; + private double[][][] hovExpUtilities; + private double[][][] nMotorExpUtilities; + private double[][][] maasExpUtilities; + + private double[] pctHighIncome; + private double[] pctMultipleAutos; + + private double[] avgtts; + private double[] transpDist; + private double[] pctDetour; + + private double[][][] nonMandatorySizeProbs; + private double[][][] nonMandatoryTazDistProbs; + private double[][][] subTourSizeProbs; + private double[][][] subTourTazDistProbs; + + private AutoTazSkimsCalculator tazDistanceCalculator; + + private boolean useNewSoaMethod; + private boolean logResults=false; + + private HouseholdChoiceModelsManager() + { + } + + public static synchronized HouseholdChoiceModelsManager getInstance() + { + // logger.info( + // "beginning of HouseholdChoiceModelsManager() - objInstance address = " + // + objInstance ); + if (objInstance == null) + { + objInstance = new HouseholdChoiceModelsManager(); + // logger.info( + // "after new HouseholdChoiceModelsManager() - objInstance address = " + // + objInstance ); + return objInstance; + } else + { + // logger.info( + // "returning current HouseholdChoiceModelsManager() - objInstance address = " + // + objInstance ); + return objInstance; + } + } + + // the task instances should call needToInitialize() first, then this method + // if necessary. + public synchronized void managerSetup(MatrixDataServerIf ms, + HouseholdDataManagerIf hhDataManager, HashMap propertyMap, + String restartModelString, ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory) + { + + if (modelQueue != null) return; + + // get the DestChoiceModelManager instance and clear the objects that + // hold large memory references + DestChoiceModelManager.getInstance().clearDcModels(); + + modelIndex = 0; + completedHouseholds = 0; + + this.propertyMap = propertyMap; + this.restartModelString = restartModelString; + this.modelStructure = modelStructure; + this.dmuFactory = dmuFactory; + + logResults = Util.getStringValueFromPropertyMap(propertyMap, "RunModel.LogResults") + .equalsIgnoreCase("true"); + + mgraManager = MgraDataManager.getInstance(propertyMap); + maxMgra = mgraManager.getMaxMgra(); + + tdm = TazDataManager.getInstance(propertyMap); + maxTaz = tdm.getMaxTaz(); + + pctHighIncome = hhDataManager.getPercentHhsIncome100Kplus(); + pctMultipleAutos = hhDataManager.getPercentHhsMultipleAutos(); + readTpChoiceAvgTtsFile(); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + + aggAcc = BuildAccessibilities.getInstance(); + if (!aggAcc.getAccessibilitiesAreBuilt()) + { + logger.info("creating Accessibilities Object for Household Choice Models."); + + aggAcc.setupBuildAccessibilities(propertyMap, false); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateConstants(); + + // assume that if the filename exists, at was created previously, + // either in another model run, or by the main client + // if the filename doesn't exist, then calculate the accessibilities + String projectDirectory = propertyMap + .get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file"); + boolean accFileReadFlag = Util.getBooleanValueFromPropertyMap(propertyMap, + CtrampApplication.READ_ACCESSIBILITIES); + + if (accFileReadFlag && (new File(accFileName)).canRead()) + { + + logger.info("filling Accessibilities Object in HouseholdChoiceModelManager by reading file: " + + accFileName + "."); + aggAcc.readAccessibilityTableFromFile(accFileName); + + } else + { + + logger.info("filling Accessibilities Object HouseholdChoiceModelManager by calculating them."); + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + } + + } + + useNewSoaMethod = Util.getBooleanValueFromPropertyMap(propertyMap, + USE_NEW_SOA_METHOD_PROPERTY_KEY); + + if (useNewSoaMethod) + { + // compute the arrays of cumulative probabilities based on mgra size + // for mgras within each origin taz. + logger.info("pre-computing non-mandatory purpose SOA Distance and Size probabilities."); + computeNonMandatorySegmentSizeArrays(dmuFactory); + + logger.info("pre-computing at-work sub-tour purpose SOA Distance and Size probabilities."); + computeSubtourSegmentSizeArrays(modelStructure, dmuFactory); + } + + tazDistanceCalculator = new AutoTazSkimsCalculator(propertyMap); + tazDistanceCalculator.computeTazDistanceArrays(); + + // the first thread to reach this method initializes the modelQueue used + // to + // recycle hhChoiceModels objects. + modelQueue = new LinkedList(); + + mgraManager = MgraDataManager.getInstance(propertyMap); + + } + + /** + * @return DestChoiceModel object created if none is available from the + * queue. + * + */ + public synchronized HouseholdChoiceModels getHouseholdChoiceModelsObject(int taskIndex) + { + + String message = ""; + HouseholdChoiceModels hhChoiceModels = null; + + if (modelQueue.isEmpty()) + { + + NonTransitUtilities ntUtilities = new NonTransitUtilities(propertyMap, sovExpUtilities, + hovExpUtilities, nMotorExpUtilities, maasExpUtilities); + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + MandatoryAccessibilitiesCalculator mandAcc = new MandatoryAccessibilitiesCalculator( + propertyMap, ntUtilities, aggAcc.getExpConstants(), + logsumHelper.getBestTransitPathCalculator()); + + // calculate array of distanceToExternalCordon logsums by taz for + // use by internal-external model + double[] distanceToCordonsLogsums = computeTazDistanceToExternalCordonLogsums(); + + // create choice model object + hhChoiceModels = new HouseholdChoiceModels(++modelIndex, restartModelString, + propertyMap, modelStructure, dmuFactory, aggAcc, logsumHelper, mandAcc, + pctHighIncome, pctMultipleAutos, avgtts, transpDist, pctDetour, + nonMandatoryTazDistProbs, nonMandatorySizeProbs, subTourTazDistProbs, + subTourSizeProbs, distanceToCordonsLogsums, tazDistanceCalculator); + if(logResults){ + message = String.format("created hhChoiceModels=%d, task=%d, thread=%s.", modelIndex, + taskIndex, Thread.currentThread().getName()); + logger.info(message); + logger.info(""); + } + + } else + { + hhChoiceModels = modelQueue.remove(); + if(logResults){ + message = String.format("removed hhChoiceModels=%d from queue, task=%d, thread=%s.", + hhChoiceModels.getModelIndex(), taskIndex, Thread.currentThread().getName()); + logger.info(message); + logger.info(""); + } + } + + return hhChoiceModels; + + } + + /** + * return the HouseholdChoiceModels object to the manager's queue so that it + * may be used by another thread without it having to create one. + * + * @param hhModels + */ + public void returnHouseholdChoiceModelsObject(HouseholdChoiceModels hhModels, int startIndex, + int endIndex) + { + modelQueue.add(hhModels); + completedHouseholds += (endIndex - startIndex + 1); + if(logResults){ + logger.info("returned hhChoiceModels=" + hhModels.getModelIndex() + " to queue: thread=" + + Thread.currentThread().getName() + ", completedHouseholds=" + completedHouseholds + + "."); + } + } + + public synchronized void clearHhModels() + { + + if (modelQueue == null) return; + + logger.info(String.format("%s: clearing household choice models modelQueue, thread=%s.", + new Date(), Thread.currentThread().getName())); + while (!modelQueue.isEmpty()) + modelQueue.remove(); + + modelIndex = 0; + completedHouseholds = 0; + + modelQueue = null; + + } + + private void readTpChoiceAvgTtsFile() + { + + // construct input household file name from properties file values + String projectDirectory = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + + String inputFileName = propertyMap.get(TP_CHOICE_AVG_TTS_FILE); + String fileName = projectDirectory + inputFileName; + + TableDataSet table; + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + table = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading tp choice avgtts data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + int[] tazField = table.getColumnAsInt(TAZ_FIELD_NAME); + double[] avgttsField = table.getColumnAsDouble(AVGTTS_COLUMN_NAME); + double[] transpDistField = table.getColumnAsDouble(TRANSP_DIST_COLUMN_NAME); + double[] pctDetourField = table.getColumnAsDouble(PCT_DETOUR_COLUMN_NAME); + + avgtts = new double[tdm.getMaxTaz() + 1]; + transpDist = new double[tdm.getMaxTaz() + 1]; + pctDetour = new double[tdm.getMaxTaz() + 1]; + + // loop over the number of mgra records in the TableDataSet. + for (int k = 0; k < tdm.getMaxTaz(); k++) + { + + // get the mgra value for TableDataSet row k from the mgra field. + int taz = tazField[k]; + + avgtts[taz] = avgttsField[k]; + transpDist[taz] = transpDistField[k]; + pctDetour[taz] = pctDetourField[k]; + + } + + } + + private void computeNonMandatorySegmentSizeArrays(CtrampDmuFactoryIf dmuFactory) + { + + // compute the array of cumulative taz distance based SOA probabilities + // for each origin taz. + DestChoiceTwoStageSoaTazDistanceUtilityDMU dcDistSoaDmu = dmuFactory + .getDestChoiceSoaTwoStageTazDistUtilityDMU(); + + // the size term array in aggAcc gives mgra*purpose - need an array of + // all mgras for one purpose + double[][] aggAccDcSizeArray = aggAcc.getSizeTerms(); + + String[] tourPurposeNames = {ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME, + ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME, + ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME, + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME, + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME, + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME}; + + int[] sizeSheetIndices = {BuildAccessibilities.ESCORT_INDEX, + BuildAccessibilities.SHOP_INDEX, BuildAccessibilities.OTH_MAINT_INDEX, + BuildAccessibilities.EATOUT_INDEX, BuildAccessibilities.VISIT_INDEX, + BuildAccessibilities.OTH_DISCR_INDEX}; + + HashMap nonMandatorySegmentNameIndexMap = new HashMap(); + HashMap nonMandatorySizeSegmentNameIndexMap = new HashMap(); + for (int k = 0; k < tourPurposeNames.length; k++) + { + nonMandatorySegmentNameIndexMap.put(tourPurposeNames[k], k); + nonMandatorySizeSegmentNameIndexMap.put(tourPurposeNames[k], sizeSheetIndices[k]); + } + + double[][] dcSizeArray = new double[tourPurposeNames.length][aggAccDcSizeArray.length]; + for (int i = 0; i < aggAccDcSizeArray.length; i++) + { + for (int m : nonMandatorySegmentNameIndexMap.values()) + { + int s = sizeSheetIndices[m]; + dcSizeArray[m][i] = aggAccDcSizeArray[i][s]; + } + } + + // compute the arrays of cumulative probabilities based on mgra size for + // mgras within each origin taz. + nonMandatorySizeProbs = new double[tourPurposeNames.length][][]; + nonMandatoryTazDistProbs = new double[tourPurposeNames.length][][]; + + DestChoiceTwoStageSoaProbabilitiesCalculator nonManSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_NON_MANDATORY_DC_SOA_UEC_FILE, + PROPERTIES_NON_MANDATORY_DC_SOA_UEC_MODEL_PAGE, + PROPERTIES_NON_MANDATORY_DC_SOA_UEC_DATA_PAGE); + + for (String tourPurpose : tourPurposeNames) + { + + int purposeSizeIndex = nonMandatorySizeSegmentNameIndexMap.get(tourPurpose); + + // compute the TAZ size values from the mgra values and the + // correspondence between mgras and tazs. + if (tourPurpose.equalsIgnoreCase(ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME)) + { + + double[] mgraData = new double[maxMgra + 1]; + double[] tazData = null; + + // aggregate TAZ grade school enrollment and set array in DMU + for (int i = 1; i <= maxMgra; i++) + mgraData[i] = aggAcc.getMgraGradeSchoolEnrollment(i); + tazData = computeTazSize(mgraData); + dcDistSoaDmu.setTazGsEnrollment(tazData); + + // aggregate TAZ high school enrollment and set array in DMU + for (int i = 1; i <= maxMgra; i++) + mgraData[i] = aggAcc.getMgraHighSchoolEnrollment(i); + tazData = computeTazSize(mgraData); + dcDistSoaDmu.setTazHsEnrollment(tazData); + + // aggregate TAZ households and set array in DMU + for (int i = 1; i <= maxMgra; i++) + mgraData[i] = aggAcc.getMgraHouseholds(i); + tazData = computeTazSize(mgraData); + dcDistSoaDmu.setNumHhs(tazData); + + DestChoiceTwoStageSoaProbabilitiesCalculator escortSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_NON_MANDATORY_DC_SOA_UEC_FILE, + PROPERTIES_ESCORT_DC_SOA_UEC_MODEL_PAGE, + PROPERTIES_ESCORT_DC_SOA_UEC_DATA_PAGE); + + logger.info(" " + tourPurpose + " probabilities"); + nonMandatoryTazDistProbs[purposeSizeIndex] = escortSoaDistProbsObject + .computeDistanceProbabilities(dcDistSoaDmu); + + } else + { + + // aggregate TAZ size for the non-mandatoy purpose and set array + // in DMU + double[] tazSize = computeTazSize(dcSizeArray[purposeSizeIndex]); + dcDistSoaDmu.setDestChoiceTazSize(tazSize); + + logger.info(" " + tourPurpose + " probabilities"); + nonMandatoryTazDistProbs[purposeSizeIndex] = nonManSoaDistProbsObject + .computeDistanceProbabilities(dcDistSoaDmu); + + } + + nonMandatorySizeProbs[purposeSizeIndex] = computeSizeSegmentProbabilities(dcSizeArray[purposeSizeIndex]); + + } + + } + + private void computeSubtourSegmentSizeArrays(ModelStructure modelStructure, + CtrampDmuFactoryIf dmuFactory) + { + + // compute the array of cumulative taz distance based SOA probabilities + // for each origin taz. + DestChoiceTwoStageSoaTazDistanceUtilityDMU dcDistSoaDmu = dmuFactory + .getDestChoiceSoaTwoStageTazDistUtilityDMU(); + + // the size term array in aggAcc gives mgra*purpose - need an array of + // all mgras for one purpose + double[][] aggAccDcSizeArray = aggAcc.getSizeTerms(); + + String[] tourPurposeNames = {modelStructure.AT_WORK_BUSINESS_PURPOSE_NAME, + modelStructure.AT_WORK_EAT_PURPOSE_NAME, modelStructure.AT_WORK_MAINT_PURPOSE_NAME}; + + int[] sizeSheetIndices = {SubtourDestChoiceModel.PROPERTIES_AT_WORK_BUSINESS_SIZE_SHEET, + SubtourDestChoiceModel.PROPERTIES_AT_WORK_EAT_OUT_SIZE_SHEET, + SubtourDestChoiceModel.PROPERTIES_AT_WORK_OTHER_SIZE_SHEET}; + + HashMap segmentNameIndexMap = new HashMap(); + HashMap sizeSegmentNameIndexMap = new HashMap(); + for (int k = 0; k < tourPurposeNames.length; k++) + { + segmentNameIndexMap.put(tourPurposeNames[k], k); + sizeSegmentNameIndexMap.put(tourPurposeNames[k], sizeSheetIndices[k]); + } + + double[][] dcSizeArray = new double[tourPurposeNames.length][aggAccDcSizeArray.length]; + for (int i = 0; i < aggAccDcSizeArray.length; i++) + { + for (int m : segmentNameIndexMap.values()) + { + int s = sizeSheetIndices[m]; + dcSizeArray[m][i] = aggAccDcSizeArray[i][s]; + } + } + + // compute the arrays of cumulative probabilities based on mgra size for + // mgras within each origin taz. + subTourSizeProbs = new double[tourPurposeNames.length][][]; + subTourTazDistProbs = new double[tourPurposeNames.length][][]; + + DestChoiceTwoStageSoaProbabilitiesCalculator subTourSoaDistProbsObject = new DestChoiceTwoStageSoaProbabilitiesCalculator( + propertyMap, dmuFactory, PROPERTIES_NON_MANDATORY_DC_SOA_UEC_FILE, + PROPERTIES_ATWORK_DC_SOA_UEC_MODEL_PAGE, PROPERTIES_ATWORK_DC_SOA_UEC_DATA_PAGE); + + for (String tourPurpose : tourPurposeNames) + { + + int purposeSizeIndex = segmentNameIndexMap.get(tourPurpose); + + // aggregate TAZ size for the non-mandatoy purpose and set array in + // DMU + double[] tazSize = computeTazSize(dcSizeArray[purposeSizeIndex]); + dcDistSoaDmu.setDestChoiceTazSize(tazSize); + + logger.info(" " + tourPurpose + " probabilities"); + subTourTazDistProbs[purposeSizeIndex] = subTourSoaDistProbsObject + .computeDistanceProbabilities(dcDistSoaDmu); + + subTourSizeProbs[purposeSizeIndex] = computeSizeSegmentProbabilities(dcSizeArray[purposeSizeIndex]); + + } + + } + + private double[] computeTazSize(double[] size) + { + + // this is a 0-based array of cumulative probabilities + double[] tazSize = new double[maxTaz + 1]; + + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + + int[] mgraArray = tdm.getMgraArray(taz); + if (mgraArray != null) + { + for (int mgra : mgraArray) + { + tazSize[taz] += size[mgra] + (size[mgra] > 0 ? 1 : 0); + } + } + + } + + return tazSize; + + } + + private double[][] computeSizeSegmentProbabilities(double[] size) + { + + // this is a 0-based array of cumulative probabilities + double[][] sizeProbs = new double[maxTaz][]; + + for (int taz = 1; taz <= tdm.getMaxTaz(); taz++) + { + + int[] mgraArray = tdm.getMgraArray(taz); + + if (mgraArray == null) + { + sizeProbs[taz - 1] = new double[0]; + } else + { + double totalSize = 0; + for (int mgra : mgraArray) + totalSize += size[mgra] + (size[mgra] > 0 ? 1 : 0); + + if (totalSize > 0) + { + sizeProbs[taz - 1] = new double[mgraArray.length]; + for (int i = 0; i < mgraArray.length; i++) + { + double mgraSize = size[mgraArray[i]]; + if (mgraSize > 0) mgraSize += 1; + sizeProbs[taz - 1][i] = mgraSize / totalSize; + } + } else + { + sizeProbs[taz - 1] = new double[0]; + } + } + + } + + return sizeProbs; + + } + + private double[] computeTazDistanceToExternalCordonLogsums() + { + + int maxTaz = tdm.getMaxTaz(); + String uecPath = propertyMap.get("uec.path"); + String altFileName = uecPath + propertyMap.get("internalExternal.dc.uec.alts.file"); + TableDataSet altData = readFile(altFileName); + + int tazCol = altData.getColumnPosition("taz"); + int ieCol = altData.getColumnPosition("iePct"); + altData.buildIndex(tazCol); + + // get parameters used to develop distance to cordon logsums for IE + // model + String coeffString = propertyMap.get(IE_DISTANCE_LOGSUM_COEFF_KEY); + double coeff = Double.parseDouble(coeffString); + + ArrayList tazList = new ArrayList(); + String externalTazListString = propertyMap.get(IE_EXTERNAL_TAZS_KEY); + StringTokenizer st = new StringTokenizer(externalTazListString, ","); + while (st.hasMoreTokens()) + { + String listValue = st.nextToken(); + int tazValue = Integer.parseInt(listValue.trim()); + tazList.add(tazValue); + } + int[] externalTazs = new int[tazList.size()]; + for (int i = 0; i < externalTazs.length; i++) + externalTazs[i] = tazList.get(i); + + // get stored distance arrays + double[][][] periodDistanceMatrices = tazDistanceCalculator + .getStoredFromTazToAllTazsDistanceSkims(); + + // compute the TAZ x EXTERNAL TAZ distance based logsums. + double[] tazDistLogsums = new double[maxTaz + 1]; + for (int i = 1; i <= maxTaz; i++) + { + + double sum = 0; + for (int j = 0; j < externalTazs.length; j++) + { + double distanceToExternal = periodDistanceMatrices[ModelStructure.MD_SKIM_PERIOD_INDEX][i][externalTazs[j]]; + double iePct = altData.getValueAt(externalTazs[j], ieCol); + sum += iePct * MathUtil.exp(coeff * distanceToExternal); + } + + tazDistLogsums[i] = MathUtil.log(sum); + } + + return tazDistLogsums; + + } + + /** + * Read the file and return the TableDataSet. + * + * @param fileName + * @return data + */ + private TableDataSet readFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet data; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + data = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + return data; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelsTaskJppf.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelsTaskJppf.java new file mode 100644 index 0000000..5ca5dcc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdChoiceModelsTaskJppf.java @@ -0,0 +1,207 @@ +package org.sandag.abm.ctramp; + +import java.net.UnknownHostException; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.jppf.node.protocol.AbstractTask; +import org.jppf.node.protocol.DataProvider; +import org.jppf.node.protocol.JPPFTask; + +import com.pb.common.calculator.MatrixDataServerIf; + +public class HouseholdChoiceModelsTaskJppf + extends AbstractTask +{ + + private transient HashMap propertyMap; + private transient MatrixDataServerIf ms; + private transient HouseholdDataManagerIf hhDataManager; + private transient ModelStructure modelStructure; + private transient CtrampDmuFactoryIf dmuFactory; + private transient String restartModelString; + + private int startIndex; + private int endIndex; + private int taskIndex; + + private int maxAlts; + + private boolean runWithTiming; + private boolean logResults=false; + + public HouseholdChoiceModelsTaskJppf(int taskIndex, int startIndex, int endIndex) + { + this.startIndex = startIndex; + this.endIndex = endIndex; + this.taskIndex = taskIndex; + runWithTiming = true; + } + + public void run() + { + + long startTime = System.nanoTime(); + + Logger logger = Logger.getLogger(this.getClass()); + + String threadName = null; + try + { + threadName = "[" + java.net.InetAddress.getLocalHost().getHostName() + "] " + + Thread.currentThread().getName(); + } catch (UnknownHostException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + try + { + + DataProvider dataProvider = getDataProvider(); + + propertyMap = (HashMap) dataProvider.getParameter("propertyMap"); + logResults = Util.getStringValueFromPropertyMap(propertyMap, "RunModel.LogResults") + .equalsIgnoreCase("true"); + ms = (MatrixDataServerIf) dataProvider.getParameter("ms"); + hhDataManager = (HouseholdDataManagerIf) dataProvider.getParameter("hhDataManager"); + modelStructure = (ModelStructure) dataProvider.getParameter("modelStructure"); + dmuFactory = (CtrampDmuFactoryIf) dataProvider.getParameter("dmuFactory"); + restartModelString = (String) dataProvider.getParameter("restartModelString"); + + } catch (Exception e) + { + e.printStackTrace(); + } + + // get the factory object used to create and recycle + // HouseholdChoiceModels objects. + HouseholdChoiceModelsManager modelManager = HouseholdChoiceModelsManager.getInstance(); + modelManager.managerSetup(ms, hhDataManager, propertyMap, restartModelString, + modelStructure, dmuFactory); + + HouseholdChoiceModels hhModel = modelManager.getHouseholdChoiceModelsObject(taskIndex); + + long setup1 = 0; + long setup2 = 0; + long setup3 = 0; + long setup4 = 0; + long setup5 = 0; + + setup1 = (System.nanoTime() - startTime) / 1000000; + + Household[] householdArray = hhDataManager.getHhArray(startIndex, endIndex); + + setup2 = (System.nanoTime() - startTime) / 1000000; + + boolean runDebugHouseholdsOnly = Util.getBooleanValueFromPropertyMap(propertyMap, + HouseholdDataManager.DEBUG_HHS_ONLY_KEY); + + if (runWithTiming) hhModel.zeroTimes(); + for (int i = 0; i < householdArray.length; i++) + { + + // for debugging only - process only household objects specified for + // debugging, if property key was set to true + if (runDebugHouseholdsOnly && !householdArray[i].getDebugChoiceModels()) continue; + + try + { + if (runWithTiming) hhModel.runModelsWithTiming(householdArray[i]); + else hhModel.runModels(householdArray[i]); + } catch (RuntimeException e) + { + logger.fatal(String + .format("exception caught in taskIndex=%d hhModel index=%d applying hh model for i=%d, hhId=%d.", + taskIndex, hhModel.getModelIndex(), i, householdArray[i].getHhId())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(e); + } + + } + + long[] componentTimes = hhModel.getTimes(); + long[] partialStopTimes = hhModel.getPartialStopTimes(); + + if (hhModel.getMaxAlts() > maxAlts) maxAlts = hhModel.getMaxAlts(); + + setup3 = (System.nanoTime() - startTime) / 1000000; + + hhDataManager.setHhArray(householdArray, startIndex); + + setup4 = (System.nanoTime() - startTime) / 1000000; + + logger.info(String + .format("end of household choice model thread=%s, task[%d], hhModel[%d], startIndex=%d, endIndex=%d", + threadName, taskIndex, hhModel.getModelIndex(), startIndex, endIndex)); + + setResult(String.format("taskIndex=%d, hhModelInstance=%d, startIndex=%d, endIndex=%d", + taskIndex, hhModel.getModelIndex(), startIndex, endIndex)); + + setup5 = (System.nanoTime() - startTime) / 1000000; + + if(logResults){ + logger.info("task=" + taskIndex + ", setup=" + setup1 + ", getHhs=" + (setup2 - setup1) + + ", processHhs=" + (setup3 - setup2) + ", putHhs=" + (setup4 - setup3) + + ", return model=" + (setup5 - setup4) + "."); + } + + if (runWithTiming) + logModelComponentTimes(componentTimes, partialStopTimes, logger, + hhModel.getModelIndex()); + + // this has to be the last statement in this method. + // add this DestChoiceModel instance to the static queue shared by other + // tasks of this type + modelManager.returnHouseholdChoiceModelsObject(hhModel, startIndex, endIndex); + + } + + private void logModelComponentTimes(long[] componentTimes, long[] partialStopTimes, + Logger logger, int modelIndex) + { + + String[] label1 = {"AO", "FP", "IE", "CDAP", "IMTF", "IMTOD", "IMMC", "JTF", "JTDC", + "JTTOD", "JTMC", "INMTF", "INMTDCSOA", "INMTDCTOT", "INMTTOD", "INMTMC", "AWTF", + "AWTDCSOA", "AWTDCTOT", "AWTTOD", "AWTMC", "STF", "STDTM"}; + + logger.info("Household choice model component runtimes (in milliseconds) for task: " + + taskIndex + ", modelIndex: " + modelIndex + ", startIndex: " + startIndex + + ", endIndex: " + endIndex); + + float total = 0; + for (int i = 0; i < componentTimes.length; i++) + { + float time = (componentTimes[i] / 1000000); + logger.info(String.format("%-6d%30s:%15.1f", (i + 1), label1[i], time)); + total += time; + } + logger.info(String.format("%-6s%30s:%10.1f", "Total", "Total all components", total)); + logger.info(""); + + String[] label2 = {"SLC SOA AUTO", "SLC SOA OTHER", "SLC LS", "SLC DIST", "SLC", "SLC TOT", + "S TOD", "S MC", "TOTAL"}; + + logger.info(""); + logger.info("Times for parts of intermediate stop models:"); + for (int i = 0; i < partialStopTimes.length; i++) + { + float time = (partialStopTimes[i] / 1000000); + logger.info(String.format("%-6d%30s:%15.1f", (i + 1), label2[i], time)); + } + + } + + public String getId() + { + return Integer.toString(taskIndex); + } + + public int getMaxAlts() + { + return maxAlts; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdCoordinatedDailyActivityPatternModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdCoordinatedDailyActivityPatternModel.java new file mode 100644 index 0000000..2b26011 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdCoordinatedDailyActivityPatternModel.java @@ -0,0 +1,1423 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import com.pb.common.calculator.VariableTable; +import com.pb.common.model.Alternative; +import com.pb.common.model.ConcreteAlternative; +import com.pb.common.model.LogitModel; +import com.pb.common.model.ModelException; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +/** + * Implements a coordinated daily activity pattern model, which is a joint + * choice of activity types of each member of a household. The class builds and + * applies separate choice models for households of sizes 1, 2, 3, 4, and 5. For + * households larger than 5, the persons in the household are ordered such that + * the first 5 members include up to 2 workers and 3 children (youngest to + * oldest), the 5-person model is applied for these 5 household members, than a + * separate, simple cross-sectional distribution is looked up for the remaining + * household members. + * + * The utilities are computed using four separate UEC spreadsheets. The first + * computes the activity utility for each person individually; the second + * computes the activity utility for each person when paired with each other + * person; the third computes the activity utility for each person when paired + * with each group of two other people in the household; and the fourth computes + * the activity utility considering all the members of the household. These + * utilities are then aggregated to represent each possible activity pattern for + * the household, and the choice is made. For households larger than 5, a second + * model is applied after the first, which selects a pattern for the 5+ + * household members from a predefined distribution. + * + * @author D. Ory + * + */ +public class HouseholdCoordinatedDailyActivityPatternModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(HouseholdCoordinatedDailyActivityPatternModel.class); + private transient Logger cdapLogger = Logger.getLogger("cdap"); + private transient Logger cdapUecLogger = Logger.getLogger("cdap_uec"); + private transient Logger cdapLogsumLogger = Logger.getLogger("cdap_logsum"); + + private static final String UEC_FILE_NAME_PROPERTY = "cdap.uec.file"; + private static final String UEC_DATA_PAGE_PROPERTY = "cdap.data.page"; + private static final String UEC_ONE_PERSON_UTILITY_PAGE_PROPERTY = "cdap.one.person.page"; + private static final String UEC_TWO_PERSON_UTILITY_PAGE_PROPERTY = "cdap.two.person.page"; + private static final String UEC_THREE_PERSON_UTILITY_PAGE_PROPERTY = "cdap.three.person.page"; + private static final String UEC_ALL_PERSON_UTILITY_PAGE_PROPERTY = "cdap.all.person.page"; + private static final String UEC_JOINT_UTILITY_PAGE_PROPERTY = "cdap.joint.page"; + + public static final int MAX_MODEL_HH_SIZE = 5; + + private static final String MANDATORY_PATTERN = Definitions.MANDATORY_PATTERN; + private static final String NONMANDATORY_PATTERN = Definitions.NONMANDATORY_PATTERN; + private static final String HOME_PATTERN = Definitions.HOME_PATTERN; + private static final String[] ACTIVITY_NAME_ARRAY = { + MANDATORY_PATTERN, NONMANDATORY_PATTERN, HOME_PATTERN }; + + private ModelStructure modelStructure; + private double[][] fixedCumulativeProportions; + + // collection of logit models - one for each household size + private ArrayList logitModelList; + + private AccessibilitiesTable accTable; + + // DMU for the UEC + private CoordinatedDailyActivityPatternDMU cdapDmuObject; + + // re-ordered collection of households + private Person[] cdapPersonArray; + + // Five separate UECs to compute segments of the utility + private UtilityExpressionCalculator onePersonUec, twoPeopleUec, threePeopleUec, + allMemberInteractionUec, jointUec; + + public HouseholdCoordinatedDailyActivityPatternModel(HashMap propertyMap, + ModelStructure myModelStructure, CtrampDmuFactoryIf dmuFactory, + AccessibilitiesTable myAccTable) + { + + modelStructure = myModelStructure; + accTable = myAccTable; + + // setup the coordinated daily activity pattern choice model objects + createLogitModels(); + setupCoordinatedDailyActivityPatternModelApplication(propertyMap, dmuFactory); + + } + + private void setupCoordinatedDailyActivityPatternModelApplication( + HashMap propertyMap, CtrampDmuFactoryIf dmuFactory) + { + + logger.info("setting up CDAP choice model."); + + // locate the coordinated daily activity pattern choice model UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String cdapUecFile = propertyMap.get(UEC_FILE_NAME_PROPERTY); + cdapUecFile = uecPath + cdapUecFile; + + int dataPage = Util.getIntegerValueFromPropertyMap(propertyMap, UEC_DATA_PAGE_PROPERTY); + int onePersonPage = Util.getIntegerValueFromPropertyMap(propertyMap, + UEC_ONE_PERSON_UTILITY_PAGE_PROPERTY); + int twoPersonPage = Util.getIntegerValueFromPropertyMap(propertyMap, + UEC_TWO_PERSON_UTILITY_PAGE_PROPERTY); + int threePersonPage = Util.getIntegerValueFromPropertyMap(propertyMap, + UEC_THREE_PERSON_UTILITY_PAGE_PROPERTY); + int allPersonPage = Util.getIntegerValueFromPropertyMap(propertyMap, + UEC_ALL_PERSON_UTILITY_PAGE_PROPERTY); + int jointPage = Util.getIntegerValueFromPropertyMap(propertyMap, + UEC_JOINT_UTILITY_PAGE_PROPERTY); + + // create the coordinated daily activity pattern choice model DMU + // object. + cdapDmuObject = dmuFactory.getCoordinatedDailyActivityPatternDMU(); + + // create the uecs + onePersonUec = new UtilityExpressionCalculator(new File(cdapUecFile), onePersonPage, + dataPage, propertyMap, (VariableTable) cdapDmuObject); + twoPeopleUec = new UtilityExpressionCalculator(new File(cdapUecFile), twoPersonPage, + dataPage, propertyMap, (VariableTable) cdapDmuObject); + threePeopleUec = new UtilityExpressionCalculator(new File(cdapUecFile), threePersonPage, + dataPage, propertyMap, (VariableTable) cdapDmuObject); + allMemberInteractionUec = new UtilityExpressionCalculator(new File(cdapUecFile), + allPersonPage, dataPage, propertyMap, (VariableTable) cdapDmuObject); + jointUec = new UtilityExpressionCalculator(new File(cdapUecFile), jointPage, dataPage, + propertyMap, (VariableTable) cdapDmuObject); + + // get the proportions by person type + double[][] fixedRelativeProportions = modelStructure.getCdap6PlusProps(); + fixedCumulativeProportions = new double[fixedRelativeProportions.length][]; + + // i loops over personTypes, 0 not used. + for (int i = 1; i < fixedRelativeProportions.length; i++) + { + fixedCumulativeProportions[i] = new double[fixedRelativeProportions[i].length]; + + // j loops over cdap patterns, can skip index 0. + fixedCumulativeProportions[i][0] = fixedRelativeProportions[i][0]; + for (int j = 1; j < fixedRelativeProportions[i].length; j++) + fixedCumulativeProportions[i][j] = fixedCumulativeProportions[i][j - 1] + + fixedRelativeProportions[i][j]; + + // calculate the difference between 1.0 and the cumulative + // proportion and + // add to the Mandatory category (j==0) + // to make sure the cumulative propbabilities sum to exactly 1.0. + double diff = 1.0 - fixedCumulativeProportions[i][fixedRelativeProportions[i].length - 1]; + fixedCumulativeProportions[i][0] += diff; + } + + } + + public void applyModel(Household hhObject) + { + + if (hhObject.getDebugChoiceModels()) + hhObject.logHouseholdObject("Pre CDAP Household " + hhObject.getHhId() + " Object", + cdapLogger); + + // get the activity pattern choice + String pattern = getCoordinatedDailyActivityPatternChoice(hhObject); + + // set the pattern for the household + hhObject.setCoordinatedDailyActivityPatternResult(pattern); + + // set the pattern for each person and count by person type + Person[] personArray = hhObject.getPersons(); + for (int j = 1; j < personArray.length; ++j) + { + String activityString = pattern.substring(j - 1, j); + personArray[j].setDailyActivityResult(activityString); + } // j (person loop) + + // log results for debug households + if (hhObject.getDebugChoiceModels()) + { + + cdapLogger.info(" "); + cdapLogger.info("CDAP Chosen Pattern by Person Type"); + cdapLogger + .info("(* indicates person was involved in coordinated choice; no * indicates choice by fixed proportions)"); + cdapLogger.info("CDAP # Type FT W PT W UNIV NONW RETR SCHD SCHN PRES"); + cdapLogger.info("------ ---- ---- ---- ---- ---- ---- ---- ---- ----"); + + String bString = ""; + for (int j = 1; j < personArray.length; ++j) + { + + Person[] tempPersonArray = getPersonsNotModeledByCdap(MAX_MODEL_HH_SIZE); + + boolean persNumMatch = false; + for (int jj = 1; jj < tempPersonArray.length; jj++) + { + if (tempPersonArray[jj].getPersonNum() == personArray[j].getPersonNum()) + persNumMatch = true; + } + + String persNumString = ""; + if (persNumMatch) persNumString = String.format("%d ", j); + else persNumString = String.format("%d *", j); + + String pString = pattern.substring(j - 1, j); + String stringToLog = ""; + + if (personArray[j].getPersonTypeIsFullTimeWorker() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "FT W", pString, bString, bString, bString, bString, bString, bString, + bString); + } else if (personArray[j].getPersonTypeIsPartTimeWorker() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "PT W", bString, pString, bString, bString, bString, bString, bString, + bString); + } else if (personArray[j].getPersonIsUniversityStudent() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "UNIV", bString, bString, pString, bString, bString, bString, bString, + bString); + } else if (personArray[j].getPersonIsNonWorkingAdultUnder65() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "NONW", bString, bString, bString, pString, bString, bString, bString, + bString); + } else if (personArray[j].getPersonIsNonWorkingAdultOver65() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "RETR", bString, bString, bString, bString, pString, bString, bString, + bString); + } else if (personArray[j].getPersonIsStudentDriving() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "SCHD", bString, bString, bString, bString, bString, pString, bString, + bString); + } else if (personArray[j].getPersonIsStudentNonDriving() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "SCHN", bString, bString, bString, bString, bString, bString, pString, + bString); + } else if (personArray[j].getPersonIsPreschoolChild() == 1) + { + stringToLog = String.format("%6s%5s%5s%5s%5s%5s%5s%5s%5s%5s", persNumString, + "PRES", bString, bString, bString, bString, bString, bString, bString, + pString); + } + + cdapLogger.info(stringToLog); + + } // j (person loop) + + cdapLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + cdapLogger.info(""); + cdapLogger.info(""); + + } // if traceMe + + hhObject.setCdapRandomCount(hhObject.getHhRandomCount()); + + } + + /** + * Prepares a separate logit model for households of size 1, 2, 3, 4, and 5. + * Each model has 3^n alternatives, where n is the household size. The + * models are cleared and re-used for each household of the specified size. + * + */ + private void createLogitModels() + { + + // new the collection of logit models + logitModelList = new ArrayList(MAX_MODEL_HH_SIZE); + + // build a model for each HH size + for (int i = 0; i < MAX_MODEL_HH_SIZE; ++i) + { + + int hhSize = i + 1; + + // create the working model + LogitModel workingLogitModel = new LogitModel(hhSize + " Person HH"); + + // compute the number of alternatives + int numberOfAlternatives = 1; + for (int j = 0; j < hhSize; ++j) + numberOfAlternatives *= ACTIVITY_NAME_ARRAY.length; + + // create a counter for each of the people in the hh + int[] counterForEachPerson = new int[hhSize]; + Arrays.fill(counterForEachPerson, 0); + + // create the alternatives and add them to the logit model + int numberOfAltsCounter = 0; + int totalAltsCounter = 0; + while (numberOfAltsCounter < numberOfAlternatives) + { + + // set the string for the alternative + String alternativeName = ""; + int numOutOfHomeActivites = 0; + for (int j = 0; j < hhSize; ++j) + { + alternativeName += ACTIVITY_NAME_ARRAY[counterForEachPerson[j]]; + if (!ACTIVITY_NAME_ARRAY[counterForEachPerson[j]] + .equalsIgnoreCase(HOME_PATTERN)) numOutOfHomeActivites++; + } + + // create the alternative and add it to the model + if (numOutOfHomeActivites < 2) + { + ConcreteAlternative tempAlt = new ConcreteAlternative(alternativeName + "0", + totalAltsCounter); + workingLogitModel.addAlternative(tempAlt); + numberOfAltsCounter++; + totalAltsCounter++; + + } else + { + + ConcreteAlternative tempAlt = new ConcreteAlternative(alternativeName + "0", + totalAltsCounter); + workingLogitModel.addAlternative(tempAlt); + numberOfAltsCounter++; + totalAltsCounter++; + + tempAlt = new ConcreteAlternative(alternativeName + "j", totalAltsCounter); + workingLogitModel.addAlternative(tempAlt); + totalAltsCounter++; + + } + + // check increment the counters + for (int j = 0; j < hhSize; ++j) + { + counterForEachPerson[j]++; + if (counterForEachPerson[j] == ACTIVITY_NAME_ARRAY.length) counterForEachPerson[j] = 0; + else break; + } + + } + + // add the model to the array list + logitModelList.add(i, workingLogitModel); + + } // for i max hh size + + } + + /** + * Selects the coordinated daily activity pattern choice for the passed in + * Household. The method works for households of all sizes, though two + * separate models are applied for households with more than 5 members. + * + * @param householdObject + * @return a string of length household size, where each character in the + * string represents the activity pattern for that person, in order + * (see Household.reOrderPersonsForCdap method). + */ + public String getCoordinatedDailyActivityPatternChoice(Household householdObject) + { + + // set all household level dmu variables + cdapDmuObject.setHousehold(householdObject); + + // set the hh size (cap modeled size at MAX_MODEL_HH_SIZE) + int actualHhSize = householdObject.getSize(); + int modelHhSize = Math.min(MAX_MODEL_HH_SIZE, actualHhSize); + + // reorder persons for large households if need be + reOrderPersonsForCdap(householdObject); + + // get the logit model we need and clear it of any lingering probilities + LogitModel workingLogitModel = logitModelList.get(modelHhSize - 1); + workingLogitModel.clear(); + + // get the alternatives and reset the utilities to zero + ArrayList alternativeList = workingLogitModel.getAlternatives(); + for (int i = 0; i < alternativeList.size(); ++i) + { + Alternative tempAlt = (Alternative) alternativeList.get(i); + tempAlt.setUtility(0.0); + } + + // write the debug header if we have a trace household + if (householdObject.getDebugChoiceModels()) + { + + LogitModel.setLogger(cdapLogsumLogger); + + cdapLogger.info(" "); + cdapLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + cdapLogger.info("CDAP Model: Debug Statement for Household ID: " + + householdObject.getHhId()); + String firstHeader = "Utility Segment PersonA PersonB PersonC"; + String secondHeader = "------------------------------ -------- -------- --------"; + for (int j = 0; j < ACTIVITY_NAME_ARRAY.length; ++j) + { + firstHeader += " " + ACTIVITY_NAME_ARRAY[j] + " util"; + secondHeader += " ---------"; + } + + cdapLogger.info(firstHeader); + cdapLogger.info(secondHeader); + + } + + // all the alternatives are available for all households (1-based, + // ignore 0 + // index and set other three to 1.) + int[] availability = {-1, 1, 1, 1}; + + String[] accStrings = {"", "hov0", "hov1", "hov2"}; + float retAccess = accTable.getAggregateAccessibility( + accStrings[householdObject.getAutoSufficiency()], householdObject.getHhMgra()); + + cdapDmuObject.setRetailAccessibility(retAccess); + + // loop through each person + for (int i = 0; i < modelHhSize; ++i) + { + + // get personA + Person personA = getCdapPerson(i + 1); + + // set the person level dmu variables + cdapDmuObject.setPersonA(personA); + + int workMgra = personA.getWorkLocation(); + if (workMgra > 0 && workMgra != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) cdapDmuObject + .setWorkLocationModeChoiceLogsumA(personA.getWorkLocationLogsum()); + else cdapDmuObject.setWorkLocationModeChoiceLogsumA(0.0); + + int schoolMgra = personA.getPersonSchoolLocationZone(); + int studentType = getStudentTypeForThisCdapPerson(personA); + if (studentType > 0 && schoolMgra > 0) + { + cdapDmuObject.setSchoolLocationModeChoiceLogsumA(personA.getSchoolLocationLogsum()); + } else + { + cdapDmuObject.setSchoolLocationModeChoiceLogsumA(0.0); + } + + // compute the single person utilities + double[] firstPersonUtilities = onePersonUec.solve(cdapDmuObject.getIndexValues(), + cdapDmuObject, availability); + + // log these utilities for trace households + if (householdObject.getDebugChoiceModels()) + { + + String stringToLog = String.format("%-30s%9d%9s%9s", "OnePerson", (i + 1), "--", + "--"); + + for (int j = 0; j < ACTIVITY_NAME_ARRAY.length; ++j) + { + stringToLog += String.format("%10.4f", firstPersonUtilities[j]); + } + cdapLogger.info(stringToLog); + + cdapUecLogger.info("PersonA:"); + personA.logEntirePersonObject(cdapUecLogger); + onePersonUec.logAnswersArray(cdapUecLogger, "ONE PERSON, personA personNum=" + + personA.getPersonNum()); + + } // debug trace + + // align the one person utilities with the alternatives for person i and calculate their individual logsum + float individualLogsum = 0; + for (int j = 0; j < alternativeList.size(); ++j) + { + + // get the name of the alternative + Alternative tempAlt = (Alternative) alternativeList.get(j); + String altName = tempAlt.getName(); + + // get the name of the activity for this person in the + // alternative + // string + String altNameForPersonA = altName.substring(i, i + 1); + + // align the utility results with this activity + for (int k = 0; k < ACTIVITY_NAME_ARRAY.length; ++k) + { + + if (altNameForPersonA.equalsIgnoreCase(ACTIVITY_NAME_ARRAY[k])) + { + double currentUtility = tempAlt.getUtility(); + tempAlt.setUtility(currentUtility + firstPersonUtilities[k]); + individualLogsum += Math.exp(firstPersonUtilities[k]); + } + } // k + + } // j + + individualLogsum = (float) Math.log(individualLogsum); + personA.setCdapLogsum(individualLogsum); + + // loop through all possible person Bs + for (int j = 0; j < modelHhSize; ++j) + { + + // skip if same as person A + if (i == j) continue; + + Person personB = getCdapPerson(j + 1); + + // skip if i>j because if we have 1,2 for person 1, we don't + // also + // want 2,1; that's the + // same combination of two people + if (i > j) continue; + + // set the two person level dmu variables + cdapDmuObject.setPersonB(personB); + + // compute the two people utilities + double[] twoPersonUtilities = twoPeopleUec.solve(cdapDmuObject.getIndexValues(), + cdapDmuObject, availability); + + // log these utilities for trace households + if (householdObject.getDebugChoiceModels()) + { + + String stringToLog = String.format("%-30s%9d%9d%9s", "TwoPeople", (i + 1), + (j + 1), "--"); + + for (int k = 0; k < ACTIVITY_NAME_ARRAY.length; ++k) + { + stringToLog += String.format("%10.4f", twoPersonUtilities[k]); + } + cdapLogger.info(stringToLog); + + cdapUecLogger.info("PersonA:"); + personA.logEntirePersonObject(cdapUecLogger); + cdapUecLogger.info("PersonB:"); + personB.logEntirePersonObject(cdapUecLogger); + twoPeopleUec.logAnswersArray(cdapUecLogger, + "TWO PERSON, personA personNum=" + personA.getPersonNum() + + " personB personNum=" + personB.getPersonNum()); + + } // debug trace + + // align the two person utilities with the alternatives for + // person i + for (int k = 0; k < alternativeList.size(); ++k) + { + Alternative tempAlt = (Alternative) alternativeList.get(k); + String altName = tempAlt.getName(); + + // get the name of the activity for this person in the + // alternative string + String altNameForPersonA = altName.substring(i, i + 1); + String altNameForPersonB = altName.substring(j, j + 1); + + for (int l = 0; l < ACTIVITY_NAME_ARRAY.length; ++l) + { + if (altNameForPersonA.equalsIgnoreCase(ACTIVITY_NAME_ARRAY[l]) + && altNameForPersonB.equalsIgnoreCase(ACTIVITY_NAME_ARRAY[l])) + { + double currentUtility = tempAlt.getUtility(); + tempAlt.setUtility(currentUtility + twoPersonUtilities[l]); + } + } // l + } // k + + // loop through all possible person Cs + for (int k = 0; k < modelHhSize; ++k) + { + + // skip if same as person A + if (i == k) continue; + + // skip if same as person B + if (j == k) continue; + + // skip if j>k because if we have 1,2,3 for person 1, we + // don't + // also want 1,3,2; that's the + // same combination of three people + if (j > k) continue; + + Person personC = getCdapPerson(k + 1); + + // set the three level dmu variables + cdapDmuObject.setPersonC(personC); + + // compute the three person utilities + double[] threePersonUtilities = threePeopleUec.solve( + cdapDmuObject.getIndexValues(), cdapDmuObject, availability); + + // log these utilities for trace households + if (householdObject.getDebugChoiceModels()) + { + + String stringToLog = String.format("%-30s%9d%9d%9d", "ThreePeople", + (i + 1), (j + 1), (k + 1)); + + for (int l = 0; l < ACTIVITY_NAME_ARRAY.length; ++l) + { + stringToLog += String.format("%10.4f", threePersonUtilities[l]); + } + cdapLogger.info(stringToLog); + + cdapUecLogger.info("PersonA:"); + personA.logEntirePersonObject(cdapUecLogger); + cdapUecLogger.info("PersonB:"); + personB.logEntirePersonObject(cdapUecLogger); + cdapUecLogger.info("PersonC:"); + personC.logEntirePersonObject(cdapUecLogger); + threePeopleUec.logAnswersArray(cdapUecLogger, + "THREE PERSON, personA personNum=" + personA.getPersonNum() + + " personB personNum=" + personB.getPersonNum() + + " personC personNum=" + personC.getPersonNum()); + + } // debug trace + + // align the three person utilities with the alternatives + // for + // person i + for (int l = 0; l < alternativeList.size(); ++l) + { + Alternative tempAlt = (Alternative) alternativeList.get(l); + String altName = tempAlt.getName(); + + // get the name of the activity for this person in the + // alternative string + String altNameForPersonA = altName.substring(i, i + 1); + String altNameForPersonB = altName.substring(j, j + 1); + String altNameForPersonC = altName.substring(k, k + 1); + + for (int m = 0; m < ACTIVITY_NAME_ARRAY.length; ++m) + { + if (altNameForPersonA.equalsIgnoreCase(ACTIVITY_NAME_ARRAY[m]) + && altNameForPersonB.equalsIgnoreCase(ACTIVITY_NAME_ARRAY[m]) + && altNameForPersonC.equalsIgnoreCase(ACTIVITY_NAME_ARRAY[m])) + { + double currentUtility = tempAlt.getUtility(); + tempAlt.setUtility(currentUtility + threePersonUtilities[m]); + } + } // m + } // l + + } // k (person C loop) + + } // j (person B loop) + + } // i (person A loop) + + // compute the interaction utilities + double[] allMemberInteractionUtilities = allMemberInteractionUec.solve( + cdapDmuObject.getIndexValues(), cdapDmuObject, availability); + + // log these utilities for trace households + if (householdObject.getDebugChoiceModels()) + { + + String stringToLog = String.format("%-30s%9s%9s%9s", "AllMembers", "--", "--", "--"); + + for (int i = 0; i < ACTIVITY_NAME_ARRAY.length; ++i) + { + stringToLog += String.format("%10.4f", allMemberInteractionUtilities[i]); + } + cdapLogger.info(stringToLog); + + allMemberInteractionUec.logAnswersArray(cdapUecLogger, "ALL MEMBER INTERACTIONS"); + + } // debug trace + + // align the utilities with the proper alternatives + for (int i = 0; i < alternativeList.size(); ++i) + { + Alternative tempAlt = (Alternative) alternativeList.get(i); + String altName = tempAlt.getName(); + + for (int j = 0; j < ACTIVITY_NAME_ARRAY.length; ++j) + { + + boolean samePattern = true; + for (int k = 0; k < modelHhSize; ++k) + { + + // alternative should have pattern j for each member k + String altNameForThisPerson = altName.substring(k, k + 1); + if (altNameForThisPerson.equalsIgnoreCase(ACTIVITY_NAME_ARRAY[j])) continue; + else + { + samePattern = false; + break; + } + } // k + + // if all have the same pattern, add the new utilities + if (samePattern) + { + double currentUtility = tempAlt.getUtility(); + tempAlt.setUtility(currentUtility + allMemberInteractionUtilities[j]); + } + } // j + + } // i + + // compute the joint utilities to be added to alternatives with joint + // tour + // indicator + + int adultsWithMand = 0; + int adultsWithNonMand = 0; + int kidsWithMand = 0; + int kidsWithNonMand = 0; + int adultsLeaveHome = 0; + int workMgra = 0; + double workLocationAccessibilityForWorkers = 0.0; + for (int i = 0; i < alternativeList.size(); ++i) + { + + Alternative tempAlt = (Alternative) alternativeList.get(i); + String altName = tempAlt.getName(); + + adultsWithMand = 0; + adultsWithNonMand = 0; + kidsWithMand = 0; + kidsWithNonMand = 0; + adultsLeaveHome = 0; + workMgra = 0; + workLocationAccessibilityForWorkers = 0.0; + for (int k = 0; k < modelHhSize; ++k) + { + + // alternative should have pattern j for each member k + String altNameForThisPerson = altName.substring(k, k + 1); + if (altNameForThisPerson.equalsIgnoreCase(MANDATORY_PATTERN)) + { + if (isThisCdapPersonAnAdult(k + 1)) + { + adultsWithMand++; + adultsLeaveHome++; + } else + { + kidsWithMand++; + } + + workMgra = getWorkLocationForThisCdapPerson(k + 1); + if (workMgra > 0 && workMgra != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + Person tempPerson = getCdapPerson(k + 1); + workLocationAccessibilityForWorkers += tempPerson.getWorkLocationLogsum(); + } + + } else if (altNameForThisPerson.equalsIgnoreCase(NONMANDATORY_PATTERN)) + { + if (isThisCdapPersonAnAdult(k + 1)) + { + adultsWithNonMand++; + adultsLeaveHome++; + } else + { + kidsWithNonMand++; + } + } + + } // k + + cdapDmuObject.setNumAdultsWithNonMandatoryDap(adultsWithNonMand); + cdapDmuObject.setNumAdultsWithMandatoryDap(adultsWithMand); + cdapDmuObject.setNumKidsWithNonMandatoryDap(kidsWithNonMand); + cdapDmuObject.setNumKidsWithMandatoryDap(kidsWithMand); + cdapDmuObject.setAllAdultsAtHome(adultsLeaveHome == 0 ? 1 : 0); + cdapDmuObject.setWorkAccessForMandatoryDap(workLocationAccessibilityForWorkers); + + double[] jointUtilities = jointUec.solve(cdapDmuObject.getIndexValues(), cdapDmuObject, + availability); + + // log these utilities for trace households + if (householdObject.getDebugChoiceModels()) + { + String stringToLog = String.format("%-13s%4d %-12s%9s%9s%9s", "Joint", (i + 1), + altName, "--", "--", "--"); + stringToLog += String.format("%10.4f", + (altName.indexOf("j") > 0 ? jointUtilities[0] : 0.0)); + cdapLogger.info(stringToLog); + + jointUec.logAnswersArray(cdapUecLogger, "JOINT Utility for CDAP Alt index = " + + (i + 1) + ", Alt name = " + altName); + } // debug trace + + // align the utilities with the proper alternatives + if (altName.indexOf("j") > 0) + { + double currentUtility = tempAlt.getUtility(); + tempAlt.setUtility(currentUtility + jointUtilities[0]); + } + + } // i + + // TODO: check this out - use computeAvailabilty() checks that an + // alternative + // is available + // all utilities are set - compute probabilities + // workingLogitModel.setAvailability(true); + workingLogitModel.computeAvailabilities(); + + // compute the exponentiated utility, logging debug if need be + if (householdObject.getDebugChoiceModels()) + { + workingLogitModel.setDebug(true); + workingLogitModel.writeUtilityHeader(); + } + float logsum = (float) workingLogitModel.getUtility(); + householdObject.setCdapLogsum(logsum); + + // compute the probabilities, logging debug if need be + if (householdObject.getDebugChoiceModels()) + { + workingLogitModel.writeProbabilityHeader(); + } + workingLogitModel.calculateProbabilities(); + + // turn debug off for the next guy + workingLogitModel.setDebug(false); + + // make a choice for the first five + Random hhRandom = householdObject.getHhRandom(); + + double randomNumber = hhRandom.nextDouble(); + + if (householdObject.getDebugChoiceModels()) + { + cdapLogger.info("randomNumber = " + randomNumber); + } + + String firstFiveChosenName = ""; + try + { + ConcreteAlternative chosenAlternative = (ConcreteAlternative) workingLogitModel + .chooseElementalAlternative(randomNumber); + firstFiveChosenName = chosenAlternative.getName(); + + if (householdObject.getDebugChoiceModels()) + { + + int chosenIndex = 0; + // get the index number for the alternative chosen + for (int i = 0; i < alternativeList.size(); ++i) + { + Alternative tempAlt = (Alternative) alternativeList.get(i); + String altName = tempAlt.getName(); + if (altName.equalsIgnoreCase(firstFiveChosenName)) + { + chosenIndex = i + 1; + break; + } + } + + cdapLogger.info("chosen pattern (5 or fewer hh members): Alt index = " + + chosenIndex + ", Alt name = " + firstFiveChosenName); + cdapLogger.info(""); + cdapLogger.info(""); + } + } catch (ModelException e) + { + logger.error(String.format( + "Exception caught for HHID=%d, no available CDAP alternatives to choose.", + householdObject.getHhId()), e); + throw new RuntimeException(); + } + + // make a choice for additional hh members if need be + if (actualHhSize > MAX_MODEL_HH_SIZE) + { + + String allMembersChosenPattern = applyModelForExtraHhMembers(householdObject, + firstFiveChosenName); + + String extraChar = ""; + int extraCharIndex = allMembersChosenPattern.indexOf("0"); + if (extraCharIndex > 0) + { + extraChar = "0"; + } else + { + extraCharIndex = allMembersChosenPattern.indexOf("j"); + if (extraCharIndex > 0) extraChar = "j"; + } + + allMembersChosenPattern = allMembersChosenPattern.substring(0, extraCharIndex) + + allMembersChosenPattern.substring(extraCharIndex + 1); + + // re-order the activities by the original order of persons + String finalHhPattern = ""; + String[] finalHhPatternActivities = new String[cdapPersonArray.length]; + for (int i = 1; i < cdapPersonArray.length; i++) + { + int k = cdapPersonArray[i].getPersonNum(); + finalHhPatternActivities[k] = allMembersChosenPattern.substring(i - 1, i); + } + + for (int i = 1; i < cdapPersonArray.length; i++) + finalHhPattern += finalHhPatternActivities[i]; + + String finalString = finalHhPattern + extraChar; + if (householdObject.getDebugChoiceModels()) + { + cdapLogger.info("final pattern (more than 5 hh members) = " + finalString); + cdapLogger.info(""); + cdapLogger.info(""); + } + return finalString; + + } + + if (householdObject.getDebugChoiceModels()) + { + // reset the logger to what it was before we changed it + LogitModel.setLogger(Logger.getLogger(LogitModel.class)); + } + + // no need to re-order the activities - hhsize <= MAX_MODEL_HH_SIZE have + // original order of persons + return firstFiveChosenName; + + } + + /** + * Applies a simple choice from fixed proportions by person type for members + * of households with more than 5 people who are not included in the CDAP + * model. The choices of the additional household members are independent of + * each other. + * + * @param householdObject + * @param patternStringForOtherHhMembers + * @return the pattern for the entire household, including the 5-member + * pattern chosen by the logit model and the additional members + * chosen by the fixed-distribution model. + * + */ + private String applyModelForExtraHhMembers(Household householdObject, + String patternStringForOtherHhMembers) + { + + String allMembersPattern = patternStringForOtherHhMembers; + + // get the persons not yet modeled + Person[] personArray = getPersonsNotModeledByCdap(MAX_MODEL_HH_SIZE); + + // person array is 1-based to be consistent with other person arrays + for (int i = 1; i < personArray.length; i++) + { + + int personType = personArray[i].getPersonTypeNumber(); + + // get choice index from fixed proportions for 6 plus persons + int chosen = ChoiceModelApplication.getMonteCarloSelection( + fixedCumulativeProportions[personType], householdObject.getHhRandom() + .nextDouble()); + + allMembersPattern += ACTIVITY_NAME_ARRAY[chosen]; + + } + + return allMembersPattern; + + } + + /** + * Method reorders the persons in the household for use with the CDAP model, + * which only explicitly models the interaction of five persons in a HH. + * Priority in the reordering is first given to full time workers (up to + * two), then to part time workers (up to two workers, of any type), then to + * children (youngest to oldest, up to three). If the method is called for a + * household with less than 5 people, the cdapPersonArray is the same as the + * person array. + * + */ + public void reOrderPersonsForCdap(Household household) + { + + // set the person array + Person[] persons = household.getPersons(); + + // if hh is not too big, set cdap equal to persons and return + int hhSize = household.getSize(); + if (hhSize <= MAX_MODEL_HH_SIZE) + { + cdapPersonArray = persons; + return; + } + + // create the end game array + cdapPersonArray = new Person[persons.length]; + + // keep track of which persons you count + boolean[] iCountedYou = new boolean[persons.length]; + Arrays.fill(iCountedYou, false); + + // define the persons we want to find among the five + int firstWorkerIndex = -99; + int secondWorkerIndex = -99; + + int youngestChildIndex = -99; + int secondYoungestChildIndex = -99; + int thirdYoungestChildIndex = -99; + + int youngestChildAge = 99; + int secondYoungestChildAge = 99; + int thirdYoungestChildAge = 99; + + // first: full-time workers (persons is 1-based array) + for (int i = 1; i < persons.length; ++i) + { + + if (iCountedYou[i]) continue; + + // is the person a full-time worker + if (persons[i].getPersonIsFullTimeWorker() == 1) + { + + // check our indices + if (firstWorkerIndex == -99) + { + firstWorkerIndex = i; + iCountedYou[i] = true; + } else if (secondWorkerIndex == -99) + { + secondWorkerIndex = i; + iCountedYou[i] = true; + } + } + + } // i (full time workers) + + // second: part-time workers (only if we don't have two workers) + if (firstWorkerIndex == -99 || secondWorkerIndex == -99) + { + + for (int i = 1; i < persons.length; ++i) + { + + if (iCountedYou[i]) continue; + + // is the person part-time worker + if (persons[i].getPersonIsPartTimeWorker() == 1) + { + + // check our indices + if (firstWorkerIndex == -99) + { + firstWorkerIndex = i; + iCountedYou[i] = true; + } else if (secondWorkerIndex == -99) + { + secondWorkerIndex = i; + iCountedYou[i] = true; + } + + } + + } // i (part-time workers) + } + + // third: youngest child loop + for (int i = 1; i < persons.length; ++i) + { + + if (iCountedYou[i]) continue; + + if (persons[i].getPersonIsPreschoolChild() == 1 + || persons[i].getPersonIsStudentNonDriving() == 1 + || persons[i].getPersonIsStudentDriving() == 1) + { + + // check our indices + if (youngestChildIndex == -99) + { + youngestChildIndex = i; + youngestChildAge = persons[i].getAge(); + iCountedYou[i] = true; + } else + { + + // see if this child is younger than the one on record + int age = persons[i].getAge(); + if (age < youngestChildAge) + { + + // reset iCountedYou for previous child + iCountedYou[youngestChildIndex] = false; + + // set variables for this child + youngestChildIndex = i; + youngestChildAge = age; + iCountedYou[i] = true; + + } + } + + } // if person is child + + } // i (youngest child loop) + + // fourth: second youngest child loop (skip if youngest child is not + // filled) + if (youngestChildIndex != -99) + { + + for (int i = 1; i < persons.length; ++i) + { + + if (iCountedYou[i]) continue; + + if (persons[i].getPersonIsPreschoolChild() == 1 + || persons[i].getPersonIsStudentNonDriving() == 1 + || persons[i].getPersonIsStudentDriving() == 1) + { + + // check our indices + if (secondYoungestChildIndex == -99) + { + secondYoungestChildIndex = i; + secondYoungestChildAge = persons[i].getAge(); + iCountedYou[i] = true; + } else + { + + // see if this child is younger than the one on record + int age = persons[i].getAge(); + if (age < secondYoungestChildAge) + { + + // reset iCountedYou for previous child + iCountedYou[secondYoungestChildIndex] = false; + + // set variables for this child + secondYoungestChildIndex = i; + secondYoungestChildAge = age; + iCountedYou[i] = true; + + } + } + + } // if person is child + + } // i (second youngest child loop) + } + + // fifth: third youngest child loop (skip if second kid not included) + if (secondYoungestChildIndex != -99) + { + + for (int i = 1; i < persons.length; ++i) + { + + if (iCountedYou[i]) continue; + + if (persons[i].getPersonIsPreschoolChild() == 1 + || persons[i].getPersonIsStudentNonDriving() == 1 + || persons[i].getPersonIsStudentDriving() == 1) + { + + // check our indices + if (thirdYoungestChildIndex == -99) + { + thirdYoungestChildIndex = i; + thirdYoungestChildAge = persons[i].getAge(); + iCountedYou[i] = true; + } else + { + + // see if this child is younger than the one on record + int age = persons[i].getAge(); + if (age < thirdYoungestChildAge) + { + + // reset iCountedYou for previous child + iCountedYou[thirdYoungestChildIndex] = false; + + // set variables for this child + thirdYoungestChildIndex = i; + thirdYoungestChildAge = age; + iCountedYou[i] = true; + + } + } + + } // if person is child + + } // i (third youngest child loop) + } + + // assign any missing spots among the top 5 to random members + int cdapPersonIndex; + + Random hhRandom = household.getHhRandom(); + + int randomCount = household.getHhRandomCount(); + // when household.getHhRandom() was applied, the random count was + // incremented, assuming a random number would be drawn right away. + // so let's decrement by 1, then increment the count each time a random + // number is actually drawn in this method. + randomCount--; + + // first worker + cdapPersonIndex = 1; // persons and cdapPersonArray are 1-based + if (firstWorkerIndex == -99) + { + + int randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + while (iCountedYou[randomIndex] || randomIndex == 0) + { + randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + } + + cdapPersonArray[cdapPersonIndex] = persons[randomIndex]; + iCountedYou[randomIndex] = true; + + } else + { + cdapPersonArray[cdapPersonIndex] = persons[firstWorkerIndex]; + } + + // second worker + cdapPersonIndex = 2; + if (secondWorkerIndex == -99) + { + + int randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + while (iCountedYou[randomIndex] || randomIndex == 0) + { + randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + } + + cdapPersonArray[cdapPersonIndex] = persons[randomIndex]; + iCountedYou[randomIndex] = true; + + } else + { + cdapPersonArray[cdapPersonIndex] = persons[secondWorkerIndex]; + } + + // youngest child + cdapPersonIndex = 3; + if (youngestChildIndex == -99) + { + + int randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + while (iCountedYou[randomIndex] || randomIndex == 0) + { + randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + } + + cdapPersonArray[cdapPersonIndex] = persons[randomIndex]; + iCountedYou[randomIndex] = true; + + } else + { + cdapPersonArray[cdapPersonIndex] = persons[youngestChildIndex]; + } + + // second youngest child + cdapPersonIndex = 4; + if (secondYoungestChildIndex == -99) + { + + int randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + while (iCountedYou[randomIndex] || randomIndex == 0) + { + randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + } + + cdapPersonArray[cdapPersonIndex] = persons[randomIndex]; + iCountedYou[randomIndex] = true; + + } else + { + cdapPersonArray[cdapPersonIndex] = persons[secondYoungestChildIndex]; + } + + // third youngest child + cdapPersonIndex = 5; + if (thirdYoungestChildIndex == -99) + { + + int randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + while (iCountedYou[randomIndex] || randomIndex == 0) + { + randomIndex = (int) (hhRandom.nextDouble() * hhSize); + randomCount++; + } + + cdapPersonArray[cdapPersonIndex] = persons[randomIndex]; + iCountedYou[randomIndex] = true; + + } else + { + cdapPersonArray[cdapPersonIndex] = persons[thirdYoungestChildIndex]; + } + + // fill spots outside the top 5 + cdapPersonIndex = 6; + for (int i = 1; i < persons.length; ++i) + { + + if (iCountedYou[i]) continue; + + cdapPersonArray[cdapPersonIndex] = persons[i]; + cdapPersonIndex++; + } + + household.setHhRandomCount(randomCount); + + } + + protected Person getCdapPerson(int persNum) + { + if (persNum < 1 || persNum > cdapPersonArray.length - 1) + { + logger.fatal(String.format("persNum value = %d is out of range for hhSize = %d", + persNum, cdapPersonArray.length - 1)); + throw new RuntimeException(); + } + + return cdapPersonArray[persNum]; + } + + /** + * Method returns an array of persons not modeled by the CDAP model (i.e. + * persons 6 to X, when ordered by the reOrderPersonsForCdap method + * + * @param personsModeledByCdap + * @return + */ + public Person[] getPersonsNotModeledByCdap(int personsModeledByCdap) + { + + // create a 1-based person array to be consistent + Person[] personArray = null; + if (cdapPersonArray.length > personsModeledByCdap + 1) personArray = new Person[cdapPersonArray.length + - personsModeledByCdap]; + else personArray = new Person[0]; + + for (int i = 1; i < personArray.length; ++i) + { + personArray[i] = cdapPersonArray[personsModeledByCdap + i]; + } + + return personArray; + + } + + /** + * Returns true if this CDAP person number (meaning the number of persons + * for the purposes of the CDAP model) is an adult; false if not. + * + * @param cdapPersonNumber + * @return + */ + public boolean isThisCdapPersonAnAdult(int cdapPersonNumber) + { + + if (cdapPersonArray[cdapPersonNumber].getPersonIsAdult() == 1) return true; + return false; + } + + public int getStudentTypeForThisCdapPerson(int cdapPersonNumber) + { + + Person p = cdapPersonArray[cdapPersonNumber]; + int type = 0; + if (p.getPersonIsPreschoolChild() == 1) type = 1; + else if (p.getPersonIsGradeSchool() == 1) type = 2; + else if (p.getPersonIsHighSchool() == 1) type = 3; + else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() < 30) type = 4; + else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() >= 30) type = 5; + + return type; + } + + public int getStudentTypeForThisCdapPerson(Person p) + { + + int type = 0; + if (p.getPersonIsPreschoolChild() == 1) type = 1; + else if (p.getPersonIsGradeSchool() == 1) type = 2; + else if (p.getPersonIsHighSchool() == 1) type = 3; + else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() < 30) type = 4; + else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() >= 30) type = 5; + + return type; + } + + public int getWorkLocationForThisCdapPerson(int cdapPersonNumber) + { + int loc = cdapPersonArray[cdapPersonNumber].getWorkLocation(); + if (loc > 0 && loc != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) return loc; + else return 0; + } + + public int getSchoolLocationForThisCdapPerson(int cdapPersonNumber) + { + return cdapPersonArray[cdapPersonNumber].getUsualSchoolLocation(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManager.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManager.java new file mode 100644 index 0000000..eb6ebe6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManager.java @@ -0,0 +1,2039 @@ +package org.sandag.abm.ctramp; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Random; +import java.util.StringTokenizer; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import umontreal.iro.lecuyer.probdist.LognormalDist; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.IndexSort; +import com.pb.common.util.ObjectUtil; +import com.pb.common.util.SeededRandom; + +/** + * @author Jim Hicks + * + * Class for managing household and person object data read from + * synthetic population files. + */ +public abstract class HouseholdDataManager + implements HouseholdDataManagerIf, Serializable +{ + + protected transient Logger logger = Logger.getLogger(HouseholdDataManager.class); + + public static final String PROPERTIES_SYNPOP_INPUT_HH = "PopulationSynthesizer.InputToCTRAMP.HouseholdFile"; + public static final String PROPERTIES_SYNPOP_INPUT_PERS = "PopulationSynthesizer.InputToCTRAMP.PersonFile"; + + public static final String RANDOM_SEED_NAME = "Model.Random.Seed"; + + public static final String OUTPUT_HH_DATA_FILE_TARGET = "outputHouseholdData.file"; + public static final String OUTPUT_PERSON_DATA_FILE_TARGET = "outputPersonData.file"; + + public static final String READ_UWSL_RESULTS_FILE = "read.uwsl.results"; + public static final String READ_UWSL_RESULTS_FILENAME = "read.uwsl.filename"; + public static final String READ_PRE_AO_RESULTS_FILE = "read.pre.ao.results"; + public static final String READ_PRE_AO_RESULTS_FILENAME = "read.pre.ao.filename"; + + public static final String PROPERTIES_DISTRIBUTED_TIME = "distributedTimeCoefficients"; + + + // HHID,household_serial_no,TAZ,MGRA,VEH,PERSONS,HWORKERS,HINCCAT1,HINC,UNITTYPE,HHT,BLDGSZ + public static final String HH_ID_FIELD_NAME = "HHID"; + public static final String HH_HOME_TAZ_FIELD_NAME = "TAZ"; + public static final String HH_HOME_MGRA_FIELD_NAME = "MGRA"; + public static final String HH_INCOME_CATEGORY_FIELD_NAME = "HINCCAT1"; + public static final String HH_INCOME_DOLLARS_FIELD_NAME = "HINC"; + public static final String HH_WORKERS_FIELD_NAME = "HWORKERS"; + public static final String HH_AUTOS_FIELD_NAME = "VEH"; + public static final String HH_SIZE_FIELD_NAME = "PERSONS"; + public static final String HH_TYPE_FIELD_NAME = "HHT"; + public static final String HH_BLDGSZ_FIELD_NAME = "BLDGSZ"; + public static final String HH_UNITTYPE_FIELD_NAME = "UNITTYPE"; + + // HHID,PERID,AGE,SEX,OCCCEN1,INDCEN,PEMPLOY,PSTUDENT,PTYPE,EDUC,GRADE + public static final String PERSON_HH_ID_FIELD_NAME = "HHID"; + public static final String PERSON_PERSON_ID_FIELD_NAME = "PERID"; + public static final String PERSON_AGE_FIELD_NAME = "AGE"; + public static final String PERSON_GENDER_FIELD_NAME = "SEX"; + public static final String PERSON_MILITARY_FIELD_NAME = "MILTARY"; + public static final String PERSON_EMPLOYMENT_CATEGORY_FIELD_NAME = "PEMPLOY"; + public static final String PERSON_STUDENT_CATEGORY_FIELD_NAME = "PSTUDENT"; + public static final String PERSON_TYPE_CATEGORY_FIELD_NAME = "PTYPE"; + public static final String PERSON_EDUCATION_ATTAINMENT_FIELD_NAME = "EDUC"; + public static final String PERSON_GRADE_ENROLLED_FIELD_NAME = "GRADE"; + public static final String PERSON_OCCCEN1_FIELD_NAME = "OCCCEN1"; + public static final String PERSON_SOC_FIELD_NAME = "OCCSOC5"; + public static final String PERSON_INDCEN_FIELD_NAME = "INDCEN"; + + public static final String PERSON_TIMEFACTOR_WORK_FIELD_NAME = "timeFactorWork"; + public static final String PERSON_TIMEFACTOR_NONWORK_FIELD_NAME = "timeFactorNonWork"; + + public static final String PROPERTIES_HOUSEHOLD_TRACE_LIST = "Debug.Trace.HouseholdIdList"; + public static final String DEBUG_HHS_ONLY_KEY = "Process.Debug.HHs.Only"; + + private static final String PROPERTIES_MIN_VALUE_OF_TIME_KEY = "HouseholdManager.MinValueOfTime"; + private static final String PROPERTIES_MAX_VALUE_OF_TIME_KEY = "HouseholdManager.MaxValueOfTime"; + private static final String PROPERTIES_MEAN_VALUE_OF_TIME_VALUES_KEY = "HouseholdManager.MeanValueOfTime.Values"; + private static final String PROPERTIES_MEAN_VALUE_OF_TIME_INCOME_LIMITS_KEY = "HouseholdManager.MeanValueOfTime.Income.Limits"; + private static final String PROPERTIES_HH_VALUE_OF_TIME_MULTIPLIER_FOR_UNDER_18_KEY = "HouseholdManager.HH.ValueOfTime.Multiplier.Under18"; + private static final String PROPERTIES_MEAN_VALUE_OF_TIME_MULTIPLIER_FOR_MU_KEY = "HouseholdManager.Mean.ValueOfTime.Multiplier.Mu"; + private static final String PROPERTIES_VALUE_OF_TIME_LOGNORMAL_SIGMA_KEY = "HouseholdManager.ValueOfTime.Lognormal.Sigma"; + + private HashMap schoolSegmentNameIndexMap; + private HashMap gsDistrictSegmentMap; + private HashMap hsDistrictSegmentMap; + private int[] mgraGsDistrict; + private int[] mgraHsDistrict; + + // these are not used for sandag; instead sandag uses distributed time coefficients read in the person file + protected float hhValueOfTimeMultiplierForPersonUnder18; + protected double meanValueOfTimeMultiplierBeforeLogForMu; + protected double valueOfTimeLognormalSigma; + protected float minValueOfTime; + protected float maxValueOfTime; + protected float[] meanValueOfTime; + protected int[] incomeDollarLimitsForValueOfTime; + protected LognormalDist[] valueOfTimeDistribution; + + protected HashMap propertyMap; + + protected String projectDirectory; + protected String outputHouseholdFileName; + protected String outputPersonFileName; + + protected ModelStructure modelStructure; + + protected TableDataSet hhTable; + protected TableDataSet personTable; + + protected HashSet householdTraceSet; + + protected Household[] hhs; + protected int[] hhIndexArray; + + protected int inputRandomSeed; + protected int numPeriods; + protected int firstPeriod; + + protected float sampleRate; + protected int sampleSeed; + + protected int maximumNumberOfHouseholdsPerFile = 0; + protected int numberOfHouseholdDiskObjectFiles = 0; + + protected MgraDataManager mgraManager; + protected TazDataManager tazManager; + + protected double[] percentHhsIncome100Kplus; + protected double[] percentHhsMultipleAutos; + + protected boolean readTimeFactors; + public HouseholdDataManager() + { + } + + /** + * Associate data in hh and person TableDataSets read from synthetic + * population files with Household objects and Person objects with + * Households. + */ + protected abstract void mapTablesToHouseholdObjects(); + + public String testRemote() + { + System.out.println("testRemote() called by remote process."); + return String.format("testRemote() method in %s called.", this.getClass() + .getCanonicalName()); + } + + public void setDebugHhIdsFromHashmap() + { + + householdTraceSet = new HashSet(); + + // get the household ids for which debug info is required + String householdTraceStringList = propertyMap.get(PROPERTIES_HOUSEHOLD_TRACE_LIST); + + if (householdTraceStringList != null) + { + StringTokenizer householdTokenizer = new StringTokenizer(householdTraceStringList, ","); + while (householdTokenizer.hasMoreTokens()) + { + String listValue = householdTokenizer.nextToken(); + int idValue = Integer.parseInt(listValue.trim()); + householdTraceSet.add(idValue); + } + } + + } + + public void readPopulationFiles(String inputHouseholdFileName, String inputPersonFileName) + { + + TimeCoefficientDistributions timeDistributions = new TimeCoefficientDistributions(); + timeDistributions.createTimeDistributions(propertyMap); + timeDistributions.appendTimeDistributionsOnPersonFile(propertyMap); + + // read synthetic population files + readHouseholdData(inputHouseholdFileName); + + readPersonData(inputPersonFileName); + } + + public void setModelStructure(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + } + + public void setupHouseholdDataManager(ModelStructure modelStructure, + String inputHouseholdFileName, String inputPersonFileName) + { + + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + setModelStructure(modelStructure); + readPopulationFiles(inputHouseholdFileName, inputPersonFileName); + + // Set the seed for the JVM default SeededRandom object - should only be + // used + // to set the order for the + // HH index array so that hhs can be processed in an arbitrary order as + // opposed to the order imposed by + // the synthetic population generator. + // The seed was set as a command line argument for the model run, or the + // default if no argument supplied + SeededRandom.setSeed(sampleSeed); + + // the seed read from the properties file controls seeding the Household + // object random number generator objects. + inputRandomSeed = Integer.parseInt(propertyMap.get(HouseholdDataManager.RANDOM_SEED_NAME)); + + // map synthetic population table data to objects to be used by CT-RAMP + mapTablesToHouseholdObjects(); + hhTable = null; + personTable = null; + + logPersonSummary(); + + setTraceHouseholdSet(); + + // if read pre-ao results flag is set, read the results file and + // populate the + // household object ao result field from these values. + String readPreAoResultsString = propertyMap.get(READ_PRE_AO_RESULTS_FILE); + if (readPreAoResultsString != null) + { + boolean readResults = Boolean.valueOf(readPreAoResultsString); + if (readResults) readPreAoResults(); + } + + // if read uwsl results flag is set, read the results file and populate + // the + // household object work/school location result fields from these + // values. + String readUwslResultsString = propertyMap.get(READ_UWSL_RESULTS_FILE); + if (readUwslResultsString != null) + { + boolean readResults = Boolean.valueOf(readUwslResultsString); + if (readResults) readWorkSchoolLocationResults(); + } + + //check if we want to read distributed time factors from the person file + String readTimeFactorsString = propertyMap.get(PROPERTIES_DISTRIBUTED_TIME); + if (readTimeFactorsString != null) + { + readTimeFactors = Boolean.valueOf(readTimeFactorsString); + logger.info("Distributed time coefficients = "+Boolean.toString(readTimeFactors)); + } + + + + } + + public void setPropertyFileValues(HashMap propertyMap) + { + + String propertyValue = ""; + this.propertyMap = propertyMap; + + // save the project specific parameters in class attributes + this.projectDirectory = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + + outputHouseholdFileName = propertyMap + .get(CtrampApplication.PROPERTIES_OUTPUT_HOUSEHOLD_FILE); + outputPersonFileName = propertyMap.get(CtrampApplication.PROPERTIES_OUTPUT_PERSON_FILE); + + setDebugHhIdsFromHashmap(); + + propertyValue = propertyMap + .get(CtrampApplication.PROPERTIES_SCHEDULING_NUMBER_OF_TIME_PERIODS); + if (propertyValue == null) numPeriods = 0; + else numPeriods = Integer.parseInt(propertyValue); + + propertyValue = propertyMap.get(CtrampApplication.PROPERTIES_SCHEDULING_FIRST_TIME_PERIOD); + if (propertyValue == null) firstPeriod = 0; + else firstPeriod = Integer.parseInt(propertyValue); + + //check if we want to read distributed time factors from the person file + String readTimeFactorsString = propertyMap.get(PROPERTIES_DISTRIBUTED_TIME); + if (readTimeFactorsString != null) + { + readTimeFactors = Boolean.valueOf(readTimeFactorsString); + logger.info("Distributed time coefficients = "+Boolean.toString(readTimeFactors)); + } + + } + + public int[] getRandomOrderHhIndexArray(int numHhs) + { + + Random myRandom = new Random(); + myRandom.setSeed(numHhs + 1); + + int[] data = new int[numHhs]; + for (int i = 0; i < numHhs; i++) + data[i] = (int) (10000000 * myRandom.nextDouble()); + + int[] index = IndexSort.indexSort(data); + + return index; + } + + // this is called at the end of UsualWorkSchoolLocation model step. + public void setUwslRandomCount(int iter) + { + + for (int r = 0; r < hhs.length; r++) + hhs[r].setUwslRandomCount(iter, hhs[r].getHhRandomCount()); + + } + + private void resetRandom(Household h, int count) + { + // get the household's Random + Random r = h.getHhRandom(); + + int seed = inputRandomSeed + h.getHhId(); + r.setSeed(seed); + + // select count Random draws to reset this household's Random to it's + // state + // prior to + // the model run for which model results were stored in + // HouseholdDataManager. + for (int i = 0; i < count; i++) + r.nextDouble(); + + // reset the randomCount for the household's Random + h.setHhRandomCount(count); + } + + public void resetPreAoRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // The Pre Auto Ownership model is the first model component, so + // reset + // counts to 0. + resetRandom(hhs[i], 0); + } + } + + public void resetUwslRandom(int iter) + { + for (int i = 0; i < hhs.length; i++) + { + // get the current random count for the end of the shadow price + // iteration + // passed in. + // this value was set at the end of UsualWorkSchoolLocation model + // step + // for the given iter. + // if < 0, random count should be set to the count at end of pre + // auto + // ownership. + int uwslCount = hhs[i].getPreAoRandomCount(); + if (iter >= 0) + { + uwslCount = hhs[i].getUwslRandomCount(iter); + } + + // draw uwslCount random numbers from the household's Random + resetRandom(hhs[i], uwslCount); + } + } + + public void resetAoRandom(int iter) + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Auto Ownership model from the + // Household + // object. + // this value was set at the end of UsualWorkSchoolLocation model + // step. + + int aoCount = hhs[i].getUwslRandomCount(iter); + + // draw aoCount random numbers from the household's Random + resetRandom(hhs[i], aoCount); + } + } + + public void resetTpRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Auto Ownership model from the + // Household + // object. + // this value was set at the end of UsualWorkSchoolLocation model + // step. + int tpCount = hhs[i].getAoRandomCount(); + + // draw aoCount random numbers from the household's Random + resetRandom(hhs[i], tpCount); + } + } + + public void resetFpRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Auto Ownership model from the + // Household + // object. + // this value was set at the end of UsualWorkSchoolLocation model + // step. + int fpCount = hhs[i].getTpRandomCount(); + + // draw aoCount random numbers from the household's Random + resetRandom(hhs[i], fpCount); + } + } + + public void resetIeRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Auto Ownership model from the + // Household + // object. + // this value was set at the end of UsualWorkSchoolLocation model + // step. + int ieCount = hhs[i].getFpRandomCount(); + + // draw aoCount random numbers from the household's Random + resetRandom(hhs[i], ieCount); + } + } + + public void resetCdapRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Coordinated Daily Activity Pattern + // model from the Household object. + // this value was set at the end of Auto Ownership model step. + int cdapCount = hhs[i].getIeRandomCount(); + + // draw cdapCount random numbers + resetRandom(hhs[i], cdapCount); + } + } + + public void resetImtfRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Individual Mandatory Tour + // Frequency + // model from the Household object. + // this value was set at the end of Coordinated Daily Activity + // Pattern + // model step. + int imtfCount = hhs[i].getCdapRandomCount(); + + // draw imtfCount random numbers + resetRandom(hhs[i], imtfCount); + } + } + + public void resetImtodRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Individual Mandatory Tour + // Departure and + // duration model from the Household object. + // this value was set at the end of Individual Mandatory Tour + // Frequency + // model step. + int imtodCount = hhs[i].getImtfRandomCount(); + + // draw imtodCount random numbers + resetRandom(hhs[i], imtodCount); + } + } + + public void resetJtfRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Joint Tour Frequency model from + // the + // Household object. + // this value was set at the end of Individual Mandatory departure + // time + // Choice model step. + int jtfCount = hhs[i].getImtodRandomCount(); + + // draw jtfCount random numbers + resetRandom(hhs[i], jtfCount); + } + } + + public void resetJtlRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Joint Tour Location model from the + // Household object. + // this value was set at the end of Joint Tour Frequency model step. + int jtlCount = hhs[i].getJtfRandomCount(); + + // draw jtlCount random numbers + resetRandom(hhs[i], jtlCount); + } + } + + public void resetJtodRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Joint Tour Departure and duration + // model + // from the Household object. + // this value was set at the end of Joint Tour Location model step. + int jtodCount = hhs[i].getJtlRandomCount(); + + // draw jtodCount random numbers + resetRandom(hhs[i], jtodCount); + } + } + + public void resetInmtfRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Individual non-mandatory tour + // frequency + // model from the Household object. + // this value was set at the end of Joint Tour Departure and + // duration + // model step. + int inmtfCount = hhs[i].getJtodRandomCount(); + + // draw inmtfCount random numbers + resetRandom(hhs[i], inmtfCount); + } + } + + public void resetInmtlRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Individual non-mandatory tour + // location + // model from the Household object. + // this value was set at the end of Individual non-mandatory tour + // frequency model step. + int inmtlCount = hhs[i].getInmtfRandomCount(); + + // draw inmtlCount random numbers + resetRandom(hhs[i], inmtlCount); + } + } + + public void resetInmtodRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to Individual non-mandatory tour + // departure + // and duration model from the Household object. + // this value was set at the end of Individual non-mandatory tour + // location model step. + int inmtodCount = hhs[i].getInmtlRandomCount(); + + // draw inmtodCount random numbers + resetRandom(hhs[i], inmtodCount); + } + } + + public void resetAwfRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to At-work Subtour Frequency model + // from + // the Household object. + // this value was set at the end of Individual Non-Mandatory Tour + // Departure and duration model step. + int awfCount = hhs[i].getInmtodRandomCount(); + + // draw awfCount random numbers + resetRandom(hhs[i], awfCount); + } + } + + public void resetAwlRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to At-work Subtour Location Choice + // model + // from the Household object. + // this value was set at the end of At-work Subtour Frequency model + // step. + int awlCount = hhs[i].getAwfRandomCount(); + + // draw awlCount random numbers + resetRandom(hhs[i], awlCount); + } + } + + public void resetAwtodRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to At-work Subtour Time-of-day and + // mode + // choice model from the Household object. + // this value was set at the end of At-work Subtour Location Choice + // model + // step. + int awtodCount = hhs[i].getAwlRandomCount(); + + // draw awtodCount random numbers + resetRandom(hhs[i], awtodCount); + } + } + + public void resetStfRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to stop frequency model from the + // Household + // object. + // this value was set at the end of At-work Subtour Time-of-day and + // mode + // choice model step. + int stfCount = hhs[i].getAwtodRandomCount(); + + // draw stfCount random numbers + resetRandom(hhs[i], stfCount); + } + } + + public void resetStlRandom() + { + for (int i = 0; i < hhs.length; i++) + { + // get the current count prior to stop location model from the + // Household + // object. + // this value was set at the end of stop frequency model step. + int stlCount = hhs[i].getStfRandomCount(); + + // draw stlCount random numbers + resetRandom(hhs[i], stlCount); + } + } + + /** + * Sets the HashSet used to trace households for debug purposes and sets the + * debug switch for each of the listed households. Also sets + */ + public void setTraceHouseholdSet() + { + + // loop through the households in the set and set the trace switches + for (int i = 0; i < hhs.length; i++) + hhs[i].setDebugChoiceModels(false); + + for (int id : householdTraceSet) + { + int index = hhIndexArray[id]; + hhs[index].setDebugChoiceModels(true); + } + + } + + /** + * Sets the sample rate used to run the model for a portion of the + * households. + * + * @param sampleRate + * , proportion of total households for which to run the model + * [0.0, 1.0]. + */ + public void setHouseholdSampleRate(float sampleRate, int sampleSeed) + { + this.sampleRate = sampleRate; + this.sampleSeed = sampleSeed; + } + + public void setHhArray(Household[] hhArray) + { + hhs = hhArray; + } + + public void setHhArray(Household[] tempHhs, int startIndex) + { + // long startTime = System.currentTimeMillis(); + // logger.info(String.format("start setHhArray for startIndex=%d, startTime=%d.", + // startIndex, + // startTime)); + + synchronized(hhs) { + for (int i = 0; i < tempHhs.length; i++) + { + hhs[startIndex + i] = tempHhs[i]; + } + } + // long endTime = System.currentTimeMillis(); + // logger.info(String.format( + // "end setHhArray for startIndex=%d, endTime=%d, elapsed=%d millisecs.", + // startIndex, + // endTime, (endTime - startTime))); + } + + /** + * return the array of Household objects holding the synthetic population + * and choice model outcomes. + * + * @return hhs + */ + public Household[] getHhArray() + { + return hhs; + } + + public Household[] getHhArray(int first, int last) + { + // long startTime = System.currentTimeMillis(); + // logger.info(String.format("start getHhArray for first=%d, last=%d, startTime=%d.", + // first, last, startTime)); + Household[] tempHhs = new Household[last - first + 1]; + for (int i = 0; i < tempHhs.length; i++) + { + tempHhs[i] = hhs[first + i]; + } + // long endTime = System.currentTimeMillis(); + // logger.info(String.format( + // "end getHhArray for first=%d, last=%d, endTime=%d, elapsed=%d millisecs.", + // first, last, endTime, (endTime - startTime))); + return tempHhs; + } + + public int getArrayIndex(int hhId) + { + int i = hhIndexArray[hhId]; + return i; + } + + /** + * return the number of household objects read from the synthetic + * population. + * + * @return + */ + public int getNumHouseholds() + { + // hhs is dimesioned to number of households + 1. + return hhs.length; + } + + /** + * set walk segment (0-none, 1-short, 2-long walk to transit access) for the + * origin for this tour + */ + public int getInitialOriginWalkSegment(int taz, double randomNumber) + { + // double[] proportions = tazDataManager.getZonalWalkPercentagesForTaz( + // taz + // ); + // return ChoiceModelApplication.getMonteCarloSelection(proportions, + // randomNumber); + return 0; + } + + private void readHouseholdData(String inputHouseholdFileName) + { + + // construct input household file name from properties file values + String fileName = projectDirectory + "/" + inputHouseholdFileName; + + try + { + logger.info("reading popsyn household data file."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + hhTable = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading synthetic household data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + } + + private void readPersonData(String inputPersonFileName) + { + + // construct input person file name from properties file values + String fileName = projectDirectory + "/" + inputPersonFileName; + + try + { + logger.info("reading popsyn person data file."); + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet("," + reader.getDelimSet()); + personTable = reader.readFile(new File(fileName)); + } catch (Exception e) + { + logger.fatal(String + .format("Exception occurred reading synthetic person data file: %s into TableDataSet object.", + fileName)); + throw new RuntimeException(e); + } + + } + + public void logPersonSummary() + { + + HashMap> summaryResults; + + summaryResults = new HashMap>(); + + for (int i = 0; i < hhs.length; ++i) + { + + Household household = hhs[i]; + + Person[] personArray = household.getPersons(); + for (int j = 1; j < personArray.length; ++j) + { + Person person = personArray[j]; + String personType = person.getPersonType(); + + String employmentStatus = person.getPersonEmploymentCategory(); + String studentStatus = person.getPersonStudentCategory(); + int age = person.getAge(); + int ageCategory; + if (age <= 5) + { + ageCategory = 0; + } else if (age <= 15) + { + ageCategory = 1; + } else if (age <= 18) + { + ageCategory = 2; + } else if (age <= 24) + { + ageCategory = 3; + } else if (age <= 44) + { + ageCategory = 4; + } else if (age <= 64) + { + ageCategory = 5; + } else + { + ageCategory = 6; + } + + if (summaryResults.containsKey(personType)) + { + // have person type + if (summaryResults.get(personType).containsKey(employmentStatus)) + { + // have employment category + summaryResults.get(personType).get(employmentStatus)[ageCategory] += 1; + } else + { + // don't have employment category + summaryResults.get(personType).put(employmentStatus, new int[7]); + summaryResults.get(personType).get(employmentStatus)[ageCategory] += 1; + } + if (summaryResults.get(personType).containsKey(studentStatus)) + { + // have student category + summaryResults.get(personType).get(studentStatus)[ageCategory] += 1; + } else + { + // don't have student category + summaryResults.get(personType).put(studentStatus, new int[7]); + summaryResults.get(personType).get(studentStatus)[ageCategory] += 1; + } + } else + { + // don't have person type + summaryResults.put(personType, new HashMap()); + summaryResults.get(personType).put(studentStatus, new int[7]); + summaryResults.get(personType).get(studentStatus)[ageCategory] += 1; + summaryResults.get(personType).put(employmentStatus, new int[7]); + summaryResults.get(personType).get(employmentStatus)[ageCategory] += 1; + } + } + } + String headerRow = String.format("%5s\t", "Age\t"); + for (String empCategory : Person.EMPLOYMENT_CATEGORY_NAME_ARRAY) + { + headerRow += String.format("%16s\t", empCategory); + } + for (String stuCategory : Person.STUDENT_CATEGORY_NAME_ARRAY) + { + headerRow += String.format("%16s\t", stuCategory); + } + String[] ageCategories = {"0-5", "6-15", "16-18", "19-24", "25-44", "45-64", "65+"}; + + for (String personType : summaryResults.keySet()) + { + + logger.info("Summary for person type: " + personType); + + logger.info(headerRow); + String row = ""; + + HashMap personTypeSummary = summaryResults.get(personType); + + for (int j = 0; j < ageCategories.length; ++j) + { + row = String.format("%5s\t", ageCategories[j]); + for (String empCategory : Person.EMPLOYMENT_CATEGORY_NAME_ARRAY) + { + if (personTypeSummary.containsKey(empCategory)) + { + row += String.format("%16d\t", personTypeSummary.get(empCategory)[j]); + } else row += String.format("%16d\t", 0); + } + for (String stuCategory : Person.STUDENT_CATEGORY_NAME_ARRAY) + { + if (personTypeSummary.containsKey(stuCategory)) + { + row += String.format("%16d\t", personTypeSummary.get(stuCategory)[j]); + } else row += String.format("%16d\t", 0); + } + logger.info(row); + } + + } + + } + + public int[][] getTourPurposePersonsByHomeMgra(String[] purposeList) + { + + int maxMgra = mgraManager.getMaxMgra(); + int[][] personsWithMandatoryPurpose = new int[purposeList.length][maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + for (int r = 0; r < hhs.length; r++) + { + + Person[] persons = hhs[r].getPersons(); + + int homeMgra = hhs[r].getHhMgra(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + int purposeIndex = -1; + try + { + + if (person.getPersonIsWorker() == 1) + { + + purposeIndex = person.getWorkLocationSegmentIndex(); + personsWithMandatoryPurpose[purposeIndex][homeMgra]++; + + } + + if (person.getPersonIsPreschoolChild() == 1 + || person.getPersonIsStudentDriving() == 1 + || person.getPersonIsStudentNonDriving() == 1 + || person.getPersonIsUniversityStudent() == 1) + { + + purposeIndex = person.getSchoolLocationSegmentIndex(); + personsWithMandatoryPurpose[purposeIndex][homeMgra]++; + + } + + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught summing workers/students by origin zone for household table record r=%d.", + r)); + throw e; + } + + } + + } // r (households) + + return personsWithMandatoryPurpose; + + } + + public double[] getPercentHhsIncome100Kplus() + { + return percentHhsIncome100Kplus; + } + + public double[] getPercentHhsMultipleAutos() + { + return percentHhsMultipleAutos; + } + + public void computeTransponderChoiceTazPercentArrays() + { + + PrintWriter out = null; + try + { + out = new PrintWriter(new BufferedWriter(new FileWriter(new File( + "./transpChoiceArrays.csv")))); + } catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + + int maxTaz = tazManager.maxTaz; + int[] numHhs = new int[maxTaz + 1]; + + // for percent of households in TAZ with income > $100K + percentHhsIncome100Kplus = new double[maxTaz + 1]; + // for percent og households in TAZ with multiple autos + percentHhsMultipleAutos = new double[maxTaz + 1]; + + for (int r = 0; r < getNumHouseholds(); r++) + { + int homeMgra = hhs[r].getHhMgra(); + int homeTaz = mgraManager.getTaz(homeMgra); + numHhs[homeTaz]++; + if (hhs[r].getIncomeInDollars() > 100000) percentHhsIncome100Kplus[homeTaz]++; + if (hhs[r].getAutosOwned() > 1) percentHhsMultipleAutos[homeTaz]++; + } + + out.println("taz,numHhsTaz,numHhsIncome100KplusTaz,numHhsMultipleAutosTaz,proportionHhsIncome100KplusTaz,proportionHhsMultipleAutosTaz"); + + for (int i = 0; i <= maxTaz; i++) + { + + out.print(i + "," + numHhs[i] + "," + percentHhsIncome100Kplus[i] + "," + + percentHhsMultipleAutos[i]); + if (numHhs[i] > 0) + { + percentHhsIncome100Kplus[i] /= numHhs[i]; + percentHhsMultipleAutos[i] /= numHhs[i]; + out.println("," + percentHhsIncome100Kplus[i] + "," + percentHhsMultipleAutos[i]); + } else + { + out.println("," + 0.0 + "," + 0.0); + } + } + + out.close(); + } + + public int[][] getWorkersByHomeMgra(HashMap segmentValueIndexMap) + { + + int maxMgra = mgraManager.getMaxMgra(); + + int[][] workersByHomeMgra = new int[segmentValueIndexMap.size()][maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + for (int r = 0; r < getNumHouseholds(); r++) + { + + Person[] persons = hhs[r].getPersons(); + + int homeMgra = hhs[r].getHhMgra(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + if (person.getPersonIsFullTimeWorker() == 1 + || person.getPersonIsPartTimeWorker() == 1) + { + + int occup = -1; + int segmentIndex = -1; + try + { + + occup = person.getPersPecasOccup(); + segmentIndex = segmentValueIndexMap.get(occup); + workersByHomeMgra[segmentIndex][homeMgra]++; + + } catch (Exception e) + { + logger.error( + String.format( + "exception caught summing workers by origin MGRA for household table record r=%d, person=%d, homeMgra=%d, occup=%d, segmentIndex=%d.", + r, person.getPersonNum(), homeMgra, occup, segmentIndex), e); + throw new RuntimeException(); + } + + } + + } + + } // r (households) + + return workersByHomeMgra; + + } + + public int[][] getStudentsByHomeMgra() + { + + int maxMgra = mgraManager.getMaxMgra(); + + // there are 5 school types - preschool, K-8, HS, University with + // typical + // students, University with non-typical students. + int[][] studentsByHomeMgra = new int[schoolSegmentNameIndexMap.size()][maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + for (int r = 0; r < getNumHouseholds(); r++) + { + + Person[] persons = hhs[r].getPersons(); + + int homeMgra = hhs[r].getHhMgra(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + if (person.getPersonIsPreschoolChild() == 1 + || person.getPersonIsStudentNonDriving() == 1 + || person.getPersonIsStudentDriving() == 1 + || person.getPersonIsUniversityStudent() == 1) + { + + int segmentIndex = -1; + try + { + + if (person.getPersonIsPreschoolChild() == 1) + { + segmentIndex = schoolSegmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.PRESCHOOL_SEGMENT_GROUP_INDEX]); + } else if (person.getPersonIsGradeSchool() == 1) + { + int gsDistrict = mgraGsDistrict[homeMgra]; + segmentIndex = gsDistrictSegmentMap.get(gsDistrict); + } else if (person.getPersonIsHighSchool() == 1) + { + int hsDistrict = mgraHsDistrict[homeMgra]; + segmentIndex = hsDistrictSegmentMap.get(hsDistrict); + } else if (person.getPersonIsUniversityStudent() == 1 + && person.getAge() < 30) + { + segmentIndex = schoolSegmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_TYPICAL_SEGMENT_GROUP_INDEX]); + } else if (person.getPersonIsUniversityStudent() == 1 + && person.getAge() >= 30) + { + segmentIndex = schoolSegmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_NONTYPICAL_SEGMENT_GROUP_INDEX]); + } + + // if person type is a student but segment index is -1, + // the person is not enrolled; assume home schooled and + // don't add to sum by home mgra + if (segmentIndex >= 0) studentsByHomeMgra[segmentIndex][homeMgra]++; + + } catch (Exception e) + { + logger.error( + String.format( + "exception caught summing students by origin MGRA for household table record r=%d, person=%d, homeMgra=%d, segmentIndex=%d.", + r, person.getPersonNum(), homeMgra, segmentIndex), e); + throw new RuntimeException(); + } + + } + + } + + } // r (households) + + return studentsByHomeMgra; + + } + + public int[] getIndividualNonMandatoryToursByHomeMgra(String purposeString) + { + + // dimension the array + int maxMgra = mgraManager.getMaxMgra(); + int[] individualNonMandatoryTours = new int[maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + int count = 0; + for (int r = 0; r < hhs.length; r++) + { + + Person[] persons = hhs[r].getPersons(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + ArrayList it = person.getListOfIndividualNonMandatoryTours(); + + try + { + + if (it.size() == 0) continue; + + for (Tour tour : it) + { + // increment the segment count if it's the right purpose + String tourPurpose = tour.getTourPurpose(); + if (purposeString.startsWith(tourPurpose)) + { + int homeMgra = hhs[r].getHhMgra(); + individualNonMandatoryTours[homeMgra]++; + count++; + } + } + + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught counting number of individualNonMandatory tours for purpose: %s, for household table record r=%d, personNum=%d.", + purposeString, r, person.getPersonNum())); + throw e; + } + + } + + } // r (households) + + return individualNonMandatoryTours; + } + + public int[][] getWorkToursByDestMgra(HashMap segmentValueIndexMap) + { + + // dimension the array + int maxMgra = mgraManager.getMaxMgra(); + int destMgra = 0; + + int[][] workTours = new int[segmentValueIndexMap.size()][maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + for (int r = 0; r < getNumHouseholds(); r++) + { + + Person[] persons = hhs[r].getPersons(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + int occup = -1; + int segmentIndex = -1; + try + { + + if (person.getPersonIsWorker() == 1) + { + + destMgra = person.getWorkLocation(); + + if (destMgra != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + occup = person.getPersPecasOccup(); + segmentIndex = segmentValueIndexMap.get(occup); + workTours[segmentIndex][destMgra]++; + } + + } + + } catch (Exception e) + { + logger.error( + String.format( + "exception caught summing workers by work location MGRA for household table record r=%d, person=%d, workMgra=%d, occup=%d, segmentIndex=%d.", + r, person.getPersonNum(), destMgra, occup, segmentIndex), e); + throw new RuntimeException(); + } + + } + + } // r (households) + + return workTours; + + } + + public int[] getWorksAtHomeBySegment(HashMap segmentValueIndexMap) + { + + int destMgra = 0; + + int[] workAtHome = new int[segmentValueIndexMap.size()]; + + // hhs is dimesioned to number of households + 1. + for (int r = 0; r < getNumHouseholds(); r++) + { + + Person[] persons = hhs[r].getPersons(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + int occup = -1; + int segmentIndex = -1; + try + { + + if (person.getPersonIsWorker() == 1) + { + + destMgra = person.getWorkLocation(); + + if (destMgra == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + occup = person.getPersPecasOccup(); + segmentIndex = segmentValueIndexMap.get(occup); + workAtHome[segmentIndex]++; + } + + } + + } catch (Exception e) + { + logger.error( + String.format( + "exception caught summing workers by work location MGRA for household table record r=%d, person=%d, workMgra=%d, occup=%d, segmentIndex=%d.", + r, person.getPersonNum(), destMgra, occup, segmentIndex), e); + throw new RuntimeException(); + } + + } + + } // r (households) + + return workAtHome; + + } + + public void setSchoolDistrictMappings(HashMap segmentNameIndexMap, + int[] mgraGsDist, int[] mgraHsDist, HashMap gsDistSegMap, + HashMap hsDistSegMap) + { + + schoolSegmentNameIndexMap = segmentNameIndexMap; + gsDistrictSegmentMap = gsDistSegMap; + hsDistrictSegmentMap = hsDistSegMap; + mgraGsDistrict = mgraGsDist; + mgraHsDistrict = mgraHsDist; + } + + public int[][] getSchoolToursByDestMgra() + { + + // dimension the array + int maxMgra = mgraManager.getMaxMgra(); + int destMgra = 0; + + int[][] schoolTours = new int[schoolSegmentNameIndexMap.size()][maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + for (int r = 0; r < getNumHouseholds(); r++) + { + + Person[] persons = hhs[r].getPersons(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + destMgra = person.getPersonSchoolLocationZone(); + if (destMgra == 0) continue; + + int segmentIndex = -1; + try + { + + if (person.getPersonIsPreschoolChild() == 1) + { + segmentIndex = schoolSegmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.PRESCHOOL_SEGMENT_GROUP_INDEX]); + } else if (person.getPersonIsGradeSchool() == 1) + { + int gsDistrict = mgraGsDistrict[destMgra]; + segmentIndex = gsDistrictSegmentMap.get(gsDistrict); + } else if (person.getPersonIsHighSchool() == 1) + { + int hsDistrict = mgraHsDistrict[destMgra]; + segmentIndex = hsDistrictSegmentMap.get(hsDistrict); + } else if (person.getPersonIsUniversityStudent() == 1 && person.getAge() < 30) + { + segmentIndex = schoolSegmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_TYPICAL_SEGMENT_GROUP_INDEX]); + } else if (person.getPersonIsUniversityStudent() == 1 && person.getAge() >= 30) + { + segmentIndex = schoolSegmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_NONTYPICAL_SEGMENT_GROUP_INDEX]); + } + + // if person type is a student but segment index is -1, the + // person is not enrolled; assume home schooled and don't + // add to sum by home mgra + if (segmentIndex >= 0) schoolTours[segmentIndex][destMgra]++; + + } catch (Exception e) + { + logger.error( + String.format( + "exception caught summing students by origin MGRA for household table record r=%d, person=%d, schoolMgra=%d, segmentIndex=%d.", + r, person.getPersonNum(), destMgra, segmentIndex), e); + throw new RuntimeException(); + } + + } + + } // r (households) + + return schoolTours; + + } + + public int[] getJointToursByHomeZoneSubZone(String purposeString) + { + + // dimension the array + int maxMgra = mgraManager.getMaxMgra(); + + int[] jointTours = new int[maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + int count = 0; + for (int r = 0; r < hhs.length; r++) + { + + try + { + + Tour[] jt = hhs[r].getJointTourArray(); + + if (jt == null) continue; + + for (int i = 0; i < jt.length; i++) + { + // increment the segment count if it's the right purpose + if (jt[i].getTourPurpose().equalsIgnoreCase(purposeString)) + { + int homeMgra = hhs[r].getHhMgra(); + jointTours[homeMgra]++; + count++; + } + } + + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught counting number of joint tours for purpose: %s, for household table record r=%d.", + purposeString, r)); + throw e; + } + + } // r (households) + + return jointTours; + } + + public int[] getAtWorkSubtoursByWorkMgra(String purposeString) + { + + // dimension the array + int maxMgra = mgraManager.getMaxMgra(); + + int[] subtours = new int[maxMgra + 1]; + + // hhs is dimesioned to number of households + 1. + int count = 0; + for (int r = 0; r < hhs.length; r++) + { + + Person[] persons = hhs[r].getPersons(); + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + ArrayList subtourList = person.getListOfAtWorkSubtours(); + + try + { + + if (subtourList.size() == 0) continue; + + for (Tour tour : subtourList) + { + // increment the segment count if it's the right purpose + String tourPurpose = tour.getTourPurpose(); + if (tourPurpose.startsWith(purposeString)) + { + int workZone = tour.getTourOrigMgra(); + subtours[workZone]++; + count++; + } + } + + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught counting number of at-work subtours for purpose: %s, for household table record r=%d, personNum=%d, count=0%d.", + purposeString, r, person.getPersonNum(), count)); + throw e; + } + + } + + } // r (households) + + return subtours; + } + + public void readWorkSchoolLocationResults() + { + + String[] headings = {"HHID", "HomeMGRA", "Income", "PersonID", "PersonNum", "PersonType", + "PersonAge", "EmploymentCategory", "StudentCategory", "WorkSegment", + "SchoolSegment", "WorkLocation", "WorkLocationDistance", "WorkLocationLogsum", + "SchoolLocation", "SchoolLocationDistance", "SchoolLocationLogsum"}; + + String wsLocResultsFileName = propertyMap.get(READ_UWSL_RESULTS_FILENAME); + + // open the input stream + String delimSet = ","; + BufferedReader uwslStream = null; + String fileName = projectDirectory + wsLocResultsFileName; + try + { + uwslStream = new BufferedReader(new FileReader(new File(fileName))); + } catch (FileNotFoundException e) + { + e.printStackTrace(); + System.exit(-1); + } + + // first parse the results file field names from the first record and + // associate column position with fields used in model + HashMap indexHeadingMap = new HashMap(); + + String line = ""; + try + { + line = uwslStream.readLine(); + } catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + StringTokenizer st = new StringTokenizer(line, delimSet); + int col = 0; + while (st.hasMoreTokens()) + { + String label = st.nextToken(); + for (String heading : headings) + { + if (heading.equalsIgnoreCase(label)) + { + indexHeadingMap.put(col, heading); + break; + } + } + col++; + } + + Household hh = null; + Person person = null; + + try + { + + while ((line = uwslStream.readLine()) != null) + { + + // set the line number for the next line in the sample of + // households + // int sortedSampleIndex = + // sortedIndices[sortedSample[sampleCount]]; + + // get the household id and personNum first, before parsing + // other + // fields. Skip to next record if not in the sample. + col = 0; + int id = -1; + int personNum = -1; + int workLocation = -1; + int schoolLocation = -1; + st = new StringTokenizer(line, delimSet); + while (st.hasMoreTokens()) + { + String fieldValue = st.nextToken(); + if (indexHeadingMap.containsKey(col)) + { + String fieldName = indexHeadingMap.get(col++); + + if (fieldName.equalsIgnoreCase("HHID")) + { + id = Integer.parseInt(fieldValue); + + int index = getArrayIndex(id); + hh = hhs[index]; + } else if (fieldName.equalsIgnoreCase("PersonNum")) + { + personNum = Integer.parseInt(fieldValue); + person = hh.getPerson(personNum); + } else if (fieldName.equalsIgnoreCase("WorkSegment")) + { + int workSegment = Integer.parseInt(fieldValue); + person.setWorkLocationSegmentIndex(workSegment); + } else if (fieldName.equalsIgnoreCase("workLocation")) + { + workLocation = Integer.parseInt(fieldValue); + person.setWorkLocation(workLocation); + } else if (fieldName.equalsIgnoreCase("WorkLocationDistance")) + { + float distance = Float.parseFloat(fieldValue); + person.setWorkLocDistance(distance); + } else if (fieldName.equalsIgnoreCase("WorkLocationLogsum")) + { + float logsum = Float.parseFloat(fieldValue); + person.setWorkLocLogsum(logsum); + } else if (fieldName.equalsIgnoreCase("SchoolSegment")) + { + int schoolSegment = Integer.parseInt(fieldValue); + person.setSchoolLocationSegmentIndex(schoolSegment); + } else if (fieldName.equalsIgnoreCase("SchoolLocation")) + { + schoolLocation = Integer.parseInt(fieldValue); + person.setSchoolLoc(schoolLocation); + } else if (fieldName.equalsIgnoreCase("SchoolLocationDistance")) + { + float distance = Float.parseFloat(fieldValue); + person.setSchoolLocDistance(distance); + } else if (fieldName.equalsIgnoreCase("SchoolLocationLogsum")) + { + float logsum = Float.parseFloat(fieldValue); + person.setSchoolLocLogsum(logsum); + break; + } + + } else + { + col++; + } + + } + + } + + } catch (NumberFormatException e) + { + e.printStackTrace(); + System.exit(-1); + } catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + + } + + public void readPreAoResults() + { + + String[] headings = {"HHID", "AO"}; + + String preAoResultsFileName = propertyMap.get(READ_PRE_AO_RESULTS_FILENAME); + + // open the input stream + String delimSet = ","; + BufferedReader inStream = null; + String fileName = projectDirectory + preAoResultsFileName; + try + { + inStream = new BufferedReader(new FileReader(new File(fileName))); + } catch (FileNotFoundException e) + { + e.printStackTrace(); + System.exit(-1); + } + + // first parse the results file field names from the first record and + // associate column position with fields used in model + HashMap indexHeadingMap = new HashMap(); + + String line = ""; + try + { + line = inStream.readLine(); + } catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + StringTokenizer st = new StringTokenizer(line, delimSet); + int col = 0; + while (st.hasMoreTokens()) + { + String label = st.nextToken(); + for (String heading : headings) + { + if (heading.equalsIgnoreCase(label)) + { + indexHeadingMap.put(col, heading); + break; + } + } + col++; + } + + Household hh = null; + + try + { + + while ((line = inStream.readLine()) != null) + { + + // set the line number for the next line in the sample of + // households + // int sortedSampleIndex = + // sortedIndices[sortedSample[sampleCount]]; + + // get the household id first, before parsing other fields. Skip + // to + // next record if not in the sample. + col = 0; + int id = -1; + int ao = -1; + st = new StringTokenizer(line, delimSet); + while (st.hasMoreTokens()) + { + String fieldValue = st.nextToken(); + if (indexHeadingMap.containsKey(col)) + { + String fieldName = indexHeadingMap.get(col++); + + if (fieldName.equalsIgnoreCase("HHID")) + { + id = Integer.parseInt(fieldValue); + + int index = getArrayIndex(id); + hh = hhs[index]; + } else if (fieldName.equalsIgnoreCase("AO")) + { + ao = Integer.parseInt(fieldValue); + // pass in the ao model alternative number to this + // method + hh.setHhAutos(ao + 1); + break; + } + + } else + { + col++; + } + + } + + } + + } catch (NumberFormatException e) + { + e.printStackTrace(); + System.exit(-1); + } catch (IOException e) + { + e.printStackTrace(); + System.exit(-1); + } + + } + + public long getBytesUsedByHouseholdArray() + { + + long numBytes = 0; + for (int i = 0; i < hhs.length; i++) + { + Household hh = hhs[i]; + long size = ObjectUtil.sizeOf(hh); + numBytes += size; + } + + return numBytes; + } + + /** + * Assigns each individual person their own value of time, drawing from a + * lognormal distribution as a function of income. + */ + protected void setDistributedValuesOfTime() + { + + // read in values from property file + setValueOfTimePropertyFileValues(); + + // set up the probability distributions + for (int i = 0; i < valueOfTimeDistribution.length; i++) + { + double mu = Math.log(meanValueOfTime[i] * meanValueOfTimeMultiplierBeforeLogForMu); + valueOfTimeDistribution[i] = new LognormalDist(mu, valueOfTimeLognormalSigma); + } + + for (int i = 0; i < hhs.length; ++i) + { + Household household = hhs[i]; + + // each HH gets a VOT for consistency + double rnum = household.getHhRandom().nextDouble(); + int incomeCategory = getIncomeIndexForValueOfTime(household.getIncomeInDollars()); + double hhValueOfTime = valueOfTimeDistribution[incomeCategory - 1].inverseF(rnum); + + // constrain to logical min and max values + if (hhValueOfTime < minValueOfTime) hhValueOfTime = minValueOfTime; + if (hhValueOfTime > maxValueOfTime) hhValueOfTime = maxValueOfTime; + + // adults get the full value, and children 2/3 (1-based) + Person[] personArray = household.getPersons(); + for (int j = 1; j < personArray.length; ++j) + { + Person person = personArray[j]; + + int age = person.getAge(); + if (age < 18) person.setValueOfTime((float) hhValueOfTime + * hhValueOfTimeMultiplierForPersonUnder18); + else person.setValueOfTime((float) hhValueOfTime); + } + } + } + + /** + * Sets additional properties specific to MTC, included distributed + * value-of-time information + */ + private void setValueOfTimePropertyFileValues() + { + + boolean errorFlag = false; + String propertyValue = ""; + + propertyValue = propertyMap.get(PROPERTIES_MIN_VALUE_OF_TIME_KEY); + if (propertyValue == null) + { + logger.error("property file key missing: " + PROPERTIES_MIN_VALUE_OF_TIME_KEY + + ", not able to set min value of time value."); + errorFlag = true; + } else minValueOfTime = Float.parseFloat(propertyValue); + + propertyValue = propertyMap.get(PROPERTIES_MAX_VALUE_OF_TIME_KEY); + if (propertyValue == null) + { + logger.error("property file key missing: " + PROPERTIES_MAX_VALUE_OF_TIME_KEY + + ", not able to set max value of time value."); + errorFlag = true; + } else maxValueOfTime = Float.parseFloat(propertyValue); + + // mean values of time by income category are specified as a + // "comma-sparated" list of float values + // the number of mean values in the lsit determines the number of income + // categories for value of time + // the number of upper limit income dollar values is expected to be + // number of mean values - 1. + int numIncomeCategories = -1; + String meanValueOfTimesPropertyValue = propertyMap + .get(PROPERTIES_MEAN_VALUE_OF_TIME_VALUES_KEY); + if (meanValueOfTimesPropertyValue == null) + { + logger.error("property file key missing: " + PROPERTIES_MEAN_VALUE_OF_TIME_VALUES_KEY + + ", not able to set mean value of time values."); + errorFlag = true; + } else + { + + ArrayList valueList = new ArrayList(); + StringTokenizer valueTokenizer = new StringTokenizer(meanValueOfTimesPropertyValue, ","); + while (valueTokenizer.hasMoreTokens()) + { + String listValue = valueTokenizer.nextToken(); + float value = Float.parseFloat(listValue.trim()); + valueList.add(value); + } + + numIncomeCategories = valueList.size(); + meanValueOfTime = new float[numIncomeCategories]; + valueOfTimeDistribution = new LognormalDist[numIncomeCategories]; + + for (int i = 0; i < numIncomeCategories; i++) + meanValueOfTime[i] = valueList.get(i); + } + + // read the upper limit values for value of time income ranges. + // there should be exactly 1 less than the number of mean value of time + // values - any other value is an error. + String valueOfTimeIncomesPropertyValue = propertyMap + .get(PROPERTIES_MEAN_VALUE_OF_TIME_INCOME_LIMITS_KEY); + if (valueOfTimeIncomesPropertyValue == null) + { + logger.error("property file key missing: " + + PROPERTIES_MEAN_VALUE_OF_TIME_INCOME_LIMITS_KEY + + ", not able to set upper limits for value of time income ranges."); + errorFlag = true; + } else + { + + ArrayList valueList = new ArrayList(); + StringTokenizer valueTokenizer = new StringTokenizer(valueOfTimeIncomesPropertyValue, + ","); + while (valueTokenizer.hasMoreTokens()) + { + String listValue = valueTokenizer.nextToken(); + int value = Integer.parseInt(listValue.trim()); + valueList.add(value); + } + + int numIncomeValues = valueList.size(); + if (numIncomeValues != (numIncomeCategories - 1)) + { + Exception e = new RuntimeException(); + logger.error("an error occurred reading properties file values for distributed value of time calculations."); + logger.error("the mean value of time values property=" + + meanValueOfTimesPropertyValue + " specifies " + numIncomeCategories + + " mean values, thus " + numIncomeCategories + " income ranges."); + logger.error("the value of time income range values property=" + + valueOfTimeIncomesPropertyValue + " specifies " + numIncomeValues + + " income range limit values."); + logger.error("there should be exactly " + (numIncomeCategories - 1) + + " income range limit values for " + numIncomeCategories + + " mean value of time values.", e); + System.exit(-1); + } + + // set the income dollar value upper limits for value of time income + // ranges + incomeDollarLimitsForValueOfTime = new int[numIncomeValues + 1]; + for (int i = 0; i < numIncomeValues; i++) + incomeDollarLimitsForValueOfTime[i] = valueList.get(i); + + incomeDollarLimitsForValueOfTime[numIncomeValues] = Integer.MAX_VALUE; + } + + propertyValue = propertyMap.get(PROPERTIES_HH_VALUE_OF_TIME_MULTIPLIER_FOR_UNDER_18_KEY); + if (propertyValue == null) + { + logger.error("property file key missing: " + + PROPERTIES_HH_VALUE_OF_TIME_MULTIPLIER_FOR_UNDER_18_KEY + + ", not able to set hh value of time multiplier for kids in hh under age 18."); + errorFlag = true; + } else hhValueOfTimeMultiplierForPersonUnder18 = Float.parseFloat(propertyValue); + + propertyValue = propertyMap.get(PROPERTIES_MEAN_VALUE_OF_TIME_MULTIPLIER_FOR_MU_KEY); + if (propertyValue == null) + { + logger.error("property file key missing: " + + PROPERTIES_MEAN_VALUE_OF_TIME_MULTIPLIER_FOR_MU_KEY + + ", not able to set lognormal distribution mu parameter multiplier."); + errorFlag = true; + } else meanValueOfTimeMultiplierBeforeLogForMu = Float.parseFloat(propertyValue); + + propertyValue = propertyMap.get(PROPERTIES_VALUE_OF_TIME_LOGNORMAL_SIGMA_KEY); + if (propertyValue == null) + { + logger.error("property file key missing: " + + PROPERTIES_VALUE_OF_TIME_LOGNORMAL_SIGMA_KEY + + ", not able to set lognormal distribution sigma parameter."); + errorFlag = true; + } else valueOfTimeLognormalSigma = Float.parseFloat(propertyValue); + + if (errorFlag) + { + Exception e = new RuntimeException(); + logger.error( + "errors occurred reading properties file values for distributed value of time calculations.", + e); + System.exit(-1); + } + + } + + private int getIncomeIndexForValueOfTime(int incomeInDollars) + { + int returnValue = -1; + for (int i = 0; i < incomeDollarLimitsForValueOfTime.length; i++) + { + if (incomeInDollars < incomeDollarLimitsForValueOfTime[i]) + { + // return a 1s based index value + returnValue = i + 1; + break; + } + } + + return returnValue; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManagerIf.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManagerIf.java new file mode 100644 index 0000000..c31368f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManagerIf.java @@ -0,0 +1,137 @@ +package org.sandag.abm.ctramp; + +import java.util.HashMap; + +/** + * @author Jim Hicks + * + * Class for managing household and person object data read from + * synthetic population files. + */ +public interface HouseholdDataManagerIf +{ + + String testRemote(); + + void setPropertyFileValues(HashMap propertyMap); + + void setDebugHhIdsFromHashmap(); + + void computeTransponderChoiceTazPercentArrays(); + + double[] getPercentHhsIncome100Kplus(); + + double[] getPercentHhsMultipleAutos(); + + int[] getRandomOrderHhIndexArray(int numHhs); + + int getArrayIndex(int hhId); + + void setHhArray(Household[] hhs); + + void setHhArray(Household[] tempHhs, int startIndex); + + void setSchoolDistrictMappings(HashMap segmentNameIndexMap, int[] mgraGsDist, + int[] mgraHsDist, HashMap gsDistSegMap, + HashMap hsDistSegMap); + + void setupHouseholdDataManager(ModelStructure modelStructure, String inputHouseholdFileName, + String inputPersonFileName); + + int[][] getTourPurposePersonsByHomeMgra(String[] purposeList); + + int[][] getWorkersByHomeMgra(HashMap segmentValueIndexMap); + + int[][] getStudentsByHomeMgra(); + + int[][] getWorkToursByDestMgra(HashMap segmentValueIndexMap); + + int[] getWorksAtHomeBySegment(HashMap segmentValueIndexMap); + + int[][] getSchoolToursByDestMgra(); + + int[] getIndividualNonMandatoryToursByHomeMgra(String purposeString); + + int[] getJointToursByHomeMgra(String purposeString); + + int[] getAtWorkSubtoursByWorkMgra(String purposeString); + + void logPersonSummary(); + + void setUwslRandomCount(int iter); + + void resetUwslRandom(int iter); + + void resetPreAoRandom(); + + void resetAoRandom(int iter); + + void resetFpRandom(); + + void resetCdapRandom(); + + void resetImtfRandom(); + + void resetImtodRandom(); + + void resetAwfRandom(); + + void resetAwlRandom(); + + void resetAwtodRandom(); + + void resetJtfRandom(); + + void resetJtlRandom(); + + void resetJtodRandom(); + + void resetInmtfRandom(); + + void resetInmtlRandom(); + + void resetInmtodRandom(); + + void resetStfRandom(); + + void resetStlRandom(); + + /** + * Sets the HashSet used to trace households for debug purposes and sets the + * debug switch for each of the listed households. Also sets + */ + void setTraceHouseholdSet(); + + /** + * Sets the HashSet used to trace households for debug purposes and sets the + * debug switch for each of the listed households. Also sets + */ + void setHouseholdSampleRate(float sampleRate, int sampleSeed); + + /** + * return the array of Household objects holding the synthetic population + * and choice model outcomes. + * + * @return hhs + */ + Household[] getHhArray(); + + Household[] getHhArray(int firstHhIndex, int lastHhIndex); + + /** + * return the number of household objects read from the synthetic + * population. + * + * @return + */ + int getNumHouseholds(); + + /** + * set walk segment (0-none, 1-short, 2-long walk to transit access) for the + * origin for this tour + */ + int getInitialOriginWalkSegment(int taz, double randomNumber); + + long getBytesUsedByHouseholdArray(); + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManagerRmi.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManagerRmi.java new file mode 100644 index 0000000..e98bdab --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataManagerRmi.java @@ -0,0 +1,373 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * @author Jim Hicks + * + * Class for managing household and person object data read from + * synthetic population files. + */ +public class HouseholdDataManagerRmi + implements HouseholdDataManagerIf, Serializable +{ + + UtilRmi remote; + String connectString; + + public HouseholdDataManagerRmi(String hostname, int port, String className) + { + + connectString = String.format("//%s:%d/%s", hostname, port, className); + remote = new UtilRmi(connectString); + + } + + public void setPropertyFileValues(HashMap propertyMap) + { + Object[] objArray = {propertyMap}; + remote.method("setPropertyFileValues", objArray); + } + + public void setDebugHhIdsFromHashmap() + { + Object[] objArray = {}; + remote.method("setDebugHhIdsFromHashmap", objArray); + } + + public void setupHouseholdDataManager(ModelStructure modelStructure, + String inputHouseholdFileName, String inputPersonFileName) + { + Object[] objArray = {modelStructure, inputHouseholdFileName, inputPersonFileName}; + remote.method("setupHouseholdDataManager", objArray); + } + + public void setSchoolDistrictMappings(HashMap segmentNameIndexMap, + int[] mgraGsDist, int[] mgraHsDist, HashMap gsDistSegMap, + HashMap hsDistSegMap) + { + Object[] objArray = {segmentNameIndexMap, mgraGsDist, mgraHsDist, gsDistSegMap, + hsDistSegMap}; + remote.method("setSchoolDistrictMappings", objArray); + } + + public void computeTransponderChoiceTazPercentArrays() + { + Object[] objArray = {}; + remote.method("computeTransponderChoiceTazPercentArrays", objArray); + } + + public double[] getPercentHhsIncome100Kplus() + { + Object[] objArray = {}; + return (double[]) remote.method("getPercentHhsIncome100Kplus", objArray); + } + + public double[] getPercentHhsMultipleAutos() + { + Object[] objArray = {}; + return (double[]) remote.method("getPercentHhsMultipleAutos", objArray); + } + + public void logPersonSummary() + { + Object[] objArray = {}; + remote.method("logPersonSummary", objArray); + } + + public int getArrayIndex(int hhId) + { + Object[] objArray = {hhId}; + return (Integer) remote.method("getArrayIndex", objArray); + } + + public int[] getWorksAtHomeBySegment(HashMap segmentValueIndexMap) + { + Object[] objArray = {segmentValueIndexMap}; + return (int[]) remote.method("getWorksAtHomeBySegment", objArray); + } + + public int[][] getWorkToursByDestMgra(HashMap segmentValueIndexMap) + { + Object[] objArray = {segmentValueIndexMap}; + return (int[][]) remote.method("getWorkToursByDestMgra", objArray); + } + + public int[][] getSchoolToursByDestMgra() + { + Object[] objArray = {}; + return (int[][]) remote.method("getSchoolToursByDestMgra", objArray); + } + + public int[][] getWorkersByHomeMgra(HashMap segmentValueIndexMap) + { + Object[] objArray = {segmentValueIndexMap}; + return (int[][]) remote.method("getWorkersByHomeMgra", objArray); + } + + public int[][] getStudentsByHomeMgra() + { + Object[] objArray = {}; + return (int[][]) remote.method("getStudentsByHomeMgra", objArray); + } + + public int[][] getTourPurposePersonsByHomeMgra(String[] purposeList) + { + Object[] objArray = {purposeList}; + return (int[][]) remote.method("getTourPurposePersonsByHomeMgra", objArray); + } + + public int[] getIndividualNonMandatoryToursByHomeMgra(String purposeString) + { + Object[] objArray = {purposeString}; + return (int[]) remote.method("getIndividualNonMandatoryToursByHomeMgra", objArray); + } + + public int[] getJointToursByHomeMgra(String purposeString) + { + Object[] objArray = {purposeString}; + return (int[]) remote.method("getJointToursByHomeMgra", objArray); + } + + public int[] getAtWorkSubtoursByWorkMgra(String purposeString) + { + Object[] objArray = {purposeString}; + return (int[]) remote.method("getAtWorkSubtoursByWorkMgra", objArray); + } + + public String testRemote() + { + Object[] objArray = {}; + return (String) remote.method("testRemote", objArray); + } + + public void mapTablesToHouseholdObjects() + { + Object[] objArray = {}; + remote.method("mapTablesToHouseholdObjects", objArray); + } + + public void writeResultData() + { + Object[] objArray = {}; + remote.method("writeResultData", objArray); + } + + public int[] getRandomOrderHhIndexArray(int numHhs) + { + Object[] objArray = {numHhs}; + return (int[]) remote.method("getRandomOrderHhIndexArray", objArray); + } + + /** + * set the hh id for which debugging info from choice models applied to this + * household will be logged if debug logging. + */ + public void setDebugHouseholdId(int debugHhId, boolean value) + { + Object[] objArray = {debugHhId, value}; + remote.method("setDebugHouseholdId", objArray); + } + + /** + * Sets the HashSet used to trace households for debug purposes and sets the + * debug switch for each of the listed households. Also sets + */ + public void setTraceHouseholdSet() + { + Object[] objArray = {}; + remote.method("setTraceHouseholdSet", objArray); + } + + public void setHouseholdSampleRate(float sampleRate, int sampleSeed) + { + Object[] objArray = {sampleRate, sampleSeed}; + remote.method("setHouseholdSampleRate", objArray); + } + + public void resetUwslRandom(int iter) + { + Object[] objArray = {iter}; + remote.method("resetUwslRandom", objArray); + } + + public void resetPreAoRandom() + { + Object[] objArray = {}; + remote.method("resetPreAoRandom", objArray); + } + + public void setUwslRandomCount(int iter) + { + Object[] objArray = {iter}; + remote.method("setUwslRandomCount", objArray); + } + + public void resetAoRandom(int iter) + { + Object[] objArray = {iter}; + remote.method("resetAoRandom", objArray); + } + + public void resetFpRandom() + { + Object[] objArray = {}; + remote.method("resetFpRandom", objArray); + } + + public void resetCdapRandom() + { + Object[] objArray = {}; + remote.method("resetCdapRandom", objArray); + } + + public void resetImtfRandom() + { + Object[] objArray = {}; + remote.method("resetImtfRandom", objArray); + } + + public void resetImtodRandom() + { + Object[] objArray = {}; + remote.method("resetImtodRandom", objArray); + } + + public void resetAwfRandom() + { + Object[] objArray = {}; + remote.method("resetAwfRandom", objArray); + } + + public void resetAwlRandom() + { + Object[] objArray = {}; + remote.method("resetAwlRandom", objArray); + } + + public void resetAwtodRandom() + { + Object[] objArray = {}; + remote.method("resetAwtodRandom", objArray); + } + + public void resetJtfRandom() + { + Object[] objArray = {}; + remote.method("resetJtfRandom", objArray); + } + + public void resetJtlRandom() + { + Object[] objArray = {}; + remote.method("resetJtlRandom", objArray); + } + + public void resetJtodRandom() + { + Object[] objArray = {}; + remote.method("resetJtodRandom", objArray); + } + + public void resetInmtfRandom() + { + Object[] objArray = {}; + remote.method("resetInmtfRandom", objArray); + } + + public void resetInmtlRandom() + { + Object[] objArray = {}; + remote.method("resetInmtlRandom", objArray); + } + + public void resetInmtodRandom() + { + Object[] objArray = {}; + remote.method("resetInmtodRandom", objArray); + } + + public void resetStfRandom() + { + Object[] objArray = {}; + remote.method("resetStfRandom", objArray); + } + + public void resetStlRandom() + { + Object[] objArray = {}; + remote.method("resetStlRandom", objArray); + } + + /** + * return the array of Household objects holding the synthetic population + * and choice model outcomes. + * + * @return hhs + */ + public Household[] getHhArray() + { + Object[] objArray = {}; + return (Household[]) remote.method("getHhArray", objArray); + } + + public Household[] getHhArray(int first, int last) + { + Object[] objArray = {first, last}; + return (Household[]) remote.method("getHhArray", objArray); + } + + public void setHhArray(Household[] hhs) + { + Object[] objArray = {hhs}; + remote.method("setHhArray", objArray); + } + + public void setHhArray(Household[] tempHhs, int startIndex) + { + Object[] objArray = {tempHhs, startIndex}; + remote.method("setHhArray", objArray); + } + + /** + * return the array of Household objects holding the synthetic population + * and choice model outcomes. + * + * @return hhs + */ + public int[] getHhIndexArray() + { + Object[] objArray = {}; + return (int[]) remote.method("getHhIndexArray", objArray); + } + + /** + * return the number of household objects read from the synthetic + * population. + * + * @return number of households in synthetic population + */ + public int getNumHouseholds() + { + Object[] objArray = {}; + return (Integer) remote.method("getNumHouseholds", objArray); + } + + /** + * set walk segment (0-none, 1-short, 2-long walk to transit access) for the + * origin for this tour + */ + public int getInitialOriginWalkSegment(int taz, double randomNumber) + { + Object[] objArray = {taz, randomNumber}; + return (Integer) remote.method("getInitialOriginWalkSegment", objArray); + } + + public long getBytesUsedByHouseholdArray() + { + Object[] objArray = {}; + return (Long) remote.method("getBytesUsedByHouseholdArray", objArray); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataWriter.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataWriter.java new file mode 100644 index 0000000..4a304b6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdDataWriter.java @@ -0,0 +1,1871 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.sql.Connection; +import java.sql.PreparedStatement; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.LinkedList; +import java.util.List; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesDMU; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +// import com.pb.common.util.ObjectUtil; + +/** + * @author crf
+ * Started: Dec 31, 2008 11:46:36 AM + */ +public class HouseholdDataWriter +{ + + private transient Logger logger = Logger.getLogger(HouseholdDataWriter.class); + + private static final String PROPERTIES_HOUSEHOLD_DATA_FILE = "Results.HouseholdDataFile"; + private static final String PROPERTIES_PERSON_DATA_FILE = "Results.PersonDataFile"; + private static final String PROPERTIES_INDIV_TOUR_DATA_FILE = "Results.IndivTourDataFile"; + private static final String PROPERTIES_JOINT_TOUR_DATA_FILE = "Results.JointTourDataFile"; + private static final String PROPERTIES_INDIV_TRIP_DATA_FILE = "Results.IndivTripDataFile"; + private static final String PROPERTIES_JOINT_TRIP_DATA_FILE = "Results.JointTripDataFile"; + + private static final String PROPERTIES_HOUSEHOLD_TABLE = "Results.HouseholdTable"; + private static final String PROPERTIES_PERSON_TABLE = "Results.PersonTable"; + private static final String PROPERTIES_INDIV_TOUR_TABLE = "Results.IndivTourTable"; + private static final String PROPERTIES_JOINT_TOUR_TABLE = "Results.JointTourTable"; + private static final String PROPERTIES_INDIV_TRIP_TABLE = "Results.IndivTripTable"; + private static final String PROPERTIES_JOINT_TRIP_TABLE = "Results.JointTripTable"; + + private static final String PROPERTIES_WRITE_LOGSUMS = "Results.WriteLogsums"; + + private static final int NUM_WRITE_PACKETS = 2000; + + private final String intFormat = "%d"; + private final String floatFormat = "%f"; + private final String doubleFormat = "%f"; + private final String fileStringFormat = "%s"; + private final String databaseStringFormat = "'%s'"; + private String stringFormat = fileStringFormat; + + private boolean saveUtilsProbsFlag = false; + private boolean writeLogsums = false; + private int setNA = -1; + + + private HashMap rbMap; + + private MandatoryAccessibilitiesDMU dmu; + private UtilityExpressionCalculator autoSkimUEC; + private IndexValues iv; + private MgraDataManager mgraManager; + + private ModelStructure modelStructure; + private int iteration; + + private HashMap purposeIndexNameMap; + + public HouseholdDataWriter(HashMap rbMap, ModelStructure modelStructure, + int iteration) + { + logger.info("Writing data structures to files."); + this.modelStructure = modelStructure; + this.iteration = iteration; + this.rbMap = rbMap; + + // create a UEC to get highway distance traveled for tours + String uecFileName = rbMap.get("acc.mandatory.uec.file"); + int dataPage = Integer.parseInt(rbMap.get("acc.mandatory.data.page")); + int autoSkimPage = Integer.parseInt(rbMap.get("acc.mandatory.auto.page")); + File uecFile = new File(uecFileName); + dmu = new MandatoryAccessibilitiesDMU(); + autoSkimUEC = new UtilityExpressionCalculator(uecFile, autoSkimPage, dataPage, rbMap, dmu); + iv = new IndexValues(); + mgraManager = MgraDataManager.getInstance(rbMap); + + purposeIndexNameMap = this.modelStructure.getIndexPrimaryPurposeNameMap(); + + // default is to not save the tour mode choice utils and probs for each + // tour + String saveUtilsProbsString = rbMap + .get(CtrampApplication.PROPERTIES_SAVE_TOUR_MODE_CHOICE_UTILS); + if (saveUtilsProbsString != null) + { + if (saveUtilsProbsString.equalsIgnoreCase("true")) saveUtilsProbsFlag = true; + } + + String writeLogsumsString = rbMap.get(PROPERTIES_WRITE_LOGSUMS); + writeLogsums = Boolean.valueOf(writeLogsumsString); + + } + + // NOTE - this method should not be called simultaneously with the file one + // one + // as the string format is changed + public void writeDataToDatabase(HouseholdDataManagerIf householdData, String dbFileName) + { + logger.info("Writing data structures to database."); + long t = System.currentTimeMillis(); + stringFormat = databaseStringFormat; + writeData(householdData, new DatabaseDataWriter(dbFileName)); + float delta = ((Long) (System.currentTimeMillis() - t)).floatValue() / 60000.0f; + logger.info("Finished writing data structures to database (" + delta + " minutes)."); + } + + // NOTE - this method should not be called simultaneously with the database + // one + // one as the string format is changed + public void writeDataToFiles(HouseholdDataManagerIf householdData) + { + logger.info("Writing data structures to csv file."); + stringFormat = fileStringFormat; + FileDataWriter fdw = new FileDataWriter(); + writeData(householdData, fdw); + } + + private void writeData(HouseholdDataManagerIf householdDataManager, DataWriter writer) + { + int hhid = 0; + int persNum = 0; + int tourid = 0; + try + { + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + long maxSize = 0; + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (Household hh : householdArray) + { + if (hh == null) continue; + hhid = hh.getHhId(); + + // long size = ObjectUtil.sizeOf(hh); + // if (size > maxSize) maxSize = size; + + writer.writeHouseholdData(formHouseholdDataEntry(hh)); + for (Person p : hh.getPersons()) + { + if (p == null) continue; + persNum = p.getPersonNum(); + + writer.writePersonData(formPersonDataEntry(p)); + for (Tour t : p.getListOfWorkTours()) + writeIndivTourData(t, writer); + for (Tour t : p.getListOfSchoolTours()) + writeIndivTourData(t, writer); + for (Tour t : p.getListOfIndividualNonMandatoryTours()) + writeIndivTourData(t, writer); + for (Tour t : p.getListOfAtWorkSubtours()) + writeIndivTourData(t, writer); + } + Tour[] jointTours = hh.getJointTourArray(); + if (jointTours != null) for (Tour t : jointTours) + { + if (t == null) continue; + writeJointTourData(t, writer); + } + } + } + + // logger.info("max size for all Household objects after writing output files is " + // + maxSize + " bytes."); + + } catch (RuntimeException e) + { + logger.error(String.format("error writing hh=%d, persNum=%d", hhid, persNum), e); + throw new RuntimeException(); + } finally + { + writer.finishActions(); + } + } + + private void writeIndivTourData(Tour t, DataWriter writer) + { + writer.writeIndivTourData(formIndivTourDataEntry(t)); + + Stop[] outboundStops = t.getOutboundStops(); + if (outboundStops != null) + { + for (int i = 0; i < outboundStops.length; i++) + { + writer.writeIndivTripData(formIndivTripDataEntry(outboundStops[i])); + } + } else + { + writer.writeIndivTripData(formTourAsIndivTripDataEntry(t, false)); + } + + Stop[] inboundStops = t.getInboundStops(); + if (inboundStops != null) + { + for (Stop s : inboundStops) + writer.writeIndivTripData(formIndivTripDataEntry(s)); + } else + { + writer.writeIndivTripData(formTourAsIndivTripDataEntry(t, true)); + } + + } + + private void writeJointTourData(Tour t, DataWriter writer) + { + writer.writeJointTourData(formJointTourDataEntry(t)); + + Stop[] outboundStops = t.getOutboundStops(); + if (outboundStops != null) + { + for (Stop s : outboundStops) + writer.writeJointTripData(formJointTripDataEntry(s)); + } else + { + writer.writeJointTripData(formTourAsJointTripDataEntry(t, false)); + } + + Stop[] inboundStops = t.getInboundStops(); + if (inboundStops != null) + { + for (Stop s : inboundStops) + writer.writeJointTripData(formJointTripDataEntry(s)); + } else + { + writer.writeJointTripData(formTourAsJointTripDataEntry(t, true)); + } + + } + + private String string(int value) + { + return String.format(intFormat, value); + } + + private String string(float value) + { + return String.format(floatFormat, value); + } + + private String string(double value) + { + return String.format(doubleFormat, value); + } + + private String string(String value) + { + return String.format(stringFormat, value); + } + + private List formHouseholdColumnNames() + { + List data = new LinkedList(); + data.add("hh_id"); + data.add("home_mgra"); + data.add("income"); + data.add("autos"); + data.add("HVs"); + data.add("AVs"); + data.add("transponder"); + data.add("cdap_pattern"); + data.add("out_escort_choice"); + data.add("inb_escort_choice"); + data.add("jtf_choice"); + + if(writeLogsums){ + data.add("aoLogsum"); + data.add("transponderLogsum"); + data.add("cdapLogsum"); + data.add("jtfLogsum"); + } + + return data; + } + + private List formHouseholdColumnTypes() + { + List data = new LinkedList(); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + + if(writeLogsums){ + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + } + return data; + } + + private List formHouseholdDataEntry(Household hh) + { + List data = new LinkedList(); + data.add(string(hh.getHhId())); + data.add(string(hh.getHhMgra())); + data.add(string(hh.getIncomeInDollars())); + data.add(string(hh.getAutosOwned())); + data.add(string(hh.getConventionalVehicles())); + data.add(string(hh.getAutomatedVehicles())); + data.add(string(hh.getTpChoice())); + data.add(string(hh.getCoordinatedDailyActivityPattern())); + data.add(string(hh.getOutboundEscortChoice())); + data.add(string(hh.getInboundEscortChoice())); + data.add(string(hh.getJointTourFreqChosenAlt())); + + if(writeLogsums){ + data.add(string(hh.getAutoOwnershipLogsum())); + data.add(string(hh.getTransponderLogsum())); + data.add(string(hh.getCdapLogsum())); + data.add(string(hh.getJtfLogsum())); + } + return data; + } + + private List formPersonColumnNames() + { + List data = new LinkedList(); + data.add("hh_id"); + data.add("person_id"); + data.add("person_num"); + data.add("age"); + data.add("gender"); + data.add("type"); + data.add("value_of_time"); + data.add("activity_pattern"); + data.add("imf_choice"); + data.add("inmf_choice"); + data.add("fp_choice"); + data.add("reimb_pct"); + data.add("tele_choice"); + data.add("ie_choice"); + data.add("timeFactorWork"); + data.add("timeFactorNonWork"); + + if(writeLogsums){ + data.add("wfhLogsum"); + data.add("wlLogsum"); + data.add("slLogsum"); + data.add("fpLogsum"); + data.add("tcLogsum"); + data.add("ieLogsum"); + data.add("cdapLogsum"); + data.add("imtfLogsum"); + data.add("inmtfLogsum"); + } + + return data; + } + + private List formPersonColumnTypes() + { + List data = new LinkedList(); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + + if(writeLogsums){ + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + + } + return data; + } + + private List formPersonDataEntry(Person p) + { + List data = new LinkedList(); + data.add(string(p.getHouseholdObject().getHhId())); + data.add(string(p.getPersonId())); + data.add(string(p.getPersonNum())); + data.add(string(p.getAge())); + data.add(string(p.getPersonIsMale() == 1 ? "m" : "f")); + data.add(string(p.getPersonType())); + data.add(string(p.getValueOfTime())); + data.add(string(p.getCdapActivity())); + data.add(string(p.getImtfChoice())); + data.add(string(p.getInmtfChoice())); + data.add(string(p.getFreeParkingAvailableResult())); + data.add(string(p.getParkingReimbursement())); + data.add(string(p.getTelecommuteChoice())); + data.add(string(p.getInternalExternalTripChoiceResult())); + data.add(string(p.getTimeFactorWork())); + data.add(string(p.getTimeFactorNonWork())); + + if(writeLogsums){ + data.add(string(p.getWorksFromHomeLogsum())); + data.add(string(p.getWorkLocationLogsum())); + data.add(string(p.getSchoolLocationLogsum())); + data.add(string(p.getParkingProvisionLogsum())); + data.add(string(p.getTelecommuteLogsum())); + data.add(string(p.getIeLogsum())); + data.add(string(p.getCdapLogsum())); + data.add(string(p.getImtfLogsum())); + data.add(string(p.getInmtfLogsum())); + + } + return data; + } + + private List formIndivTourColumnNames() + { + List data = new LinkedList(); + data.add("hh_id"); + data.add("person_id"); + data.add("person_num"); + data.add("person_type"); + data.add("tour_id"); + data.add("tour_category"); + data.add("tour_purpose"); + data.add("orig_mgra"); + data.add("dest_mgra"); + data.add("start_period"); + data.add("end_period"); + data.add("tour_mode"); + data.add("av_avail"); + data.add("tour_distance"); + data.add("atWork_freq"); + data.add("num_ob_stops"); + data.add("num_ib_stops"); + data.add("valueOfTime"); + + data.add("escort_type_out"); + data.add("escort_type_in"); + data.add("driver_num_out"); + data.add("driver_num_in"); + + if (saveUtilsProbsFlag) + { + int numModeAlts = modelStructure.getMaxTourModeIndex(); + for (int i = 1; i <= numModeAlts; i++) + { + String colName = String.format("util_%d", i); + data.add(colName); + } + + for (int i = 1; i <= numModeAlts; i++) + { + String colName = String.format("prob_%d", i); + data.add(colName); + } + } + + if(writeLogsums){ + data.add("timeOfDayLogsum"); + data.add("tourModeLogsum"); + data.add("subtourFreqLogsum"); + data.add("tourDestinationLogsum"); + data.add("stopFreqLogsum"); + + int numStopAlts = modelStructure.MAX_STOPS_PER_DIRECTION; + for(int i = 1; i<= numStopAlts;++i){ + String colName = String.format("outStopDCLogsum_%d", i); + data.add(colName); + } + for(int i = 1; i<= numStopAlts;++i){ + String colName = String.format("inbStopDCLogsum_%d", i); + data.add(colName); + } + } + + return data; + } + + private List formJointTourColumnNames() + { + List data = new LinkedList(); + data.add("hh_id"); + data.add("tour_id"); + data.add("tour_category"); + data.add("tour_purpose"); + data.add("tour_composition"); + data.add("tour_participants"); + data.add("orig_mgra"); + data.add("dest_mgra"); + data.add("start_period"); + data.add("end_period"); + data.add("tour_mode"); + data.add("av_avail"); + data.add("tour_distance"); + data.add("num_ob_stops"); + data.add("num_ib_stops"); + data.add("valueOfTime"); + + if (saveUtilsProbsFlag) + { + int numModeAlts = modelStructure.getMaxTourModeIndex(); + for (int i = 1; i <= numModeAlts; i++) + { + String colName = String.format("util_%d", i); + data.add(colName); + } + + for (int i = 1; i <= numModeAlts; i++) + { + String colName = String.format("prob_%d", i); + data.add(colName); + } + } + if(writeLogsums){ + data.add("timeOfDayLogsum"); + data.add("tourModeLogsum"); + data.add("subtourFreqLogsum"); + data.add("tourDestinationLogsum"); + data.add("stopFreqLogsum"); + + int numStopAlts = modelStructure.MAX_STOPS_PER_DIRECTION; + for(int i = 1; i<= numStopAlts;++i){ + String colName = String.format("outStopDCLogsum_%d", i); + data.add(colName); + } + for(int i = 1; i<= numStopAlts;++i){ + String colName = String.format("inbStopDCLogsum_%d", i); + data.add(colName); + } + } + + return data; + } + + private List formIndivTourColumnTypes() + { + List data = new LinkedList(); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + + if (saveUtilsProbsFlag) + { + int numModeAlts = modelStructure.getMaxTourModeIndex(); + for (int i = 1; i <= numModeAlts; i++) + { + data.add(SqliteDataTypes.REAL); + } + + for (int i = 1; i <= numModeAlts; i++) + { + data.add(SqliteDataTypes.REAL); + } + } + if(writeLogsums){ + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + + int numStopAlts = modelStructure.MAX_STOPS_PER_DIRECTION; + for(int i = 1; i<= numStopAlts;++i){ + data.add(SqliteDataTypes.REAL); + } + for(int i = 1; i<= numStopAlts;++i){ + data.add(SqliteDataTypes.REAL); + } + } + + + return data; + } + + private List formJointTourColumnTypes() + { + List data = new LinkedList(); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + + if (saveUtilsProbsFlag) + { + int numModeAlts = modelStructure.getMaxTourModeIndex(); + for (int i = 1; i <= numModeAlts; i++) + { + data.add(SqliteDataTypes.REAL); + } + + for (int i = 1; i <= numModeAlts; i++) + { + data.add(SqliteDataTypes.REAL); + } + } + + if(writeLogsums){ + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + + int numStopAlts = modelStructure.MAX_STOPS_PER_DIRECTION; + for(int i = 1; i<= numStopAlts;++i){ + data.add(SqliteDataTypes.REAL); + } + for(int i = 1; i<= numStopAlts;++i){ + data.add(SqliteDataTypes.REAL); + } + } + return data; + } + + private List formIndivTourDataEntry(Tour t) + { + + List data = new LinkedList(); + data.add(string(t.getHhId())); + data.add(string(t.getPersonObject().getPersonId())); + data.add(string(t.getPersonObject().getPersonNum())); + data.add(string(t.getPersonObject().getPersonTypeNumber())); + data.add(string(t.getTourId())); + data.add(string(t.getTourCategory())); + data.add(string(t.getTourPurpose())); + data.add(string(t.getTourOrigMgra())); + data.add(string(t.getTourDestMgra())); + data.add(string(t.getTourDepartPeriod())); + data.add(string(t.getTourArrivePeriod())); + data.add(string(t.getTourModeChoice())); + data.add(string(t.getUseOwnedAV() ? 1 : 0)); + data.add(string(calculateDistancesForAllMgras(t.getTourOrigMgra(), t.getTourDestMgra()))); + data.add(string(t.getSubtourFreqChoice())); + data.add(string(t.getNumOutboundStops() == 0 ? 0 : t.getNumOutboundStops() - 1)); + data.add(string(t.getNumInboundStops() == 0 ? 0 : t.getNumInboundStops() - 1)); + data.add(string(t.getValueOfTime())); + + data.add(string(t.getEscortTypeOutbound())); + data.add(string(t.getEscortTypeInbound())); + data.add(string(t.getDriverPnumOutbound())); + data.add(string(t.getDriverPnumInbound())); + + if (saveUtilsProbsFlag) + { + int numModeAlts = modelStructure.getMaxTourModeIndex(); + float[] utils = t.getTourModalUtilities(); + + if (utils != null){ + + for (int i = 0; i < utils.length; i++) + data.add(string(utils[i])); + for (int i = utils.length; i < numModeAlts; i++) + data.add("-999"); + + }else{ + for(int i =0;i outboundStopDCLogsums = t.getOutboundStopDestinationLogsums(); + for(int i = 0; i inboundStopDCLogsums = t.getInboundStopDestinationLogsums(); + for(int i = 0; i formJointTourDataEntry(Tour t) + { + List data = new LinkedList(); + data.add(string(t.getHhId())); + data.add(string(t.getTourId())); + data.add(string(t.getTourCategory())); + data.add(string(t.getTourPurpose())); + data.add(string(t.getJointTourComposition())); + data.add(string(formTourParticipationEntry(t))); + data.add(string(t.getTourOrigMgra())); + data.add(string(t.getTourDestMgra())); + data.add(string(t.getTourDepartPeriod())); + data.add(string(t.getTourArrivePeriod())); + data.add(string(t.getTourModeChoice())); + data.add(string(t.getUseOwnedAV() ? 1 : 0)); + data.add(string(calculateDistancesForAllMgras(t.getTourOrigMgra(), t.getTourDestMgra()))); + data.add(string(t.getNumOutboundStops() == 0 ? 0 : t.getNumOutboundStops() - 1)); + data.add(string(t.getNumInboundStops() == 0 ? 0 : t.getNumInboundStops() - 1)); + data.add(string(t.getValueOfTime())); + + if (saveUtilsProbsFlag) + { + int numModeAlts = modelStructure.getMaxTourModeIndex(); + float[] utils = t.getTourModalUtilities(); + + int dummy = 0; + if (utils == null) dummy = 1; + + for (int i = 0; i < utils.length; i++) + data.add(string(utils[i])); + for (int i = utils.length; i < numModeAlts; i++) + data.add("-999"); + + float[] probs = t.getTourModalProbabilities(); + for (int i = 0; i < probs.length; i++) + data.add(string(probs[i])); + for (int i = probs.length; i < numModeAlts; i++) + data.add("0.0"); + } + + if(writeLogsums){ + data.add(string(t.getTimeOfDayLogsum())); + data.add(string(t.getTourModeLogsum())); + data.add(string(t.getSubtourFreqLogsum())); + data.add(string(t.getTourDestinationLogsum())); + data.add(string(t.getStopFreqLogsum())); + + int numStopAlts = modelStructure.MAX_STOPS_PER_DIRECTION; + ArrayList outboundStopDCLogsums = t.getOutboundStopDestinationLogsums(); + for(int i = 0; i inboundStopDCLogsums = t.getInboundStopDestinationLogsums(); + for(int i = 0; i formIndivTripColumnNames() + { + List data = new LinkedList(); + data.add("hh_id"); + data.add("person_id"); + data.add("person_num"); + data.add("tour_id"); + data.add("stop_id"); + data.add("inbound"); + data.add("tour_purpose"); + data.add("orig_purpose"); + data.add("dest_purpose"); + data.add("orig_mgra"); + data.add("dest_mgra"); + data.add("parking_mgra"); + data.add("stop_period"); + data.add("trip_mode"); + data.add("av_avail"); + data.add("trip_board_tap"); + data.add("trip_alight_tap"); + data.add("set"); + data.add("tour_mode"); + data.add("driver_pnum"); + data.add("orig_escort_stoptype"); + data.add("orig_escortee_pnum"); + data.add("dest_escort_stoptype"); + data.add("dest_escortee_pnum"); + data.add("valueOfTime"); + data.add("transponder_avail"); + data.add("micro_walkMode"); + data.add("micro_trnAcc"); + data.add("micro_trnEgr"); + data.add("parkingCost"); + + if(writeLogsums) { + data.add("tripModeLogsum"); + data.add("microWalkModeLogsum"); + data.add("microTrnAccLogsum"); + data.add("microTrnEgrLogsum"); + } + return data; + } + + private List formJointTripColumnNames() + { + List data = new LinkedList(); + data.add("hh_id"); + data.add("tour_id"); + data.add("stop_id"); + data.add("inbound"); + data.add("tour_purpose"); + data.add("orig_purpose"); + data.add("dest_purpose"); + data.add("orig_mgra"); + data.add("dest_mgra"); + data.add("parking_mgra"); + data.add("stop_period"); + data.add("trip_mode"); + data.add("av_avail"); + data.add("num_participants"); + data.add("trip_board_tap"); + data.add("trip_alight_tap"); + data.add("set"); + data.add("tour_mode"); + data.add("valueOfTime"); + data.add("transponder_avail"); + //wsu remove micromobility columns, not applicable to joint trips + //data.add("micro_walkMode"); + //data.add("micro_trnAcc"); + //data.add("micro_trnEgr"); + data.add("parkingCost"); + + if(writeLogsums) { + data.add("tripModeLogsum"); + data.add("microWalkModeLogsum"); + data.add("microTrnAccLogsum"); + data.add("microTrnEgrLogsum"); + } + + return data; + } + + private List formIndivTripColumnTypes() + { + List data = new LinkedList(); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + + if(writeLogsums) { + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + } + return data; + } + + private List formJointTripColumnTypes() + { + List data = new LinkedList(); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.TEXT); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.INTEGER); + data.add(SqliteDataTypes.REAL); + + if(writeLogsums) { + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + data.add(SqliteDataTypes.REAL); + } + return data; + } + + private List formIndivTripDataEntry(Stop s) + { + Tour t = s.getTour(); + Household h = t.getPersonObject().getHouseholdObject(); + + List data = new LinkedList(); + data.add(string(t.getHhId())); + data.add(string(t.getPersonObject().getPersonId())); + data.add(string(t.getPersonObject().getPersonNum())); + data.add(string(t.getTourId())); + data.add(string(s.getStopId())); + data.add(string(s.isInboundStop() ? 1 : 0)); + data.add(string(t.getTourPurpose())); + + if (s.getStopId() == 0) + { + if (s.isInboundStop()) + { + // first trip on inbound half-tour with stops + data.add(s.getOrigPurpose()); + data.add(s.getDestPurpose()); + data.add(string(t.getTourDestMgra())); + data.add(string(s.getDest())); + } else + { + // first trip on outbound half-tour with stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add("Work"); + data.add(s.getDestPurpose()); + } else + { + data.add("Home"); + data.add(s.getDestPurpose()); + } + data.add(string(t.getTourOrigMgra())); + data.add(string(s.getDest())); + } + } else if (s.isInboundStop() && s.getStopId() == t.getNumInboundStops() - 1) + { + // last trip on inbound half-tour with stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add(s.getOrigPurpose()); + data.add("Work"); + } else + { + data.add(s.getOrigPurpose()); + data.add("Home"); + } + data.add(string(s.getOrig())); + data.add(string(t.getTourOrigMgra())); + } else if (!s.isInboundStop() && s.getStopId() == t.getNumOutboundStops() - 1) + { + // last trip on outbound half-tour with stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add(s.getOrigPurpose()); + data.add(t.getTourPurpose()); + } else + { + data.add(s.getOrigPurpose()); + data.add(t.getTourPurpose()); + } + data.add(string(s.getOrig())); + data.add(string(t.getTourDestMgra())); + } else + { + data.add(s.getOrigPurpose()); + data.add(s.getDestPurpose()); + data.add(string(s.getOrig())); + data.add(string(s.getDest())); + } + + data.add(string(s.getPark())); + data.add(string(s.getStopPeriod())); + data.add(string(s.getMode())); + data.add(string(t.getUseOwnedAV() ? 1 : 0)); + data.add(string(s.getBoardTap())); + data.add(string(s.getAlightTap())); + int set = setNA; + if(modelStructure.getTripModeIsTransit(s.getMode())) { + set = s.getSet(); + } + data.add(string(set)); + data.add(string(t.getTourModeChoice())); + data.add(string(s.isInboundStop() ? t.getDriverPnumInbound() : t.getDriverPnumOutbound())); + data.add(string(s.getEscortStopTypeOrig())); + data.add(string(s.getEscorteePnumOrig())); + data.add(string(s.getEscortStopTypeDest())); + data.add(string(s.getEscorteePnumDest())); + data.add(string(s.getValueOfTime())); + data.add(string(h.getTpChoice())); + data.add(string(s.getMicromobilityWalkMode())); + data.add(string(s.getMicromobilityAccessMode())); + data.add(string(s.getMicromobilityEgressMode())); + data.add(string(s.getParkingCost())); + + if(writeLogsums) { + data.add(string(s.getModeLogsum())); + data.add(string(s.getMicromobilityWalkLogsum())); + data.add(string(s.getMicromobilityAccessLogsum())); + data.add(string(s.getMicromobilityEgressLogsum())); + + } + return data; + } + + private List formJointTripDataEntry(Stop s) + { + Tour t = s.getTour(); + Household h = t.getPersonObject().getHouseholdObject(); + List data = new LinkedList(); + data.add(string(t.getHhId())); + data.add(string(t.getTourId())); + data.add(string(s.getStopId())); + data.add(string(s.isInboundStop() ? 1 : 0)); + data.add(string(t.getTourPurpose())); + + if (s.getStopId() == 0) + { + if (s.isInboundStop()) + { + // first trip on inbound half-tour with stops + data.add(s.getOrigPurpose()); + data.add(s.getDestPurpose()); + } else + { + // first trip on outbound half-tour with stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add("Work"); + data.add(s.getDestPurpose()); + } else + { + data.add("Home"); + data.add(s.getDestPurpose()); + } + } + } else if (s.isInboundStop() && s.getStopId() == t.getNumInboundStops() - 1) + { + // last trip on inbound half-tour with stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add(s.getOrigPurpose()); + data.add("Work"); + } else + { + data.add(s.getOrigPurpose()); + data.add("Home"); + } + } else if (!s.isInboundStop() && s.getStopId() == t.getNumOutboundStops() - 1) + { + // last trip on outbound half-tour with stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add(s.getOrigPurpose()); + data.add(t.getTourPurpose()); + } else + { + data.add(s.getOrigPurpose()); + data.add(t.getTourPurpose()); + } + } else + { + data.add(s.getOrigPurpose()); + data.add(s.getDestPurpose()); + } + + data.add(string(s.getOrig())); + data.add(string(s.getDest())); + data.add(string(s.getPark())); + data.add(string(s.getStopPeriod())); + data.add(string(s.getMode())); + data.add(string(t.getUseOwnedAV() ? 1 : 0)); + + int[] participants = t.getPersonNumArray(); + if (participants == null) + { + logger.error("tour participants array is null, hhid=" + t.getHhId() + "."); + throw new RuntimeException(); + } + if (participants.length < 2) + { + logger.error("length of tour participants array is not null, but is < 2; should be >= 2 for joint tour, hhid=" + + t.getHhId() + "."); + throw new RuntimeException(); + } + + data.add(string(participants.length)); + data.add(string(s.getBoardTap())); + data.add(string(s.getAlightTap())); + int set = setNA; + if(modelStructure.getTripModeIsTransit(s.getMode())) { + set = s.getSet(); + } + data.add(string(set)); + data.add(string(t.getTourModeChoice())); + data.add(string(s.getValueOfTime())); + data.add(string(h.getTpChoice())); + //wsu, remove micromobility columns, not applicable to joint trips + //data.add(string(s.getMicromobilityWalkMode())); + //data.add(string(s.getMicromobilityAccessMode())); + //data.add(string(s.getMicromobilityEgressMode())); + data.add(string(s.getParkingCost())); + + if(writeLogsums) { + data.add(string(s.getModeLogsum())); + data.add(string(s.getMicromobilityWalkLogsum())); + data.add(string(s.getMicromobilityAccessLogsum())); + data.add(string(s.getMicromobilityEgressLogsum())); + + } + + + if(writeLogsums) + data.add(string(s.getModeLogsum())); + + return data; + } + + private List formTourAsIndivTripDataEntry(Tour t, boolean inbound) + { + List data = new LinkedList(); + Household h = t.getPersonObject().getHouseholdObject(); + + data.add(string(t.getHhId())); + data.add(string(t.getPersonObject().getPersonId())); + data.add(string(t.getPersonObject().getPersonNum())); + data.add(string(t.getTourId())); + data.add(string(-1)); + data.add(string((inbound ? 1 : 0))); + data.add(string(t.getTourPurpose())); + + if (inbound) + { + // inbound trip on half-tour with no stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add(t.getTourPurpose()); + data.add("Work"); + } else + { + data.add(t.getTourPurpose()); + data.add("Home"); + } + } else + { + // outbound trip on half-tour with no stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add("Work"); + data.add(t.getTourPurpose()); + } else + { + data.add("Home"); + data.add(t.getTourPurpose()); + } + } + + data.add(string((inbound ? t.getTourDestMgra() : t.getTourOrigMgra()))); + data.add(string((inbound ? t.getTourOrigMgra() : t.getTourDestMgra()))); + data.add(string(t.getTourParkMgra())); + data.add(string(0)); + data.add(string(inbound ? t.getTourArrivePeriod() : t.getTourDepartPeriod())); + data.add(string(t.getTourModeChoice())); + data.add(string(t.getUseOwnedAV() ? 1 : 0)); + data.add(string(inbound ? t.getDriverPnumInbound() : t.getDriverPnumOutbound())); + + /* //outbound chauffeured school tour no stops; origin stop type and escortee is zero, dest stop type is dropoff, escortee is pnum. + if(!inbound && t.getTourPurpose().equals("School") && t.getDriverPnumOutbound()>0){ + + data.add(string(0)); + data.add(string(0)); + data.add(string(ModelStructure.ESCORT_STOP_TYPE_DROPOFF)); + data.add(string(t.getPersonObject().getPersonNum())); + + }else if(inbound && t.getTourPurpose().equals("School") && t.getDriverPnumInbound()>0){ + + data.add(string(ModelStructure.ESCORT_STOP_TYPE_PICKUP)); + data.add(string(t.getPersonObject().getPersonNum())); + data.add(string(0)); + data.add(string(0)); + }else + */ + if (!inbound && t.getDriverPnumOutbound()>0){ //outbound + data.add(string(0)); //origin = home + data.add(string(0)); //origin = home + Stop[] stops = t.getInboundStops(); //there must be stops in inbound direction + int stopType = stops[0].getEscortStopTypeOrig(); //first inbound stop + int pnum = stops[0].getEscorteePnumOrig(); //first inbound stop + data.add(string(stopType)); //destination + data.add(string(pnum)); //destination + }else if (inbound && t.getDriverPnumInbound()>0){ //inbound + Stop[] stops = t.getOutboundStops(); + int stopType = stops[stops.length-1].getEscortStopTypeOrig(); //last outbound stop + int pnum = stops[stops.length-1].getEscorteePnumOrig(); //last outbound stop + data.add(string(stopType)); //origin + data.add(string(pnum)); //origin + data.add(string(0)); //destination = home + data.add(string(0)); //destination = home + } + else{ + data.add(string(0)); + data.add(string(0)); + data.add(string(0)); + data.add(string(0)); + } + + data.add(string(t.getTourModeChoice())); + + /* if(true){logger.error("Trying to write a tour as a trip"); + + logger.info("HHID: " +t.getHhId()); + logger.info("PERSNUM: "+ t.getPersonObject().getPersonNum()); + logger.info("TOURID: "+t.getTourId()); + logger.info(inbound ? "inbound" : "outbound"); + } + */ + + data.add(string(t.getValueOfTime())); + data.add(string(h.getTpChoice())); + + if(writeLogsums) + data.add(string(t.getTourModeLogsum())); + + return data; + } + + private List formTourAsJointTripDataEntry(Tour t, boolean inbound) + { + List data = new LinkedList(); + data.add(string(t.getHhId())); + data.add(string(t.getTourId())); + data.add(string(-1)); + data.add(string((inbound ? 1 : 0))); + data.add(string(t.getTourPurpose())); + + if (inbound) + { + // inbound trip on half-tour with no stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add(t.getTourPurpose()); + data.add("Work"); + } else + { + data.add(t.getTourPurpose()); + data.add("Home"); + } + } else + { + // outbound trip on half-tour with no stops + if (t.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + data.add("Work"); + data.add(t.getTourPurpose()); + } else + { + data.add("Home"); + data.add(t.getTourPurpose()); + } + } + + data.add(string((inbound ? t.getTourDestMgra() : t.getTourOrigMgra()))); + data.add(string((inbound ? t.getTourOrigMgra() : t.getTourDestMgra()))); + data.add(string(t.getTourParkMgra())); + data.add(string(inbound ? t.getTourArrivePeriod() : t.getTourDepartPeriod())); + data.add(string(t.getTourModeChoice())); + data.add(string(t.getUseOwnedAV() ? 1 : 0)); + + int[] participants = t.getPersonNumArray(); + if (participants == null) + { + logger.error("tour participants array is null, hhid=" + t.getHhId() + "."); + throw new RuntimeException(); + } + if (participants.length < 2) + { + logger.error("length of tour participants array is not null, but is < 2; should be >= 2 for joint tour, hhid=" + + t.getHhId() + "."); + throw new RuntimeException(); + } + + data.add(string(participants.length)); + data.add(string(t.getTourModeChoice())); + data.add(string(t.getValueOfTime())); + + if(writeLogsums) + data.add(string(t.getTourModeLogsum())); + + return data; + } + + private static enum SqliteDataTypes + { + INTEGER, TEXT, REAL + } + + private interface DataWriter + { + void writeHouseholdData(List data); + + void writePersonData(List data); + + void writeIndivTourData(List data); + + void writeJointTourData(List data); + + void writeIndivTripData(List data); + + void writeJointTripData(List data); + + void finishActions(); + } + + private class DatabaseDataWriter + implements DataWriter + { + private final String householdTable = rbMap.get(PROPERTIES_HOUSEHOLD_TABLE); + private final String personTable = rbMap.get(PROPERTIES_PERSON_TABLE); + private final String indivTourTable = rbMap.get(PROPERTIES_INDIV_TOUR_TABLE); + private final String jointTourTable = rbMap.get(PROPERTIES_JOINT_TOUR_TABLE); + private final String indivTripTable = rbMap.get(PROPERTIES_INDIV_TRIP_TABLE); + private final String jointTripTable = rbMap.get(PROPERTIES_JOINT_TRIP_TABLE); + private Connection connection = null; + private PreparedStatement hhPreparedStatement = null; + private PreparedStatement personPreparedStatement = null; + private PreparedStatement indivTourPreparedStatement = null; + private PreparedStatement jointTourPreparedStatement = null; + private PreparedStatement indivTripPreparedStatement = null; + private PreparedStatement jointTripPreparedStatement = null; + + public DatabaseDataWriter(String dbFileName) + { + initializeTables(dbFileName); + } + + private void initializeTables(String dbFileName) + { + Statement s = null; + try + { + connection = ConnectionHelper.getConnection(dbFileName); + s = connection.createStatement(); + s.addBatch(getTableInitializationString(householdTable, formHouseholdColumnNames(), + formHouseholdColumnTypes())); + s.addBatch(getTableInitializationString(personTable, formPersonColumnNames(), + formPersonColumnTypes())); + s.addBatch(getTableInitializationString(indivTourTable, formIndivTourColumnNames(), + formIndivTourColumnTypes())); + s.addBatch(getTableInitializationString(jointTourTable, formJointTourColumnNames(), + formJointTourColumnTypes())); + s.addBatch(getTableInitializationString(indivTripTable, formIndivTripColumnNames(), + formIndivTripColumnTypes())); + s.addBatch(getTableInitializationString(jointTripTable, formJointTripColumnNames(), + formJointTripColumnTypes())); + s.addBatch(getClearTableString(householdTable)); + s.addBatch(getClearTableString(personTable)); + s.addBatch(getClearTableString(indivTourTable)); + s.addBatch(getClearTableString(jointTourTable)); + s.addBatch(getClearTableString(indivTripTable)); + s.addBatch(getClearTableString(jointTripTable)); + s.executeBatch(); + } catch (SQLException e) + { + try + { + if (connection != null) connection.close(); + } catch (SQLException ee) + { + // swallow + } + throw new RuntimeException(e); + } finally + { + closeStatement(s); + } + setupPreparedStatements(); + } + + private void setupPreparedStatements() + { + String psStart = "INSERT INTO "; + String psMiddle = " VALUES (?"; + StringBuilder hhp = new StringBuilder(psStart); + hhp.append(householdTable).append(psMiddle); + for (int i = 1; i < formHouseholdColumnNames().size(); i++) + hhp.append(",?"); + hhp.append(");"); + StringBuilder pp = new StringBuilder(psStart); + pp.append(personTable).append(psMiddle); + for (int i = 1; i < formPersonColumnNames().size(); i++) + pp.append(",?"); + pp.append(");"); + StringBuilder itp = new StringBuilder(psStart); + itp.append(indivTourTable).append(psMiddle); + for (int i = 1; i < formIndivTourColumnNames().size(); i++) + itp.append(",?"); + itp.append(");"); + StringBuilder jtp = new StringBuilder(psStart); + jtp.append(jointTourTable).append(psMiddle); + for (int i = 1; i < formJointTourColumnNames().size(); i++) + jtp.append(",?"); + jtp.append(");"); + StringBuilder itp2 = new StringBuilder(psStart); + itp2.append(indivTripTable).append(psMiddle); + for (int i = 1; i < formIndivTripColumnNames().size(); i++) + itp2.append(",?"); + itp2.append(");"); + StringBuilder jtp2 = new StringBuilder(psStart); + jtp2.append(jointTripTable).append(psMiddle); + for (int i = 1; i < formJointTripColumnNames().size(); i++) + jtp2.append(",?"); + jtp2.append(");"); + try + { + hhPreparedStatement = connection.prepareStatement(hhp.toString()); + personPreparedStatement = connection.prepareStatement(pp.toString()); + indivTourPreparedStatement = connection.prepareStatement(itp.toString()); + jointTourPreparedStatement = connection.prepareStatement(jtp.toString()); + indivTripPreparedStatement = connection.prepareStatement(itp2.toString()); + jointTripPreparedStatement = connection.prepareStatement(jtp2.toString()); + connection.setAutoCommit(false); + } catch (SQLException e) + { + throw new RuntimeException(e); + } + } + + private String getTableInitializationString(String table, List columns, + List types) + { + StringBuilder sb = new StringBuilder("CREATE TABLE IF NOT EXISTS "); + sb.append(table).append(" ("); + Iterator cols = columns.iterator(); + Iterator tps = types.iterator(); + sb.append(cols.next()).append(" ").append(tps.next().name()); + while (cols.hasNext()) + sb.append(",").append(cols.next()).append(" ").append(tps.next().name()); + sb.append(");"); + return sb.toString(); + } + + private String getClearTableString(String table) + { + return "DELETE FROM " + table + ";"; + } + + private void writeToTable(PreparedStatement ps, List values) + { + try + { + int counter = 1; + for (String value : values) + ps.setString(counter++, value); + ps.executeUpdate(); + } catch (SQLException e) + { + throw new RuntimeException(e); + } + } + + // private void writeToTable(String table, List values) { + // StringBuilder sb = new StringBuilder("INSERT INTO"); + // sb.append(" ").append(table).append(" VALUES("); + // Iterator vls = values.iterator(); + // sb.append(vls.next()); + // while (vls.hasNext()) + // sb.append(",").append(vls.next()); + // sb.append(");"); + // try { + // s.addBatch(sb.toString()); + // } catch (SQLException e) { + // try { + // throw new RuntimeException(e); + // } finally { + // try { + // if (s != null) + // s.close(); + // } catch (SQLException ee) { + // //swallow + // } + // try { + // if (connection != null) + // connection.close(); + // } catch (SQLException ee) { + // //swallow + // } + // } + // } + // } + + public void writeHouseholdData(List data) + { + writeToTable(hhPreparedStatement, data); + } + + public void writePersonData(List data) + { + writeToTable(personPreparedStatement, data); + } + + public void writeIndivTourData(List data) + { + writeToTable(indivTourPreparedStatement, data); + } + + public void writeJointTourData(List data) + { + writeToTable(jointTourPreparedStatement, data); + } + + public void writeIndivTripData(List data) + { + writeToTable(indivTripPreparedStatement, data); + } + + public void writeJointTripData(List data) + { + writeToTable(jointTripPreparedStatement, data); + } + + public void finishActions() + { + + try + { + connection.commit(); + } catch (SQLException e) + { + throw new RuntimeException(e); + } finally + { + closeStatement(hhPreparedStatement); + closeStatement(personPreparedStatement); + closeStatement(indivTourPreparedStatement); + closeStatement(jointTourPreparedStatement); + closeStatement(indivTripPreparedStatement); + closeStatement(jointTripPreparedStatement); + try + { + if (connection != null) connection.close(); + } catch (SQLException ee) + { + // swallow + } + } + } + + private void closeStatement(Statement s) + { + try + { + if (s != null) s.close(); + } catch (SQLException e) + { + // swallow + } + } + } + + private class FileDataWriter + implements DataWriter + { + private final PrintWriter hhWriter; + private final PrintWriter personWriter; + private final PrintWriter indivTourWriter; + private final PrintWriter jointTourWriter; + private final PrintWriter indivTripWriter; + private final PrintWriter jointTripWriter; + + public FileDataWriter() + { + String baseDir = rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + + String hhFile = formFileName(rbMap.get(PROPERTIES_HOUSEHOLD_DATA_FILE), iteration); + String personFile = formFileName(rbMap.get(PROPERTIES_PERSON_DATA_FILE), iteration); + String indivTourFile = formFileName(rbMap.get(PROPERTIES_INDIV_TOUR_DATA_FILE), + iteration); + String jointTourFile = formFileName(rbMap.get(PROPERTIES_JOINT_TOUR_DATA_FILE), + iteration); + String indivTripFile = formFileName(rbMap.get(PROPERTIES_INDIV_TRIP_DATA_FILE), + iteration); + String jointTripFile = formFileName(rbMap.get(PROPERTIES_JOINT_TRIP_DATA_FILE), + iteration); + + try + { + hhWriter = new PrintWriter(new File(baseDir + hhFile)); + personWriter = new PrintWriter(new File(baseDir + personFile)); + indivTourWriter = new PrintWriter(new File(baseDir + indivTourFile)); + jointTourWriter = new PrintWriter(new File(baseDir + jointTourFile)); + indivTripWriter = new PrintWriter(new File(baseDir + indivTripFile)); + jointTripWriter = new PrintWriter(new File(baseDir + jointTripFile)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + writeHouseholdData(formHouseholdColumnNames()); + writePersonData(formPersonColumnNames()); + writeIndivTourData(formIndivTourColumnNames()); + writeJointTourData(formJointTourColumnNames()); + writeIndivTripData(formIndivTripColumnNames()); + writeJointTripData(formJointTripColumnNames()); + } + + private String formFileName(String originalFileName, int iteration) + { + int lastDot = originalFileName.lastIndexOf('.'); + + String returnString = ""; + if (lastDot > 0) + { + String base = originalFileName.substring(0, lastDot); + String ext = originalFileName.substring(lastDot); + returnString = String.format("%s_%d%s", base, iteration, ext); + } else + { + returnString = String.format("%s_%d.csv", originalFileName, iteration); + } + + logger.info("writing household csv file to " + returnString); + + return returnString; + } + + public void writeHouseholdData(List data) + { + writeEntryToCsv(hhWriter, data); + } + + public void writePersonData(List data) + { + writeEntryToCsv(personWriter, data); + } + + public void writeIndivTourData(List data) + { + writeEntryToCsv(indivTourWriter, data); + } + + public void writeJointTourData(List data) + { + writeEntryToCsv(jointTourWriter, data); + } + + public void writeIndivTripData(List data) + { + writeEntryToCsv(indivTripWriter, data); + } + + public void writeJointTripData(List data) + { + writeEntryToCsv(jointTripWriter, data); + } + + private void writeEntryToCsv(PrintWriter pw, List data) + { + pw.println(formCsvString(data)); + } + + private String formCsvString(List data) + { + char delimiter = ','; + Iterator it = data.iterator(); + StringBuilder sb = new StringBuilder(it.next()); + while (it.hasNext()) + sb.append(delimiter).append(it.next()); + return sb.toString(); + } + + public void finishActions() + { + try + { + hhWriter.flush(); + personWriter.flush(); + indivTourWriter.flush(); + jointTourWriter.flush(); + indivTripWriter.flush(); + jointTripWriter.flush(); + } finally + { + hhWriter.close(); + personWriter.close(); + indivTourWriter.close(); + jointTourWriter.close(); + indivTripWriter.close(); + jointTripWriter.close(); + } + + } + } + + private ArrayList getWriteHouseholdRanges(int numberOfHouseholds) + { + + ArrayList startEndIndexList = new ArrayList(); + + int startIndex = 0; + int endIndex = 0; + + while (endIndex < numberOfHouseholds - 1) + { + endIndex = startIndex + NUM_WRITE_PACKETS - 1; + if (endIndex + NUM_WRITE_PACKETS > numberOfHouseholds) + endIndex = numberOfHouseholds - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += NUM_WRITE_PACKETS; + } + + return startEndIndexList; + + } + + /** + * Calculate auto skims for a given origin to all destination mgras, and + * return auto distance. + * + * @param oMgra + * The origin mgra + * @return An array of distances + */ + private double calculateDistancesForAllMgras(int oMgra, int dMgra) + { + + int oTaz = mgraManager.getTaz(oMgra); + int dTaz = mgraManager.getTaz(dMgra); + + iv.setOriginZone(oTaz); + iv.setDestZone(dTaz); + + // sov time in results[0] and distance in resuls[1] + double[] results = autoSkimUEC.solve(iv, dmu, null); + + return results[1]; + } +} + diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualMandatoryTourDepartureAndDurationTime.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualMandatoryTourDepartureAndDurationTime.java new file mode 100644 index 0000000..369b6e9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualMandatoryTourDepartureAndDurationTime.java @@ -0,0 +1,1672 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; + +import java.io.Serializable; +import java.util.*; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; +import com.pb.common.newmodel.ChoiceModelApplication; + +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + + + + + +/** + * Created by IntelliJ IDEA. User: Jim Date: Jul 11, 2008 Time: 9:25:30 AM To + * change this template use File | Settings | File Templates. + */ +public class HouseholdIndividualMandatoryTourDepartureAndDurationTime + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(HouseholdIndividualMandatoryTourDepartureAndDurationTime.class); + private transient Logger todLogger = Logger.getLogger("todLogger"); + private transient Logger tourMCManLogger = Logger.getLogger("tourMcMan"); + + private static final String IMTOD_UEC_FILE_TARGET = "departTime.uec.file"; + private static final String IMTOD_UEC_DATA_TARGET = "departTime.data.page"; + private static final String IMTOD_UEC_WORK_MODEL_TARGET = "departTime.work.page"; + private static final String IMTOD_UEC_SCHOOL_MODEL_TARGET = "departTime.school.page"; + private static final String IMTOD_UEC_UNIV_MODEL_TARGET = "departTime.univ.page"; + + private int[] workTourDepartureTimeChoiceSample; + private int[] schoolTourDepartureTimeChoiceSample; + + // DMU for the UEC + private TourDepartureTimeAndDurationDMU imtodDmuObject; + private TourModeChoiceDMU mcDmuObject; + + private String tourCategory = ModelStructure.MANDATORY_CATEGORY; + + private ModelStructure modelStructure; + + private TazDataManager tazs; + private MgraDataManager mgraManager; + + private ChoiceModelApplication workTourChoiceModel; + private ChoiceModelApplication schoolTourChoiceModel; + private ChoiceModelApplication univTourChoiceModel; + private TourModeChoiceModel mcModel; + + private boolean[] needToComputeLogsum; + private double[] modeChoiceLogsums; + + private int[] altStarts; + private int[] altEnds; + + private int noAvailableWorkWindowCount = 0; + private int noAvailableSchoolWindowCount = 0; + + private int noUsualWorkLocationForMandatoryActivity = 0; + private int noUsualSchoolLocationForMandatoryActivity = 0; + + private HashMap rbMap; + + private long mcTime; + + public HouseholdIndividualMandatoryTourDepartureAndDurationTime( + HashMap propertyMap, ModelStructure modelStructure, + String[] tourPurposeList, CtrampDmuFactoryIf dmuFactory, TourModeChoiceModel mcModel) + { + + setupHouseholdIndividualMandatoryTourDepartureAndDurationTime(propertyMap, modelStructure, + tourPurposeList, dmuFactory, mcModel); + + } + + private void setupHouseholdIndividualMandatoryTourDepartureAndDurationTime( + HashMap propertyMap, ModelStructure modelStructure, + String[] tourPurposeList, CtrampDmuFactoryIf dmuFactory, TourModeChoiceModel mcModel) + { + + logger.info(String.format("setting up %s time-of-day choice model.", tourCategory)); + + // set the model structure + this.modelStructure = modelStructure; + this.mcModel = mcModel; + rbMap = propertyMap; + + tazs = TazDataManager.getInstance(); + mgraManager = MgraDataManager.getInstance(); + + // locate the individual mandatory tour frequency choice model UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String imtodUecFile = propertyMap.get(IMTOD_UEC_FILE_TARGET); + imtodUecFile = uecPath + imtodUecFile; + + int dataPage = Util.getIntegerValueFromPropertyMap(propertyMap, IMTOD_UEC_DATA_TARGET); + int workModelPage = Util.getIntegerValueFromPropertyMap(propertyMap, + IMTOD_UEC_WORK_MODEL_TARGET); + int schoolModelPage = Util.getIntegerValueFromPropertyMap(propertyMap, + IMTOD_UEC_SCHOOL_MODEL_TARGET); + int univModelPage = Util.getIntegerValueFromPropertyMap(propertyMap, + IMTOD_UEC_UNIV_MODEL_TARGET); + + // get the dmu objects from the factory + imtodDmuObject = dmuFactory.getTourDepartureTimeAndDurationDMU(); + mcDmuObject = dmuFactory.getModeChoiceDMU(); + + // set up the models + workTourChoiceModel = new ChoiceModelApplication(imtodUecFile, workModelPage, dataPage, + propertyMap, (VariableTable) imtodDmuObject); + schoolTourChoiceModel = new ChoiceModelApplication(imtodUecFile, schoolModelPage, dataPage, + propertyMap, (VariableTable) imtodDmuObject); + univTourChoiceModel = new ChoiceModelApplication(imtodUecFile, univModelPage, dataPage, + propertyMap, (VariableTable) imtodDmuObject); + + // get the alternatives table from the work tod UEC. + TableDataSet altsTable = workTourChoiceModel.getUEC().getAlternativeData(); + altStarts = altsTable.getColumnAsInt(CtrampApplication.START_FIELD_NAME); + altEnds = altsTable.getColumnAsInt(CtrampApplication.END_FIELD_NAME); + altsTable = null; + + imtodDmuObject.setTodAlts(altStarts, altEnds); + + int numWorkDepartureTimeChoiceAlternatives = workTourChoiceModel.getNumberOfAlternatives(); + workTourDepartureTimeChoiceSample = new int[numWorkDepartureTimeChoiceAlternatives + 1]; + Arrays.fill(workTourDepartureTimeChoiceSample, 1); + + int numSchoolDepartureTimeChoiceAlternatives = schoolTourChoiceModel + .getNumberOfAlternatives(); + schoolTourDepartureTimeChoiceSample = new int[numSchoolDepartureTimeChoiceAlternatives + 1]; + Arrays.fill(schoolTourDepartureTimeChoiceSample, 1); + + int numLogsumIndices = modelStructure.getSkimPeriodCombinationIndices().length; + needToComputeLogsum = new boolean[numLogsumIndices]; + + modeChoiceLogsums = new double[numLogsumIndices]; + + } + + public void applyModel(Household household, boolean runTODChoice, boolean runModeChoice) + { + mcTime = 0; + + Logger modelLogger = todLogger; + if (household.getDebugChoiceModels()) + { + household.logHouseholdObject( + "Pre Individual Mandatory Departure Time Choice Model HHID=" + + household.getHhId(), modelLogger); + if (runModeChoice) + household.logHouseholdObject( + "Pre Individual Mandatory Tour Mode Choice Model HHID=" + + household.getHhId(), tourMCManLogger); + } + + // set the household id, origin taz, hh taz, and debugFlag=false in the + // dmu + imtodDmuObject.setHousehold(household); + + // get the array of persons for this household + Person[] personArray = household.getPersons(); + + + if(!runTODChoice) { + // loop through the persons (1-based array) + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + if (runModeChoice) + household.logPersonObject(decisionMakerLabel, tourMCManLogger, person); + } + + try { + ArrayList workTours = person.getListOfWorkTours(); + if(workTours!=null) + if(workTours.size()>0) { + for(Tour tour: workTours) { + runModeChoice(household,person,tour,tour.getTourDepartPeriod(),tour.getTourArrivePeriod()); + } + } + ArrayList schoolTours = person.getListOfSchoolTours(); + if(schoolTours!=null) + if(schoolTours.size()>0) { + for(Tour tour: schoolTours) { + runModeChoice(household,person,tour,tour.getTourDepartPeriod(),tour.getTourArrivePeriod()); + } + } + }catch(Exception e) { + logger.error(String + .format("error mandatory mode choice model for j=%d, hhId=%d, persId=%d, persNum=%d, personType=%s.", + j, person.getHouseholdObject().getHhId(), person.getPersonId(), + person.getPersonNum(), person.getPersonType())); + throw new RuntimeException(e); + + } + + } + return; + } + + // loop through the persons (1-based array) + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + person.resetTimeWindow(); + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + if (runModeChoice) + household.logPersonObject(decisionMakerLabel, tourMCManLogger, person); + } + + // mandatory tour departure time and dureation choice models for + // each + // worker/student require a specific order: + // 1. Work tours made by workers, school/university tours made by + // students. + // 2. Work tours made by students, school/university tours made by + // workers. + // TODO: check consistency of these definitions - + // TODO: workers can also be students (school-age and university)?, + // non-driving students can be workers?, + // TODO: cannot be school-age student and university? etc... + + try + { + + if (person.getPersonIsWorker() == 1) + { + applyDepartureTimeChoiceForWorkTours(person, runModeChoice); + if (person.getListOfSchoolTours().size() > 0) + { + if (person.getPersonIsUniversityStudent() == 1) + { + applyDepartureTimeChoiceForUnivTours(person, runModeChoice); + } else + { + applyDepartureTimeChoiceForSchoolTours(person, runModeChoice); + } + } + } else if (person.getPersonIsStudent() == 1 + || person.getPersonIsPreschoolChild() == 1) + { + if (person.getPersonIsUniversityStudent() == 1) + { + applyDepartureTimeChoiceForUnivTours(person, runModeChoice); + } else + { + applyDepartureTimeChoiceForSchoolTours(person, runModeChoice); + } + if (person.getListOfWorkTours().size() > 0) + applyDepartureTimeChoiceForWorkTours(person, runModeChoice); + } else + { + if (person.getListOfWorkTours().size() > 0 + || person.getListOfSchoolTours().size() > 0) + { + logger.error(String + .format("error mandatory departure time choice model for j=%d, hhId=%d, persNum=%d, personType=%s.", + j, person.getHouseholdObject().getHhId(), + person.getPersonNum(), person.getPersonType())); + logger.error(String + .format("person with type other than worker or student has %d work tours and %d school tours.", + person.getListOfWorkTours().size(), person + .getListOfSchoolTours().size())); + throw new RuntimeException(); + } + } + + } catch (Exception e) + { + logger.error(String + .format("error mandatory departure time choice model for j=%d, hhId=%d, persId=%d, persNum=%d, personType=%s.", + j, person.getHouseholdObject().getHhId(), person.getPersonId(), + person.getPersonNum(), person.getPersonType())); + throw new RuntimeException(e); + } + + } + + household.setImtodRandomCount(household.getHhRandomCount()); + + } + + /** + * + * @param person + * object for which time choice should be made + * @return the number of work tours this person had scheduled. + */ + private int applyDepartureTimeChoiceForWorkTours(Person person, boolean runModeChoice) + { + + Logger modelLogger = todLogger; + + // set the dmu object + imtodDmuObject.setPerson(person); + + Household household = person.getHouseholdObject(); + + ArrayList workTours = person.getListOfWorkTours(); + ArrayList schoolTours = person.getListOfSchoolTours(); + + for (int i = 0; i < workTours.size(); i++) + { + + Tour t = workTours.get(i); + t.setTourDepartPeriod(-1); + t.setTourArrivePeriod(-1); + + // dest taz was set from result of usual school location choice when + // tour + // object was created in mandatory tour frequency model. + // TODO: if the destMgra value is -1, then this mandatory tour was + // created for a non-student (retired probably) + // TODO: and we have to resolve this somehow - either genrate a + // work/school location for retired, or change activity type for + // person. + // TODO: for now, we'll just skip the tour, and keep count of them. + int destMgra = t.getTourDestMgra(); + if (destMgra <= 0) + { + noUsualWorkLocationForMandatoryActivity++; + continue; + } + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = String + .format("Individual Mandatory Work Tour Departure Time Choice Model for: Purpose=%s", + t.getTourPurpose()); + decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), + person.getPersonNum(), person.getPersonType(), t.getTourId(), + workTours.size()); + + workTourChoiceModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = "Individual Mandatory Work Tour Departure Time Choice Model: Debug Statement for Household ID: " + + household.getHhId() + + ", Person Num: " + + person.getPersonNum() + + ", Person Type: " + + person.getPersonType() + + ", Work Tour Id: " + + t.getTourId() + " of " + workTours.size() + " work tours."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + + } + + imtodDmuObject.setDestinationZone(destMgra); + imtodDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(t.getTourDestMgra())); + + // set the dmu object + imtodDmuObject.setTour(t); + + int origMgra = t.getTourOrigMgra(); + imtodDmuObject.setOriginZone(mgraManager.getTaz(origMgra)); + imtodDmuObject.setDestinationZone(mgraManager.getTaz(destMgra)); + + // set the choice availability and initialize sample array - + // choicemodelapplication will change sample[] according to + // availability[] + boolean[] departureTimeChoiceAvailability = person.getAvailableTimeWindows(altStarts, + altEnds); + Arrays.fill(workTourDepartureTimeChoiceSample, 1); + + if (departureTimeChoiceAvailability.length != workTourDepartureTimeChoiceSample.length) + { + logger.error(String + .format("error in work departure time choice model for hhId=%d, persId=%d, persNum=%d, work tour %d of %d.", + person.getHouseholdObject().getHhId(), person.getPersonId(), + person.getPersonNum(), i, workTours.size())); + logger.error(String + .format("length of the availability array determined by the number of alternatiuves set in the person scheduler=%d", + departureTimeChoiceAvailability.length)); + logger.error(String + .format("does not equal the length of the sample array determined by the number of alternatives in the work tour UEC=%d.", + workTourDepartureTimeChoiceSample.length)); + throw new RuntimeException(); + } + + // if no time window is available for the tour, make the first and + // last + // alternatives available + // for that alternative, and keep track of the number of times this + // condition occurs. + boolean noAlternativeAvailable = true; + for (int a = 0; a < departureTimeChoiceAvailability.length; a++) + { + if (departureTimeChoiceAvailability[a]) + { + noAlternativeAvailable = false; + break; + } + } + + if (noAlternativeAvailable) + { + noAvailableWorkWindowCount++; + departureTimeChoiceAvailability[1] = true; + departureTimeChoiceAvailability[departureTimeChoiceAvailability.length - 1] = true; + } + + // check for multiple tours for this person + // set the first or second switch if multiple tours for person + if (workTours.size() == 1 && person.getListOfSchoolTours().size() == 0) + { + // not a multiple tour pattern + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + } else if (workTours.size() > 1 && person.getListOfSchoolTours().size() == 0) + { + // Two work tour multiple tour pattern + if (i == 0) + { + // first of 2 work tours + imtodDmuObject.setFirstTour(1); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(i + 1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(1); + imtodDmuObject.setSubsequentTourIsSchool(0); + } else + { + // second of 2 work tours + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(1); + imtodDmuObject.setTourNumber(i + 1); + int otherTourArrivePeriod = workTours.get(0).getTourArrivePeriod(); + imtodDmuObject.setEndOfPreviousScheduledTour(otherTourArrivePeriod); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + + // block alternatives for this second work tour with depart + // <= first work tour departure AND arrive >= first work + // tour arrival. + for (int a = 1; a <= altStarts.length; a++) + { + // if the depart/arrive alternative is unavailable, no + // need to check to see if a logsum has been calculated + if (!departureTimeChoiceAvailability[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + if (startPeriod <= workTours.get(0).getTourDepartPeriod() + && endPeriod >= workTours.get(0).getTourArrivePeriod()) + departureTimeChoiceAvailability[a] = false; + } + } + } else if (workTours.size() == 1 && schoolTours.size() == 1) + { + // One work tour, one school tour multiple tour pattern + if (person.getPersonIsWorker() == 1) + { + // worker, so work tour is first scheduled, school tour + // comes later. + imtodDmuObject.setFirstTour(1); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(1); + + } else + { + // student, so school tour was already scheduled, this work + // tour is the second. + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(1); + imtodDmuObject.setTourNumber(i + 1); + int otherTourArrivePeriod = person.getListOfSchoolTours().get(0) + .getTourArrivePeriod(); + imtodDmuObject.setEndOfPreviousScheduledTour(otherTourArrivePeriod); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + + // block alternatives for this work tour with depart <= + // first school tour departure AND arrive >= first school + // tour arrival. + for (int a = 1; a <= altStarts.length; a++) + { + // if the depart/arrive alternative is unavailable, no + // need to check to see if a logsum has been calculated + if (!departureTimeChoiceAvailability[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + if (startPeriod <= schoolTours.get(0).getTourDepartPeriod() + && endPeriod >= schoolTours.get(0).getTourArrivePeriod()) + departureTimeChoiceAvailability[a] = false; + } + } + } + + // calculate and store the mode choice logsum for the usual work + // location + // for this worker at the various + // departure time and duration alternativees + setWorkTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(person, t, + departureTimeChoiceAvailability); + + if (household.getDebugChoiceModels()) + { + household.logTourObject(loggingHeader, modelLogger, person, t); + } + + float logsum=0; + try + { + logsum = (float) workTourChoiceModel.computeUtilities(imtodDmuObject, + imtodDmuObject.getIndexValues(), departureTimeChoiceAvailability, + workTourDepartureTimeChoiceSample); + } catch (Exception e) + { + logger.error("exception caught computing work tour TOD choice utilities."); + throw new RuntimeException(); + } + t.setTimeOfDayLogsum(logsum); + + Random hhRandom = imtodDmuObject.getDmuHouseholdObject().getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has no available alternatives, choose between + // the + // first and last alternative. + int chosen; + if (workTourChoiceModel.getAvailabilityCount() > 0) chosen = workTourChoiceModel + .getChoiceResult(rn); + else chosen = rn < 0.5 ? 1 : altStarts.length; + + // schedule the chosen alternative + int chosenStartPeriod = altStarts[chosen - 1]; + int chosenEndPeriod = altEnds[chosen - 1]; + try + { + person.scheduleWindow(chosenStartPeriod, chosenEndPeriod); + } catch (Exception e) + { + logger.error("exception caught updating work tour TOD choice time windows."); + throw new RuntimeException(); + } + + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = workTourChoiceModel.getUtilities(); + double[] probabilities = workTourChoiceModel.getProbabilities(); + boolean[] availabilities = workTourChoiceModel.getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString + + ", Tour Id: " + t.getTourId()); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("-------------------- ------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < workTourChoiceModel.getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d out=%-3d, in=%-3d", k + 1, altStarts[k], + altEnds[k]); + modelLogger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", altString, + availabilities[k + 1], utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d out=%-3d, in=%-3d", chosen, + altStarts[chosen - 1], altEnds[chosen - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + workTourChoiceModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + workTourChoiceModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, + rn, chosen); + + // write UEC calculation results to separate model specific log + // file + loggingHeader = String.format("%s %s", choiceModelDescription, decisionMakerLabel); + workTourChoiceModel.logUECResults(modelLogger, loggingHeader); + + } + + if (runModeChoice) + { + runModeChoice(household, person, t, chosenStartPeriod, chosenEndPeriod); + } + + } + + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format( + "Final Work Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + return workTours.size(); + + } + + private void runModeChoice(Household household, Person person, Tour t, int chosenStartPeriod, int chosenEndPeriod) { + + long check = System.nanoTime(); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, t, chosenStartPeriod, chosenEndPeriod); + + // use the mcModel object already setup for computing logsums + // and get + // the mode choice, where the selected + // worklocation and subzone an departure time and duration are + // set + // for this work tour. + int chosenMode = mcModel.getModeChoice(mcDmuObject, t.getTourPurpose()); + t.setTourModeChoice(chosenMode); + + mcTime += (System.nanoTime() - check); + } + + + + private void setWorkTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(Person person, + Tour tour, boolean[] altAvailable) + { + + Household household = person.getHouseholdObject(); + + Arrays.fill(needToComputeLogsum, true); + Arrays.fill(modeChoiceLogsums, -999); + + Logger modelLogger = todLogger; + String choiceModelDescription = String.format( + "Work Tour Mode Choice Logsum calculation for %s Departure Time Choice", + tour.getTourPurpose()); + String decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), person + .getPersonNum(), person.getPersonType(), tour.getTourId(), person + .getListOfWorkTours().size()); + String loggingHeader = String + .format("%s %s", choiceModelDescription, decisionMakerLabel); + + for (int a = 1; a <= altStarts.length; a++) + { + + // if the depart/arrive alternative is unavailable, no need to check + // to see if a logsum has been calculated + if (!altAvailable[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + if (needToComputeLogsum[index]) + { + + String periodString = modelStructure.getSkimMatrixPeriodString(startPeriod) + + " to " + modelStructure.getSkimMatrixPeriodString(endPeriod); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, startPeriod, endPeriod); + + if (household.getDebugChoiceModels()) + household.logTourObject(loggingHeader + ", " + periodString, modelLogger, + person, mcDmuObject.getTourObject()); + + try + { + modeChoiceLogsums[index] = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel + ", " + + periodString); + } catch (Exception e) + { + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + periodString + " work tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + throw new RuntimeException(e); + } + needToComputeLogsum[index] = false; + } + + } + + imtodDmuObject.setModeChoiceLogsums(modeChoiceLogsums); + + mcDmuObject.getTourObject().setTourDepartPeriod(0); + mcDmuObject.getTourObject().setTourArrivePeriod(0); + } + + private void setSchoolTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives( + Person person, Tour tour, boolean[] altAvailable) + { + + Household household = person.getHouseholdObject(); + + Arrays.fill(needToComputeLogsum, true); + Arrays.fill(modeChoiceLogsums, -999); + + Logger modelLogger = todLogger; + String choiceModelDescription = String.format( + "School Tour Mode Choice Logsum calculation for %s Departure Time Choice", + tour.getTourPurpose()); + String decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), person + .getPersonNum(), person.getPersonType(), tour.getTourId(), person + .getListOfSchoolTours().size()); + String loggingHeader = String + .format("%s %s", choiceModelDescription, decisionMakerLabel); + + for (int a = 1; a <= altStarts.length; a++) + { + + // if the depart/arrive alternative is unavailable, no need to check + // to see if a logsum has been calculated + if (!altAvailable[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + if (needToComputeLogsum[index]) + { + + String periodString = modelStructure.getSkimMatrixPeriodString(startPeriod) + + " to " + modelStructure.getSkimMatrixPeriodString(endPeriod); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, startPeriod, endPeriod); + + if (household.getDebugChoiceModels()) + household.logTourObject(loggingHeader + ", " + periodString, modelLogger, + person, mcDmuObject.getTourObject()); + + try + { + modeChoiceLogsums[index] = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel + ", " + + periodString); + } catch (Exception e) + { + logger.error(e); + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + periodString + " school tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + throw new RuntimeException(); + } + needToComputeLogsum[index] = false; + } + + } + + imtodDmuObject.setModeChoiceLogsums(modeChoiceLogsums); + + } + + /** + * + * @param person + * object for which time choice should be made + * @return the number of school tours this person had scheduled. + */ + private int applyDepartureTimeChoiceForSchoolTours(Person person, boolean runModeChoice) + { + + Logger modelLogger = todLogger; + + // set the dmu object + imtodDmuObject.setPerson(person); + + Household household = person.getHouseholdObject(); + + ArrayList workTours = person.getListOfWorkTours(); + ArrayList schoolTours = person.getListOfSchoolTours(); + + for (int i = 0; i < schoolTours.size(); i++) + { + + Tour t = schoolTours.get(i); + t.setTourDepartPeriod(-1); + t.setTourArrivePeriod(-1); + + // dest taz was set from result of usual school location choice when + // tour + // object was created in mandatory tour frequency model. + // TODO: if the destMgra value is -1, then this mandatory tour was + // created for a non-student (retired probably) + // TODO: and we have to resolve this somehow - either genrate a + // work/school location for retired, or change activity type for + // person. + // TODO: for now, we'll just skip the tour, and keep count of them. + int destMgra = t.getTourDestMgra(); + if (destMgra <= 0) + { + noUsualSchoolLocationForMandatoryActivity++; + continue; + } + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = String + .format("Individual Mandatory School Tour Departure Time Choice Model for: Purpose=%s", + t.getTourPurpose()); + decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), + person.getPersonNum(), person.getPersonType(), t.getTourId(), + schoolTours.size()); + + schoolTourChoiceModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = "Individual Mandatory School Tour Departure Time Choice Model: Debug Statement for Household ID: " + + household.getHhId() + + ", Person Num: " + + person.getPersonNum() + + ", Person Type: " + + person.getPersonType() + + ", Tour Id: " + + t.getTourId() + " of " + schoolTours.size() + " school tours."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + } + + imtodDmuObject.setDestinationZone(destMgra); + imtodDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(t.getTourDestMgra())); + + // set the dmu object + imtodDmuObject.setTour(t); + + int origMgra = t.getTourOrigMgra(); + imtodDmuObject.setOriginZone(mgraManager.getTaz(origMgra)); + imtodDmuObject.setDestinationZone(mgraManager.getTaz(destMgra)); + + // set the choice availability and sample + boolean[] departureTimeChoiceAvailability = person.getAvailableTimeWindows(altStarts, + altEnds); + Arrays.fill(schoolTourDepartureTimeChoiceSample, 1); + + if (departureTimeChoiceAvailability.length != schoolTourDepartureTimeChoiceSample.length) + { + logger.error(String + .format("error in school departure time choice model for hhId=%d, persId=%d, persNum=%d, school tour %d of %d.", + person.getHouseholdObject().getHhId(), person.getPersonId(), + person.getPersonNum(), i, schoolTours.size())); + logger.error(String + .format("length of the availability array determined by the number of alternatiuves set in the person scheduler=%d", + departureTimeChoiceAvailability.length)); + logger.error(String + .format("does not equal the length of the sample array determined by the number of alternatives in the school tour UEC=%d.", + schoolTourDepartureTimeChoiceSample.length)); + throw new RuntimeException(); + } + + // if no time window is available for the tour, make the first and + // last + // alternatives available + // for that alternative, and keep track of the number of times this + // condition occurs. + boolean noAlternativeAvailable = true; + for (int a = 0; a < departureTimeChoiceAvailability.length; a++) + { + if (departureTimeChoiceAvailability[a]) + { + noAlternativeAvailable = false; + break; + } + } + + if (noAlternativeAvailable) + { + noAvailableSchoolWindowCount++; + departureTimeChoiceAvailability[1] = true; + schoolTourDepartureTimeChoiceSample[1] = 1; + departureTimeChoiceAvailability[departureTimeChoiceAvailability.length - 1] = true; + schoolTourDepartureTimeChoiceSample[schoolTourDepartureTimeChoiceSample.length - 1] = 1; + } + + // check for multiple tours for this person + // set the first or second switch if multiple tours for person + if (schoolTours.size() == 1 && person.getListOfWorkTours().size() == 0) + { + // not a multiple tour pattern + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + } else if (schoolTours.size() > 1 && person.getListOfWorkTours().size() == 0) + { + // Two school tour multiple tour pattern + if (i == 0) + { + // first of 2 school tours + imtodDmuObject.setFirstTour(1); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(i + 1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(1); + } else + { + // second of 2 school tours + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(1); + imtodDmuObject.setTourNumber(i + 1); + int otherTourArrivePeriod = schoolTours.get(0).getTourArrivePeriod(); + imtodDmuObject.setEndOfPreviousScheduledTour(otherTourArrivePeriod); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + + // block alternatives for this 2nd school tour with depart + // <= first school tour departure AND arrive >= first school + // tour arrival. + for (int a = 1; a <= altStarts.length; a++) + { + // if the depart/arrive alternative is unavailable, no + // need to check to see if a logsum has been calculated + if (!departureTimeChoiceAvailability[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + if (startPeriod <= schoolTours.get(0).getTourDepartPeriod() + && endPeriod >= schoolTours.get(0).getTourArrivePeriod()) + departureTimeChoiceAvailability[a] = false; + } + } + } else if (schoolTours.size() == 1 && workTours.size() == 1) + { + // One school tour, one work tour multiple tour pattern + if (person.getPersonIsStudent() == 1) + { + // student, so school tour is first scheduled, work comes + // later. + imtodDmuObject.setFirstTour(1); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(1); + imtodDmuObject.setSubsequentTourIsSchool(0); + } else + { + // worker, so work tour was already scheduled, this school + // tour is the second. + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(1); + imtodDmuObject.setTourNumber(i + 1); + int otherTourArrivePeriod = person.getListOfWorkTours().get(0) + .getTourArrivePeriod(); + imtodDmuObject.setEndOfPreviousScheduledTour(otherTourArrivePeriod); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + + // block alternatives for this 2nd school tour with depart + // <= first work tour departure AND arrive >= first work + // tour arrival. + for (int a = 1; a <= altStarts.length; a++) + { + // if the depart/arrive alternative is unavailable, no + // need to check to see if a logsum has been calculated + if (!departureTimeChoiceAvailability[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + if (startPeriod <= workTours.get(0).getTourDepartPeriod() + && endPeriod >= workTours.get(0).getTourArrivePeriod()) + departureTimeChoiceAvailability[a] = false; + } + } + } + + // calculate and store the mode choice logsum for the usual school + // location for this student at the various + // departure time and duration alternativees + setSchoolTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(person, t, + departureTimeChoiceAvailability); + + if (household.getDebugChoiceModels()) + { + household.logTourObject(loggingHeader, modelLogger, person, t); + } + + float logsum = (float) schoolTourChoiceModel.computeUtilities(imtodDmuObject, imtodDmuObject.getIndexValues(), + departureTimeChoiceAvailability, schoolTourDepartureTimeChoiceSample); + t.setTimeOfDayLogsum(logsum); + + Random hhRandom = imtodDmuObject.getDmuHouseholdObject().getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has no available alternatives, choose between + // the + // first and last alternative. + int chosen; + if (schoolTourChoiceModel.getAvailabilityCount() > 0) chosen = schoolTourChoiceModel + .getChoiceResult(rn); + else chosen = rn < 0.5 ? 1 : altStarts.length; + + // schedule the chosen alternative + int chosenStartPeriod = altStarts[chosen - 1]; + int chosenEndPeriod = altEnds[chosen - 1]; + try + { + person.scheduleWindow(chosenStartPeriod, chosenEndPeriod); + } catch (Exception e) + { + logger.error("exception caught updating school tour TOD choice time windows."); + throw new RuntimeException(); + } + + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = schoolTourChoiceModel.getUtilities(); + double[] probabilities = schoolTourChoiceModel.getProbabilities(); + boolean[] availabilities = schoolTourChoiceModel.getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString + + ", Tour Id: " + t.getTourId()); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("-------------------- ------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < schoolTourChoiceModel.getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d out=%-3d, in=%-3d", k + 1, altStarts[k], + altEnds[k]); + modelLogger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", altString, + availabilities[k + 1], utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d out=%-3d, in=%-3d", chosen, + altStarts[chosen - 1], altEnds[chosen - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + schoolTourChoiceModel.logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + schoolTourChoiceModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, + rn, chosen); + + // write UEC calculation results to separate model specific log + // file + loggingHeader = String.format("%s %s", choiceModelDescription, decisionMakerLabel); + schoolTourChoiceModel.logUECResults(modelLogger, loggingHeader, 200); + + } + + if (runModeChoice) + { + + long check = System.nanoTime(); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, t, chosenStartPeriod, chosenEndPeriod); + + // use the mcModel object already setup for computing logsums + // and get + // the mode choice, where the selected + // school location and subzone and departure time and duration + // are + // set for this school tour. + int chosenMode = -1; + chosenMode = mcModel.getModeChoice(mcDmuObject, t.getTourPurpose()); + + t.setTourModeChoice(chosenMode); + + mcTime += (System.nanoTime() - check); + } + + } + + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String + .format("Final School Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + return schoolTours.size(); + + } + + private void setUnivTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(Person person, + Tour tour, boolean[] altAvailable) + { + + Household household = person.getHouseholdObject(); + + Arrays.fill(needToComputeLogsum, true); + Arrays.fill(modeChoiceLogsums, -999); + + Logger modelLogger = todLogger; + String choiceModelDescription = String.format( + "University Tour Mode Choice Logsum calculation for %s Departure Time Choice", + tour.getTourPurpose()); + String decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), person + .getPersonNum(), person.getPersonType(), tour.getTourId(), person + .getListOfSchoolTours().size()); + String loggingHeader = String + .format("%s %s", choiceModelDescription, decisionMakerLabel); + + for (int a = 1; a <= altStarts.length; a++) + { + + // if the depart/arrive alternative is unavailable, no need to check + // to see if a logsum has been calculated + if (!altAvailable[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + if (needToComputeLogsum[index]) + { + + String periodString = modelStructure.getSkimMatrixPeriodString(startPeriod) + + " to " + modelStructure.getSkimMatrixPeriodString(endPeriod); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, startPeriod, endPeriod); + + if (household.getDebugChoiceModels()) + household.logTourObject(loggingHeader + ", " + periodString, modelLogger, + person, mcDmuObject.getTourObject()); + + try + { + modeChoiceLogsums[index] = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel + ", " + + periodString); + } catch (Exception e) + { + logger.error(e); + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + periodString + " university tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + throw new RuntimeException(); + } + needToComputeLogsum[index] = false; + } + + } + + imtodDmuObject.setModeChoiceLogsums(modeChoiceLogsums); + + } + + /** + * + * @param person + * object for which time choice should be made + * @return the number of school tours this person had scheduled. + */ + private int applyDepartureTimeChoiceForUnivTours(Person person, boolean runModeChoice) + { + + Logger modelLogger = todLogger; + + // set the dmu object + imtodDmuObject.setPerson(person); + + Household household = person.getHouseholdObject(); + + ArrayList workTours = person.getListOfWorkTours(); + ArrayList schoolTours = person.getListOfSchoolTours(); + + for (int i = 0; i < schoolTours.size(); i++) + { + + Tour t = schoolTours.get(i); + t.setTourDepartPeriod(-1); + t.setTourArrivePeriod(-1); + + // dest taz was set from result of usual school location choice when + // tour + // object was created in mandatory tour frequency model. + // TODO: if the destMgra value is -1, then this mandatory tour was + // created for a non-student (retired probably) + // TODO: and we have to resolve this somehow - either genrate a + // work/school location for retired, or change activity type for + // person. + // TODO: for now, we'll just skip the tour, and keep count of them. + int destMgra = t.getTourDestMgra(); + if (destMgra <= 0) + { + noUsualSchoolLocationForMandatoryActivity++; + continue; + } + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = String + .format("Individual Mandatory University Tour Departure Time Choice Model for: Purpose=%s", + t.getTourPurpose()); + decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), + person.getPersonNum(), person.getPersonType(), t.getTourId(), + schoolTours.size()); + + univTourChoiceModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = "Individual Mandatory University Tour Departure Time Choice Model: Debug Statement for Household ID: " + + household.getHhId() + + ", Person Num: " + + person.getPersonNum() + + ", Person Type: " + + person.getPersonType() + + ", Tour Id: " + + t.getTourId() + " of " + schoolTours.size() + " school tours."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + } + + imtodDmuObject.setDestinationZone(destMgra); + imtodDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(t.getTourDestMgra())); + + // set the dmu object + imtodDmuObject.setTour(t); + + int origMgra = t.getTourOrigMgra(); + imtodDmuObject.setOriginZone(mgraManager.getTaz(origMgra)); + imtodDmuObject.setDestinationZone(mgraManager.getTaz(destMgra)); + + // set the choice availability and sample + boolean[] departureTimeChoiceAvailability = person.getAvailableTimeWindows(altStarts, + altEnds); + Arrays.fill(schoolTourDepartureTimeChoiceSample, 1); + + if (departureTimeChoiceAvailability.length != schoolTourDepartureTimeChoiceSample.length) + { + logger.error(String + .format("error in university departure time choice model for hhId=%d, persId=%d, persNum=%d, school tour %d of %d.", + person.getHouseholdObject().getHhId(), person.getPersonId(), + person.getPersonNum(), i, schoolTours.size())); + logger.error(String + .format("length of the availability array determined by the number of alternatives set in the person scheduler=%d", + departureTimeChoiceAvailability.length)); + logger.error(String + .format("does not equal the length of the sample array determined by the number of alternatives in the university tour UEC=%d.", + schoolTourDepartureTimeChoiceSample.length)); + throw new RuntimeException(); + } + + // if no time window is available for the tour, make the first and + // last + // alternatives available + // for that alternative, and keep track of the number of times this + // condition occurs. + boolean noAlternativeAvailable = true; + for (int a = 0; a < departureTimeChoiceAvailability.length; a++) + { + if (departureTimeChoiceAvailability[a]) + { + noAlternativeAvailable = false; + break; + } + } + + if (noAlternativeAvailable) + { + noAvailableSchoolWindowCount++; + departureTimeChoiceAvailability[1] = true; + schoolTourDepartureTimeChoiceSample[1] = 1; + departureTimeChoiceAvailability[departureTimeChoiceAvailability.length - 1] = true; + schoolTourDepartureTimeChoiceSample[schoolTourDepartureTimeChoiceSample.length - 1] = 1; + } + + // check for multiple tours for this person + // set the first or second switch if multiple tours for person + if (schoolTours.size() == 1 && person.getListOfWorkTours().size() == 0) + { + // not a multiple tour pattern + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + } else if (schoolTours.size() > 1 && person.getListOfWorkTours().size() == 0) + { + // Two school tour multiple tour pattern + if (i == 0) + { + // first of 2 school tours + imtodDmuObject.setFirstTour(1); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(i + 1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(1); + } else + { + // second of 2 school tours + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(1); + imtodDmuObject.setTourNumber(i + 1); + int otherTourArrivePeriod = schoolTours.get(0).getTourArrivePeriod(); + imtodDmuObject.setEndOfPreviousScheduledTour(otherTourArrivePeriod); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + + // block alternatives for this 2nd school tour with depart + // <= first school tour departure AND arrive >= first school + // tour arrival. + for (int a = 1; a <= altStarts.length; a++) + { + // if the depart/arrive alternative is unavailable, no + // need to check to see if a logsum has been calculated + if (!departureTimeChoiceAvailability[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + if (startPeriod <= schoolTours.get(0).getTourDepartPeriod() + && endPeriod >= schoolTours.get(0).getTourArrivePeriod()) + departureTimeChoiceAvailability[a] = false; + } + } + } else if (schoolTours.size() == 1 && workTours.size() == 1) + { + // One school tour, one work tour multiple tour pattern + if (person.getPersonIsStudent() == 1) + { + // student, so school tour is first scheduled, work comes + // later. + imtodDmuObject.setFirstTour(1); + imtodDmuObject.setSubsequentTour(0); + imtodDmuObject.setTourNumber(1); + imtodDmuObject.setEndOfPreviousScheduledTour(0); + imtodDmuObject.setSubsequentTourIsWork(1); + imtodDmuObject.setSubsequentTourIsSchool(0); + } else + { + // worker, so work tour was already scheduled, this school + // tour is the second. + imtodDmuObject.setFirstTour(0); + imtodDmuObject.setSubsequentTour(1); + imtodDmuObject.setTourNumber(i + 1); + int otherTourArrivePeriod = person.getListOfWorkTours().get(0) + .getTourArrivePeriod(); + imtodDmuObject.setEndOfPreviousScheduledTour(otherTourArrivePeriod); + imtodDmuObject.setSubsequentTourIsWork(0); + imtodDmuObject.setSubsequentTourIsSchool(0); + + // block alternatives for this 2nd school tour with depart + // <= first work tour departure AND arrive >= first work + // tour arrival. + for (int a = 1; a <= altStarts.length; a++) + { + // if the depart/arrive alternative is unavailable, no + // need to check to see if a logsum has been calculated + if (!departureTimeChoiceAvailability[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + if (startPeriod <= workTours.get(0).getTourDepartPeriod() + && endPeriod >= workTours.get(0).getTourArrivePeriod()) + departureTimeChoiceAvailability[a] = false; + } + } + } + + // calculate and store the mode choice logsum for the usual school + // location for this student at the various + // departure time and duration alternativees + setUnivTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(person, t, + departureTimeChoiceAvailability); + + if (household.getDebugChoiceModels()) + { + household.logTourObject(loggingHeader, modelLogger, person, t); + } + + float logsum = (float) univTourChoiceModel.computeUtilities(imtodDmuObject, imtodDmuObject.getIndexValues(), + departureTimeChoiceAvailability, schoolTourDepartureTimeChoiceSample); + t.setTimeOfDayLogsum(logsum); + + Random hhRandom = imtodDmuObject.getDmuHouseholdObject().getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has no available alternatives, choose between + // the + // first and last alternative. + int chosen; + if (univTourChoiceModel.getAvailabilityCount() > 0) chosen = univTourChoiceModel + .getChoiceResult(rn); + else chosen = rn < 0.5 ? 1 : altStarts.length; + + // schedule the chosen alternative + int chosenStartPeriod = altStarts[chosen - 1]; + int chosenEndPeriod = altEnds[chosen - 1]; + try + { + person.scheduleWindow(chosenStartPeriod, chosenEndPeriod); + } catch (Exception e) + { + logger.error("exception caught updating school tour TOD choice time windows."); + throw new RuntimeException(); + } + + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = univTourChoiceModel.getUtilities(); + double[] probabilities = univTourChoiceModel.getProbabilities(); + boolean[] availabilities = univTourChoiceModel.getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString + + ", Tour Id: " + t.getTourId()); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("-------------------- ------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < schoolTourChoiceModel.getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d out=%-3d, in=%-3d", k + 1, altStarts[k], + altEnds[k]); + modelLogger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", altString, + availabilities[k + 1], utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d out=%-3d, in=%-3d", chosen, + altStarts[chosen - 1], altEnds[chosen - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + univTourChoiceModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + univTourChoiceModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, + rn, chosen); + + // write UEC calculation results to separate model specific log + // file + loggingHeader = String.format("%s %s", choiceModelDescription, decisionMakerLabel); + univTourChoiceModel.logUECResults(modelLogger, loggingHeader, 200); + + } + + if (runModeChoice) + { + long check = System.nanoTime(); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, t, chosenStartPeriod, chosenEndPeriod); + + // use the mcModel object already setup for computing logsums + // and get + // the mode choice, where the selected + // school location and subzone and departure time and duration + // are + // set for this school tour. + int chosenMode = -1; + chosenMode = mcModel.getModeChoice(mcDmuObject, t.getTourPurpose()); + + t.setTourModeChoice(chosenMode); + + mcTime += (System.nanoTime() - check); + } + + } + + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String + .format("Final University Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + return schoolTours.size(); + + } + + private void setModeChoiceDmuAttributes(Household household, Person person, Tour t, + int startPeriod, int endPeriod) + { + + t.setTourDepartPeriod(startPeriod); + t.setTourArrivePeriod(endPeriod); + + // update the MC dmuObjects for this person + mcDmuObject.setHouseholdObject(household); + mcDmuObject.setPersonObject(person); + mcDmuObject.setTourObject(t); + mcDmuObject.setDmuIndexValues(household.getHhId(), t.getTourOrigMgra(), + t.getTourOrigMgra(), t.getTourDestMgra(), household.getDebugChoiceModels()); + + + + mcDmuObject.setOrigDuDen(mgraManager.getDuDenValue(t.getTourOrigMgra())); + mcDmuObject.setOrigEmpDen(mgraManager.getEmpDenValue(t.getTourOrigMgra())); + mcDmuObject.setOrigTotInt(mgraManager.getTotIntValue(t.getTourOrigMgra())); + + mcDmuObject.setDestDuDen(mgraManager.getDuDenValue(t.getTourDestMgra())); + mcDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(t.getTourDestMgra())); + mcDmuObject.setDestTotInt(mgraManager.getTotIntValue(t.getTourDestMgra())); + + mcDmuObject.setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(t + .getTourOrigMgra()))); + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager.getTaz(t + .getTourDestMgra()))); + + mcDmuObject.setOriginMgra(t.getTourOrigMgra()); + mcDmuObject.setDestMgra(t.getTourDestMgra()); + + } + + public long getModeChoiceTime() + { + return mcTime; + } + + public static void main(String[] args) + { + + // set values for these arguments so an object instance can be created + // and setup run to test integrity of UEC files before running full + // model. + HashMap propertyMap; + TourModeChoiceModel mcModel = null; + + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + ResourceBundle rb = ResourceBundle.getBundle(args[0]); + propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + } + + ModelStructure modelStructure = new SandagModelStructure(); + SandagCtrampDmuFactory dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + String[] tourPurposeList = {"White Collar", "Services", "Health", "Retail and Food", + "Blue Collar", "Military"}; + + HouseholdIndividualMandatoryTourDepartureAndDurationTime testObject = new HouseholdIndividualMandatoryTourDepartureAndDurationTime( + propertyMap, modelStructure, tourPurposeList, dmuFactory, mcModel); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualMandatoryTourFrequencyModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualMandatoryTourFrequencyModel.java new file mode 100644 index 0000000..bce9e2c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualMandatoryTourFrequencyModel.java @@ -0,0 +1,414 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +/** + * Implements an invidual mandatory tour frequency model, which selects the + * number of work, school, or work and school tours for each person who selects + * a mandatory activity. There are essentially seven separate models, one for + * each person type (full-time worker, part-time worker, university student, non + * working adults, retired, driving students, and non-driving students), except + * pre-school students. The choices are one work tour, two work tours, one + * school tour, two school tours, and one work and school tour. Availability + * arrays are defined for each person type. + * + * The UEC for the model has two additional matrix calcuation tabs, which + * computes the one-way walk distance and the round-trip auto time to work + * and/or school for the model. This allows us to compute the work and/or school + * time, by setting the DMU destination index, just using the UEC. + * + * @author D. Ory + * + */ +public class HouseholdIndividualMandatoryTourFrequencyModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(HouseholdIndividualMandatoryTourFrequencyModel.class); + private transient Logger tourFreq = Logger.getLogger("tourFreq"); + + private static final String IMTF_CONTROL_FILE_TARGET = "imtf.uec.file"; + private static final String IMTF_DATA_SHEET_TARGET = "imtf.data.page"; + private static final String IMTF_MODEL_SHEET_TARGET = "imtf.model.page"; + + private static final String MANDATORY_ACTIVITY = Definitions.MANDATORY_PATTERN; + + // model results + public static final int CHOICE_ONE_WORK = 1; + public static final int CHOICE_TWO_WORK = 2; + public static final int CHOICE_ONE_SCHOOL = 3; + public static final int CHOICE_TWO_SCHOOL = 4; + public static final int CHOICE_WORK_AND_SCHOOL = 5; + + public static final String[] CHOICE_RESULTS = {"1 Work", "2 Work", + "1 School", "2 School", "Wrk & Schl", "Worker Works At Home", "Student Works At Home", + "Worker School At Home", "Student School At Home" }; + + private IndividualMandatoryTourFrequencyDMU imtfDmuObject; + private ChoiceModelApplication choiceModelApplication; + + private AccessibilitiesTable accTable; + private MandatoryAccessibilitiesCalculator mandAcc; + + /** + * Constructor establishes the ChoiceModelApplication, which applies the + * logit model via the UEC spreadsheet, and it also establishes the UECs + * used to compute the one-way walk distance to work and/or school and the + * round-trip auto time to work and/or school. The model must be the first + * UEC tab, the one-way distance calculations must be the second UEC tab, + * round-trip time must be the third UEC tab. + * + * @param dmuObject + * is the UEC dmu object for this choice model + * @param uecFileName + * is the UEC control file name + * @param resourceBundle + * is the application ResourceBundle, from which a properties + * file HashMap will be created for the UEC + * @param tazDataManager + * is the object used to interact with the zonal data table + * @param modelStructure + * is the ModelStructure object that defines segmentation and + * other model structure relate atributes + */ + public HouseholdIndividualMandatoryTourFrequencyModel(HashMap propertyMap, + ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory, + AccessibilitiesTable accTable, MandatoryAccessibilitiesCalculator myMandAcc) + { + + setupHouseholdIndividualMandatoryTourFrequencyModel(propertyMap, modelStructure, + dmuFactory, accTable, myMandAcc); + + } + + private void setupHouseholdIndividualMandatoryTourFrequencyModel( + HashMap propertyMap, ModelStructure modelStructure, + CtrampDmuFactoryIf dmuFactory, AccessibilitiesTable myAccTable, + MandatoryAccessibilitiesCalculator myMandAcc) + { + + logger.info("setting up IMTF choice model."); + + accTable = myAccTable; + + // locate the individual mandatory tour frequency choice model UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String imtfUecFile = propertyMap.get(IMTF_CONTROL_FILE_TARGET); + imtfUecFile = uecPath + imtfUecFile; + + int dataPage = Util.getIntegerValueFromPropertyMap(propertyMap, IMTF_DATA_SHEET_TARGET); + int modelPage = Util.getIntegerValueFromPropertyMap(propertyMap, IMTF_MODEL_SHEET_TARGET); + + // get the dmu object from the factory + imtfDmuObject = dmuFactory.getIndividualMandatoryTourFrequencyDMU(); + + // set up the model + choiceModelApplication = new ChoiceModelApplication(imtfUecFile, modelPage, dataPage, + propertyMap, (VariableTable) imtfDmuObject); + + mandAcc = myMandAcc; + + } + + /** + * Applies the model for the array of households that are stored in the + * HouseholdDataManager. The results are summarized by person type. + * + * @param householdDataManager + * is the object containg the Household objects for which this + * model is to be applied. + */ + public void applyModel(Household household) + { + + Logger modelLogger = tourFreq; + if (household.getDebugChoiceModels()) + household.logHouseholdObject("Pre Individual Mandatory Tour Frequency Choice HHID=" + + household.getHhId() + " Object", modelLogger); + + int choice = -1; + + // get this household's person array + Person[] personArray = household.getPersons(); + + // set the household id, origin taz, hh taz, and debugFlag=false in the + // dmu + imtfDmuObject.setHousehold(household); + + // set the auto sufficiency dependent escort accessibility value for the + // household + String[] types = {"", "escort0", "escort1", "escort2"}; + int autoSufficiency = household.getAutoSufficiency(); + float accessibility = accTable.getAggregateAccessibility(types[autoSufficiency], + household.getHhMgra()); + imtfDmuObject.setEscortAccessibility(accessibility); + + // loop through the person array (1-based) + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + String activity = person.getCdapActivity(); + + try + { + + // only apply the model for those with mandatory activities and + // not + // preschool children + if (person.getPersonIsPreschoolChild() == 0 + && activity.equalsIgnoreCase(MANDATORY_ACTIVITY)) + { + + // set the person + imtfDmuObject.setPerson(person); + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = String + .format("Individual Mandatory Tour Frequency Choice Model:"); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s.", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + + choiceModelApplication.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = "Individual Mandatory Tour Frequency Choice Model: Debug Statement for Household ID: " + + household.getHhId() + + ", Person Num: " + + person.getPersonNum() + + ", Person Type: " + person.getPersonType() + "."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + + } + + double distance = 999.0; + double time = 999.0; + if (person.getPersonIsWorker() == 1) + { + + int workMgra = person.getWorkLocation(); + if (workMgra != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + + double[] accessibilities = mandAcc.calculateAccessibilitiesForMgraPair( + household.getHhMgra(), workMgra, + household.getDebugChoiceModels(), tourFreq); + + distance = person.getWorkLocationDistance(); + time = accessibilities[0]; // sov time + // wt time + if (accessibilities[2] > 0.0 && accessibilities[2] < time) + time = accessibilities[2]; + // dt time + if (accessibilities[3] > 0.0 && accessibilities[3] < time) + time = accessibilities[3]; + + } else + { + // no work location; skip the rest if no school + // location. + int schoolMgra = person.getUsualSchoolLocation(); + if (schoolMgra <= 0 + || schoolMgra == ModelStructure.NOT_ENROLLED_SEGMENT_INDEX) + continue; + } + + } + imtfDmuObject.setDistanceToWorkLoc(distance); + imtfDmuObject.setBestTimeToWorkLoc(time); + + distance = 999.0; + if (person.getPersonIsUniversityStudent() == 1 + || person.getPersonIsStudentDriving() == 1 + || person.getPersonIsStudentNonDriving() == 1) + { + + int schoolMgra = person.getUsualSchoolLocation(); + if (schoolMgra != ModelStructure.NOT_ENROLLED_SEGMENT_INDEX) + { + distance = person.getSchoolLocationDistance(); + } else + { + // no school location; skip the rest if no work + // location. + int workMgra = person.getWorkLocation(); + if (workMgra <= 0 + || workMgra == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + continue; + } + + } + imtfDmuObject.setDistanceToSchoolLoc(distance); + + // compute the utilities + IndexValues index = imtfDmuObject.getIndexValues(); + float logsum = (float) choiceModelApplication.computeUtilities(imtfDmuObject, index); + person.setImtfLogsum(logsum); + + // get the random number from the household + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, + // make choice. + if (choiceModelApplication.getAvailabilityCount() > 0) choice = choiceModelApplication + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught for j=%d, activity=%s, HHID=%d, no available alternatives to choose from in choiceModelApplication.", + j, activity, household.getHhId())); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = choiceModelApplication.getUtilities(); + double[] probabilities = choiceModelApplication.getProbabilities(); + + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + + person.getPersonType()); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("------------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < probabilities.length; ++k) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %10s", k + 1, CHOICE_RESULTS[k]); + modelLogger.info(String.format("%-15s%18.6e%18.6e%18.6e", altString, + utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %10s", choice, + CHOICE_RESULTS[choice - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + choiceModelApplication.logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + choiceModelApplication.logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, choice); + + // write UEC calculation results to separate model + // specific + // log file + choiceModelApplication.logUECResults(modelLogger, loggingHeader); + + } + + person.setImtfChoice(choice); + + // set the person choices + if (choice == CHOICE_ONE_WORK) + { + person.createWorkTours(1, 0, ModelStructure.WORK_PRIMARY_PURPOSE_NAME, + ModelStructure.WORK_PRIMARY_PURPOSE_INDEX); + } else if (choice == CHOICE_TWO_WORK) + { + person.createWorkTours(2, 0, ModelStructure.WORK_PRIMARY_PURPOSE_NAME, + ModelStructure.WORK_PRIMARY_PURPOSE_INDEX); + } else if (choice == CHOICE_ONE_SCHOOL) + { + if (person.getPersonIsUniversityStudent() == 1) person.createSchoolTours(1, + 0, ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME, + ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX); + else person.createSchoolTours(1, 0, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX); + } else if (choice == CHOICE_TWO_SCHOOL) + { + if (person.getPersonIsUniversityStudent() == 1) person.createSchoolTours(2, + 0, ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME, + ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX); + else person.createSchoolTours(2, 0, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX); + } else if (choice == CHOICE_WORK_AND_SCHOOL) + { + person.createWorkTours(1, 0, ModelStructure.WORK_PRIMARY_PURPOSE_NAME, + ModelStructure.WORK_PRIMARY_PURPOSE_INDEX); + if (person.getPersonIsUniversityStudent() == 1) person.createSchoolTours(1, + 0, ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME, + ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX); + else person.createSchoolTours(1, 0, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX); + } + + } else if (activity.equalsIgnoreCase(MANDATORY_ACTIVITY) + && person.getPersonIsPreschoolChild() == 1) + { + // mandatory activity if + // pre-school child with mandatory activity type is assigned + // choice = 3 (1 school tour). + choice = 3; + + person.setImtfChoice(choice); + + // get the school purpose name for a non-driving age person + // to + // use for preschool tour purpose + person.createSchoolTours(1, 0, ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX); + } + + } catch (Exception e) + { + logger.error(String.format("Exception caught for j=%d, activity=%s, HHID=%d", j, + activity, household.getHhId())); + throw new RuntimeException(); + } + + } // j (person loop) + + household.setImtfRandomCount(household.getHhRandomCount()); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualNonMandatoryTourFrequencyModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualNonMandatoryTourFrequencyModel.java new file mode 100644 index 0000000..a0cf96e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdIndividualNonMandatoryTourFrequencyModel.java @@ -0,0 +1,823 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Map; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; + +/** + * Implements an invidual mandatory tour frequency model, which selects the + * number of work, school, or work and school tours for each person who selects + * a mandatory activity. There are essentially seven separate models, one for + * each person type (full-time worker, part-time worker, university student, non + * working adults, retired, driving students, and non-driving students), except + * pre-school students. The choices are one work tour, two work tours, one + * school tour, two school tours, and one work and school tour. Availability + * arrays are defined for each person type. + * + * The UEC for the model has two additional matrix calcuation tabs, which + * computes the one-way walk distance and the round-trip auto time to work + * and/or school for the model. This allows us to compute the work and/or school + * time, by setting the DMU destination index, just using the UEC. + * + * @author D. Ory + * + */ +public class HouseholdIndividualNonMandatoryTourFrequencyModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(HouseholdIndividualNonMandatoryTourFrequencyModel.class); + private transient Logger tourFreq = Logger.getLogger("tourFreq"); + + private static final String UEC_DATA_PAGE_KEY = "inmtf.data.page"; + private static final String UEC_PERSONTYPE_1_PAGE_KEY = "inmtf.perstype1.page"; + private static final String UEC_PERSONTYPE_2_PAGE_KEY = "inmtf.perstype2.page"; + private static final String UEC_PERSONTYPE_3_PAGE_KEY = "inmtf.perstype3.page"; + private static final String UEC_PERSONTYPE_4_PAGE_KEY = "inmtf.perstype4.page"; + private static final String UEC_PERSONTYPE_5_PAGE_KEY = "inmtf.perstype5.page"; + private static final String UEC_PERSONTYPE_6_PAGE_KEY = "inmtf.perstype6.page"; + private static final String UEC_PERSONTYPE_7_PAGE_KEY = "inmtf.perstype7.page"; + private static final String UEC_PERSONTYPE_8_PAGE_KEY = "inmtf.perstype8.page"; + + private static final String HOME_ACTIVITY = Definitions.HOME_PATTERN; + + private static final String PROPERTIES_UEC_INDIV_NON_MANDATORY_TOUR_FREQ = "inmtf.uec.file"; + + private static final String PROPERTIES_TOUR_FREQUENCY_EXTENSION_PROBABILITIES_FILE = "inmtf.FrequencyExtension.ProbabilityFile"; + + private static final int AUTO_LOGSUM_INDEX = 6; + + private AccessibilitiesTable accTable; + private MandatoryAccessibilitiesCalculator mandAcc; + + private HashMap purposeIndexToNameMap; + private HashMap personTypeIndexToModelIndexMap; + + private IndividualNonMandatoryTourFrequencyDMU dmuObject; + private ChoiceModelApplication[] choiceModelApplication; + private TableDataSet alternativesTable; + + private Map tourFrequencyIncreaseProbabilityMap; + private int[] maxTourFrequencyChoiceList; + + private static String[] escortTypes = { + "", "escort0", "escort1", "escort2" }; + private static String[] shopTypes = { + "", "shop0", "shop1", "shop2" }; + private static String[] maintTypes = { + "", "maint0", "maint1", "maint2" }; + private static String[] discrTypes = { + "", "discr0", "discr1", "discr2" }; + private static String[] eatOutTypes = { + "", "eatOut0", "eatOut1", "eatOut2" }; + private static String[] visitTypes = { + "", "visit0", "visit1", "visit2" }; + + /** + * Constructor establishes the ChoiceModelApplication, which applies the + * logit model via the UEC spreadsheet, and it also establishes the UECs + * used to compute the one-way walk distance to work and/or school and the + * round-trip auto time to work and/or school. The model must be the first + * UEC tab, the one-way distance calculations must be the second UEC tab, + * round-trip time must be the third UEC tab. + * + * @param dmuObject + * is the UEC dmu object for this choice model + * @param uecFileName + * is the UEC control file name + * @param resourceBundle + * is the application ResourceBundle, from which a properties + * file HashMap will be created for the UEC + * @param tazDataManager + * is the object used to interact with the zonal data table + * @param modelStructure + * is the ModelStructure object that defines segmentation and + * other model structure relate atributes + */ + + public HouseholdIndividualNonMandatoryTourFrequencyModel(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory, AccessibilitiesTable myAccTable, + MandatoryAccessibilitiesCalculator myMandAcc) + { + + accTable = myAccTable; + mandAcc = myMandAcc; + + setUpModels(propertyMap, dmuFactory); + + } + + private void setUpModels(HashMap propertyMap, CtrampDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up %s tour frequency choice model.", + ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY)); + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String inmtfUecFile = propertyMap.get(PROPERTIES_UEC_INDIV_NON_MANDATORY_TOUR_FREQ); + String uecFileName = uecPath + inmtfUecFile; + + dmuObject = dmuFactory.getIndividualNonMandatoryTourFrequencyDMU(); + + personTypeIndexToModelIndexMap = new HashMap(); + + int dataSheet = Integer.parseInt(propertyMap.get(UEC_DATA_PAGE_KEY)); + int sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_1_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(1, sheet); + sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_2_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(2, sheet); + sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_3_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(3, sheet); + sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_4_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(4, sheet); + sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_5_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(5, sheet); + sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_6_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(6, sheet); + sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_7_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(7, sheet); + sheet = Integer.parseInt(propertyMap.get(UEC_PERSONTYPE_8_PAGE_KEY)); + personTypeIndexToModelIndexMap.put(8, sheet); + + choiceModelApplication = new ChoiceModelApplication[personTypeIndexToModelIndexMap.size() + 1]; // one + // choice + // model + // for + // each + // person + // type + // that + // has model specified; Ones indexing for + // personType. + + // set up the model + for (int i : personTypeIndexToModelIndexMap.keySet()) + choiceModelApplication[i] = new ChoiceModelApplication(uecFileName, + personTypeIndexToModelIndexMap.get(i), dataSheet, propertyMap, + (VariableTable) dmuObject); + + // the alternatives are the same for each person type; use the first + // choiceModelApplication to get its uec and from it, get the + // TableDataSet + // of alternatives + // to use to determine which tour purposes should be generated for the + // chose + // alternative. + int ftIndex = personTypeIndexToModelIndexMap.get(1); + alternativesTable = choiceModelApplication[ftIndex].getUEC().getAlternativeData(); + + // check the field names in the alternatives table; make sure the their + // order + // is as expected. + String[] fieldNames = alternativesTable.getColumnLabels(); + + // create a mapping between names used in lookup file and purpose names + // used + // in model + HashMap primaryPurposeMap = new HashMap(); + primaryPurposeMap.put(ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME, + dmuObject.TOUR_FREQ_ALTERNATIVES_FILE_ESCORT_NAME); + primaryPurposeMap.put(ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME, + dmuObject.TOUR_FREQ_ALTERNATIVES_FILE_SHOPPING_NAME); + primaryPurposeMap.put(ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME, + dmuObject.TOUR_FREQ_ALTERNATIVES_FILE_MAINT_NAME); + primaryPurposeMap.put(ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME, + dmuObject.TOUR_FREQ_ALTERNATIVES_FILE_EAT_OUT_NAME); + primaryPurposeMap.put(ModelStructure.VISITING_PRIMARY_PURPOSE_NAME, + dmuObject.TOUR_FREQ_ALTERNATIVES_FILE_VISIT_NAME); + primaryPurposeMap.put(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME, + dmuObject.TOUR_FREQ_ALTERNATIVES_FILE_DISCR_NAME); + + purposeIndexToNameMap = new HashMap(); + purposeIndexToNameMap.put(1, ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME); + purposeIndexToNameMap.put(2, ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME); + purposeIndexToNameMap.put(3, ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME); + purposeIndexToNameMap.put(4, ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME); + purposeIndexToNameMap.put(5, ModelStructure.VISITING_PRIMARY_PURPOSE_NAME); + purposeIndexToNameMap.put(6, ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME); + + if (!fieldNames[0].equalsIgnoreCase("a") && !fieldNames[0].equalsIgnoreCase("alt")) + { + logger.error("error while checking order of fields in IndividualNonMandatoryTourFrequencyModel alternatives file."); + logger.error(String + .format("first field expected to be 'a' or 'alt' (case insensitive), but %s was found instead.", + fieldNames[0])); + throw new RuntimeException(); + } else + { + + for (int i : purposeIndexToNameMap.keySet()) + { + String primaryName = purposeIndexToNameMap.get(i).trim(); + String name = primaryPurposeMap.get(primaryName).trim(); + if (!fieldNames[i].equalsIgnoreCase(name)) + { + logger.error("error while checking order of fields in IndividualNonMandatoryTourFrequencyModel alternatives file."); + logger.error(String + .format("field %d expected to be '%s' (case insensitive), but %s was found instead.", + i, name, fieldNames[i])); + throw new RuntimeException(); + } + } + } + + // load data used for tour frequency extension model + loadIndividualNonMandatoryIncreaseModelData(uecPath + + propertyMap.get(PROPERTIES_TOUR_FREQUENCY_EXTENSION_PROBABILITIES_FILE)); + + } + + /** + * Applies the model for the array of households that are stored in the + * HouseholdDataManager. The results are summarized by person type. + * + * @param householdDataManager + * is the object containg the Household objects for which this + * model is to be applied. + */ + public void applyModel(Household household) + { + + int modelIndex = -1; + int choice = -1; + String personTypeString = "Missing"; + + Logger modelLogger = tourFreq; + if (household.getDebugChoiceModels()) + household.logHouseholdObject("Pre Individual Non-Mandatory Tour Frequency Choice HHID=" + + household.getHhId() + " Object", modelLogger); + + // this will be an array with values 1 -> tours.length being the number + // of + // non-mandatory tours in each category + // this keeps it consistent with the way the alternatives are held in + // the + // alternatives file/arrays + float[] tours = null; + + // get this household's person array + Person[] personArray = household.getPersons(); + + // set the household id, origin taz, hh taz, and debugFlag=false in the + // dmu + dmuObject.setHouseholdObject(household); + + // set the auto sufficiency dependent non-mandatory accessibility values + // for + // the household + int autoSufficiency = household.getAutoSufficiency(); + dmuObject.setShopAccessibility(accTable.getAggregateAccessibility( + shopTypes[autoSufficiency], household.getHhMgra())); + dmuObject.setMaintAccessibility(accTable.getAggregateAccessibility( + maintTypes[autoSufficiency], household.getHhMgra())); + dmuObject.setEatOutAccessibility(accTable.getAggregateAccessibility( + eatOutTypes[autoSufficiency], household.getHhMgra())); + dmuObject.setVisitAccessibility(accTable.getAggregateAccessibility( + visitTypes[autoSufficiency], household.getHhMgra())); + dmuObject.setDiscrAccessibility(accTable.getAggregateAccessibility( + discrTypes[autoSufficiency], household.getHhMgra())); + dmuObject.setEscortAccessibility(accTable.getAggregateAccessibility( + escortTypes[autoSufficiency], household.getHhMgra())); + + dmuObject.setNmDcLogsum(accTable.getAggregateAccessibility("nonmotor", + household.getHhMgra())); + + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + // loop through the person array (1-based) + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + + String activity = person.getCdapActivity(); + + try + { + + // only apply the model if person does not have H daily activity + // pattern + if (!activity.equalsIgnoreCase(HOME_ACTIVITY)) + { + + // set the person + dmuObject.setPersonObject(person); + + if (household.getDebugChoiceModels()) + { + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + // set the availability array for the tour frequency model + // same number of alternatives for each person type, so use + // person type 1 to get num alts. + int numberOfAlternatives = choiceModelApplication[1].getNumberOfAlternatives(); + boolean[] availabilityArray = new boolean[numberOfAlternatives + 1]; + Arrays.fill(availabilityArray, true); + + modelIndex = personTypeIndexToModelIndexMap.get(person.getPersonTypeNumber()); + personTypeString = person.getPersonType(); + + int workMgra = person.getWorkLocation(); + double accessibility = 0.0; + if (workMgra > 0 && workMgra != ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + double[] accessibilities = mandAcc.calculateAccessibilitiesForMgraPair( + household.getHhMgra(), workMgra, household.getDebugChoiceModels(), + tourFreq); + accessibility = accessibilities[AUTO_LOGSUM_INDEX]; + } + dmuObject.setWorkAccessibility(accessibility); + + int schoolMgra = person.getUsualSchoolLocation(); + accessibility = 0.0; + if (schoolMgra > 0 && schoolMgra != ModelStructure.NOT_ENROLLED_SEGMENT_INDEX) + { + double[] accessibilities = mandAcc.calculateAccessibilitiesForMgraPair( + household.getHhMgra(), schoolMgra, + household.getDebugChoiceModels(), tourFreq); + accessibility = accessibilities[AUTO_LOGSUM_INDEX]; + } + dmuObject.setSchoolAccessibility(accessibility); + + // person.computeIdapResidualWindows(); + + // create the sample array + int[] sampleArray = new int[availabilityArray.length]; + Arrays.fill(sampleArray, 1); + + // compute the utilities + dmuObject.setDmuIndexValues(household.getHhId(), household.getHhTaz(), + household.getHhTaz(), -1); + + if (household.getDebugChoiceModels()) + { + + // write debug header + choiceModelDescription = String + .format("Individual Non-Mandatory Tour Frequency Orignal Choice Model:"); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType()); + choiceModelApplication[modelIndex].choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = choiceModelDescription + " for " + decisionMakerLabel + + "."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + } + + float logsum = (float) choiceModelApplication[modelIndex].computeUtilities(dmuObject, + dmuObject.getDmuIndexValues(), availabilityArray, sampleArray); + person.setInmtfLogsum(logsum); + + // get the random number from the household + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, + // make choice. + if (choiceModelApplication[modelIndex].getAvailabilityCount() > 0) choice = choiceModelApplication[modelIndex] + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught for j=%d, activity=%s, HHID=%d, no Non-Mandatory Tour Frequency alternatives available to choose from in choiceModelApplication.", + j, activity, person.getHouseholdObject().getHhId())); + throw new RuntimeException(); + } + + // create the non-mandatory tour objects for the choice + // made. + // createIndividualNonMandatoryTours ( person, choice ); + tours = runIndividualNonMandatoryToursIncreaseModel(person, choice); + createIndividualNonMandatoryTours_new(person, tours); + + // debug output + if (household.getDebugChoiceModels()) + { + + String[] alternativeNames = choiceModelApplication[modelIndex] + .getAlternativeNames(); + double[] utilities = choiceModelApplication[modelIndex].getUtilities(); + double[] probabilities = choiceModelApplication[modelIndex] + .getProbabilities(); + + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + + personTypeString); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("--------------------------------------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < alternativeNames.length; k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %-66s", k + 1, + getAlternativeNameFromChoice(k + 1)); + modelLogger.info(String.format("%-72s%18.6e%18.6e%18.6e", altString, + utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %s", choice, + getAlternativeNameFromChoice(choice)); + modelLogger.info(String.format( + "Original Choice: %s, with rn=%.8f, randomCount=%d", altString, rn, + randomCount)); + + altString = String.format("%-3d %s", choice, + getAlternativeNameFromModifiedChoice(tours)); + modelLogger.info(String.format("Revised Choice After Increase: %s", + altString)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + choiceModelApplication[modelIndex].logAlternativesInfo( + choiceModelDescription, decisionMakerLabel); + choiceModelApplication[modelIndex].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, choice); + + loggingHeader = choiceModelDescription + " for " + decisionMakerLabel; + + // write UEC calculation results to separate model + // specific + // log file + choiceModelApplication[modelIndex] + .logUECResults(modelLogger, loggingHeader); + + } + + person.setInmtfChoice(choice); + + } + + } catch (Exception e) + { + logger.error(String.format("Exception caught for j=%d, activity=%s, HHID=%d", j, + activity, household.getHhId())); + throw new RuntimeException(e); + } + + } // j (person loop) + + household.setInmtfRandomCount(household.getHhRandomCount()); + + } + + private String getAlternativeNameFromChoice(int choice) + { + + // use the 1s based choice value as the table row number + float[] rowValues = alternativesTable.getRowValues(choice); + + String altName = ""; + + // rowValues is a 0s based indexed array, but the first field is the + // alternative number, + // and subsequent fields indicate the number of tours to be generated + // for the + // purpose corresponding to the field. + for (int i = 1; i < rowValues.length; i++) + { + + int numTours = (int) rowValues[i]; + if (numTours == 0) continue; + + String purposeName = purposeIndexToNameMap.get(i); + if (altName.length() == 0) altName = String.format(", %d %s", numTours, purposeName); + else altName += String.format(", %d %s", numTours, purposeName); + } + + if (altName.length() == 0) altName = "no tours"; + + return altName; + } + + private String getAlternativeNameFromModifiedChoice(float[] rowValues) + { + + String altName = ""; + + // rowValues is a 0s based indexed array, but the first field is the + // alternative number, + // and subsequent fields indicate the nuimber of tours to be generated + // for + // the purpose corresponding to the field. + for (int i = 1; i < rowValues.length; i++) + { + + int numTours = (int) rowValues[i]; + if (numTours == 0) continue; + + String purposeName = purposeIndexToNameMap.get(i); + if (altName.length() == 0) altName = String.format(", %d %s", numTours, purposeName); + else altName += String.format(", %d %s", numTours, purposeName); + } + + if (altName.length() == 0) altName = "no tours"; + + return altName; + } + + /** + * Logs the results of the model. + * + * public void logResults(){ + * + * logger.info(" "); logger.info( + * "~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~" + * ); logger.info("Individual Non-Mandatory Tour Frequency Model Results"); + * + * // count of model results logger.info(" "); String firstHeader = + * "Person type "; String secondHeader = + * "----------------------------- "; + * + * + * + * String[] purposeNames = alternativesTable.getColumnLabels(); int[] + * columnTotals = new int[purposeNames.length-1]; + * + * for( int i=0; i < columnTotals.length; i++ ) { firstHeader += + * String.format("%12s", purposeNames[i+1]); secondHeader += "----------- "; + * } + * + * firstHeader += String.format("%12s","Total"); secondHeader += + * "-----------"; + * + * logger.info(firstHeader); logger.info(secondHeader); + * + * + * + * int lineTotal = 0; for(int i=0;i(); + TableDataSet probabilityTable; + try + { + probabilityTable = (new CSVFileReader().readFile(new File(filePath))); + } catch (IOException e) + { + logger.error( + "Exception caught reading Individual Non-Mandatory Tour Frequency extension probability table.", + e); + throw new RuntimeException(e); + } + + String personTypeColumnName = "person_type"; + String mandatoryTourParticipationColumnName = "mandatory_tour"; + String jointTourParticipationColumnName = "joint_tour"; + String nonMandatoryTourTypeColumn = "nonmandatory_tour_type"; + String zeroAdditionalToursColumnName = "0_tours"; + String oneAdditionalToursColumnName = "1_tours"; + String twoAdditionalToursColumnName = "2_tours"; + + for (int i = 1; i <= probabilityTable.getRowCount(); i++) + { + int key = getTourIncreaseTableKey( + (int) probabilityTable.getValueAt(i, nonMandatoryTourTypeColumn), + (int) probabilityTable.getValueAt(i, personTypeColumnName), + ((int) probabilityTable.getValueAt(i, mandatoryTourParticipationColumnName)) == 1, + ((int) probabilityTable.getValueAt(i, jointTourParticipationColumnName)) == 1); + tourFrequencyIncreaseProbabilityMap.put(key, + new float[] {probabilityTable.getValueAt(i, zeroAdditionalToursColumnName), + probabilityTable.getValueAt(i, oneAdditionalToursColumnName), + probabilityTable.getValueAt(i, twoAdditionalToursColumnName)}); + } + } + + private float[] runIndividualNonMandatoryToursIncreaseModel(Person person, int choice) + { + // use the 1s based choice value as the table row number + // rowValues is a 0s based indexed array, but the first field is the + // alternative number, + // and subsequent fields indicate the nuimber of tours to be generated + // for + // the purpose corresponding to the field. + + Household household = person.getHouseholdObject(); + + int personType = person.getPersonTypeNumber(); + boolean participatedInMandatoryTour = person.getListOfWorkTours().size() > 0 + || person.getListOfSchoolTours().size() > 0; + + boolean participatedInJointTour = false; + Tour[] jointTours = person.getHouseholdObject().getJointTourArray(); + if (jointTours != null) + { + for (Tour t : jointTours) + { + if (t.getPersonInJointTour(person)) + { + participatedInJointTour = true; + break; + } + } + } + + float[] rowValues = null; + + boolean notDone = true; + while (notDone) + { + + rowValues = alternativesTable.getRowValues(choice); + + int firstCount = tourCountSum(rowValues); + if (firstCount == 0 || firstCount >= 5) // if 0 or 5+ tours already, + // we + // are done + break; + + for (int i = 1; i < rowValues.length; i++) + { + + if (rowValues[i] < maxTourFrequencyChoiceList[i]) continue; + + int newChoice = -1; + int key = getTourIncreaseTableKey(i, personType, participatedInMandatoryTour, + participatedInJointTour); + float[] probabilities = tourFrequencyIncreaseProbabilityMap.get(key); + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + for (int j = 0; j < probabilities.length; j++) + { + if (rn <= probabilities[j]) + { + rowValues[i] += j; + newChoice = j; + break; + } + } + + // debug output + if (household.getDebugChoiceModels()) + { + + Logger modelLogger = tourFreq; + String[] alternativeNames = {"no additional", "1 additional", "2 additional"}; + + modelLogger + .info("Individual Non-Mandatory Tour Frequency Increase Choice for tour purposeName=" + + purposeIndexToNameMap.get(i) + ", purposeIndex=" + i); + modelLogger.info("Alternative Probability CumProb"); + modelLogger.info("--------------- -------------- --------------"); + + // probabilities array has tour frequency extension + // probabilities alread stored as cumulative probabilities. + // calculate alternative probabilities from cumulative for + // logging. + double prob = probabilities[0]; + double cumProb = probabilities[0]; + for (int k = 1; k < alternativeNames.length; k++) + { + cumProb = probabilities[k]; + prob = probabilities[k] - probabilities[k - 1]; + String altString = String.format("%-3d %-15s", k + 1, alternativeNames[k]); + modelLogger.info(String.format("%-20s%18.6e%18.6e", altString, prob, + cumProb)); + } + + modelLogger.info(String.format("choice: %s, with rn=%.8f, randomCount=%d", + newChoice + 1, rn, randomCount)); + + modelLogger.info(""); + modelLogger.info(""); + + } + + } + notDone = tourCountSum(rowValues) > 5; + } + + return rowValues; + } + + private int tourCountSum(float[] tours) + { + // tours are located in indices 1 -> tours.length + int sum = 0; + for (int i = 1; i < tours.length; i++) + sum += tours[i]; + return sum; + } + + private int getTourIncreaseTableKey(int nonMandatoryTourType, int personType, + boolean participatedInMandatoryTour, boolean participatedInJointTour) + { + return nonMandatoryTourType + 100 * personType + 10000 + * (participatedInMandatoryTour ? 1 : 0) + 100000 + * (participatedInJointTour ? 1 : 0); + } + + private void createIndividualNonMandatoryTours_new(Person person, float[] tours) + { + // person.clearIndividualNonMandatoryToursArray(); + + for (int i = 1; i < tours.length; i++) + { + int numTours = (int) tours[i]; + if (numTours > 0) + person.createIndividualNonMandatoryTours(numTours, purposeIndexToNameMap.get(i)); + } + } + + // private void createIndividualNonMandatoryTours ( Person person, int + // choice ) { + // + // // use the 1s based choice value as the table row number + // float[] rowValues = alternativesTable.getRowValues( choice ); + // + // // rowValues is a 0s based indexed array, but the first field is the + // alternative number, + // // and subsequent fields indicate the nuimber of tours to be generated + // for the + // purpose corresponding to the field. + // for ( int i=1; i < rowValues.length; i++ ) { + // + // int numTours = (int)rowValues[i]; + // if ( numTours == 0 ) + // continue; + // + // String purposeName = purposeIndexToNameMap.get(i); + // + // person.createIndividualNonMandatoryTours( numTours, i, purposeName ); + // } + // + // } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdValidator.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdValidator.java new file mode 100644 index 0000000..9b6d466 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/HouseholdValidator.java @@ -0,0 +1,82 @@ +package org.sandag.abm.ctramp; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagTourBasedModel; + +public class HouseholdValidator +{ + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + + public static boolean vailidateWorkLocChoices(Household hh) + { + boolean result = true; + + for (int j = 1; j <= hh.getHhSize(); j++) + { + Person p = hh.getPerson(j); + int windex = p.getWorkLocationSegmentIndex(); + int wmgra = p.getWorkLocation(); + if (windex != -1 && wmgra == 0) + { + result = false; + logger.info("Invalid work location choice for " + p.getPersonId() + " a " + + p.getAge() + " years old with work segment index " + + p.getWorkLocationSegmentIndex() + " resubmitting job......"); + break; + } + } + return result; + } + + public static boolean vailidateSchoolLocChoices(Household hh) + { + boolean result = true; + + for (int j = 1; j <= hh.getHhSize(); j++) + { + Person p = hh.getPerson(j); + int sindex = p.getSchoolLocationSegmentIndex(); + int smgra = p.getPersonSchoolLocationZone(); + if (sindex != -1 && smgra == 0) + { + result = false; + logger.fatal("Invalid school location choice for " + p.getPersonId() + " a " + + p.getAge() + " years old with school segment index " + + p.getSchoolLocationSegmentIndex() + " resubmitting job....."); + break; + } + } + return result; + } + + public static boolean validateMandatoryDestinationChoices(Household[] householdArray, + String type) + { + boolean result = true; + if (type.equalsIgnoreCase("work")) + { + for (int i = 0; i < householdArray.length; i++) + { + if (!vailidateWorkLocChoices(householdArray[i])) + { + result = false; + break; + } + } + } else if (type.equalsIgnoreCase("school")) + { + for (int i = 0; i < householdArray.length; i++) + { + if (!vailidateSchoolLocChoices(householdArray[i])) + { + result = false; + break; + } + } + } else + { + logger.fatal("invalide mandatory destination choice type:" + type); + } + return result; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/IndividualMandatoryTourFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/IndividualMandatoryTourFrequencyDMU.java new file mode 100644 index 0000000..6098701 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/IndividualMandatoryTourFrequencyDMU.java @@ -0,0 +1,301 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class IndividualMandatoryTourFrequencyDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(IndividualMandatoryTourFrequencyDMU.class); + + protected HashMap methodIndexMap; + + protected IndexValues dmuIndex; + protected Household household; + protected Person person; + + protected double walkDistanceToWork, walkDistanceToSchool; + protected double roundTripAutoTimeToWork, roundTripAutoTimeToSchool; + + protected double distanceToWork; + protected double timeToWork; + protected double distanceToSchool; + protected double escortAccessibility; + + private int homeTazAreaType; + + public IndividualMandatoryTourFrequencyDMU() + { + dmuIndex = new IndexValues(); + } + + public IndexValues getIndexValues() + { + return dmuIndex; + } + + public void setHousehold(Household passedInHousehold) + { + household = passedInHousehold; + + // set the origin and zone indices + dmuIndex.setOriginZone(household.getHhMgra()); + dmuIndex.setZoneIndex(household.getHhMgra()); + dmuIndex.setHHIndex(household.getHhId()); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (household.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug IMTF UEC"); + } + + } + + public void setHomeTazAreaType(int at) + { + homeTazAreaType = at; + } + + public void setDestinationZone(int destinationZone) + { + dmuIndex.setDestZone(destinationZone); + } + + public void setPerson(Person passedInPerson) + { + person = passedInPerson; + } + + public void setDistanceToWorkLoc(double distance) + { + distanceToWork = distance; + } + + public void setBestTimeToWorkLoc(double time) + { + timeToWork = time; + } + + public void setDistanceToSchoolLoc(double distance) + { + distanceToSchool = distance; + } + + public void setEscortAccessibility(double accessibility) + { + escortAccessibility = accessibility; + } + + public double getDistanceToWorkLocation() + { + return distanceToWork; + } + + public double getBestTimeToWorkLocation() + { + return timeToWork; + } + + public double getDistanceToSchoolLocation() + { + return distanceToSchool; + } + + public double getEscortAccessibility() + { + return escortAccessibility; + } + + public int getFullTimeWorker() + { + return (person.getPersonTypeIsFullTimeWorker()); + } + + public int getPartTimeWorker() + { + return (person.getPersonTypeIsPartTimeWorker()); + } + + public int getUniversityStudent() + { + return (person.getPersonIsUniversityStudent()); + } + + public int getNonWorkingAdult() + { + return (person.getPersonIsNonWorkingAdultUnder65()); + } + + public int getRetired() + { + return (person.getPersonIsNonWorkingAdultOver65()); + } + + public int getDrivingAgeSchoolChild() + { + return (person.getPersonIsStudentDriving()); + } + + public int getPreDrivingAgeSchoolChild() + { + return (person.getPersonIsStudentNonDriving()); + } + + public int getFemale() + { + return (person.getPersonIsFemale()); + } + + public int getPersonType() + { + return person.getPersonTypeNumber(); + } + + public int getAge() + { + return (person.getAge()); + } + + public int getStudentIsEmployed() + { + + if (person.getPersonIsUniversityStudent() == 1 || person.getPersonIsStudentDriving() == 1) + { + return (person.getPersonIsWorker()); + } + + return (0); + } + + public int getNonStudentGoesToSchool() + { + + if (person.getPersonTypeIsFullTimeWorker() == 1 + || person.getPersonTypeIsPartTimeWorker() == 1 + || person.getPersonIsNonWorkingAdultUnder65() == 1 + || person.getPersonIsNonWorkingAdultOver65() == 1) + { + + return (person.getPersonIsStudent()); + } + + return (0); + + } + + public int getNotEmployed() + { + return person.notEmployed(); + } + + public int getNumberOfChildren6To18WithoutMandatoryActivity() + { + return household.getNumberOfChildren6To18WithoutMandatoryActivity(); + } + + public int getAutos() + { + return (household.getAutosOwned()); + } + + public int getDrivers() + { + return (household.getDrivers()); + } + + public int getPreschoolChildren() + { + return household.getNumPreschool(); + } + + public int getNonWorkers() + { + return (household.getNumberOfNonWorkingAdults()); + } + + public int getIncomeInDollars() + { + return (household.getIncomeInDollars()); + } + + public int getIncomeHigherThan50k() + { + if (household.getIncomeCategory() > 2) return (1); + return (0); + } + + public int getNonFamilyHousehold() + { + if (household.getIsNonFamilyHousehold() == 1 || household.getIsGroupQuarters() == 1) return 1; + else return 0; + } + + public int getAreaType() + { + return homeTazAreaType; + } + + public int getUsualWorkLocation() + { + return person.getWorkLocation(); + } + + public int getWorkAtHome() + { + return person.getWorkLocation() == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR ? 1 + : 0; + } + + public int getSchoolAtHome() + { + return person.getPersonSchoolLocationZone() == ModelStructure.NOT_ENROLLED_SEGMENT_INDEX ? 1 + : 0; + } + + public int getTelecommuteFrequency() { + return person.getTelecommuteChoice(); + } + + + public int getUsualSchoolLocation() + { + return person.getUsualSchoolLocation(); + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/IndividualNonMandatoryTourFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/IndividualNonMandatoryTourFrequencyDMU.java new file mode 100644 index 0000000..317e940 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/IndividualNonMandatoryTourFrequencyDMU.java @@ -0,0 +1,773 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class IndividualNonMandatoryTourFrequencyDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(IndividualNonMandatoryTourFrequencyDMU.class); + + protected HashMap methodIndexMap; + + protected Household hh; + protected Person person; + protected IndexValues dmuIndex; + + protected int homeTazIsUrban; + protected double distanceToWork; + protected double distanceToSchool; + protected double escortAccessibility; + protected double shopAccessibility; + protected double maintAccessibility; + protected double eatOutAccessibility; + protected double visitAccessibility; + protected double discrAccessibility; + protected double nmDcLogsum; + protected double workAccessibility; + protected double schoolAccessibility; + + public String TOUR_FREQ_ALTERNATIVES_FILE_ESCORT_NAME = "Escort"; + public String TOUR_FREQ_ALTERNATIVES_FILE_SHOPPING_NAME = "Shopping"; + public String TOUR_FREQ_ALTERNATIVES_FILE_MAINT_NAME = "Maint"; + public String TOUR_FREQ_ALTERNATIVES_FILE_EAT_OUT_NAME = "EatOut"; + public String TOUR_FREQ_ALTERNATIVES_FILE_VISIT_NAME = "Visit"; + public String TOUR_FREQ_ALTERNATIVES_FILE_DISCR_NAME = "Discr"; + + public IndividualNonMandatoryTourFrequencyDMU() + { + dmuIndex = new IndexValues(); + } + + public Household getHouseholdObject() + { + return hh; + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + public void setPersonObject(Person persObject) + { + person = persObject; + } + + // DMU methods - define one of these for every @var in the mode choice + // control + // file. + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug INMTF UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return household income in dollars + */ + public int getIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + /** + * @return the number of persons in the "decision making" household. + */ + public int getHouseholdSize() + { + // 1-based indexing, so the array is dimensioned 1 more than the number + // of + // persons. + return hh.getPersons().length - 1; + } + + public int getNumAutos() + { + return hh.getAutosOwned(); + } + + /** + * @return 1 if household has at least 1 car, and the number of cars equals + * the number of workers + */ + public int getCarsEqualsWorkers() + { + int numAutos = hh.getAutosOwned(); + int numWorkers = hh.getWorkers(); + + // household must have at least 1 car, otherwise return 0. + if (numAutos > 0) + { + // if at least one car and numWorkers == numAutos, return 1, + // otherwise 0. + if (numAutos == numWorkers) return 1; + else return 0; + } else + { + return 0; + } + } + + /** + * @return 1 if household has at least 1 car, and the number of cars equals + * the number of workers + */ + public int getMoreCarsThanWorkers() + { + int numAutos = hh.getAutosOwned(); + int numWorkers = hh.getWorkers(); + + if (numAutos > numWorkers) return 1; + else return 0; + } + + public int getNumAdults() + { + int num = 0; + Person[] persons = hh.getPersons(); + for (int i = 1; i < persons.length; i++) + num += persons[i].getPersonIsAdult(); + return num; + } + + public int getNumChildren() + { + int num = 0; + Person[] persons = hh.getPersons(); + for (int i = 1; i < persons.length; i++) + num += (persons[i].getPersonIsAdult() == 0 ? 1 : 0); + return num; + } + + public int getPersonIsAdult() + { + return person.getPersonIsAdult(); + } + + public int getPersonIsChild() + { + return person.getPersonIsAdult() == 0 ? 1 : 0; + } + + public int getPersonIsFullTimeWorker() + { + return person.getPersonIsFullTimeWorker(); + } + + public int getPersonIsPartTimeWorker() + { + return person.getPersonIsPartTimeWorker(); + } + + public int getPersonIsUniversity() + { + return person.getPersonIsUniversityStudent(); + } + + public int getPersonIsNonworker() + { + return person.getPersonIsNonWorkingAdultUnder65() + + person.getPersonIsNonWorkingAdultOver65(); + } + + public int getPersonIsPreschool() + { + return person.getPersonIsPreschoolChild(); + } + + public int getPersonIsStudentNonDriving() + { + return person.getPersonIsStudentNonDriving(); + } + + public int getPersonIsStudentDriving() + { + return person.getPersonIsStudentDriving(); + } + + public int getPersonStaysHome() + { + return person.getCdapActivity().equalsIgnoreCase("H") ? 1 : 0; + } + + public int getWorksAtHome() + { + if (person.getPersonIsWorker() == 1 + && person.getWorkLocation() == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) return 1; + else return 0; + } + + public int getFemale() + { + return person.getPersonIsFemale(); + } + + /** + * determines the number of persons in the "decision making" household of + * type: full-time worker. returns the count, or 3, if count is 3 or more. + * + * @return count (up to a max of 3) of the number of full-time workers. + */ + public int getFullTimeWorkers() + { + Person[] p = hh.getPersons(); + + // get the count of persons of type: full time worker; if more than 3, + // return + // 3. + int count = 0; + for (int i = 1; i < p.length; i++) + { + count += p[i].getPersonIsFullTimeWorker(); + if (count == 3) break; + } + + return count; + } + + /** + * determines the number of persons in the "decision making" household of + * type: part-time worker. returns the count, or 3, if count is 3 or more. + * + * @return count (up to a max of 3) of the number of part-time workers. + */ + public int getPartTimeWorkers() + { + Person[] p = hh.getPersons(); + + // get the count of persons of type: part-time worker; if more than 3, + // return + // 3. + int count = 0; + for (int i = 1; i < p.length; i++) + { + count += p[i].getPersonIsPartTimeWorker(); + if (count == 3) break; + } + + return count; + } + + /** + * determines the number of persons in the "decision making" household of + * type: university student. returns the count, or 3, if count is 3 or more. + * + * @return count (up to a max of 3) of the number of university students. + */ + public int getUniversityStudents() + { + Person[] p = hh.getPersons(); + + // get the count of persons of type: university student; if more than 3, + // return 3. + int count = 0; + for (int i = 1; i < p.length; i++) + { + count += p[i].getPersonIsUniversityStudent(); + if (count == 3) break; + } + + return count; + } + + /** + * determines the number of persons in the "decision making" household of + * type: non-worker. returns the count, or 3, if count is 3 or more. + * + * @return count (up to a max of 3) of the number of non-workers. + */ + public int getNonWorkers() + { + Person[] p = hh.getPersons(); + + // get the count of persons of type: nonworker + retired; if more than + // 3, + // return 3. + int count = 0; + for (int i = 1; i < p.length; i++) + { + count += p[i].getPersonIsNonWorkingAdultUnder65() + + p[i].getPersonIsNonWorkingAdultOver65(); + if (count == 3) break; + } + + return count; + } + + /** + * determines the number of persons in the "decision making" household of + * type: driving-age student. returns the count, or 3, if count is 3 or + * more. + * + * @return count (up to a max of 3) of the number of driving-age students. + */ + public int getDrivingAgeStudents() + { + Person[] p = hh.getPersons(); + + // get the count of persons of type: driving-age student; if more than + // 3, + // return 3. + int count = 0; + for (int i = 1; i < p.length; i++) + { + count += p[i].getPersonIsStudentDriving(); + if (count == 3) break; + } + + return count; + } + + /** + * determines the number of persons in the "decision making" household of + * type: non-driving-age student. returns the count, or 3, if count is 3 or + * more. + * + * @return count (up to a max of 3) of the number of non-driving-age + * students. + */ + public int getNonDrivingAgeStudents() + { + Person[] p = hh.getPersons(); + + // get the count of persons of type: non-driving-age student; if more + // than 3, + // return 3. + int count = 0; + for (int i = 1; i < p.length; i++) + { + count += p[i].getPersonIsStudentNonDriving(); + if (count == 3) break; + } + + return count; + } + + /** + * determines the number of persons in the "decision making" household of + * type: pre-school age. returns the count, or 3, if count is 3 or more. + * + * @return count (up to a max of 3) of the number of pre-school age + * children. + */ + public int getPreSchoolers() + { + Person[] p = hh.getPersons(); + + // get the count of persons of type: pre-school; if more than 3, return + // 3. + int count = 0; + for (int i = 1; i < p.length; i++) + { + count += p[i].getPersonIsPreschoolChild(); + if (count == 3) break; + } + + return count; + } + + public void setEscortAccessibility(double accessibility) + { + escortAccessibility = accessibility; + } + + public void setShopAccessibility(double accessibility) + { + shopAccessibility = accessibility; + } + + public void setMaintAccessibility(double accessibility) + { + maintAccessibility = accessibility; + } + + public void setEatOutAccessibility(double accessibility) + { + eatOutAccessibility = accessibility; + } + + public void setVisitAccessibility(double accessibility) + { + visitAccessibility = accessibility; + } + + public void setDiscrAccessibility(double accessibility) + { + discrAccessibility = accessibility; + } + + public void setNmDcLogsum(double logsum) + { + nmDcLogsum = logsum; + } + + public void setWorkAccessibility(double accessibility) + { + workAccessibility = accessibility; + } + + public void setSchoolAccessibility(double accessibility) + { + schoolAccessibility = accessibility; + } + + /** + * called by methods invoked by UEC.solve() + * + * @return maximum number of hours mutually available between pairs of + * adults in household + */ + public int getMaxAdultOverlaps() + { + return hh.getMaxAdultOverlaps(); + } + + /** + * called by methods invoked by UEC.solve() + * + * @return maximum number of hours mutually available between pairs of + * children in household + */ + public int getMaxChildOverlaps() + { + return hh.getMaxChildOverlaps(); + } + + /** + * called by methods invoked by UEC.solve() + * + * @return maximum number of hours mutually available between pairs or + * adults/children where pairs consist of different types in + * household + */ + public int getMaxMixedOverlaps() + { + return hh.getMaxMixedOverlaps(); + } + + public int getMaxPairwiseOverlapAdult() + { + int maxOverlap = 0; + + // get array of person objects for the decision making household + Person[] dmuPersons = hh.getPersons(); + + for (int i = 1; i < dmuPersons.length; i++) + { + if (dmuPersons[i].getPersonIsAdult() == 1) + { + int overlap = getOverlap(person, dmuPersons[i]); + if (overlap > maxOverlap) maxOverlap = overlap; + } + } + + return maxOverlap; + } + + public int getMaxPairwiseOverlapChild() + { + int maxOverlap = 0; + + // get array of person objects for the decision making household + Person[] dmuPersons = hh.getPersons(); + + for (int i = 1; i < dmuPersons.length; i++) + { + if (dmuPersons[i].getPersonIsAdult() == 0) + { + int overlap = getOverlap(person, dmuPersons[i]); + if (overlap > maxOverlap) maxOverlap = overlap; + } + } + + return maxOverlap; + } + + // TODO: find out if this is suposed to be total pairwise available hours, + // or + // largest consecutive hours available for persons. + // TODO: right now, assuming total pairwise available hours + private int getOverlap(Person dmuPerson, Person otherPerson) + { + short[] dmuWindow = dmuPerson.getTimeWindows(); + short[] otherWindow = otherPerson.getTimeWindows(); + + int overlap = 0; + for (int i = 0; i < dmuWindow.length; i++) + { + if (dmuWindow[i] == 0 && otherWindow[i] == 0) overlap++; + } + + return overlap; + } + + public int getWindowBeforeFirstMandJointTour() + { + return person.getWindowBeforeFirstMandJointTour(); + } + + public int getWindowBetweenFirstLastMandJointTour() + { + return person.getWindowBetweenFirstLastMandJointTour(); + } + + public int getWindowAfterLastMandJointTour() + { + return person.getWindowAfterLastMandJointTour(); + } + + public int getNumHhFtWorkers() + { + return hh.getNumFtWorkers(); + } + + public int getNumHhPtWorkers() + { + return hh.getNumPtWorkers(); + } + + public int getNumHhUnivStudents() + { + return hh.getNumUnivStudents(); + } + + public int getNumHhNonWorkAdults() + { + return hh.getNumNonWorkAdults(); + } + + public int getNumHhRetired() + { + return hh.getNumRetired(); + } + + public int getNumHhDrivingStudents() + { + return hh.getNumDrivingStudents(); + } + + public int getNumHhNonDrivingStudents() + { + return hh.getNumNonDrivingStudents(); + } + + public int getNumHhPreschool() + { + return hh.getNumPreschool(); + } + + public int getTravelActiveAdults() + { + return hh.getTravelActiveAdults(); + } + + public int getTravelActiveChildren() + { + return hh.getTravelActiveChildren(); + } + + public int getNumMandatoryTours() + { + return person.getNumMandatoryTours(); + } + + public int getNumJointShoppingTours() + { + return person.getNumJointShoppingTours(); + } + + public int getNumJointOthMaintTours() + { + return person.getNumJointOthMaintTours(); + } + + public int getNumJointEatOutTours() + { + return person.getNumJointEatOutTours(); + } + + public int getNumJointSocialTours() + { + return person.getNumJointSocialTours(); + } + + public int getNumJointOthDiscrTours() + { + return person.getNumJointOthDiscrTours(); + } + + public int getJTours() + { + return hh.getJointTourArray().length; + } + + public int getPreDrivingAtHome() + { + int num = 0; + Person[] persons = hh.getPersons(); + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getPersonIsStudentNonDriving() == 1 + && persons[i].getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) + num++; + } + return num; + } + + public int getPreschoolAtHome() + { + int num = 0; + Person[] persons = hh.getPersons(); + for (int i = 1; i < persons.length; i++) + { + if (persons[i].getPersonIsPreschoolChild() == 1 + && persons[i].getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) + num++; + } + return num; + } + + public double getDistanceToWorkLocation() + { + return person.getWorkLocationDistance(); + } + + public double getDistanceToSchoolLocation() + { + return person.getSchoolLocationDistance(); + } + + public double getEscortAccessibility() + { + return escortAccessibility; + } + + public double getShopAccessibility() + { + return shopAccessibility; + } + + public double getMaintAccessibility() + { + return maintAccessibility; + } + + public double getEatOutAccessibility() + { + return eatOutAccessibility; + } + + public double getVisitAccessibility() + { + return visitAccessibility; + } + + public double getDiscrAccessibility() + { + return discrAccessibility; + } + + public int getCdapIndex() + { + return person.getCdapIndex(); + } + + public double getNonMotorizedDcLogsum() + { + return nmDcLogsum; + } + + public int getNumPredrivingKidsGoOut() + { + return hh.getNumberOfPreDrivingWithNonHomeActivity(); + } + + public int getNumPreschoolKidsGoOut() + { + return hh.getNumberOfPreschoolWithNonHomeActivity(); + } + + public int getCollegeEducation() + { + return person.getHasBachelors(); + } + + public int getLowEducation() + { + return person.getPersonIsHighSchoolGraduate() == 1 ? 0 : 1; + } + + public int getDetachedHh() + { + return hh.getHhBldgsz() == 1 ? 1 : 0; + } + + public double getWorkAccessibility() + { + return workAccessibility; + } + + public double getSchoolAccessibility() + { + return schoolAccessibility; + } + + public int getTelecommuteFrequency() { + return person.getTelecommuteChoice(); + } + + + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/IntermediateStopChoiceModels.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/IntermediateStopChoiceModels.java new file mode 100644 index 0000000..bd1e1db --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/IntermediateStopChoiceModels.java @@ -0,0 +1,5075 @@ +package org.sandag.abm.ctramp; + +import org.sandag.abm.ctramp.CtrampDmuFactoryIf; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Stop; +import org.sandag.abm.ctramp.StopLocationDMU; +import org.sandag.abm.ctramp.Tour; +import org.sandag.abm.ctramp.TripModeChoiceDMU; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Random; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +/** + * This class will be used for determining the trip departure time for outbound + * stops, trip arrival time for inbound stops, location of stops, and trip mode + * for trips between stops on individual mandatory, individual non-mandatory and + * joint tours. + * + * @author Jim Hicks + * @version Oct 2010 + */ +public class IntermediateStopChoiceModels + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(IntermediateStopChoiceModels.class); + private transient Logger slcLogger = Logger.getLogger("slcLogger"); + private transient Logger slcSoaLogger = Logger.getLogger("slcSoaLogger"); + private transient Logger smcLogger = Logger.getLogger("tripMcLog"); + private transient Logger tripDepartLogger = Logger.getLogger("tripDepartLog"); + private transient Logger parkLocLogger = Logger.getLogger("parkLocLog"); + + public static final int WTW = 0; + public static final int WTD = 1; + public static final int DTW = 2; + public static final int[] ACC_EGR = {WTW,WTD,DTW}; + private static final String USE_NEW_SOA_METHOD_PROPERTY_KEY = "slc.use.new.soa"; + + public static final String PROPERTIES_UEC_TRIP_MODE_CHOICE = "tripModeChoice.uec.file"; + + private static final String PROPERTIES_UEC_SLC_CHOICE = "slc.uec.file"; + private static final String PROPERTIES_UEC_SLC_DATA_PAGE = "slc.uec.data.page"; + private static final String PROPERTIES_UEC_MAND_SLC_MODEL_PAGE = "slc.mandatory.uec.model.page"; + private static final String PROPERTIES_UEC_MAINT_SLC_MODEL_PAGE = "slc.maintenance.uec.model.page"; + private static final String PROPERTIES_UEC_DISCR_SLC_MODEL_PAGE = "slc.discretionary.uec.model.page"; + + public static final String PROPERTIES_UEC_SLC_SOA_CHOICE = "slc.soa.uec.file"; + public static final String PROPERTIES_UEC_SLC_SOA_DISTANCE_UTILITY = "auto.slc.soa.distance.uec.file"; + public static final String PROPERTIES_UEC_SLC_SOA_DISTANCE_DATA_PAGE = "auto.slc.soa.distance.data.page"; + public static final String PROPERTIES_UEC_SLC_SOA_DISTANCE_MODEL_PAGE = "auto.slc.soa.distance.model.page"; + + private static final String PROPERTIES_UEC_STOP_LOCATION_SIZE = "slc.soa.size.uec.file"; + private static final String PROPERTIES_UEC_STOP_LOCATION_SIZE_DATA = "slc.soa.size.uec.data.page"; + private static final String PROPERTIES_UEC_STOP_LOCATION_SIZE_MODEL = "slc.soa.size.uec.model.page"; + + private static final String PROPERTIES_UEC_PARKING_LOCATION_CHOICE = "plc.uec.file"; + private static final String PROPERTIES_UEC_PLC_DATA_PAGE = "plc.uec.data.page"; + private static final String PROPERTIES_UEC_PLC_MODEL_PAGE = "plc.uec.model.page"; + + private static final String PROPERTIES_UEC_PARKING_LOCATION_CHOICE_ALTERNATIVES = "plc.alts.corresp.file"; + + public static final int WORK_SHEET = 1; + public static final int UNIVERSITY_SHEET = 2; + public static final int SCHOOL_SHEET = 3; + public static final int MAINTENANCE_SHEET = 4; + public static final int DISCRETIONARY_SHEET = 5; + public static final int SUBTOUR_SHEET = 6; + public static final int[] MC_PURPOSE_SHEET_INDICES = { + -1, WORK_SHEET, UNIVERSITY_SHEET, SCHOOL_SHEET, MAINTENANCE_SHEET, MAINTENANCE_SHEET, + MAINTENANCE_SHEET, DISCRETIONARY_SHEET, DISCRETIONARY_SHEET, DISCRETIONARY_SHEET, + SUBTOUR_SHEET }; + + public static final int WORK_CATEGORY = 0; + public static final int UNIVERSITY_CATEGORY = 1; + public static final int SCHOOL_CATEGORY = 2; + public static final int MAINTENANCE_CATEGORY = 3; + public static final int DISCRETIONARY_CATEGORY = 4; + public static final int SUBTOUR_CATEGORY = 5; + public static final String[] PURPOSE_CATEGORY_LABELS = { + "work", "university", "school", "maintenance", "discretionary", "subtour" }; + public static final int[] PURPOSE_CATEGORIES = { + -1, WORK_CATEGORY, UNIVERSITY_CATEGORY, SCHOOL_CATEGORY, MAINTENANCE_CATEGORY, + MAINTENANCE_CATEGORY, MAINTENANCE_CATEGORY, DISCRETIONARY_CATEGORY, + DISCRETIONARY_CATEGORY, DISCRETIONARY_CATEGORY, SUBTOUR_CATEGORY }; + + private static final String PARK_MGRA_COLUMN = "mgra"; + private static final String PARK_AREA_COLUMN = "parkarea"; + private static final int MAX_PLC_SAMPLE_SIZE = 1200; + + private static final int WORK_STOP_PURPOSE_INDEX = 1; + private static final int UNIV_STOP_PURPOSE_INDEX = 2; + private static final int ESCORT_STOP_PURPOSE_INDEX = 4; + private static final int SHOP_STOP_PURPOSE_INDEX = 5; + private static final int MAINT_STOP_PURPOSE_INDEX = 6; + private static final int EAT_OUT_STOP_PURPOSE_INDEX = 7; + private static final int VISIT_STOP_PURPOSE_INDEX = 8; + private static final int DISCR_STOP_PURPOSE_INDEX = 9; + + private static final int OTHER_STOP_LOC_SOA_SHEET_INDEX = 2; + private static final int WALK_STOP_LOC_SOA_SHEET_INDEX = 3; + private static final int BIKE_STOP_LOC_SOA_SHEET_INDEX = 4; + private static final int MAX_STOP_LOC_SOA_SHEET_INDEX = 4; + + private static final int WORK_STOP_PURPOSE_SOA_SIZE_INDEX = 0; + private static final int UNIV_STOP_PURPOSE_SOA_SIZE_INDEX = 1; + private static final int ESCORT_0_STOP_PURPOSE_SOA_SIZE_INDEX = 2; + private static final int ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX = 3; + private static final int ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX = 4; + private static final int ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX = 5; + private static final int ESCORT_PS_GS_STOP_PURPOSE_SOA_SIZE_INDEX = 6; + private static final int ESCORT_PS_HS_STOP_PURPOSE_SOA_SIZE_INDEX = 7; + private static final int ESCORT_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX = 8; + private static final int ESCORT_PS_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX = 9; + private static final int SHOP_STOP_PURPOSE_SOA_SIZE_INDEX = 10; + private static final int MAINT_STOP_PURPOSE_SOA_SIZE_INDEX = 11; + private static final int EAT_OUT_STOP_PURPOSE_SOA_SIZE_INDEX = 12; + private static final int VISIT_STOP_PURPOSE_SOA_SIZE_INDEX = 13; + private static final int DISCR_STOP_PURPOSE_SOA_SIZE_INDEX = 14; + + public static final int[] SLC_SIZE_SEGMENT_INDICES = { + WORK_STOP_PURPOSE_SOA_SIZE_INDEX, UNIV_STOP_PURPOSE_SOA_SIZE_INDEX, + ESCORT_0_STOP_PURPOSE_SOA_SIZE_INDEX, ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX, + ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX, ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX, + ESCORT_PS_GS_STOP_PURPOSE_SOA_SIZE_INDEX, ESCORT_PS_HS_STOP_PURPOSE_SOA_SIZE_INDEX, + ESCORT_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX, ESCORT_PS_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX, + SHOP_STOP_PURPOSE_SOA_SIZE_INDEX, MAINT_STOP_PURPOSE_SOA_SIZE_INDEX, + EAT_OUT_STOP_PURPOSE_SOA_SIZE_INDEX, VISIT_STOP_PURPOSE_SOA_SIZE_INDEX, + DISCR_STOP_PURPOSE_SOA_SIZE_INDEX }; + + public static final String[] SLC_SIZE_SEGMENT_NAMES = { + "work", "univ", "escort_0", "escort_ps", "escort_gs", "escort_hs", "escort_ps_gs", + "escort_ps_hs", "escort_gs_hs", "escort_ps_gs_hs", "shop", "maint", "eatout", "visit", + "discr" }; + + private static final int MAND_SLC_MODEL_INDEX = 0; + private static final int MAINT_SLC_MODEL_INDEX = 1; + private static final int DISCR_SLC_MODEL_INDEX = 2; + + private static final String PROPERTIES_TRIP_UTILITY_IVT_COEFFS = "trip.utility.ivt.coeffs"; + private static final String PROPERTIES_TRIP_UTILITY_INCOME_COEFFS = "trip.utility.income.coeffs"; + private static final String PROPERTIES_TRIP_UTILITY_INCOME_EXPONENTS = "trip.utility.income.exponents"; + + + private boolean[] sampleAvailability; + private int[] inSample; + private boolean[] soaAvailability; + private int[] soaSample; + private boolean[] soaAvailabilityBackup; + private int[] soaSampleBackup; + private int[] finalSample; + private double[] sampleCorrectionFactors; + private double[] tripModeChoiceLogsums; + private boolean[] sampleMgraInBoardingTapShed; + private boolean[] sampleMgraInAlightingTapShed; + private boolean earlierTripWasLocatedInAlightingTapShed; + + private double[] tourOrigToAllMgraDistances; + private double[] tourDestToAllMgraDistances; + private double[] ikDistance; + private double[] kjDistance; + private double[] okDistance; + private double[] kdDistance; + + private AutoAndNonMotorizedSkimsCalculator anm; + private McLogsumsCalculator logsumHelper; + private ModelStructure modelStructure; + private TazDataManager tazs; + private MgraDataManager mgraManager; + + private int sampleSize; + private HashMap altFreqMap; + private StopLocationDMU stopLocDmuObj; + private TripModeChoiceDMU mcDmuObject; + private ParkingChoiceDMU parkingChoiceDmuObj; + + private double[][] slcSizeTerms; + private int[][] slcSizeSample; + private boolean[][] slcSizeAvailable; + + private double[] distanceFromStopOrigToAllMgras; + private double[] distanceToFinalDestFromAllMgras; + + private final BikeLogsum bls; + private BikeLogsumSegment segment; + + private double[] bikeLogsumFromStopOrigToAllMgras; + private double[] bikeLogsumToFinalDestFromAllMgras; + + private double[][] mcCumProbsSegmentIk; + private double[][] mcCumProbsSegmentKj; + + private double[] mcLogsumsSegmentIk; + private double[] mcLogsumsSegmentKj; + + private double[][] mcVOTsSegmentIk; //by sample and occupancy (0=non-SR,1=S2,2=S3) + private double[][] mcVOTsSegmentKj; + + private float[] parkingCostSegmentIk; //by sample + private float[] parkingCostSegmentKj; + + private double[][][][] segmentIkBestTapPairs; + private double[][][][] segmentKjBestTapPairs; + + + private ChoiceModelApplication[] mcModelArray; + private ChoiceModelApplication[] slcSoaModel; + private ChoiceModelApplication[] slcModelArray; + private ChoiceModelApplication plcModel; + + private int[] altMgraIndices; + private double[] altOsDistances; + private double[] altSdDistances; + private boolean[] altParkAvail; + private int[] altParkSample; + + private int numAltsInSample; + private int maxAltsInSample; + + private TableDataSet plcAltsTable; + private HashMap mgraAltLocationIndex; + private HashMap mgraAltParkArea; + private int[] parkMgras; + private int[] parkAreas; + + private int[] mgraParkArea; + private int[] numfreehrs; + private int[] hstallsoth; + private int[] hstallssam; + private float[] hparkcost; + private int[] dstallsoth; + private int[] dstallssam; + private float[] dparkcost; + private int[] mstallsoth; + private int[] mstallssam; + private float[] mparkcost; + + private double[] lsWgtAvgCostM; + private double[] lsWgtAvgCostD; + private double[] lsWgtAvgCostH; + + private double[] altParkingCostsM; + private double[] altParkingCostsD; + private double[] altParkingCostsH; + private int[] altMstallsoth; + private int[] altMstallssam; + private float[] altMparkcost; + private int[] altDstallsoth; + private int[] altDstallssam; + private float[] altDparkcost; + private int[] altHstallsoth; + private int[] altHstallssam; + private float[] altHparkcost; + private int[] altNumfreehrs; + + private HashMap sizeSegmentNameIndexMap; + + private StopDepartArrivePeriodModel stopTodModel; + + private int availAltsToLog = 55; + // this + private TNCAndTaxiWaitTimeCalculator tncTaxiWaitTimeCalculator; + // logging + // private int availAltsToLog = 5; + + // set this constant for checking the number of times depart/arrive period + // selection is made so that no infinite loop occurs. + private static final int MAX_INVALID_FIRST_ARRIVAL_COUNT = 100; + + public static final int NUM_CPU_TIME_VALUES = 9; + private long soaAutoTime; + private long soaOtherTime; + private long slsTime; + private long sldTime; + private long slcTime; + private long todTime; + private long smcTime; + private long[] hhTimes = new long[NUM_CPU_TIME_VALUES]; + + private DestChoiceTwoStageModel dcTwoStageModelObject; + + private boolean useNewSoaMethod; + + private String loggerSeparator = ""; + + // following arrays used to store ivt coefficients, and income coefficients, income exponents to calculate cost coefficient, by tour purpose + double[] ivtCoeffs; + double[] incomeCoeffs; + double[] incomeExponents; + + /** + * Constructor that will be used to set up the ChoiceModelApplications for + * each type of tour + * + * @param projectDirectory + * - name of root level project directory + * @param resourceBundle + * - properties file with paths identified + * @param dmuObject + * - decision making unit for stop frequency + * @param modelStructure + * - holds the model structure info + */ + public IntermediateStopChoiceModels(HashMap propertyMap, + ModelStructure myModelStructure, CtrampDmuFactoryIf dmuFactory, + McLogsumsCalculator myLogsumHelper) + { + + tazs = TazDataManager.getInstance(propertyMap); + mgraManager = MgraDataManager.getInstance(propertyMap); + + mgraParkArea = mgraManager.getMgraParkAreas(); + numfreehrs = mgraManager.getNumFreeHours(); + lsWgtAvgCostM = mgraManager.getLsWgtAvgCostM(); + lsWgtAvgCostD = mgraManager.getLsWgtAvgCostD(); + lsWgtAvgCostH = mgraManager.getLsWgtAvgCostH(); + mstallsoth = mgraManager.getMStallsOth(); + mstallssam = mgraManager.getMStallsSam(); + mparkcost = mgraManager.getMParkCost(); + dstallsoth = mgraManager.getDStallsOth(); + dstallssam = mgraManager.getDStallsSam(); + dparkcost = mgraManager.getDParkCost(); + hstallsoth = mgraManager.getHStallsOth(); + hstallssam = mgraManager.getHStallsSam(); + hparkcost = mgraManager.getHParkCost(); + + modelStructure = myModelStructure; + logsumHelper = myLogsumHelper; + + setupStopLocationChoiceModels(propertyMap, dmuFactory); + setupParkingLocationModel(propertyMap, dmuFactory); + + bls = BikeLogsum.getBikeLogsum(propertyMap); + + //get the coefficients for ivt and the coefficients to calculate the cost coefficient + ivtCoeffs = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TRIP_UTILITY_IVT_COEFFS); + incomeCoeffs = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TRIP_UTILITY_INCOME_COEFFS); + incomeExponents = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TRIP_UTILITY_INCOME_EXPONENTS); + + tncTaxiWaitTimeCalculator = new TNCAndTaxiWaitTimeCalculator(); + tncTaxiWaitTimeCalculator.createWaitTimeDistributions(propertyMap); + + + } + + private void setupStopLocationChoiceModels(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up stop location choice models.")); + + useNewSoaMethod = Util.getBooleanValueFromPropertyMap(propertyMap, + USE_NEW_SOA_METHOD_PROPERTY_KEY); + + stopLocDmuObj = dmuFactory.getStopLocationDMU(); + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String slcSoaUecFile = propertyMap.get(PROPERTIES_UEC_SLC_SOA_CHOICE); + slcSoaUecFile = uecPath + slcSoaUecFile; + + String slcUecFile = propertyMap.get(PROPERTIES_UEC_SLC_CHOICE); + slcUecFile = uecPath + slcUecFile; + + slcSoaModel = new ChoiceModelApplication[MAX_STOP_LOC_SOA_SHEET_INDEX + 1]; + slcSoaModel[OTHER_STOP_LOC_SOA_SHEET_INDEX] = new ChoiceModelApplication(slcSoaUecFile, + OTHER_STOP_LOC_SOA_SHEET_INDEX, 0, propertyMap, (VariableTable) stopLocDmuObj); + slcSoaModel[WALK_STOP_LOC_SOA_SHEET_INDEX] = new ChoiceModelApplication(slcSoaUecFile, + WALK_STOP_LOC_SOA_SHEET_INDEX, 0, propertyMap, (VariableTable) stopLocDmuObj); + slcSoaModel[BIKE_STOP_LOC_SOA_SHEET_INDEX] = new ChoiceModelApplication(slcSoaUecFile, + BIKE_STOP_LOC_SOA_SHEET_INDEX, 0, propertyMap, (VariableTable) stopLocDmuObj); + + int numSlcSoaAlternatives = slcSoaModel[OTHER_STOP_LOC_SOA_SHEET_INDEX] + .getNumberOfAlternatives(); + stopLocDmuObj = dmuFactory.getStopLocationDMU(); + + sizeSegmentNameIndexMap = new HashMap(); + for (int k = 0; k < SLC_SIZE_SEGMENT_INDICES.length; k++) + { + sizeSegmentNameIndexMap.put(SLC_SIZE_SEGMENT_NAMES[k], k); + sizeSegmentNameIndexMap.put(SLC_SIZE_SEGMENT_NAMES[k], SLC_SIZE_SEGMENT_INDICES[k]); + } + + // set the second argument to a positive, non-zero mgra value to get + // logging for the size term calculation for the specified mgra. + slcSizeTerms = calculateLnSlcSizeTerms(propertyMap, -1); + + String mcUecFile = propertyMap.get(PROPERTIES_UEC_TRIP_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + mcDmuObject = dmuFactory.getTripModeChoiceDMU(); + + // logsumHelper.setupSkimCalculators(propertyMap); + anm = logsumHelper.getAnmSkimCalculator(); + mcDmuObject.setParkingCostInfo(mgraParkArea, lsWgtAvgCostM, lsWgtAvgCostD, lsWgtAvgCostH); + + mcModelArray = new ChoiceModelApplication[5 + 1]; + mcModelArray[WORK_CATEGORY] = new ChoiceModelApplication(mcUecFile, WORK_SHEET, 0, + propertyMap, (VariableTable) mcDmuObject); + mcModelArray[UNIVERSITY_CATEGORY] = new ChoiceModelApplication(mcUecFile, UNIVERSITY_SHEET, + 0, propertyMap, (VariableTable) mcDmuObject); + mcModelArray[SCHOOL_CATEGORY] = new ChoiceModelApplication(mcUecFile, SCHOOL_SHEET, 0, + propertyMap, (VariableTable) mcDmuObject); + mcModelArray[MAINTENANCE_CATEGORY] = new ChoiceModelApplication(mcUecFile, + MAINTENANCE_SHEET, 0, propertyMap, (VariableTable) mcDmuObject); + mcModelArray[DISCRETIONARY_CATEGORY] = new ChoiceModelApplication(mcUecFile, + DISCRETIONARY_SHEET, 0, propertyMap, (VariableTable) mcDmuObject); + mcModelArray[SUBTOUR_CATEGORY] = new ChoiceModelApplication(mcUecFile, SUBTOUR_SHEET, 0, + propertyMap, (VariableTable) mcDmuObject); + + // set up the stop location choice model object + int slcDataPage = Integer.parseInt(propertyMap.get(PROPERTIES_UEC_SLC_DATA_PAGE)); + int slcMandModelPage = Integer + .parseInt(propertyMap.get(PROPERTIES_UEC_MAND_SLC_MODEL_PAGE)); + int slcMaintModelPage = Integer.parseInt(propertyMap + .get(PROPERTIES_UEC_MAINT_SLC_MODEL_PAGE)); + int slcDiscrModelPage = Integer.parseInt(propertyMap + .get(PROPERTIES_UEC_DISCR_SLC_MODEL_PAGE)); + slcModelArray = new ChoiceModelApplication[3]; + slcModelArray[MAND_SLC_MODEL_INDEX] = new ChoiceModelApplication(slcUecFile, + slcMandModelPage, slcDataPage, propertyMap, (VariableTable) stopLocDmuObj); + slcModelArray[MAINT_SLC_MODEL_INDEX] = new ChoiceModelApplication(slcUecFile, + slcMaintModelPage, slcDataPage, propertyMap, (VariableTable) stopLocDmuObj); + slcModelArray[DISCR_SLC_MODEL_INDEX] = new ChoiceModelApplication(slcUecFile, + slcDiscrModelPage, slcDataPage, propertyMap, (VariableTable) stopLocDmuObj); + + sampleSize = slcModelArray[MAND_SLC_MODEL_INDEX].getNumberOfAlternatives(); + altFreqMap = new HashMap(sampleSize); + finalSample = new int[sampleSize + 1]; + sampleCorrectionFactors = new double[sampleSize + 1]; + + // decalre the arrays for storing stop location choice ik and kj segment + // mode choice probability arrays + mcCumProbsSegmentIk = new double[sampleSize + 1][]; + mcCumProbsSegmentKj = new double[sampleSize + 1][]; + + //declare the arrays for storing the VOTs calculated by trip mode choice for ik and kj segment + mcVOTsSegmentIk = new double[sampleSize+1][3]; + mcVOTsSegmentKj = new double[sampleSize+1][3]; + + //declare arrays for storing the trip mode choice parking cost for ik and kj segment + parkingCostSegmentIk = new float[sampleSize+1]; + parkingCostSegmentKj = new float[sampleSize+1]; + + //declare the arrays for storing the stop location choice ik and kj segment + //mode choice logsum arrays + mcLogsumsSegmentIk = new double[sampleSize + 1]; + mcLogsumsSegmentKj = new double[sampleSize + 1]; + + // declare the arrays for storing stop location choice ik and kj segment best tap pair arrays + segmentIkBestTapPairs = new double[sampleSize+1][ACC_EGR.length][][]; + segmentKjBestTapPairs = new double[sampleSize+1][ACC_EGR.length][][]; + + // declare the arrays that holds ik and kj segment logsum values for + // each location choice sample alternative + tripModeChoiceLogsums = new double[sampleSize + 1]; + + // declare the arrays that holds ik and kj distance values for each + // location choice sample alternative + // these are set as stop location dmu attributes for stop orig to stop + // alt, and stop alt to half-tour final dest. + ikDistance = new double[sampleSize + 1]; + kjDistance = new double[sampleSize + 1]; + + // declare the arrays that holds ik and kj distance values for each + // location choice sample alternative + // these are set as stop location dmu attributes for tour orig to stop + // alt, and stop alt to tour dest. + okDistance = new double[sampleSize + 1]; + kdDistance = new double[sampleSize + 1]; + + // this array has elements with values of 0 if utility is not to be + // computed for alternative, or 1 if utility is to be computed. + inSample = new int[sampleSize + 1]; + + // this array has elements that are boolean that set availability of + // alternative - unavailable altrnatives do not get utility computed. + sampleAvailability = new boolean[sampleSize + 1]; + + soaSample = new int[numSlcSoaAlternatives + 1]; + soaAvailability = new boolean[numSlcSoaAlternatives + 1]; + soaSampleBackup = new int[numSlcSoaAlternatives + 1]; + soaAvailabilityBackup = new boolean[numSlcSoaAlternatives + 1]; + + sampleMgraInBoardingTapShed = new boolean[mgraManager.getMaxMgra() + 1]; + sampleMgraInAlightingTapShed = new boolean[mgraManager.getMaxMgra() + 1]; + + distanceFromStopOrigToAllMgras = new double[mgraManager.getMaxMgra() + 1]; + distanceToFinalDestFromAllMgras = new double[mgraManager.getMaxMgra() + 1]; + + bikeLogsumFromStopOrigToAllMgras = new double[mgraManager.getMaxMgra() + 1]; + bikeLogsumToFinalDestFromAllMgras = new double[mgraManager.getMaxMgra() + 1]; + + tourOrigToAllMgraDistances = new double[mgraManager.getMaxMgra() + 1]; + tourDestToAllMgraDistances = new double[mgraManager.getMaxMgra() + 1]; + + // create the array of 1s for MGRAs that have a non-empty set of TAPs + // within walk egress distance of them + // for the setting walk transit available for teh stop location + // alternatives. + // createWalkTransitAvailableArray(); + + setupTripDepartTimeModel(propertyMap, dmuFactory); + + loggerSeparator += "-"; + + } + + public void setupSlcDistanceBaseSoaModel(HashMap propertyMap, + double[][] soaExpUtils, double[][][] soaSizeProbs, double[][] soaTazSize) + { + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String slcSoaDistanceUecFile = propertyMap.get(PROPERTIES_UEC_SLC_SOA_DISTANCE_UTILITY); + slcSoaDistanceUecFile = uecPath + slcSoaDistanceUecFile; + + dcTwoStageModelObject = new DestChoiceTwoStageModel(propertyMap, sampleSize); + dcTwoStageModelObject.setSlcSoaProbsAndUtils(soaExpUtils, soaSizeProbs, soaTazSize); + + } + + private void setupTripDepartTimeModel(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + stopTodModel = new StopDepartArrivePeriodModel(propertyMap, modelStructure); + } + + private void setupParkingLocationModel(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + + logger.info("setting up parking location choice models."); + + // locate the UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String plcUecFile = propertyMap.get(PROPERTIES_UEC_PARKING_LOCATION_CHOICE); + plcUecFile = uecPath + plcUecFile; + + int plcDataPage = Integer.parseInt(propertyMap.get(PROPERTIES_UEC_PLC_DATA_PAGE)); + int plcModelPage = Integer.parseInt(propertyMap.get(PROPERTIES_UEC_PLC_MODEL_PAGE)); + + altMgraIndices = new int[MAX_PLC_SAMPLE_SIZE + 1]; + altOsDistances = new double[MAX_PLC_SAMPLE_SIZE + 1]; + altSdDistances = new double[MAX_PLC_SAMPLE_SIZE + 1]; + altParkingCostsM = new double[MAX_PLC_SAMPLE_SIZE + 1]; + altParkingCostsD = new double[MAX_PLC_SAMPLE_SIZE + 1]; + altParkingCostsH = new double[MAX_PLC_SAMPLE_SIZE + 1]; + altMstallsoth = new int[MAX_PLC_SAMPLE_SIZE + 1]; + altMstallssam = new int[MAX_PLC_SAMPLE_SIZE + 1]; + altMparkcost = new float[MAX_PLC_SAMPLE_SIZE + 1]; + altDstallsoth = new int[MAX_PLC_SAMPLE_SIZE + 1]; + altDstallssam = new int[MAX_PLC_SAMPLE_SIZE + 1]; + altDparkcost = new float[MAX_PLC_SAMPLE_SIZE + 1]; + altHstallsoth = new int[MAX_PLC_SAMPLE_SIZE + 1]; + altHstallssam = new int[MAX_PLC_SAMPLE_SIZE + 1]; + altHparkcost = new float[MAX_PLC_SAMPLE_SIZE + 1]; + altNumfreehrs = new int[MAX_PLC_SAMPLE_SIZE + 1]; + + altParkAvail = new boolean[MAX_PLC_SAMPLE_SIZE + 1]; + altParkSample = new int[MAX_PLC_SAMPLE_SIZE + 1]; + + parkingChoiceDmuObj = dmuFactory.getParkingChoiceDMU(); + + plcModel = new ChoiceModelApplication(plcUecFile, plcModelPage, plcDataPage, propertyMap, + (VariableTable) parkingChoiceDmuObj); + + // read the parking choice alternatives data file to get alternatives + // names + String plcAltsFile = propertyMap.get(PROPERTIES_UEC_PARKING_LOCATION_CHOICE_ALTERNATIVES); + plcAltsFile = uecPath + plcAltsFile; + + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + plcAltsTable = reader.readFile(new File(plcAltsFile)); + } catch (IOException e) + { + logger.error("problem reading table of cbd zones for parking location choice model.", e); + System.exit(1); + } + + parkMgras = plcAltsTable.getColumnAsInt(PARK_MGRA_COLUMN); + parkAreas = plcAltsTable.getColumnAsInt(PARK_AREA_COLUMN); + + parkingChoiceDmuObj.setParkAreaMgraArray(parkMgras); + parkingChoiceDmuObj.setSampleIndicesArray(altMgraIndices); + parkingChoiceDmuObj.setDistancesOrigAlt(altOsDistances); + parkingChoiceDmuObj.setDistancesAltDest(altSdDistances); + parkingChoiceDmuObj.setParkingCostsM(altParkingCostsM); + parkingChoiceDmuObj.setMstallsoth(altMstallsoth); + parkingChoiceDmuObj.setMstallssam(altMstallssam); + parkingChoiceDmuObj.setMparkCost(altMparkcost); + parkingChoiceDmuObj.setDstallsoth(altDstallsoth); + parkingChoiceDmuObj.setDstallssam(altDstallssam); + parkingChoiceDmuObj.setDparkCost(altDparkcost); + parkingChoiceDmuObj.setHstallsoth(altHstallsoth); + parkingChoiceDmuObj.setHstallssam(altHstallssam); + parkingChoiceDmuObj.setHparkCost(altHparkcost); + parkingChoiceDmuObj.setNumfreehrs(altNumfreehrs); + + mgraAltLocationIndex = new HashMap(); + mgraAltParkArea = new HashMap(); + + for (int i = 0; i < parkMgras.length; i++) + { + mgraAltLocationIndex.put(parkMgras[i], i); + mgraAltParkArea.put(parkMgras[i], parkAreas[i]); + } + + } + + private double[][] calculateLnSlcSizeTerms(HashMap rbMap, int logMgra) + { + + logger.info("calculating Stop Location SOA Size Terms"); + + String uecPath = rbMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String slcSizeUecFile = rbMap.get(PROPERTIES_UEC_STOP_LOCATION_SIZE); + slcSizeUecFile = uecPath + slcSizeUecFile; + int slcSizeUecData = Integer.parseInt(rbMap.get(PROPERTIES_UEC_STOP_LOCATION_SIZE_DATA)); + int slcSizeUecModel = Integer.parseInt(rbMap.get(PROPERTIES_UEC_STOP_LOCATION_SIZE_MODEL)); + + IndexValues iv = new IndexValues(); + UtilityExpressionCalculator slcSizeUec = new UtilityExpressionCalculator(new File( + slcSizeUecFile), slcSizeUecModel, slcSizeUecData, rbMap, null); + + ArrayList mgras = mgraManager.getMgras(); + int maxMgra = mgraManager.getMaxMgra(); + int numSizeSegments = slcSizeUec.getNumberOfAlternatives(); + + // create the array for storing logged size term values - to be returned + // by this method + double[][] lnSlcSoaSize = new double[numSizeSegments][maxMgra + 1]; + slcSizeSample = new int[numSizeSegments][maxMgra + 1]; + slcSizeAvailable = new boolean[numSizeSegments][maxMgra + 1]; + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + iv.setZoneIndex(mgra); + double[] size = slcSizeUec.solve(iv, null, null); + + // if a logMgra values > 0 was specified, log the size term utility + // calculation for that mgra + if (mgra == logMgra) + slcSizeUec.logAnswersArray(slcSoaLogger, "Stop Location SOA Size Terms, MGRA = " + + mgra); + + // store the logged size terms + for (int i = 0; i < numSizeSegments; i++) + { + lnSlcSoaSize[i][mgra] = Math.log(size[i] + 1); + if (size[i] > 0) + { + slcSizeSample[i][mgra] = 1; + slcSizeAvailable[i][mgra] = true; + } + } + + } + + return lnSlcSoaSize; + + } + + private double[] getLnSlcSizeTermsForStopPurpose(int stopPurpose, Household hh) + { + + double[] lnSlcSizeTerms = null; + + switch (stopPurpose) + { + + case WORK_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = slcSizeTerms[WORK_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[WORK_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[WORK_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case UNIV_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = slcSizeTerms[UNIV_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[UNIV_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[UNIV_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case ESCORT_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = getLnSlcSizeTermsForEscortStopPurpose(hh); + break; + case SHOP_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = slcSizeTerms[SHOP_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[SHOP_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[SHOP_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case MAINT_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = slcSizeTerms[MAINT_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[MAINT_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[MAINT_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case EAT_OUT_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = slcSizeTerms[EAT_OUT_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[EAT_OUT_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[EAT_OUT_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case VISIT_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = slcSizeTerms[VISIT_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[VISIT_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[VISIT_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + case DISCR_STOP_PURPOSE_INDEX: + lnSlcSizeTerms = slcSizeTerms[DISCR_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[DISCR_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[DISCR_STOP_PURPOSE_SOA_SIZE_INDEX]; + break; + } + + // save backup arrays with oroginal availability and sample values. + // the procedure to generate availabilty for transit tours overwrites + // the arrays used by the UECs, + // so they need to be restored after that happens. + for (int i = 0; i < soaSample.length; i++) + { + soaSampleBackup[i] = soaSample[i]; + soaAvailabilityBackup[i] = soaAvailability[i]; + } + + return lnSlcSizeTerms; + + } + + private double[] getLnSlcSizeTermsForEscortStopPurpose(Household hh) + { + + double[] lnSlcSizeTermsForEscort = null; + + // set booleans for presence of preschool, grade school, and high school + // students in the hh + boolean psInHh = hh.getNumPreschool() > 0; + boolean gsInHh = hh.getNumGradeSchoolStudents() > 0; + boolean hsInHh = hh.getNumHighSchoolStudents() > 0; + + if (!psInHh && !gsInHh && !hsInHh) + { + // if hh has no preschool, grade school or high school children, set + // the array to that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_0_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_0_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_0_STOP_PURPOSE_SOA_SIZE_INDEX]; + } else if (psInHh && !gsInHh && !hsInHh) + { + // if hh has a preschool child and no gs or hs, set the array to + // that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_PS_STOP_PURPOSE_SOA_SIZE_INDEX]; + } else if (!psInHh && gsInHh && !hsInHh) + { + // if hh has a grade school child and no ps or hs, set the array to + // that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_GS_STOP_PURPOSE_SOA_SIZE_INDEX]; + } else if (!psInHh && !gsInHh && hsInHh) + { + // if hh has a high school child and no ps or gs, set the array to + // that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + } else if (psInHh && gsInHh && !hsInHh) + { + // if hh has a preschool and a grade school child and no hs, set the + // array to that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_PS_GS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_PS_GS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_PS_GS_STOP_PURPOSE_SOA_SIZE_INDEX]; + } else if (psInHh && !gsInHh && hsInHh) + { + // if hh has a preschool and a high school child and no gs, set the + // array to that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_PS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_PS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_PS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + } else if (!psInHh && gsInHh && hsInHh) + { + // if hh has a grade school and a high school child and no ps, set + // the array to that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + } else if (psInHh && gsInHh && hsInHh) + { + // if hh has a preschool a grade school and a high school child, set + // the array to that specific size term field + lnSlcSizeTermsForEscort = slcSizeTerms[ESCORT_PS_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaSample = slcSizeSample[ESCORT_PS_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + soaAvailability = slcSizeAvailable[ESCORT_PS_GS_HS_STOP_PURPOSE_SOA_SIZE_INDEX]; + } + + return lnSlcSizeTermsForEscort; + } + + public void applyModel(Household household, boolean withTiming) + { + + if (withTiming) zeroOutCpuTimes(); + + if (household.getDebugChoiceModels()) + { + slcLogger.info("applying SLC model for hhid=" + household.getHhId()); + } + + // get this household's person array + Person[] personArray = household.getPersons(); + + // loop through the person array (1-based) + for (int j = 1; j < personArray.length; ++j) + { + + ArrayList tours = new ArrayList(); + + Person person = personArray[j]; + + // apply stop location and mode choice for all individual tours. + tours.addAll(person.getListOfWorkTours()); + tours.addAll(person.getListOfSchoolTours()); + tours.addAll(person.getListOfIndividualNonMandatoryTours()); + tours.addAll(person.getListOfAtWorkSubtours()); + + for (Tour tour : tours) + { + + if (withTiming) applyForOutboundStopsWithTiming(tour, person, household); + else applyForOutboundStops(tour, person, household); + + if (withTiming) applyForInboundStopsWithTiming(tour, person, household); + else applyForInboundStops(tour, person, household); + + } // tour loop + + } // j (person loop) + + // apply stop location and mode choice for all joint tours. + Tour[] jointTours = household.getJointTourArray(); + if (jointTours != null) + { + + for (Tour tour : jointTours) + { + + if (withTiming) applyForOutboundStopsWithTiming(tour, null, household); + else applyForOutboundStops(tour, null, household); + + if (withTiming) applyForInboundStopsWithTiming(tour, null, household); + else applyForInboundStops(tour, null, household); + + } // tour loop + + } + + household.setStlRandomCount(household.getHhRandomCount()); + + } + + private void applyForOutboundStops(Tour tour, Person person, Household household) + { + + //don't apply if the outbound direction is escort + if((tour.getEscortTypeOutbound()==ModelStructure.RIDE_SHARING_TYPE)||(tour.getEscortTypeOutbound()==ModelStructure.PURE_ESCORTING_TYPE)) + return; + + Stop[] stops = tour.getOutboundStops(); + + // select trip depart periods for outbound stops + if (stops != null) + { + setOutboundTripDepartTimes(stops); + } + + int origMgra = tour.getTourOrigMgra(); + int destMgra = tour.getTourDestMgra(); + + applySlcModel(household, person, tour, stops, origMgra, destMgra, false); + + } + + private void applyForOutboundStopsWithTiming(Tour tour, Person person, Household household) + { + + //don't apply if the outbound direction is escort + if((tour.getEscortTypeOutbound()==ModelStructure.RIDE_SHARING_TYPE)||(tour.getEscortTypeOutbound()==ModelStructure.PURE_ESCORTING_TYPE)) + return; + + long check = System.nanoTime(); + + Stop[] stops = tour.getOutboundStops(); + + // select trip depart periods for outbound stops + if (stops != null) + { + setOutboundTripDepartTimes(stops); + } + + int origMgra = tour.getTourOrigMgra(); + int destMgra = tour.getTourDestMgra(); + + todTime += (System.nanoTime() - check); + + applySlcModelWithTiming(household, person, tour, stops, origMgra, destMgra, false); + + } + + private void applyForInboundStops(Tour tour, Person person, Household household) + { + + //don't apply if the inbound direction is escort + if((tour.getEscortTypeInbound()==ModelStructure.RIDE_SHARING_TYPE)||(tour.getEscortTypeInbound()==ModelStructure.PURE_ESCORTING_TYPE)) + return; + + Stop[] stops = tour.getInboundStops(); + + // select trip arrive periods for inbound stops + if (stops != null) + { + int lastOutboundTripDeparts = -1; + + // get the outbound stops array - note, if there were no outbound + // stops for half-tour, one stop object would have been generated + // to hold information about the half-tour trip, so this array + // should never be null. + Stop[] obStops = tour.getOutboundStops(); + if (obStops == null) + { + logger.error("error getting last outbound stop object for setting lastOutboundTripDeparts attribute for inbound stop arrival time choice."); + logger.error("HHID=" + household.getHhId() + ", persNum=" + person.getPersonNum() + + ", tourPurpose=" + tour.getTourPrimaryPurpose() + ", tourId=" + + tour.getTourId() + ", tourMode=" + tour.getTourModeChoice()); + throw new RuntimeException(); + } else + { + Stop lastStop = obStops[obStops.length - 1]; + lastOutboundTripDeparts = lastStop.getStopPeriod(); + } + + setInboundTripDepartTimes(stops, lastOutboundTripDeparts); + } + + int origMgra = tour.getTourDestMgra(); + int destMgra = tour.getTourOrigMgra(); + + applySlcModel(household, person, tour, stops, origMgra, destMgra, true); + + } + + private void applyForInboundStopsWithTiming(Tour tour, Person person, Household household) + { + + //don't apply if the inbound direction is escort + if((tour.getEscortTypeInbound()==ModelStructure.RIDE_SHARING_TYPE)||(tour.getEscortTypeInbound()==ModelStructure.PURE_ESCORTING_TYPE)) + return; + + long check = System.nanoTime(); + + Stop[] stops = tour.getInboundStops(); + + // select trip arrive periods for inbound stops + if (stops != null) + { + int lastOutboundTripDeparts = -1; + + // get the outbound stops array - note, if there were no outbound + // stops for half-tour, one stop object would have been generated + // to hold information about the half-tour trip, so this array + // should never be null. + Stop[] obStops = tour.getOutboundStops(); + if (obStops == null) + { + logger.error("error getting last outbound stop object for setting lastOutboundTripDeparts attribute for inbound stop arrival time choice."); + logger.error("HHID=" + household.getHhId() + ", persNum=" + person.getPersonNum() + + ", tourPurpose=" + tour.getTourPrimaryPurpose() + ", tourId=" + + tour.getTourId() + ", tourMode=" + tour.getTourModeChoice()); + throw new RuntimeException(); + } else + { + Stop lastStop = obStops[obStops.length - 1]; + lastOutboundTripDeparts = lastStop.getStopPeriod(); + } + + setInboundTripDepartTimes(stops, lastOutboundTripDeparts); + } + + int origMgra = tour.getTourDestMgra(); + int destMgra = tour.getTourOrigMgra(); + + todTime += (System.nanoTime() - check); + + applySlcModelWithTiming(household, person, tour, stops, origMgra, destMgra, true); + + } + + private void applySlcModel(Household household, Person person, Tour tour, Stop[] stops, + int origMgra, int destMgra, boolean directionIsInbound) + { + + int lastDest = -1; + int newOrig = -1; + + // get the array of distances from the tour origin mgra to all MGRAs. + // use these distances for tour orig to stop alt distances + anm.getDistancesFromMgra(origMgra, tourOrigToAllMgraDistances, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + anm.getDistancesFromMgra(destMgra, tourDestToAllMgraDistances, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + // anm.getDistancesToMgra( destMgra, tourDestToAllMgraDistances, + // modelStructure.getTourModeIsSovOrHov( tour.getTourModeChoice() ) ); + + // if there are stops on this half-tour, determine their destinations, + // depart hours, trip modes, and parking tazs. + if (stops != null) + { + + int oldSelectedIndex = -1; + for (int i = 0; i < stops.length; i++) + { + + Stop stop = stops[i]; + + // if i is 0, the stop origin is set to origMgra; otherwise stop + // orig is the chosen dest from the previous stop. + if (i == 0){ + newOrig = origMgra; + } + else{ + newOrig = lastDest; + } + stop.setOrig(newOrig); + + stopLocDmuObj.setStopObject(stop); + stopLocDmuObj.setDmuIndexValues(household.getHhId(), household.getHhMgra(), + newOrig, destMgra); + + int choice = -1; + int selectedIndex = -1; + int modeAlt = -1; + float modeLogsum = 0; + double vot = -1.0; + // if not the last stop object, make a destination choice and a + // mode choice from IK MC probabilities; + // otherwise stop dest is set to destMgra, and make a mode + // choice from KJ MC probabilities. + if (i < stops.length - 1) + { + + //new code - depart period to and from stop + int departPeriodToStop = stop.getStopPeriod(); + int departPeriodFromStop = -1; + if(!directionIsInbound) + departPeriodFromStop = tour.getOutboundStops()[i+1].getStopPeriod(); + else + departPeriodFromStop = tour.getInboundStops()[i+1].getStopPeriod(); + + try + { + + selectedIndex = selectDestination(stop, departPeriodToStop, departPeriodFromStop); + choice = finalSample[selectedIndex]; + stop.setDest(choice); + lastDest = choice; + + if (household.getDebugChoiceModels()) + { + smcLogger + .info("Monte Carlo selection for determining Mode Choice from IK Probabilities for " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " stop."); + smcLogger.info("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + smcLogger.info("StopID=" + (stop.getStopId() + 1) + " of " + + (stops.length - 1) + " stops, inbound=" + + stop.isInboundStop() + ", stopPurpose=" + + stop.getDestPurpose() + ", stopDepart=" + + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + } + + modeAlt = selectModeFromProbabilities(stop, + mcCumProbsSegmentIk[selectedIndex]); + modeLogsum = (float) mcLogsumsSegmentIk[selectedIndex]; + + if (modeAlt < 0) + { + logger.info("error getting trip mode choice for IK proportions, i=" + i); + logger.info("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + logger.info("StopID=" + (stop.getStopId() + 1) + " of " + + (stops.length - 1) + " stops, inbound=" + + stop.isInboundStop() + ", stopPurpose=" + + stop.getDestPurpose() + ", stopDepart=" + + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + throw new RuntimeException(); + } + + //value of time; lookup vot, votS2, or votS3 depending on chosen mode + if(modelStructure.getTripModeIsS2(modeAlt)){ + vot = mcVOTsSegmentIk[selectedIndex][1]; + }else if (modelStructure.getTripModeIsS3(modeAlt)){ + vot = mcVOTsSegmentIk[selectedIndex][2]; + }else{ + vot = mcVOTsSegmentIk[selectedIndex][0]; + } + + int park = -1; + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + if (park > 0) lastDest = park; + float parkingCost = parkingCostSegmentIk[selectedIndex]; + stop.setParkingCost(parkingCost); + + } + + } catch (Exception e) + { + logger.error(String + .format("Exception caught processing %s stop location choice model for %s type tour %s stop: HHID=%d, personNum=%s, stop=%d.", + (stopLocDmuObj.getInboundStop() == 1 ? "inbound" + : "outbound"), + tour.getTourCategory(), + tour.getTourPurpose(), + household.getHhId(), + (person == null ? "N/A" : Integer.toString(person + .getPersonNum())), (i + 1))); + throw new RuntimeException(e); + } + + stop.setMode(modeAlt); + stop.setModeLogsum(modeLogsum); + stop.setValueOfTime(vot); + + // if the trip is a transit mode, set the boarding and + // alighting tap pairs in the stop object based on the ik + // segment pairs + if ( modelStructure.getTripModeIsWalkTransit(modeAlt) | modelStructure.getTripModeIsPnrTransit(modeAlt) || modelStructure.getTripModeIsKnrTransit(modeAlt) ) { + + int accEgr = -1; + if(modelStructure.getTripModeIsWalkTransit(modeAlt)) { + accEgr = WTW; + } else { + if (stop.isInboundStop()) { + accEgr = WTD; + } else { + accEgr = DTW; + } + } + + if ( segmentIkBestTapPairs[selectedIndex][accEgr] == null ) { + stop.setBoardTap( 0 ); + stop.setAlightTap( 0 ); + stop.setSet( 0 ); + } + else { + + //pick transit path from N-paths + double rn = household.getHhRandom().nextDouble(); + int pathindex = logsumHelper.chooseTripPath(rn, segmentIkBestTapPairs[selectedIndex][accEgr], household.getDebugChoiceModels(), smcLogger); + + stop.setBoardTap( (int)segmentIkBestTapPairs[selectedIndex][accEgr][pathindex][0] ); + stop.setAlightTap( (int)segmentIkBestTapPairs[selectedIndex][accEgr][pathindex][1] ); + stop.setSet( (int)segmentIkBestTapPairs[selectedIndex][accEgr][pathindex][2] ); + + } + + } + + oldSelectedIndex = selectedIndex; + + } else + { + // last stop on half-tour, so dest is the half-tour final + // dest, and oldSelectedIndex was + // the selectedIndex determined for the previous stop + // location choice. + stop.setDest(destMgra); + + if (household.getDebugChoiceModels()) + { + smcLogger + .info("Monte Carlo selection for determining Mode Choice from KJ Probabilities for " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " stop."); + smcLogger.info("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + smcLogger.info("StopID=End of " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " half-tour, stopPurpose=" + stop.getDestPurpose() + + ", stopDepart=" + stop.getStopPeriod() + ", stopOrig=" + + stop.getOrig() + ", stopDest=" + stop.getDest()); + } + + modeAlt = selectModeFromProbabilities(stop, + mcCumProbsSegmentKj[oldSelectedIndex]); + modeLogsum = (float) mcLogsumsSegmentKj[oldSelectedIndex]; + + if (modeAlt < 0) + { + logger.error("error getting trip mode choice for KJ proportions, i=" + i); + logger.error("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + logger.error("StopID=End of " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " half-tour, stopPurpose=" + stop.getDestPurpose() + + ", stopDepart=" + stop.getStopPeriod() + ", stopOrig=" + + stop.getOrig() + ", stopDest=" + stop.getDest()); + throw new RuntimeException(); + } + + //value of time; lookup vot, votS2, or votS3 depending on chosen mode + if(modelStructure.getTripModeIsS2(modeAlt)){ + vot = mcVOTsSegmentKj[oldSelectedIndex][1]; + }else if (modelStructure.getTripModeIsS3(modeAlt)){ + vot = mcVOTsSegmentKj[oldSelectedIndex][2]; + }else{ + vot = mcVOTsSegmentKj[oldSelectedIndex][0]; + } + + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) { + float parkingCost = parkingCostSegmentKj[oldSelectedIndex]; + stop.setParkingCost(parkingCost); + } + // last stop on tour, so if inbound, only need park location + // choice if tour is work-based subtour; + // otherwise dest is home. + int park = -1; + if (directionIsInbound) + { + if (tour.getTourCategory() + .equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + } else + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + + stop.setMode(modeAlt); + stop.setModeLogsum(modeLogsum); + stop.setValueOfTime(vot); + + // if the last trip is a transit mode, set the boarding and + // alighting tap pairs in the stop object based on the kj + // segment pairs + if ( modelStructure.getTripModeIsWalkTransit(modeAlt) | modelStructure.getTripModeIsPnrTransit(modeAlt) || modelStructure.getTripModeIsKnrTransit(modeAlt) ) { + + int accEgr = -1; + if(modelStructure.getTripModeIsWalkTransit(modeAlt)) { + accEgr = WTW; + } else { + if (stop.isInboundStop()) { + accEgr = WTD; + } else { + accEgr = DTW; + } + } + + if ( segmentKjBestTapPairs[oldSelectedIndex][accEgr] == null ) { + stop.setBoardTap( 0 ); + stop.setAlightTap( 0 ); + stop.setSet( 0 ); + } + else { + + + //pick transit path from N-paths + float rn = (float)household.getHhRandom().nextDouble(); + int pathindex = logsumHelper.chooseTripPath(rn, segmentKjBestTapPairs[oldSelectedIndex][accEgr], household.getDebugChoiceModels(), smcLogger); + + stop.setBoardTap( (int)segmentKjBestTapPairs[oldSelectedIndex][accEgr][pathindex][0] ); + stop.setAlightTap( (int)segmentKjBestTapPairs[oldSelectedIndex][accEgr][pathindex][1] ); + stop.setSet( (int)segmentKjBestTapPairs[oldSelectedIndex][accEgr][pathindex][2] ); + } + + } + + } + + } + + } else + { + // create a stop object to hold attributes for orig, dest, mode, + // departtime, etc. + // for the half-tour with no stops. + + // create a Stop object for use in applying trip mode choice for + // this half tour without stops + String origStopPurpose = ""; + String destStopPurpose = ""; + if (!directionIsInbound) + { + origStopPurpose = tour.getTourCategory().equalsIgnoreCase( + ModelStructure.AT_WORK_CATEGORY) ? "Work" : "Home"; + destStopPurpose = tour.getTourPrimaryPurpose(); + } else + { + origStopPurpose = tour.getTourPrimaryPurpose(); + destStopPurpose = tour.getTourCategory().equalsIgnoreCase( + ModelStructure.AT_WORK_CATEGORY) ? "Work" : "Home"; + } + + Stop stop = null; + try + { + stop = tour.createStop(origStopPurpose, destStopPurpose, + directionIsInbound, + tour.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)); + } catch (Exception e) + { + logger.info("exception creating stop."); + throw new RuntimeException(e); + } + + // set stop origin and destination mgra, the stop period based on + // direction, then calculate the half-tour trip mode choice + stop.setOrig(origMgra); + stop.setDest(destMgra); + + if (directionIsInbound) stop.setStopPeriod(tour.getTourArrivePeriod()); + else stop.setStopPeriod(tour.getTourDepartPeriod()); + + int modeAlt = getHalfTourModeChoice(stop); + if (modeAlt < 0) + { + logger.info("error getting trip mode choice for half-tour with no stops."); + logger.info("HHID=" + household.getHhId() + ", persNum=" + person.getPersonNum() + + ", tourPurpose=" + tour.getTourPrimaryPurpose() + ", tourId=" + + tour.getTourId()); + logger.info("StopID=" + (stop.getStopId() + 1) + " of no stops, inbound=" + + stop.isInboundStop() + ", stopPurpose=" + stop.getDestPurpose() + + ", stopDepart=" + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + throw new RuntimeException(); + } + + stop.setMode(modeAlt); + + double[][] bestTaps = null; + if ( modelStructure.getTripModeIsWalkTransit(modeAlt) ) { + if ( directionIsInbound ) + bestTaps = tour.getBestWtwTapPairsIn(); + else + bestTaps = tour.getBestWtwTapPairsOut(); + } + else if ( modelStructure.getTripModeIsPnrTransit(modeAlt) || modelStructure.getTripModeIsKnrTransit(modeAlt) ) { + if ( directionIsInbound ) + bestTaps = tour.getBestWtdTapPairsIn(); + else + bestTaps = tour.getBestDtwTapPairsOut(); + } + + if ( bestTaps == null ) { + stop.setBoardTap( 0 ); + stop.setAlightTap( 0 ); + stop.setSet( 0 ); + } + else { + + //pick transit path from N-paths + float rn = (float)household.getHhRandom().nextDouble(); + int pathindex = logsumHelper.chooseTripPath(rn, bestTaps, household.getDebugChoiceModels(), smcLogger); + + stop.setBoardTap( (int)bestTaps[pathindex][0] ); + stop.setAlightTap( (int)bestTaps[pathindex][1] ); + stop.setSet( (int)bestTaps[pathindex][2] ); + } + + // inbound half-tour, only need park location choice if tour is + // work-based subtour; + // otherwise dest is home. + int park = -1; + if (directionIsInbound) + { + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + } else + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + + } + + } + + private void applySlcModelWithTiming(Household household, Person person, Tour tour, + Stop[] stops, int origMgra, int destMgra, boolean directionIsInbound) + { + + int lastDest = -1; + int newOrig = -1; + + // get the array of distances from the tour origin mgra to all MGRAs. + // use these distances for tour orig to stop alt distances + long check = System.nanoTime(); + anm.getDistancesFromMgra(origMgra, tourOrigToAllMgraDistances, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + anm.getDistancesFromMgra(destMgra, tourDestToAllMgraDistances, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + // anm.getDistancesToMgra( destMgra, tourDestToAllMgraDistances, + // modelStructure.getTourModeIsSovOrHov( tour.getTourModeChoice() ) ); + sldTime += (System.nanoTime() - check); + + // if there are stops on this half-tour, determine their destinations, + // depart hours, trip modes, and parking tazs. + if (stops != null) + { + + int oldSelectedIndex = -1; + earlierTripWasLocatedInAlightingTapShed = false; + + for (int i = 0; i < stops.length; i++) + { + + Stop stop = stops[i]; + + // if i is 0, the stop origin is set to origMgra; otherwise stop + // orig is the chosen dest from the previous stop. + if (i == 0) newOrig = origMgra; + else newOrig = lastDest; + stop.setOrig(newOrig); + + stopLocDmuObj.setStopObject(stop); + stopLocDmuObj.setDmuIndexValues(household.getHhId(), household.getHhMgra(), + newOrig, destMgra); + + int choice = -1; + int selectedIndex = -1; + int modeAlt = -1; + float modeLogsum = 0; + double vot= -1; + + // if not the last stop object, make a destination choice and a + // mode choice from IK MC probabilities; + // otherwise stop dest is set to destMgra, and make a mode + // choice from KJ MC probabilities. + if (i < stops.length - 1) + { + + //new code - depart period to and from stop + int departPeriodToStop = stop.getStopPeriod(); + int departPeriodFromStop = -1; + if(!directionIsInbound) + departPeriodFromStop = tour.getOutboundStops()[i+1].getStopPeriod(); + else + departPeriodFromStop = tour.getInboundStops()[i+1].getStopPeriod(); + + try + { + + check = System.nanoTime(); + + selectedIndex = selectDestinationWithTiming(stop,departPeriodToStop,departPeriodFromStop); + //close small probability logical hole, reset stop destination as intrazonal stop, log out reset cases + if(selectedIndex<0) { + selectedIndex=0; + choice=origMgra; + stop.setDest(choice); + modeAlt=tour.getTourModeChoice(); + modeLogsum=0; + logger.warn("Stop ID"+stop.id+" :destination set as intrazonal stop"); + }else { + choice = finalSample[selectedIndex]; + stop.setDest(choice); + modeAlt = selectModeFromProbabilities(stop, + mcCumProbsSegmentIk[selectedIndex]); + modeLogsum = (float) mcLogsumsSegmentIk[selectedIndex]; + } + + if (sampleMgraInAlightingTapShed[choice]) + earlierTripWasLocatedInAlightingTapShed = true; + lastDest = choice; + slcTime += (System.nanoTime() - check); + + if (household.getDebugChoiceModels()) + { + if (tour.getTourCategory().equalsIgnoreCase( + ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + smcLogger + .info("Monte Carlo selection for determining Mode Choice from IK Probabilities for " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " for joint tour stop."); + smcLogger.info("HHID=" + household.getHhId() + ", persNum=" + "N/A" + + ", tourPurpose=" + tour.getTourPrimaryPurpose() + + ", tourId=" + tour.getTourId() + ", tourMode=" + + tour.getTourModeChoice()); + smcLogger.info("StopID=" + (stop.getStopId() + 1) + " of " + + (stops.length - 1) + " stops, inbound=" + + stop.isInboundStop() + ", stopPurpose=" + + stop.getDestPurpose() + ", stopDepart=" + + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + } else + { + smcLogger + .info("Monte Carlo selection for determining Mode Choice from IK Probabilities for " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " stop."); + smcLogger.info("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + + tour.getTourId() + ", tourMode=" + + tour.getTourModeChoice()); + smcLogger.info("StopID=" + (stop.getStopId() + 1) + " of " + + (stops.length - 1) + " stops, inbound=" + + stop.isInboundStop() + ", stopPurpose=" + + stop.getDestPurpose() + ", stopDepart=" + + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + } + } + + check = System.nanoTime(); + /* + modeAlt = selectModeFromProbabilities(stop, + mcCumProbsSegmentIk[selectedIndex]); + modeLogsum = (float) mcLogsumsSegmentIk[selectedIndex]; + */ + + if (modeAlt < 0) + { + logger.info("error getting trip mode choice for IK proportions, i=" + i); + logger.info("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + logger.info("StopID=" + (stop.getStopId() + 1) + " of " + + (stops.length - 1) + " stops, inbound=" + + stop.isInboundStop() + ", stopPurpose=" + + stop.getDestPurpose() + ", stopDepart=" + + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + throw new RuntimeException(); + } + + //value of time; lookup vot, votS2, or votS3 depending on chosen mode + if(modelStructure.getTripModeIsS2(modeAlt)){ + vot = mcVOTsSegmentIk[selectedIndex][1]; + }else if (modelStructure.getTripModeIsS3(modeAlt)){ + vot = mcVOTsSegmentIk[selectedIndex][2]; + }else{ + vot = mcVOTsSegmentIk[selectedIndex][0]; + } + + int park = -1; + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + if (park > 0) lastDest = park; + float parkingCost = parkingCostSegmentIk[selectedIndex]; + stop.setParkingCost(parkingCost); + + } + + smcTime += (System.nanoTime() - check); + } catch (Exception e) + { + logger.error(String.format( + "Exception caught processing %s stop location choice model.", + (stopLocDmuObj.getInboundStop() == 1 ? "inbound" : "outbound"))); + logger.error("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tour category=" + + tour.getTourCategory() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + logger.error("StopID=" + (stop.getStopId() + 1) + " of " + + (stops.length - 1) + " stops, inbound=" + stop.isInboundStop() + + ", stopPurpose=" + stop.getDestPurpose() + ", stopDepart=" + + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + logger.error(String + .format("origMgra=%d, destMgra=%d, newOrig=%d, lastDest=%d, modeAlt=%d, selectedIndex=%d, choice=%d.", + origMgra, destMgra, newOrig, lastDest, modeAlt, + selectedIndex, choice)); + throw new RuntimeException(e); + } + + stop.setMode(modeAlt); + stop.setModeLogsum(modeLogsum); + stop.setValueOfTime(vot); + + // if the trip is a transit mode, set the boarding and + // alighting tap pairs in the stop object based on the ik + // segment pairs + if ( modelStructure.getTripModeIsWalkTransit(modeAlt) | modelStructure.getTripModeIsPnrTransit(modeAlt) || modelStructure.getTripModeIsKnrTransit(modeAlt) ) { + + int accEgr = -1; + if(modelStructure.getTripModeIsWalkTransit(modeAlt)) { + accEgr = WTW; + } else { + if (stop.isInboundStop()) { + accEgr = WTD; + } else { + accEgr = DTW; + } + } + + if ( segmentIkBestTapPairs[selectedIndex] == null ) { + stop.setBoardTap( 0 ); + stop.setAlightTap( 0 ); + stop.setSet( 0 ); + } + else { + + //pick transit path from N-paths + double rn = household.getHhRandom().nextDouble(); + int pathindex = logsumHelper.chooseTripPath(rn, segmentIkBestTapPairs[selectedIndex][accEgr], household.getDebugChoiceModels(), smcLogger); + + stop.setBoardTap( (int)segmentIkBestTapPairs[selectedIndex][accEgr][pathindex][0] ); + stop.setAlightTap( (int)segmentIkBestTapPairs[selectedIndex][accEgr][pathindex][1] ); + stop.setSet( (int)segmentIkBestTapPairs[selectedIndex][accEgr][pathindex][2] ); + + } + + } + + oldSelectedIndex = selectedIndex; + + } else + { + + // last stop on half-tour, so dest is the half-tour final + // dest, and oldSelectedIndex was + // the selectedIndex determined for the previous stop + // location choice. + stop.setDest(destMgra); + + if (household.getDebugChoiceModels()) + { + if (tour.getTourCategory().equalsIgnoreCase( + ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + smcLogger + .info("Monte Carlo selection for determining Mode Choice from KJ Probabilities for " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " joint tour stop."); + smcLogger.info("HHID=" + household.getHhId() + ", persNum=" + "N/A" + + ", tourPurpose=" + tour.getTourPrimaryPurpose() + ", tourId=" + + tour.getTourId() + ", tourMode=" + tour.getTourModeChoice()); + smcLogger.info("StopID=End of " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " half-tour, stopPurpose=" + stop.getDestPurpose() + + ", stopDepart=" + stop.getStopPeriod() + ", stopOrig=" + + stop.getOrig() + ", stopDest=" + stop.getDest()); + } else + { + smcLogger + .info("Monte Carlo selection for determining Mode Choice from KJ Probabilities for " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " stop."); + smcLogger.info("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + smcLogger.info("StopID=End of " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " half-tour, stopPurpose=" + stop.getDestPurpose() + + ", stopDepart=" + stop.getStopPeriod() + ", stopOrig=" + + stop.getOrig() + ", stopDest=" + stop.getDest()); + } + } + check = System.nanoTime(); + //Wu added + if(mcCumProbsSegmentKj[oldSelectedIndex]!=null&&mcLogsumsSegmentKj!=null) { + modeAlt = selectModeFromProbabilities(stop, + mcCumProbsSegmentKj[oldSelectedIndex]); + modeLogsum = (float) mcLogsumsSegmentKj[oldSelectedIndex]; + }else { + modeAlt = tour.getTourModeChoice(); + modeLogsum = 0; + logger.warn("Stop ID"+stop.id+" :mode and mode logsum reset."); + } + + if (modeAlt < 0) + { + logger.error("error getting trip mode choice for KJ proportions, i=" + i); + logger.error("HHID=" + household.getHhId() + ", persNum=" + + person.getPersonNum() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId() + + ", tourMode=" + tour.getTourModeChoice()); + logger.error("StopID=End of " + + (stop.isInboundStop() ? "INBOUND" : "OUTBOUND") + + " half-tour, stopPurpose=" + stop.getDestPurpose() + + ", stopDepart=" + stop.getStopPeriod() + ", stopOrig=" + + stop.getOrig() + ", stopDest=" + stop.getDest()); + throw new RuntimeException(); + } + + //value of time; lookup vot, votS2, or votS3 depending on chosen mode + if(modelStructure.getTripModeIsS2(modeAlt)){ + vot = mcVOTsSegmentKj[oldSelectedIndex][1]; + }else if (modelStructure.getTripModeIsS3(modeAlt)){ + vot = mcVOTsSegmentKj[oldSelectedIndex][2]; + }else{ + vot = mcVOTsSegmentKj[oldSelectedIndex][0]; + } + + + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) { + float parkingCost = parkingCostSegmentKj[oldSelectedIndex]; + stop.setParkingCost(parkingCost); + } + // last stop on tour, so if inbound, only need park location + // choice if tour is work-based subtour; + // otherwise dest is home. + int park = -1; + if (directionIsInbound) + { + if (tour.getTourCategory() + .equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + } else + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + + smcTime += (System.nanoTime() - check); + + stop.setMode(modeAlt); + stop.setModeLogsum(modeLogsum); + stop.setValueOfTime(vot); + + // if the last trip is a transit mode, set the boarding and + // alighting tap pairs in the stop object based on the kj + // segment pairs + if ( modelStructure.getTripModeIsWalkTransit(modeAlt) || modelStructure.getTripModeIsPnrTransit(modeAlt) || modelStructure.getTripModeIsKnrTransit(modeAlt) ) { + + int accEgr = -1; + if(modelStructure.getTripModeIsWalkTransit(modeAlt)) { + accEgr = WTW; + } else { + if (stop.isInboundStop()) { + accEgr = WTD; + } else { + accEgr = DTW; + } + } + + if ( segmentKjBestTapPairs[oldSelectedIndex] == null ) { + stop.setBoardTap( 0 ); + stop.setAlightTap( 0 ); + stop.setSet( 0 ); + } + else { + + //pick transit path from N-paths + float rn = (float)household.getHhRandom().nextDouble(); + int pathindex = logsumHelper.chooseTripPath(rn, segmentKjBestTapPairs[oldSelectedIndex][accEgr], household.getDebugChoiceModels(), smcLogger); + + stop.setBoardTap( (int)segmentKjBestTapPairs[oldSelectedIndex][accEgr][pathindex][0] ); + stop.setAlightTap( (int)segmentKjBestTapPairs[oldSelectedIndex][accEgr][pathindex][1] ); + stop.setSet( (int)segmentKjBestTapPairs[oldSelectedIndex][accEgr][pathindex][2] ); + + } + + } + + } + + } + + } else + { // create a stop object to hold attributes for orig, dest, mode, + // departtime, etc. + // for the half-tour with no stops. + + check = System.nanoTime(); + + // create a Stop object for use in applying trip mode choice for + // this half tour without stops + String origStopPurpose = ""; + String destStopPurpose = ""; + if (!directionIsInbound) + { + origStopPurpose = tour.getTourCategory().equalsIgnoreCase( + ModelStructure.AT_WORK_CATEGORY) ? "Work" : "Home"; + destStopPurpose = tour.getTourPrimaryPurpose(); + } else + { + origStopPurpose = tour.getTourPrimaryPurpose(); + destStopPurpose = tour.getTourCategory().equalsIgnoreCase( + ModelStructure.AT_WORK_CATEGORY) ? "Work" : "Home"; + } + + Stop stop = null; + try + { + stop = tour.createStop(origStopPurpose, destStopPurpose, + directionIsInbound, + tour.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)); + } catch (Exception e) + { + logger.info("exception creating stop."); + } + + stop.setOrig(origMgra); + stop.setDest(destMgra); + + if (directionIsInbound) stop.setStopPeriod(tour.getTourArrivePeriod()); + else stop.setStopPeriod(tour.getTourDepartPeriod()); + + int modeAlt = getHalfTourModeChoice(stop); + if (modeAlt < 0) + { + logger.info("error getting trip mode choice for half-tour with no stops."); + logger.info("HHID=" + household.getHhId() + ", tourPurpose=" + + tour.getTourPrimaryPurpose() + ", tourId=" + tour.getTourId()); + logger.info("StopID=" + (stop.getStopId() + 1) + " of no stops, inbound=" + + stop.isInboundStop() + ", stopPurpose=" + stop.getDestPurpose() + + ", stopDepart=" + stop.getStopPeriod() + ", stopOrig=" + stop.getOrig() + + ", stopDest=" + stop.getDest()); + + modeAlt = stop.getTour().getTourModeChoice(); + // throw new RuntimeException(); + } + + stop.setMode(modeAlt); + + double[][] bestTaps = null; + if ( modelStructure.getTripModeIsWalkTransit(modeAlt) ) { + if ( directionIsInbound ) + bestTaps = tour.getBestWtwTapPairsIn(); + else + bestTaps = tour.getBestWtwTapPairsOut(); + } + else if ( modelStructure.getTripModeIsPnrTransit(modeAlt) || modelStructure.getTripModeIsKnrTransit(modeAlt) ) { + if ( directionIsInbound ) + bestTaps = tour.getBestWtdTapPairsIn(); + else + bestTaps = tour.getBestDtwTapPairsOut(); + } + + if ( bestTaps == null ) { + stop.setBoardTap( 0 ); + stop.setAlightTap( 0 ); + stop.setSet( 0 ); + } + else { + + // set taps + if ( modelStructure.getTripModeIsWalkTransit(modeAlt) || modelStructure.getTripModeIsPnrTransit(modeAlt) || modelStructure.getTripModeIsKnrTransit(modeAlt) ) { + + //pick transit path from N-paths + float rn = (float)household.getHhRandom().nextDouble(); + int pathindex = logsumHelper.chooseTripPath(rn, bestTaps, household.getDebugChoiceModels(), smcLogger); + + stop.setBoardTap( (int)bestTaps[pathindex][0] ); + stop.setAlightTap( (int)bestTaps[pathindex][1] ); + stop.setSet( (int)bestTaps[pathindex][2] ); + + } + + } + + // inbound half-tour, only need park location choice if tour is + // work-based subtour; + // otherwise dest is home. + int park = -1; + if (directionIsInbound) + { + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + } else + { + if (modelStructure.getTripModeIsSovOrHov(modeAlt)) + { + park = selectParkingLocation(household, tour, stop); + stop.setPark(park); + } + } + + smcTime += (System.nanoTime() - check); + } + + } + + private int selectDestination(Stop s, int departPeriodToStop, int departPeriodFromStop) + { + + Logger modelLogger = slcLogger; + + int[] loggingSample = null; + int[] debugLoggingSample = null; + // int[] debugLoggingSample = { 0, 16569 }; + // int[] debugLoggingSample = { 0, 4886, 16859, 18355, 3222, 14879, + // 26894, 16512, 9908, 18287, 14989 }; + + Tour tour = s.getTour(); + Person person = tour.getPersonObject(); + Household household = person.getHouseholdObject(); + + if (household.getDebugChoiceModels()) + { + household.logHouseholdObject( + "Pre Stop Location Choice for trip: HH_" + household.getHhId() + ", Pers_" + + tour.getPersonObject().getPersonNum() + ", Tour Purpose_" + + tour.getTourPurpose() + ", Tour_" + tour.getTourId() + + ", Tour Purpose_" + tour.getTourPurpose() + ", Stop_" + + (s.getStopId() + 1), modelLogger); + household.logPersonObject("Pre Stop Location Choice for person " + + tour.getPersonObject().getPersonNum(), modelLogger, tour.getPersonObject()); + household.logTourObject("Pre Stop Location Choice for tour " + tour.getTourId(), + modelLogger, tour.getPersonObject(), tour); + household.logStopObject("Pre Stop Location Choice for stop " + (s.getStopId() + 1), + modelLogger, s, modelStructure); + + loggingSample = debugLoggingSample; + } + + int numAltsInSample = -1; + + stopLocDmuObj.setTourModeIndex(tour.getTourModeChoice()); + + // set the size terms array for the stop purpose in the dmu object + stopLocDmuObj + .setLogSize(getLnSlcSizeTermsForStopPurpose(s.getStopPurposeIndex(), household)); + + // get the array of distances from the stop origin mgra to all MGRAs and + // set in the dmu object + anm.getDistancesFromMgra(s.getOrig(), distanceFromStopOrigToAllMgras, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + stopLocDmuObj.setDistancesFromOrigMgra(distanceFromStopOrigToAllMgras); + + + // bike logsums from origin to all destinations + if(modelStructure.getTourModeIsBike(tour.getTourModeChoice())){ + + Arrays.fill(bikeLogsumFromStopOrigToAllMgras, 0); + segment = new BikeLogsumSegment(person.getPersonIsFemale() == 1,tour.getTourPrimaryPurposeIndex() <= 3,s.isInboundStop()); + + for (int dMgra = 1; dMgra <= mgraManager.getMaxMgra(); dMgra++) + { + bikeLogsumFromStopOrigToAllMgras[dMgra] = bls.getLogsum(segment,s.getOrig(),dMgra); + } + stopLocDmuObj.setBikeLogsumsFromOrigMgra(bikeLogsumFromStopOrigToAllMgras); + } + + + + // if tour mode is transit, set availablity of location alternatives + // based on transit accessibility relative to best transit TAP pair for + // tour + if (modelStructure.getTourModeIsTransit(tour.getTourModeChoice())) + { + + Arrays.fill(sampleMgraInBoardingTapShed, false); + Arrays.fill(sampleMgraInAlightingTapShed, false); + + int numAvailableAlternatives = setSoaAvailabilityForTransitTour(s, tour, household.getDebugChoiceModels()); + if (numAvailableAlternatives == 0) + { + logger.error("no available locations - empty sample."); + logger.error("best tap pair which is empty: " + Arrays.deepToString(s.isInboundStop() ? tour.getBestWtwTapPairsIn() : tour.getBestWtwTapPairsOut())); + throw new RuntimeException(); + } + } + + // get the array of distances to the half-tour final destination mgra + // from all MGRAs and set in the dmu object + if (s.isInboundStop()) + { + // if inbound, final half-tour destination is the tour origin + anm.getDistancesToMgra(tour.getTourOrigMgra(), distanceToFinalDestFromAllMgras, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + stopLocDmuObj.setDistancesToDestMgra(distanceToFinalDestFromAllMgras); + + + // set the distance from the stop origin to the final half-tour + // destination + stopLocDmuObj + .setOrigDestDistance(distanceFromStopOrigToAllMgras[tour.getTourOrigMgra()]); + + + // bike logsums from all MGRAs back to tour origin + if(modelStructure.getTourModeIsBike(tour.getTourModeChoice())){ + + Arrays.fill(bikeLogsumToFinalDestFromAllMgras, 0); + segment = new BikeLogsumSegment(person.getPersonIsFemale() == 1,tour.getTourPrimaryPurposeIndex() <= 3,s.isInboundStop()); + + for (int oMgra = 1; oMgra <= mgraManager.getMaxMgra(); oMgra++) + { + bikeLogsumToFinalDestFromAllMgras[oMgra] = bls.getLogsum(segment,oMgra,tour.getTourOrigMgra()); + } + stopLocDmuObj.setBikeLogsumsToDestMgra(bikeLogsumToFinalDestFromAllMgras); + } + + + + + + } else + { + // if outbound, final half-tour destination is the tour destination + anm.getDistancesToMgra(tour.getTourDestMgra(), distanceToFinalDestFromAllMgras, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + stopLocDmuObj.setDistancesToDestMgra(distanceToFinalDestFromAllMgras); + + // set the distance from the stop origin to the final half-tour + // destination + stopLocDmuObj + .setOrigDestDistance(distanceFromStopOrigToAllMgras[tour.getTourDestMgra()]); + + // bike logsums from all MGRAs back to tour origin + if(modelStructure.getTourModeIsBike(tour.getTourModeChoice())){ + + Arrays.fill(bikeLogsumToFinalDestFromAllMgras, 0); + segment = new BikeLogsumSegment(person.getPersonIsFemale() == 1,tour.getTourPrimaryPurposeIndex() <= 3,s.isInboundStop()); + + for (int oMgra = 1; oMgra <= mgraManager.getMaxMgra(); oMgra++) + { + bikeLogsumToFinalDestFromAllMgras[oMgra] = bls.getLogsum(segment,oMgra,tour.getTourDestMgra()); + } + stopLocDmuObj.setBikeLogsumsToDestMgra(bikeLogsumToFinalDestFromAllMgras); + } + + + + + } + + if (useNewSoaMethod) + { + if (modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())) selectSampleOfAlternativesAutoTourNew( + s, tour, person, household, loggingSample); + else selectSampleOfAlternativesOther(s, tour, person, household, loggingSample); + + numAltsInSample = dcTwoStageModelObject.getNumberofUniqueMgrasInSample(); + } else + { + if (modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())) selectSampleOfAlternativesAutoTour( + s, tour, person, household, loggingSample); + else selectSampleOfAlternativesOther(s, tour, person, household, loggingSample); + + numAltsInSample = altFreqMap.size(); + } + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + String separator = ""; + + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = "Stop Location Choice"; + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopId=%d", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourPurpose(), tour.getTourModeChoice(), tour.getTourId(), + s.getDestPurpose(), (s.getStopId() + 1)); + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + } + + setupStopLocationChoiceAlternativeArrays(numAltsInSample, s, departPeriodToStop,departPeriodFromStop); + + int slcModelIndex = -1; + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.MANDATORY_CATEGORY)) slcModelIndex = MAND_SLC_MODEL_INDEX; + else if (tour.getTourPrimaryPurposeIndex() == ModelStructure.ESCORT_PRIMARY_PURPOSE_INDEX + || tour.getTourPrimaryPurposeIndex() == ModelStructure.SHOPPING_PRIMARY_PURPOSE_INDEX + || tour.getTourPrimaryPurposeIndex() == ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_INDEX) slcModelIndex = MAINT_SLC_MODEL_INDEX; + else slcModelIndex = DISCR_SLC_MODEL_INDEX; + + float logsum = (float) slcModelArray[slcModelIndex].computeUtilities(stopLocDmuObj, + stopLocDmuObj.getDmuIndexValues(), sampleAvailability, inSample); + + if(s.isInboundStop()) + tour.addInboundStopDestinationLogsum(logsum); + else + tour.addOutboundStopDestinationLogsum(logsum); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + int selectedIndex = -1; + if (slcModelArray[slcModelIndex].getAvailabilityCount() > 0) + { + chosen = slcModelArray[slcModelIndex].getChoiceResult(rn); + selectedIndex = chosen; + }else{ + //wu's tempory fix to set chosen stop alternative to origin mgra if no alternative is available-8/27/2014 + //instead of this method, seems selectDestinationWithTiming(Stop s) is called (similar change made there too) + //tempory fix is put in here just in case. + chosen=tour.getTourOrigMgra(); + } + + // write choice model alternative info to log file + if (household.getDebugChoiceModels() || chosen < 0) + { + + if (chosen < 0) + { + + modelLogger + .error("ERROR selecting stop location choice due to no alternatives available."); + modelLogger + .error("setting debug to true and recomputing sample of alternatives selection."); + modelLogger + .error(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopId=%d, StopOrig=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourPurpose(), + tour.getTourModeChoice(), tour.getTourId(), + s.getDestPurpose(), (s.getStopId() + 1), s.getOrig())); + + choiceModelDescription = "Stop Location Choice"; + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopId=%d, StopOrig=%d", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourPurpose(), tour.getTourModeChoice(), tour.getTourId(), + s.getDestPurpose(), (s.getStopId() + 1), s.getOrig()); + loggingHeader = String.format("%s for %s", choiceModelDescription, + decisionMakerLabel); + + modelLogger.error(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.error(loggingHeader); + modelLogger.error(separator); + modelLogger.error(""); + modelLogger.error(""); + + // utilities and probabilities are 0 based. + double[] utilities = slcModelArray[slcModelIndex].getUtilities(); + double[] probabilities = slcModelArray[slcModelIndex].getProbabilities(); + + // availabilities is 1 based. + boolean[] availabilities = slcModelArray[slcModelIndex].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger + .error("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .error("Alternative Availability Utility Probability CumProb"); + modelLogger + .error("--------------------- ------------ ----------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 1; j <= numAltsInSample; j++) + { + + int alt = finalSample[j]; + + if (j == chosen) selectedIndex = j; + + cumProb += probabilities[j - 1]; + String altString = String.format("%-3d %5d", j, alt); + modelLogger.error(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j], utilities[j - 1], probabilities[j - 1], cumProb)); + } + + modelLogger.error(" "); + String altString = String.format("%-3d %5d", selectedIndex, -1); + modelLogger.error(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.error(separator); + modelLogger.error(""); + modelLogger.error(""); + + slcModelArray[slcModelIndex].logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + slcModelArray[slcModelIndex].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log + // file + slcModelArray[slcModelIndex].logUECResults(modelLogger, loggingHeader); + + logger.error(String + .format("Error for HHID=%d, PersonNum=%d, no available %s stop destination choice alternatives to choose from in choiceModelApplication.", + tour.getHhId(), tour.getPersonObject().getPersonNum(), + tour.getTourPurpose())); + throw new RuntimeException(); + + } + + // utilities and probabilities are 0 based. + double[] utilities = slcModelArray[slcModelIndex].getUtilities(); + double[] probabilities = slcModelArray[slcModelIndex].getProbabilities(); + + // availabilities is 1 based. + boolean[] availabilities = slcModelArray[slcModelIndex].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- ------------ ----------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 1; j <= numAltsInSample; j++) + { + + int alt = finalSample[j]; + + if (j == chosen) selectedIndex = j; + + cumProb += probabilities[j - 1]; + String altString = String.format("%-3d %5d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j], utilities[j - 1], probabilities[j - 1], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %5d", selectedIndex, finalSample[selectedIndex]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + slcModelArray[slcModelIndex].logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + slcModelArray[slcModelIndex].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log file + slcModelArray[slcModelIndex].logUECResults(modelLogger, loggingHeader); + + } + + return selectedIndex; + } + + private int selectDestinationWithTiming(Stop s,int departPeriodToStop,int departPeriodFromStop) + { + + Logger modelLogger = slcLogger; + + int[] loggingSample = null; + int[] debugLoggingSample = null; + // int[] debugLoggingSample = { 0, 16569 }; + // int[] debugLoggingSample = { 0, 4886, 16859, 18355, 3222, 14879, + // 26894, 16512, 9908, 18287, 14989 }; + + Tour tour = s.getTour(); + Person person = tour.getPersonObject(); + Household household = person.getHouseholdObject(); + + if (household.getDebugChoiceModels()) + { + household.logHouseholdObject( + "Pre Stop Location Choice for trip: HH_" + household.getHhId() + ", Pers_" + + tour.getPersonObject().getPersonNum() + ", Tour Purpose_" + + tour.getTourPurpose() + ", Tour_" + tour.getTourId() + + ", Tour Purpose_" + tour.getTourPurpose() + ", Stop_" + + (s.getStopId() + 1), modelLogger); + household.logPersonObject("Pre Stop Location Choice for person " + + tour.getPersonObject().getPersonNum(), modelLogger, tour.getPersonObject()); + household.logTourObject("Pre Stop Location Choice for tour " + tour.getTourId(), + modelLogger, tour.getPersonObject(), tour); + household.logStopObject("Pre Stop Location Choice for stop " + (s.getStopId() + 1), + modelLogger, s, modelStructure); + + loggingSample = debugLoggingSample; + } + + int numAltsInSample = -1; + + stopLocDmuObj.setTourModeIndex(tour.getTourModeChoice()); + + // set the size terms array for the stop purpose in the dmu object + stopLocDmuObj + .setLogSize(getLnSlcSizeTermsForStopPurpose(s.getStopPurposeIndex(), household)); + + // get the array of distances from the stop origin mgra to all MGRAs and + // set in the dmu object + anm.getDistancesFromMgra(s.getOrig(), distanceFromStopOrigToAllMgras, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + stopLocDmuObj.setDistancesFromOrigMgra(distanceFromStopOrigToAllMgras); + + + // bike logsums from origin to all destinations + if(modelStructure.getTourModeIsBike(tour.getTourModeChoice())){ + + Arrays.fill(bikeLogsumFromStopOrigToAllMgras, 0); + segment = new BikeLogsumSegment(person.getPersonIsFemale() == 1,tour.getTourPrimaryPurposeIndex() <= 3,s.isInboundStop()); + + for (int dMgra = 1; dMgra <= mgraManager.getMaxMgra(); dMgra++) + { + bikeLogsumFromStopOrigToAllMgras[dMgra] = bls.getLogsum(segment,s.getOrig(),dMgra); + } + stopLocDmuObj.setBikeLogsumsFromOrigMgra(bikeLogsumFromStopOrigToAllMgras); + } + + // if tour mode is transit, set availablity of location alternatives + // based on transit accessibility relative to best transit TAP pair for + // tour + if (modelStructure.getTourModeIsTransit(tour.getTourModeChoice())) + { + + Arrays.fill(sampleMgraInBoardingTapShed, false); + Arrays.fill(sampleMgraInAlightingTapShed, false); + + int numAvailableAlternatives = setSoaAvailabilityForTransitTour(s, tour, household.getDebugChoiceModels()); + if (numAvailableAlternatives == 0) + { + logger.error("no available locations - empty sample."); + logger.error("best tap pair which is empty: " + Arrays.deepToString(s.isInboundStop() ? tour.getBestWtwTapPairsIn() : tour.getBestWtwTapPairsOut())); + throw new RuntimeException(); + } + } + + // get the array of distances to the half-tour final destination mgra + // from all MGRAs and set in the dmu object + if (s.isInboundStop()) + { + // if inbound, final half-tour destination is the tour origin + anm.getDistancesToMgra(tour.getTourOrigMgra(), distanceToFinalDestFromAllMgras, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + stopLocDmuObj.setDistancesToDestMgra(distanceToFinalDestFromAllMgras); + + // set the distance from the stop origin to the final half-tour + // destination + stopLocDmuObj + .setOrigDestDistance(distanceFromStopOrigToAllMgras[tour.getTourOrigMgra()]); + + // bike logsums from all MGRAs back to tour origin + if(modelStructure.getTourModeIsBike(tour.getTourModeChoice())){ + + Arrays.fill(bikeLogsumToFinalDestFromAllMgras, 0); + segment = new BikeLogsumSegment(person.getPersonIsFemale() == 1,tour.getTourPrimaryPurposeIndex() <= 3,s.isInboundStop()); + + for (int oMgra = 1; oMgra <= mgraManager.getMaxMgra(); oMgra++) + { + bikeLogsumToFinalDestFromAllMgras[oMgra] = bls.getLogsum(segment,oMgra,tour.getTourOrigMgra()); + } + stopLocDmuObj.setBikeLogsumsToDestMgra(bikeLogsumToFinalDestFromAllMgras); + } + + + } else + { + // if outbound, final half-tour destination is the tour destination + anm.getDistancesToMgra(tour.getTourDestMgra(), distanceToFinalDestFromAllMgras, + modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())); + stopLocDmuObj.setDistancesToDestMgra(distanceToFinalDestFromAllMgras); + + // set the distance from the stop origin to the final half-tour + // destination + stopLocDmuObj + .setOrigDestDistance(distanceFromStopOrigToAllMgras[tour.getTourDestMgra()]); + + // bike logsums from all MGRAs back to tour origin + if(modelStructure.getTourModeIsBike(tour.getTourModeChoice())){ + + Arrays.fill(bikeLogsumToFinalDestFromAllMgras, 0); + segment = new BikeLogsumSegment(person.getPersonIsFemale() == 1,tour.getTourPrimaryPurposeIndex() <= 3,s.isInboundStop()); + + for (int oMgra = 1; oMgra <= mgraManager.getMaxMgra(); oMgra++) + { + bikeLogsumToFinalDestFromAllMgras[oMgra] = bls.getLogsum(segment,oMgra,tour.getTourDestMgra()); + } + stopLocDmuObj.setBikeLogsumsToDestMgra(bikeLogsumToFinalDestFromAllMgras); + } + + + } + + long check = System.nanoTime(); + if (useNewSoaMethod) + { + if (modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())) + { + selectSampleOfAlternativesAutoTourNew(s, tour, person, household, loggingSample); + soaAutoTime += (System.nanoTime() - check); + numAltsInSample = dcTwoStageModelObject.getNumberofUniqueMgrasInSample(); + } else + { + selectSampleOfAlternativesOther(s, tour, person, household, loggingSample); + soaOtherTime += (System.nanoTime() - check); + numAltsInSample = altFreqMap.size(); + } + } else + { + if (modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice())) + { + selectSampleOfAlternativesAutoTour(s, tour, person, household, loggingSample); + soaAutoTime += (System.nanoTime() - check); + } else + { + selectSampleOfAlternativesOther(s, tour, person, household, loggingSample); + soaOtherTime += (System.nanoTime() - check); + } + numAltsInSample = altFreqMap.size(); + } + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + String separator = ""; + + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = "Stop Location Choice"; + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopId=%d", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourPurpose(), tour.getTourModeChoice(), tour.getTourId(), + s.getDestPurpose(), (s.getStopId() + 1)); + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + } + + check = System.nanoTime(); + setupStopLocationChoiceAlternativeArrays(numAltsInSample, s,departPeriodToStop,departPeriodFromStop); + slsTime += (System.nanoTime() - check); + + int slcModelIndex = -1; + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.MANDATORY_CATEGORY)) slcModelIndex = MAND_SLC_MODEL_INDEX; + else if (tour.getTourPrimaryPurposeIndex() == ModelStructure.ESCORT_PRIMARY_PURPOSE_INDEX + || tour.getTourPrimaryPurposeIndex() == ModelStructure.SHOPPING_PRIMARY_PURPOSE_INDEX + || tour.getTourPrimaryPurposeIndex() == ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_INDEX) slcModelIndex = MAINT_SLC_MODEL_INDEX; + else slcModelIndex = DISCR_SLC_MODEL_INDEX; + + float logsum = (float) slcModelArray[slcModelIndex].computeUtilities(stopLocDmuObj, + stopLocDmuObj.getDmuIndexValues(), sampleAvailability, inSample); + if(s.isInboundStop()) + tour.addInboundStopDestinationLogsum(logsum); + else + tour.addOutboundStopDestinationLogsum(logsum); + + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + int selectedIndex = -1; + if (slcModelArray[slcModelIndex].getAvailabilityCount() > 0) + { + selectedIndex = slcModelArray[slcModelIndex].getChoiceResult(rn); + chosen = finalSample[selectedIndex]; + }else{ + //wu's tempory fix to set chosen stop alternative to origin mgra if no alternative is available-8/27/2014 + chosen=tour.getTourOrigMgra(); + } + + // write choice model alternative info to log file + if (household.getDebugChoiceModels() || chosen < 0) + { + + if (chosen < 0) + { + + modelLogger + .error("ERROR selecting stop location choice due to no alternatives available."); + modelLogger + .error("setting debug to true and recomputing sample of alternatives selection."); + modelLogger + .error(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopId=%d, StopOrig=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourPurpose(), + tour.getTourModeChoice(), tour.getTourId(), + s.getDestPurpose(), (s.getStopId() + 1), s.getOrig())); + + choiceModelDescription = "Stop Location Choice"; + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopId=%d, StopOrig=%d", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourPurpose(), tour.getTourModeChoice(), tour.getTourId(), + s.getDestPurpose(), (s.getStopId() + 1), s.getOrig()); + loggingHeader = String.format("%s for %s", choiceModelDescription, + decisionMakerLabel); + + modelLogger.error(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.error(loggingHeader); + modelLogger.error(separator); + modelLogger.error(""); + modelLogger.error(""); + + // utilities and probabilities are 0 based. + double[] utilities = slcModelArray[slcModelIndex].getUtilities(); + double[] probabilities = slcModelArray[slcModelIndex].getProbabilities(); + + // availabilities is 1 based. + boolean[] availabilities = slcModelArray[slcModelIndex].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger + .error("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .error("Alternative Availability Utility Probability CumProb"); + modelLogger + .error("--------------------- ------------ ----------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 1; j <= numAltsInSample; j++) + { + + int alt = finalSample[j]; + + if (j == chosen) selectedIndex = j; + + cumProb += probabilities[j - 1]; + String altString = String.format("%-3d %5d", j, alt); + modelLogger.error(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j], utilities[j - 1], probabilities[j - 1], cumProb)); + } + + modelLogger.error(" "); + String altString = String.format("%-3d %5d", selectedIndex, -1); + modelLogger.error(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.error(separator); + modelLogger.error(""); + modelLogger.error(""); + + slcModelArray[slcModelIndex].logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + slcModelArray[slcModelIndex].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log + // file + slcModelArray[slcModelIndex].logUECResults(modelLogger, loggingHeader); + + logger.error(String + .format("Error for HHID=%d, PersonNum=%d, no available %s stop destination choice alternatives to choose from in choiceModelApplication.", + tour.getHhId(), tour.getPersonObject().getPersonNum(), + tour.getTourPurpose())); + throw new RuntimeException(); + + } + + // utilities and probabilities are 0 based. + double[] utilities = slcModelArray[slcModelIndex].getUtilities(); + double[] probabilities = slcModelArray[slcModelIndex].getProbabilities(); + + // availabilities is 1 based. + boolean[] availabilities = slcModelArray[slcModelIndex].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- ------------ ----------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 1; j <= numAltsInSample; j++) + { + + int alt = finalSample[j]; + + if (j == chosen) selectedIndex = j; + + cumProb += probabilities[j - 1]; + String altString = String.format("%-3d %5d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j], utilities[j - 1], probabilities[j - 1], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %5d", selectedIndex, finalSample[selectedIndex]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + slcModelArray[slcModelIndex].logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + slcModelArray[slcModelIndex].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log file + slcModelArray[slcModelIndex].logUECResults(modelLogger, loggingHeader); + + } + + return selectedIndex; + } + + private void setupStopLocationChoiceAlternativeArrays(int numAltsInSample, Stop s,int departPeriodToStop, int departPeriodFromStop) + { + + stopLocDmuObj.setNumberInSample(numAltsInSample); + stopLocDmuObj.setSampleOfAlternatives(finalSample); + stopLocDmuObj.setSlcSoaCorrections(sampleCorrectionFactors); + + // create arrays for ik and kj mode choice logsums for the stop origin, + // the sample stop location, and the half-tour final destination. + setupLogsumCalculation(s); + + int category = PURPOSE_CATEGORIES[s.getTour().getTourPrimaryPurposeIndex()]; + ChoiceModelApplication mcModel = mcModelArray[category]; + + Household household = s.getTour().getPersonObject().getHouseholdObject(); + double income = (double) household.getIncomeInDollars(); + double ivtCoeff = ivtCoeffs[category]; + double incomeCoeff = incomeCoeffs[category]; + double incomeExpon = incomeExponents[category]; + double costCoeff = calculateCostCoefficient(income, incomeCoeff,incomeExpon); + double timeFactor = 1.0f; + if(s.getTour().getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + timeFactor = mcDmuObject.getJointTourTimeFactor(); + else if(s.getTour().getTourPrimaryPurposeIndex()==ModelStructure.WORK_PRIMARY_PURPOSE_INDEX) + timeFactor = mcDmuObject.getWorkTimeFactor(); + else + timeFactor = mcDmuObject.getNonWorkTimeFactor(); + + mcDmuObject.setIvtCoeff(ivtCoeff * timeFactor); + mcDmuObject.setCostCoeff(costCoeff); + + int halfTourFinalDest = s.isInboundStop() ? s.getTour().getTourOrigMgra() : s.getTour() + .getTourDestMgra(); + + // set the land use data items in the DMU for the stop origin + mcDmuObject.setOrigDuDen(mgraManager.getDuDenValue(s.getOrig())); + mcDmuObject.setOrigEmpDen(mgraManager.getEmpDenValue(s.getOrig())); + mcDmuObject.setOrigTotInt(mgraManager.getTotIntValue(s.getOrig())); + + for (int i = 1; i <= numAltsInSample; i++) + { + + int altMgra = finalSample[i]; + mcDmuObject.getDmuIndexValues().setDestZone(altMgra); + + // set distances to/from stop anchor points to stop location alternative. + ikDistance[i] = distanceFromStopOrigToAllMgras[altMgra]; + kjDistance[i] = distanceToFinalDestFromAllMgras[altMgra]; + + // set distances from tour anchor points to stop location + // alternative. + okDistance[i] = tourOrigToAllMgraDistances[altMgra]; + kdDistance[i] = tourDestToAllMgraDistances[altMgra]; + + // set the land use data items in the DMU for the sample location + mcDmuObject.setDestDuDen(mgraManager.getDuDenValue(altMgra)); + mcDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(altMgra)); + mcDmuObject.setDestTotInt(mgraManager.getTotIntValue(altMgra)); + + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager + .getTaz(altMgra))); + + // for walk-transit tours - if half-tour direction is outbound and + // stop alternative is in the walk shed, walk and walk-transit + // should be allowed for ik segments + // if half-tour direction is inbound and stop alternative is in the + // walk shed, walk and walk-transit should be allowed for kj + // segments + // if half-tour direction is outbound and stop alternative is in the + // walk shed, walk and walk-transit should be allowed for kj + // segments + // if half-tour direction is inbound and stop alternative is in the + // walk shed, walk and walk-transit should be allowed for ik + // segments + + // for drive-transit tours - if half-tour direction is outbound and + // stop alternative is in the drive shed, auto should be allowed for + // ik segments + // if half-tour direction is inbound and stop alternative is in the + // drive shed, auto should be allowed for kj segments + // if half-tour direction is outbound and stop alternative is in the + // walk shed, walk and walk-transit should be allowed for kj + // segments + // if half-tour direction is inbound and stop alternative is in the + // walk shed, walk and walk-transit should be allowed for ik + // segments + + // set values for walk-transit and drive-transit tours according to + // logic for IK segments + mcDmuObject.setAutoModeRequiredForTripSegment(false); + mcDmuObject.setWalkModeAllowedForTripSegment(false); + + mcDmuObject.setSegmentIsIk(true); + + double ikSegment = -999; + // drive transit tours are handled differently than walk transit + // tours + if (modelStructure.getTourModeIsDriveTransit(s.getTour().getTourModeChoice())) + { + + // if the direction is outbound + if (!s.isInboundStop()) + { + + // if the sampled mgra is in the outbound half-tour boarding tap shed (near tour origin) + if ( sampleMgraInBoardingTapShed[altMgra] ) { + logsumHelper.setWalkTransitLogSumUnavailable( mcDmuObject ); + logsumHelper.setDriveTransitLogSumUnavailable( mcDmuObject, s.isInboundStop() ); + } + + // if the sampled mgra is in the outbound half-tour alighting tap shed (near tour primary destination) + if ( sampleMgraInAlightingTapShed[altMgra] ) { + logsumHelper.setWalkTransitLogSumUnavailable( mcDmuObject ); + logsumHelper.setDtwTripMcDmuAttributes(mcDmuObject,s.getOrig(),altMgra,departPeriodToStop,s.getTour().getPersonObject().getHouseholdObject().getDebugChoiceModels()); + } + + + // if the trip origin and sampled mgra are in the outbound half-tour alighting tap shed (near tour origin) + if ( sampleMgraInAlightingTapShed[s.getOrig()] && sampleMgraInAlightingTapShed[altMgra] ) { + logsumHelper.setWtwTripMcDmuAttributes(mcDmuObject, s.getOrig(), altMgra, departPeriodToStop,s.getTour().getPersonObject().getHouseholdObject().getDebugChoiceModels()); + logsumHelper.setDriveTransitLogSumUnavailable( mcDmuObject, s.isInboundStop() ); + } + + } else + { + // if the sampled mgra is in the inbound half-tour boarding tap shed (near tour primary destination) + if ( sampleMgraInBoardingTapShed[altMgra] ) { + logsumHelper.setWtwTripMcDmuAttributes( mcDmuObject, s.getOrig(), altMgra, departPeriodToStop, s.getTour().getPersonObject().getHouseholdObject().getDebugChoiceModels() ); + logsumHelper.setDriveTransitLogSumUnavailable( mcDmuObject, s.isInboundStop() ); + } + + // if the sampled mgra is in the inbound half-tour alighting tap shed (near tour origin) + if ( sampleMgraInAlightingTapShed[altMgra] ) { + logsumHelper.setWalkTransitLogSumUnavailable( mcDmuObject ); + logsumHelper.setWtdTripMcDmuAttributes(mcDmuObject,s.getOrig(),altMgra,departPeriodToStop,s.getTour().getPersonObject().getHouseholdObject().getDebugChoiceModels()); + } + + // if the trip origin and sampled mgra are in the inbound half-tour alighting tap shed (near tour origin) + if ( sampleMgraInAlightingTapShed[s.getOrig()] && sampleMgraInAlightingTapShed[altMgra] ) { + logsumHelper.setWalkTransitLogSumUnavailable( mcDmuObject ); + logsumHelper.setDriveTransitLogSumUnavailable( mcDmuObject, s.isInboundStop() ); + } + + } + + } else if (modelStructure.getTourModeIsWalkTransit(s.getTour().getTourModeChoice())) + { // tour mode is walk-transit + + logsumHelper.setWtwTripMcDmuAttributes(mcDmuObject, s.getOrig(), altMgra, + departPeriodToStop, s.getTour().getPersonObject().getHouseholdObject() + .getDebugChoiceModels()); + + } else + { + logsumHelper.setWalkTransitLogSumUnavailable( mcDmuObject ); + logsumHelper.setDriveTransitLogSumUnavailable( mcDmuObject, s.isInboundStop() ); + } + ikSegment = logsumHelper.calculateTripMcLogsum(s.getOrig(), altMgra, departPeriodToStop, + mcModel, mcDmuObject, slcLogger); + + if (ikSegment < -900) + { + slcLogger.error("ERROR calculating trip mode choice logsum for " + + (s.isInboundStop() ? "inbound" : "outbound") + + " stop location choice - ikLogsum = " + ikSegment + "."); + slcLogger + .error("setting debug to true and recomputing ik segment logsum in order to log utility expression results."); + + if (s.isInboundStop()) slcLogger + .error(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, TourOrigMGRA=%d, TourDestMGRA=%d, StopPurpose=%s, StopDirection=%s, StopId=%d, NumIBStops=%d, StopOrig=%d, AltStopLoc=%d", + s.getTour().getPersonObject().getHouseholdObject() + .getHhId(), s.getTour().getPersonObject() + .getPersonNum(), s.getTour().getPersonObject() + .getPersonType(), s.getTour().getTourPurpose(), s + .getTour().getTourModeChoice(), s.getTour() + .getTourId(), s.getTour().getTourOrigMgra(),s.getTour().getTourDestMgra(),s.getDestPurpose(), "inbound", (s + .getStopId() + 1), + s.getTour().getNumInboundStops() - 1, s.getOrig(), altMgra)); + else slcLogger + .error(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d,TourOrigMGRA=%d,TourDestMGRA=%d,StopPurpose=%s, StopDirection=%s, StopId=%d, NumOBStops=%d, StopOrig=%d, AltStopLoc=%d", + s.getTour().getPersonObject().getHouseholdObject() + .getHhId(), s.getTour().getPersonObject() + .getPersonNum(), s.getTour().getPersonObject() + .getPersonType(), s.getTour().getTourPurpose(), s + .getTour().getTourModeChoice(), s.getTour() + .getTourId(),s.getTour().getTourOrigMgra(),s.getTour().getTourDestMgra(),s.getDestPurpose(), "outbound", (s + .getStopId() + 1), s.getTour() + .getNumOutboundStops() - 1, s.getOrig(), altMgra)); + + mcDmuObject.getDmuIndexValues().setDebug(true); + mcDmuObject.getHouseholdObject().setDebugChoiceModels(true); + /* suppress log: Wu + mcDmuObject.getHouseholdObject().setDebugChoiceModels(true); + */ + mcDmuObject.getDmuIndexValues().setHHIndex( + s.getTour().getPersonObject().getHouseholdObject().getHhId()); + ikSegment = logsumHelper.calculateTripMcLogsum(s.getOrig(), altMgra, + departPeriodToStop, mcModel, mcDmuObject, slcLogger); + mcDmuObject.getDmuIndexValues().setDebug(false); + mcDmuObject.getHouseholdObject().setDebugChoiceModels(false); + + } + + // store the mode choice probabilities for the segment + mcCumProbsSegmentIk[i] = logsumHelper.getStoredSegmentCumulativeProbabilities(); + mcVOTsSegmentIk[i] = logsumHelper.getStoredSegmentVOTs(); + parkingCostSegmentIk[i] = logsumHelper.getTripModeChoiceSegmentStoredParkingCost(); + + // Store the mode choice logsum for the segment + mcLogsumsSegmentIk[i] = ikSegment; + + // store the best tap pairs for the segment + for(int j=0; j it = altFreqMap.keySet().iterator(); + int k = 0; + while (it.hasNext()) + { + + int alt = it.next(); + int freq = altFreqMap.get(alt); + + double prob = 0; + prob = probabilitiesList[alt - 1]; + + finalSample[k + 1] = alt; + sampleCorrectionFactors[k + 1] = Math.log((double) freq / prob); + + k++; + } + + while (k < sampleSize) + { + finalSample[k + 1] = -1; + sampleCorrectionFactors[k + 1] = Double.NaN; + sampleAvailability[k + 1] = false; + inSample[k + 1] = 0; + k++; + } + + } + + private void selectSampleOfAlternativesOther(Stop s, Tour tour, Person person, + Household household, int[] loggingSample) + { + + Logger soaLogger = Logger.getLogger("slcSoaLogger"); + + altFreqMap.clear(); + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + ChoiceModelApplication cm; + if (modelStructure.getTourModeIsWalk(tour.getTourModeChoice())) cm = slcSoaModel[WALK_STOP_LOC_SOA_SHEET_INDEX]; + else if (modelStructure.getTourModeIsBike(tour.getTourModeChoice())) cm = slcSoaModel[BIKE_STOP_LOC_SOA_SHEET_INDEX]; + else cm = slcSoaModel[OTHER_STOP_LOC_SOA_SHEET_INDEX]; + + if (household.getDebugChoiceModels()) + { + choiceModelDescription = String + .format("Stop Location SOA Choice Model for: stop purpose=%s, direction=%s, stopId=%d, stopOrig=%d", + s.getDestPurpose(), s.isInboundStop() ? "inbound" : "outbound", + (s.getStopId() + 1), s.getOrig()); + decisionMakerLabel = String + .format("HH=%d, persNum=%d, persType=%s, tourId=%d, tourPurpose=%s, tourOrig=%d, tourDest=%d, tourMode=%d", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourId(), tour.getTourPrimaryPurpose(), tour.getTourOrigMgra(), + tour.getTourDestMgra(), tour.getTourModeChoice()); + cm.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, decisionMakerLabel); + } + + IndexValues dmuIndex = stopLocDmuObj.getDmuIndexValues(); + dmuIndex.setDebug(household.getDebugChoiceModels()); + + // stopLocDmuObj.setTourModeIndex( tour.getTourModeChoice() ); + // + // // set the size terms array for the stop purpose in the dmu object + // stopLocDmuObj.setLogSize( + // getLnSlcSizeTermsForStopPurpose(s.getStopPurposeIndex(), household) + // ); + // + // // get the array of distances from the stop origin mgra to all MGRAs + // and set in the dmu object + // anm.getDistancesFromMgra( s.getOrig(), + // distanceFromStopOrigToAllMgras, modelStructure.getTourModeIsSovOrHov( + // tour.getTourModeChoice() ) ); + // stopLocDmuObj.setDistancesFromOrigMgra( + // distanceFromStopOrigToAllMgras ); + // + // // if tour mode is transit, set availablity of location alternatives + // based on transit accessibility relative to best transit TAP pair for + // tour + // if ( modelStructure.getTourModeIsTransit( tour.getTourModeChoice() ) + // ) { + // int numAvailableAlternatives = setSoaAvailabilityForTransitTour(s, + // tour); + // if ( numAvailableAlternatives == 0 ) { + // logger.error( "no available locations - empty sample." ); + // throw new RuntimeException(); + // } + // } + // + // // get the array of distances to the half-tour final destination mgra + // from all MGRAs and set in the dmu object + if (s.isInboundStop()) + { + // // if inbound, final half-tour destination is the tour origin + // anm.getDistancesToMgra( tour.getTourOrigMgra(), + // distanceToFinalDestFromAllMgras, + // modelStructure.getTourModeIsSovOrHov( tour.getTourModeChoice() ) + // ); + // stopLocDmuObj.setDistancesToDestMgra( + // distanceToFinalDestFromAllMgras ); + // + // // set the distance from the stop origin to the final half-tour + // destination + // stopLocDmuObj.setOrigDestDistance( + // distanceFromStopOrigToAllMgras[tour.getTourOrigMgra()] ); + // + // // not used in UEC to reference matrices, but may be for + // debugging using $ORIG and $DEST as an expression + dmuIndex.setOriginZone(mgraManager.getTaz(s.getOrig())); + dmuIndex.setDestZone(mgraManager.getTaz(tour.getTourOrigMgra())); + } else + { + // // if outbound, final half-tour destination is the tour + // destination + // anm.getDistancesToMgra( tour.getTourDestMgra(), + // distanceToFinalDestFromAllMgras, + // modelStructure.getTourModeIsSovOrHov( tour.getTourModeChoice() ) + // ); + // stopLocDmuObj.setDistancesToDestMgra( + // distanceToFinalDestFromAllMgras ); + // + // // set the distance from the stop origin to the final half-tour + // destination + // stopLocDmuObj.setOrigDestDistance( + // distanceFromStopOrigToAllMgras[tour.getTourDestMgra()]); + // + // // not used in UEC to reference matrices, but may be for + // debugging using $ORIG and $DEST as an expression + dmuIndex.setOriginZone(mgraManager.getTaz(s.getOrig())); + dmuIndex.setDestZone(mgraManager.getTaz(tour.getTourDestMgra())); + } + + cm.computeUtilities(stopLocDmuObj, dmuIndex, soaAvailability, soaSample); + double[] probabilitiesList = cm.getProbabilities(); + double[] cumProbabilitiesList = cm.getCumulativeProbabilities(); + + // debug output + if (household.getDebugChoiceModels()) + { + + // write choice model alternative info to debug log file + cm.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + + // write UEC calculation results to separate model specific log file + loggingHeader = choiceModelDescription + ", " + decisionMakerLabel; + + if (loggingSample == null) + { + cm.logUECResultsSpecificAlts(soaLogger, loggingHeader, new int[] {0, s.getOrig(), + tour.getTourOrigMgra(), tour.getTourDestMgra()}); + // cm.logUECResults( soaLogger, loggingHeader, 10 ); + } else + { + cm.logUECResultsSpecificAlts(soaLogger, loggingHeader, loggingSample); + } + + } + + // loop over sampleSize, select alternatives based on probabilitiesList, + // and count frequency of alternatives chosen. + // may include duplicate alternative selections. + + Random hhRandom = household.getHhRandom(); + int rnCount = household.getHhRandomCount(); + // when household.getHhRandom() was applied, the random count was + // incremented, assuming a random number would be drawn right away. + // so let's decrement by 1, then increment the count each time a random + // number is actually drawn in this method. + rnCount--; + + // log degenerative cases + if (cm.getAvailabilityCount() == 0) + { + Logger badSlcLogger = Logger.getLogger("badSlc"); + + choiceModelDescription = String + .format("Stop Location SOA Choice Model for: stop purpose=%s, direction=%s, stopId=%d, stopOrig=%d", + s.getDestPurpose(), s.isInboundStop() ? "inbound" : "outbound", + (s.getStopId() + 1), s.getOrig()); + decisionMakerLabel = String + .format("HH=%d, persNum=%d, persType=%s, tourId=%d, tourPurpose=%s, tourOrig=%d, tourDest=%d, tourMode=%d", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourId(), tour.getTourPrimaryPurpose(), tour.getTourOrigMgra(), + tour.getTourDestMgra(), tour.getTourModeChoice()); + loggingHeader = choiceModelDescription + ", " + decisionMakerLabel; + + badSlcLogger.info("....... Start Logging ......."); + badSlcLogger + .info("setting stop location sample to be an array with 1 element - just the stop origin mgra."); + badSlcLogger.info(""); + + household.logHouseholdObject( + "Stop Location Choice for trip: HH_" + household.getHhId() + ", Pers_" + + tour.getPersonObject().getPersonNum() + ", Tour Purpose_" + + tour.getTourPurpose() + ", Tour_" + tour.getTourId() + + ", Tour Purpose_" + tour.getTourPurpose() + ", Stop_" + + (s.getStopId() + 1), badSlcLogger); + household.logPersonObject("Stop Location Choice for person " + + tour.getPersonObject().getPersonNum(), badSlcLogger, tour.getPersonObject()); + household.logTourObject("Stop Location Choice for tour " + tour.getTourId(), + badSlcLogger, tour.getPersonObject(), tour); + household.logStopObject("Stop Location Choice for stop " + (s.getStopId() + 1), + badSlcLogger, s, modelStructure); + + badSlcLogger.info(decisionMakerLabel + " has no available alternatives for " + + choiceModelDescription + "."); + badSlcLogger.info("Logging StopLocation SOA Choice utility calculations for: stopOrig=" + + s.getOrig() + ", tourOrig=" + tour.getTourOrigMgra() + ", and tourDest=" + + tour.getTourDestMgra() + "."); + cm.logUECResultsSpecificAlts(badSlcLogger, loggingHeader, new int[] {0, s.getOrig(), + tour.getTourOrigMgra(), tour.getTourDestMgra()}); + + int chosenAlt = s.getOrig(); + probabilitiesList[chosenAlt - 1] = 1.0; + for (int j = chosenAlt - 1; j < cumProbabilitiesList.length; j++) + cumProbabilitiesList[j] = 1.0; + + double sum = 0; + double epsilon = .0000001; + for (int j = 0; j < probabilitiesList.length; j++) + { + sum += probabilitiesList[j]; + if (!(Math.abs(sum - cumProbabilitiesList[j]) < epsilon) || sum > 1.0) + { + badSlcLogger.info("error condition found! sum=" + sum + ", j=" + j + + ", cumProbabilitiesList[j]=" + cumProbabilitiesList[j]); + badSlcLogger.info("....... End Logging ......."); + throw new RuntimeException(); + } + } + + badSlcLogger.info("....... End Logging ......."); + badSlcLogger.info(""); + badSlcLogger.info(""); + } + + int chosenAlt = -1; + for (int i = 0; i < sampleSize; i++) + { + + double rn = hhRandom.nextDouble(); + rnCount++; + chosenAlt = Util.binarySearchDouble(cumProbabilitiesList, rn) + 1; + + // write choice model alternative info to log file + if (household.getDebugChoiceModels()) + { + cm.logSelectionInfo(loggingHeader, String.format("rnCount=%d", rnCount), rn, + chosenAlt); + } + + int freq = 0; + if (altFreqMap.containsKey(chosenAlt)) freq = altFreqMap.get(chosenAlt); + altFreqMap.put(chosenAlt, (freq + 1)); + + } + + // sampleSize random number draws were made from this Random object, so + // update the count in the hh's Random. + household.setHhRandomCount(rnCount); + + Arrays.fill(sampleAvailability, true); + Arrays.fill(inSample, 1); + + // create arrays of the unique chosen alternatives and the frequency + // with which those alternatives were chosen. + Iterator it = altFreqMap.keySet().iterator(); + int k = 0; + while (it.hasNext()) + { + + int alt = it.next(); + int freq = altFreqMap.get(alt); + + double prob = 0; + prob = probabilitiesList[alt - 1]; + + finalSample[k + 1] = alt; + sampleCorrectionFactors[k + 1] = Math.log((double) freq / prob); + + k++; + } + + while (k < sampleSize) + { + finalSample[k + 1] = -1; + sampleCorrectionFactors[k + 1] = Double.NaN; + sampleAvailability[k + 1] = false; + inSample[k + 1] = 0; + k++; + } + + // if the sample was determined for a transit tour, the sample and + // availability arrays for the full set of SOA alternatives need to be + // restored. + if (modelStructure.getTourModeIsTransit(tour.getTourModeChoice())) + { + for (int i = 0; i < soaSample.length; i++) + { + soaSample[i] = soaSampleBackup[i]; + soaAvailability[i] = soaAvailabilityBackup[i]; + } + } + + } + + private void setupLogsumCalculation(Stop s) + { + + Tour t = s.getTour(); + Person p = t.getPersonObject(); + Household hh = p.getHouseholdObject(); + + mcDmuObject.setHouseholdObject(hh); + mcDmuObject.setPersonObject(p); + mcDmuObject.setTourObject(t); + + int category = PURPOSE_CATEGORIES[s.getTour().getTourPrimaryPurposeIndex()]; + double income = (double) hh.getIncomeInDollars(); + double ivtCoeff = ivtCoeffs[category]; + double incomeCoeff = incomeCoeffs[category]; + double incomeExpon = incomeExponents[category]; + double costCoeff = calculateCostCoefficient(income, incomeCoeff,incomeExpon); + double timeFactor = 1.0f; + if(t.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + timeFactor = mcDmuObject.getJointTourTimeFactor(); + else if(t.getTourPrimaryPurposeIndex()==ModelStructure.WORK_PRIMARY_PURPOSE_INDEX) + timeFactor = mcDmuObject.getWorkTimeFactor(); + else + timeFactor = mcDmuObject.getNonWorkTimeFactor(); + + mcDmuObject.setIvtCoeff(ivtCoeff * timeFactor); + mcDmuObject.setCostCoeff(costCoeff); + + int tourMode = t.getTourModeChoice(); + int origMgra = s.getOrig(); + + mcDmuObject.getDmuIndexValues().setHHIndex(hh.getHhId()); + mcDmuObject.getDmuIndexValues().setZoneIndex(hh.getHhMgra()); + mcDmuObject.getDmuIndexValues().setOriginZone(origMgra); + mcDmuObject.getDmuIndexValues().setDebug(hh.getDebugChoiceModels()); + + mcDmuObject.setOutboundStops(t.getOutboundStops() == null ? 0 + : t.getOutboundStops().length - 1); + mcDmuObject.setInboundStops(t.getInboundStops() == null ? 0 + : t.getInboundStops().length - 1); + + mcDmuObject.setTripOrigIsTourDest(s.isInboundStop() && s.getStopId() == 0 ? 1 : 0); + mcDmuObject.setTripDestIsTourDest(!s.isInboundStop() + && ((s.getStopId() + 1) == (t.getNumOutboundStops() - 1)) ? 1 : 0); + + mcDmuObject.setInbound(s.isInboundStop()); + + mcDmuObject.setFirstTrip(0); + mcDmuObject.setLastTrip(0); + if (s.isInboundStop()) + { + mcDmuObject.setOutboundHalfTourDirection(0); + // compare stopId (0-based, so add 1) with number of stops (stops + // array length - 1); if last stop, set flag to 1, otherwise 0. + mcDmuObject.setLastTrip(((s.getStopId() + 1) == (t.getNumInboundStops() - 1)) ? 1 : 0); + } else + { + mcDmuObject.setOutboundHalfTourDirection(1); + // if first stopId (0-based), set flag to 1, otherwise 0. + mcDmuObject.setFirstTrip(s.getStopId() == 0 ? 1 : 0); + } + + mcDmuObject.setJointTour(t.getTourCategory().equalsIgnoreCase( + ModelStructure.JOINT_NON_MANDATORY_CATEGORY) ? 1 : 0); + mcDmuObject + .setEscortTour(t.getTourPrimaryPurposeIndex() == ModelStructure.ESCORT_PRIMARY_PURPOSE_INDEX ? 1 + : 0); + + mcDmuObject.setIncomeInDollars(hh.getIncomeInDollars()); + mcDmuObject.setAdults(hh.getNumPersons18plus()); + mcDmuObject.setAutos(hh.getAutosOwned()); + mcDmuObject.setAge(p.getAge()); + mcDmuObject.setHhSize(hh.getHhSize()); + mcDmuObject.setPersonIsFemale(p.getPersonIsFemale()); + + mcDmuObject.setTourModeIsDA(modelStructure.getTourModeIsSov(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsS2(modelStructure.getTourModeIsS2(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsS3(modelStructure.getTourModeIsS3(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsWalk(modelStructure.getTourModeIsWalk(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsBike(modelStructure.getTourModeIsBike(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsWTran(modelStructure.getTourModeIsWalkTransit(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsPnr(modelStructure.getTourModeIsPnr(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsKnr(modelStructure.getTourModeIsKnr(tourMode) ? 1 : 0); + mcDmuObject.setTourModeIsSchBus(modelStructure.getTourModeIsSchoolBus(tourMode) ? 1 : 0); + + mcDmuObject + .setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(origMgra))); + + mcDmuObject.setDepartPeriod(t.getTourDepartPeriod()); + mcDmuObject.setArrivePeriod(t.getTourArrivePeriod()); + mcDmuObject.setTripPeriod(s.getStopPeriod()); + + double reimbursePct = mcDmuObject.getPersonObject().getParkingReimbursement(); + mcDmuObject.setReimburseProportion( reimbursePct ); + + + float popEmpDenOrig = (float) mgraManager.getPopEmpPerSqMi(origMgra); + float waitTimeSingleTNC=0; + float waitTimeSharedTNC=0; + float waitTimeTaxi=0; + + Random hhRandom = hh.getHhRandom(); + double rnum = hhRandom.nextDouble(); + waitTimeSingleTNC = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenOrig); + waitTimeSharedTNC = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenOrig); + waitTimeTaxi = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenOrig); + mcDmuObject.setWaitTimeSingleTNC(waitTimeSingleTNC); + mcDmuObject.setWaitTimeSharedTNC(waitTimeSharedTNC); + mcDmuObject.setWaitTimeTaxi(waitTimeTaxi); + + + } + + /** + * determine if each indexed mgra has transit access to the best tap pairs + * for the tour create an array with 1 if the mgra indexed has at least one + * TAP within walk egress distance of the mgra or zero if no walk TAPS exist + * for the mgra. + */ + private int setSoaAvailabilityForTransitTour(Stop s, Tour t, boolean debug) + { + + int availableCount = 0; + double[][] bestTaps = null; + + if (s.isInboundStop()) + { + + if ( modelStructure.getTourModeIsWalkTransit(t.getTourModeChoice() ) ) + bestTaps = t.getBestWtwTapPairsIn(); + else + bestTaps = t.getBestWtdTapPairsIn(); + + // loop through mgras and determine if they are available as a stop + // location + ArrayList mgras = mgraManager.getMgras(); + for (int alt : mgras) + { + // if alternative mgra is unavailable because it has no size, no + // need to check its accessibility + // if ( ! soaAvailability[alt] ) + // continue; + + boolean accessible = false; + int i=-1; + for (double[] tapPair : bestTaps) + { + if (tapPair == null) continue; + + ++i; + if ( modelStructure.getTourModeIsWalkTransit(t.getTourModeChoice() ) ) { + // if alternative location mgra is accessible by walk to any of the best inbound boarding taps, AND it's accessible by walk to the stop origin, it's available. + if ( mgraManager.getTapIsWalkAccessibleFromMgra(alt, (int)tapPair[0]) + && mgraManager.getMgrasAreWithinWalkDistance(s.getOrig(), alt) + && earlierTripWasLocatedInAlightingTapShed == false ) { + accessible = true; + sampleMgraInBoardingTapShed[alt] = true; + } + // if alternative location mgra is accessible by walk to any of the best inbound alighting taps, AND it's accessible by walk to the tour origin, it's available. + else if ( mgraManager.getTapIsWalkAccessibleFromMgra(alt, (int)tapPair[1]) && mgraManager.getMgrasAreWithinWalkDistance(alt, t.getTourOrigMgra()) ) { + accessible = true; + sampleMgraInAlightingTapShed[alt] = true; + } + } + else { + // if alternative location mgra is accessible by walk to any of the best origin taps, AND it's accessible by walk to the stop origin, it's available. + if ( mgraManager.getTapIsWalkAccessibleFromMgra(alt, (int)tapPair[0]) + && mgraManager.getMgrasAreWithinWalkDistance(s.getOrig(), alt) + && earlierTripWasLocatedInAlightingTapShed == false ) { + accessible = true; + sampleMgraInBoardingTapShed[alt] = true; + } + // if alternative location mgra is accessible by drive to any of the best destination taps it's available. + else if ( mgraManager.getTapIsDriveAccessibleFromMgra(alt, (int)tapPair[1]) ) { + accessible = true; + sampleMgraInAlightingTapShed[alt] = true; + } + } + + if ( accessible ){ + if(debug){ + slcSoaLogger.info(""); + if(sampleMgraInBoardingTapShed[alt]==true){ + slcSoaLogger.info("Stop alternative MGRA "+alt+" is accessible for TapPair "+i+" in boarding shed of TAP "+tapPair[0]); + }else if(sampleMgraInAlightingTapShed[alt]==true){ + slcSoaLogger.info("Stop alternative MGRA "+alt+" is accessible for TapPair "+i+" in alighting shed of TAP "+tapPair[1]); + } + if((sampleMgraInBoardingTapShed[alt]==true) && (sampleMgraInAlightingTapShed[alt]==true)) //should not happen + slcSoaLogger.info("Stop alternative MGRA "+alt+" is accessible for TapPair "+i+" in both boarding shed of TAP "+tapPair[0]+" and alighting shed of TAP "+tapPair[1]); + } + + break; + } + } + + if (accessible) + { + availableCount++; + } else + { + soaSample[alt] = 0; + soaAvailability[alt] = false; + } + + } + + } else + { + if (modelStructure.getTourModeIsWalkTransit(t.getTourModeChoice())) + bestTaps = t.getBestWtwTapPairsOut(); + else + bestTaps = t.getBestDtwTapPairsOut(); + + // loop through mgras and determine if they have walk egress + ArrayList mgras = mgraManager.getMgras(); + for (int alt : mgras) + { + // if alternative mgra is unavailable because it has no size, no + // need to check its accessibility + // if ( ! soaAvailability[alt] ) + // continue; + + // check whether any of the outbound dtw boarding taps or best + // wtw alighting taps are in the set of walk accessible TAPs for + // the alternative mgra. + // if not, the alternative is not available. + boolean accessible = false; + int i=-1; + for (double[] tapPair : bestTaps) + { + if (tapPair == null) continue; + + ++i; + if ( modelStructure.getTourModeIsWalkTransit(t.getTourModeChoice() ) ) { + // if alternative location mgra is accessible by walk to any of the best origin taps, AND it's accessible by walk to the stop origin, it's available. + if ( mgraManager.getTapIsWalkAccessibleFromMgra(alt, (int)tapPair[0]) + && mgraManager.getMgrasAreWithinWalkDistance(s.getOrig(), alt) + && earlierTripWasLocatedInAlightingTapShed == false ) { + accessible = true; + sampleMgraInBoardingTapShed[alt] = true; + } + // if alternative location mgra is accessible by walk to any of the best destination taps, AND it's accessible by walk to the tour primary destination, it's available. + else if ( mgraManager.getTapIsWalkAccessibleFromMgra(alt, (int)tapPair[1]) && mgraManager.getMgrasAreWithinWalkDistance(alt, t.getTourDestMgra()) ) { + accessible = true; + sampleMgraInAlightingTapShed[alt] = true; + } + } + else { + // if alternative location mgra is accessible by drive to any of the best origin taps, it's available. + if ( mgraManager.getTapIsDriveAccessibleFromMgra(alt, (int)tapPair[0]) + && earlierTripWasLocatedInAlightingTapShed == false ) { + accessible = true; + sampleMgraInBoardingTapShed[alt] = true; + } + // if alternative location mgra is accessible by walk to any of the best destination taps, AND it's accessible by walk to the tour primary destination, it's available. + else if ( mgraManager.getTapIsWalkAccessibleFromMgra(alt, (int)tapPair[1]) && mgraManager.getMgrasAreWithinWalkDistance(alt, t.getTourDestMgra()) ) { + accessible = true; + sampleMgraInAlightingTapShed[alt] = true; + } + } + + if ( accessible ){ + if(debug){ + slcSoaLogger.info(""); + if(sampleMgraInBoardingTapShed[alt]==true){ + slcSoaLogger.info("Stop alternative MGRA "+alt+" is accessible for TapPair "+i+" in boarding shed of TAP "+tapPair[0]); + }else if(sampleMgraInAlightingTapShed[alt]==true){ + slcSoaLogger.info("Stop alternative MGRA "+alt+" is accessible for TapPair "+i+" in alighting shed of TAP "+tapPair[1]); + } + if((sampleMgraInBoardingTapShed[alt]==true) && (sampleMgraInAlightingTapShed[alt]==true)) //should not happen + slcSoaLogger.info("Stop alternative MGRA "+alt+" is accessible for TapPair "+i+" in both boarding shed of TAP "+tapPair[0]+" and alighting shed of TAP "+tapPair[1]); + } + + break; + } + + } + if (accessible) + { + availableCount++; + } else + { + soaSample[alt] = 0; + soaAvailability[alt] = false; + } + + } + + } + + return availableCount; + } + + /** + * create an array with 1 if the mgra indexed has at least one TAP within + * walk egress distance of the mgra or zero if no walk TAPS exist for the + * mgra. private void createWalkTransitAvailableArray() { + * + * ArrayList mgras = mgraManager.getMgras(); int maxMgra = + * mgraManager.getMaxMgra(); + * + * walkTransitAvailable = new int[maxMgra+1]; + * + * // loop through mgras and determine if they have walk egress for (int alt + * : mgras) { + * + * // get the TAP set within walk egress distance of the stop location + * alternative. int[] aMgraSet = + * mgraManager.getMgraWlkTapsDistArray()[alt][0]; + * + * // set to 1 if the list of TAPS with walk accessible egress to alt is not + * empty; 0 otherwise if ( aMgraSet != null && aMgraSet.length > 0 ) + * walkTransitAvailable[alt] = 1; + * + * } + * + * stopLocDmuObj.setWalkTransitAvailable( walkTransitAvailable ); } + */ + + /** + * Do a monte carlo selection from the array of stored mode choice + * cumulative probabilities (0 based array). The probabilities were saved at + * the time the stop location alternative segment mode choice logsums were + * calculated. If the stop is not the last stop for the half-tour, the IK + * segment probabilities are passed in. If the stop is the last stop, the KJ + * probabilities are passeed in. + * + * @param household + * object frim which to get the Random object. + * @param props + * is the array of stored mode choice probabilities - 0s based + * array. + * + * @return the selected mode choice alternative from [1,...,numMcAlts]. + */ + private int selectModeFromProbabilities(Stop s, double[] cumProbs) + { + + Household household = s.getTour().getPersonObject().getHouseholdObject(); + + int selectedModeAlt = -1; + double rn = household.getHhRandom().nextDouble(); + int randomCount = household.getHhRandomCount(); + + int numAvailAlts = 0; + double sumProb = 0.0; + for (int i = 0; i < cumProbs.length; i++) + { + double tempProb = cumProbs[i] - sumProb; + sumProb += tempProb; + + if (tempProb > 0) numAvailAlts++; + + if (rn < cumProbs[i]) + { + selectedModeAlt = i + 1; + break; + } + } + + if (household.getDebugChoiceModels() || selectedModeAlt < 0 + || numAvailAlts >= availAltsToLog) + { + + // set the number of available alts to log value to a large number + // so no more get logged. + if (numAvailAlts >= availAltsToLog) + { + Person person = s.getTour().getPersonObject(); + Tour tour = s.getTour(); + smcLogger + .info("Monte Carlo selection for determining Mode Choice from Probabilities for stop with more than " + + availAltsToLog + " mode alts available."); + smcLogger.info("HHID=" + household.getHhId() + ", persNum=" + person.getPersonNum() + + ", tourPurpose=" + tour.getTourPrimaryPurpose() + ", tourId=" + + tour.getTourId() + ", tourMode=" + tour.getTourModeChoice()); + smcLogger.info("StopID=" + + (s.getStopId() + 1) + + " of " + + (s.isInboundStop() ? tour.getNumInboundStops() - 1 : tour + .getNumOutboundStops() - 1) + " stops, inbound=" + + s.isInboundStop() + ", stopPurpose=" + s.getDestPurpose() + + ", stopDepart=" + s.getStopPeriod() + ", stopOrig=" + s.getOrig() + + ", stopDest=" + s.getDest()); + availAltsToLog = 9999; + } + + smcLogger.info(""); + smcLogger.info(""); + String separator = ""; + for (int k = 0; k < 60; k++) + separator += "+"; + smcLogger.info(separator); + + smcLogger + .info("Alternative Availability Utility Probability CumProb"); + smcLogger + .info("--------------------- ------------ ----------- -------------- --------------"); + + sumProb = 0.0; + for (int j = 0; j < cumProbs.length; j++) + { + String altString = String.format("%-3d %-25s", j + 1, ""); + double tempProb = cumProbs[j] - sumProb; + smcLogger.info(String.format("%-30s%15s%18s%18.6e%18.6e", altString, "", "", + tempProb, cumProbs[j])); + sumProb += tempProb; + } + + if (selectedModeAlt < 0) + { + smcLogger.info(" "); + String altString = String.format("%-3d %-25s", selectedModeAlt, + "no MC alt available"); + smcLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + throw new RuntimeException(); + } else + { + smcLogger.info(" "); + String altString = String.format("%-3d %-25s", selectedModeAlt, ""); + smcLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + } + + smcLogger.info(separator); + smcLogger.info(""); + smcLogger.info(""); + + } + + // if this statement is reached, there's a problem with the cumulative + // probabilities array, so return -1. + return selectedModeAlt; + } + + /** + * This method is taken from the setupStopLocationChoiceAlternativeArrays(), + * except that the stop location choice dmu attributes are not set and the + * logsum calculation setup is done only for the selected stop location + * alternative. + * + * @param stop + * object representing the half-tour. + * + * @return the selected mode choice alternative from [1,...,numMcAlts]. + */ + private int getHalfTourModeChoice(Stop s) + { + + Household hh = s.getTour().getPersonObject().getHouseholdObject(); + + // create arrays for ik and kj mode choice logsums for the stop origin, + // the sample stop location, and the half-tour final destination. + setupLogsumCalculation(s); + + int category = PURPOSE_CATEGORIES[s.getTour().getTourPrimaryPurposeIndex()]; + ChoiceModelApplication mcModel = mcModelArray[category]; + + int altMgra = s.getDest(); + mcDmuObject.getDmuIndexValues().setDestZone(altMgra); + + // set the mode choice attributes for the sample location + mcDmuObject.setDestDuDen(mgraManager.getDuDenValue(altMgra)); + mcDmuObject.setDestEmpDen(mgraManager.getEmpDenValue(altMgra)); + mcDmuObject.setDestTotInt(mgraManager.getTotIntValue(altMgra)); + + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager + .getTaz(altMgra))); + + mcDmuObject.setAutoModeRequiredForTripSegment(false); + mcDmuObject.setWalkModeAllowedForTripSegment(false); + + if (hh.getDebugChoiceModels()) + { + smcLogger.info("LOGSUM calculation for determining Mode Choice Probabilities for " + + (s.isInboundStop() ? "INBOUND" : "OUTBOUND") + " half-tour with no stops."); + + hh.logHouseholdObject( + "Half Tour Mode Choice: HH_" + hh.getHhId() + ", Pers_" + + s.getTour().getPersonObject().getPersonNum() + ", Tour Purpose_" + + s.getTour().getTourPurpose() + ", Tour_" + s.getTour().getTourId() + + ", Tour Purpose_" + s.getTour().getTourPurpose() + ", Stop_" + + (s.getStopId() + 1), smcLogger); + hh.logPersonObject("Half Tour Mode Choice for person " + + s.getTour().getPersonObject().getPersonNum(), smcLogger, s.getTour().getPersonObject()); + hh.logTourObject("Half Tour Mode Choice for tour " + s.getTour().getTourId(), + smcLogger, s.getTour().getPersonObject(), s.getTour()); + hh.logStopObject("Half Tour Mode Choice for stop " + (s.getStopId() + 1), + smcLogger, s, modelStructure); + } + + if (modelStructure.getTourModeIsDriveTransit(s.getTour().getTourModeChoice())) + { + + logsumHelper.setWalkTransitLogSumUnavailable( mcDmuObject ); + + if (s.isInboundStop()) logsumHelper.setWtdTripMcDmuAttributesForBestTapPairs( + mcDmuObject, s.getOrig(), altMgra, s.getStopPeriod(), s.getTour() + .getBestWtdTapPairsIn(), s.getTour().getPersonObject() + .getHouseholdObject().getDebugChoiceModels()); + else logsumHelper.setDtwTripMcDmuAttributesForBestTapPairs(mcDmuObject, s.getOrig(), + altMgra, s.getStopPeriod(), s.getTour().getBestDtwTapPairsOut(), s.getTour() + .getPersonObject().getHouseholdObject().getDebugChoiceModels()); + + } else + { + + logsumHelper.setDriveTransitLogSumUnavailable( mcDmuObject, s.isInboundStop() ); + + if (s.isInboundStop()) logsumHelper.setWtwTripMcDmuAttributesForBestTapPairs( + mcDmuObject, s.getOrig(), altMgra, s.getStopPeriod(), s.getTour() + .getBestWtwTapPairsIn(), s.getTour().getPersonObject() + .getHouseholdObject().getDebugChoiceModels()); + else logsumHelper.setWtwTripMcDmuAttributesForBestTapPairs(mcDmuObject, s.getOrig(), + altMgra, s.getStopPeriod(), s.getTour().getBestWtwTapPairsOut(), s.getTour() + .getPersonObject().getHouseholdObject().getDebugChoiceModels()); + + } + double logsum = logsumHelper.calculateTripMcLogsum(s.getOrig(), altMgra, s.getStopPeriod(), + mcModel, mcDmuObject, smcLogger); + + s.setModeLogsum((float) logsum); + + double rn = hh.getHhRandom().nextDouble(); + int randomCount = hh.getHhRandomCount(); + + int selectedModeAlt = -1; + if (mcModel.getAvailabilityCount() > 0) + { + selectedModeAlt = mcModel.getChoiceResult(rn); + } + + if (hh.getDebugChoiceModels() || selectedModeAlt < 0 + || mcModel.getAvailabilityCount() >= availAltsToLog) + { + + // set the number of available alts to log value to a large number + // so no more get logged. + if (selectedModeAlt < 0 || mcModel.getAvailabilityCount() >= availAltsToLog) + { + Person person = s.getTour().getPersonObject(); + Tour tour = s.getTour(); + if (mcModel.getAvailabilityCount() >= availAltsToLog) + { + availAltsToLog = 9999; + smcLogger + .info("Logsum calculation for determining Mode Choice for half-tour more than " + + availAltsToLog + " mode alts available."); + } else + { + smcLogger + .info("Logsum calculation for determining Mode Choice for half-tour with no stops."); + } + smcLogger.info("HHID=" + hh.getHhId() + ", persNum=" + person.getPersonNum() + + ", tourPurpose=" + tour.getTourPrimaryPurpose() + ", tourId=" + + tour.getTourId() + ", tourMode=" + tour.getTourModeChoice()); + smcLogger.info("StopID=" + + (s.getStopId() + 1) + + " of " + + (s.isInboundStop() ? tour.getNumInboundStops() - 1 : tour + .getNumOutboundStops() - 1) + " stops, inbound=" + + s.isInboundStop() + ", stopPurpose=" + s.getDestPurpose() + + ", stopDepart=" + s.getStopPeriod() + ", stopOrig=" + s.getOrig() + + ", stopDest=" + s.getDest()); + } + + // altNames, utilities and probabilities are 0 based. + String[] altNames = mcModel.getAlternativeNames(); + double[] utilities = mcModel.getUtilities(); + double[] probabilities = mcModel.getProbabilities(); + + // availabilities is 1 based. + boolean[] availabilities = mcModel.getAvailabilities(); + + smcLogger.info(""); + smcLogger.info(""); + String separator = ""; + for (int k = 0; k < 60; k++) + separator += "+"; + smcLogger.info(separator); + + smcLogger + .info("Alternative Availability Utility Probability CumProb"); + smcLogger + .info("--------------------- ------------ ----------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 0; j < utilities.length; j++) + { + cumProb += probabilities[j]; + String altString = String.format("%-3d %-25s", j + 1, altNames[j]); + smcLogger.info(String.format("%-30s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j + 1], utilities[j], probabilities[j], cumProb)); + } + + if (selectedModeAlt < 0) + { + smcLogger.info(" "); + String altString = String.format("%-3d %-25s", selectedModeAlt, + "no MC alt available"); + smcLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + } else + { + smcLogger.info(" "); + String altString = String.format("%-3d %-25s", selectedModeAlt, + altNames[selectedModeAlt - 1]); + smcLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + } + + smcLogger.info(separator); + smcLogger.info(""); + smcLogger.info(""); + + if (logsum < -900 || selectedModeAlt < 0) + { + if (logsum < -900 || selectedModeAlt < 0) smcLogger + .error("ERROR calculating trip mode choice logsum for " + + (s.isInboundStop() ? "inbound" : "outbound") + + " half-tour with no stops - ikLogsum = " + logsum + "."); + else smcLogger.error("No half-tour mode choice alternatives available " + + (s.isInboundStop() ? "inbound" : "outbound") + + " half-tour with no stops - ikLogsum = " + logsum + "."); + smcLogger + .error("setting debug to true and recomputing half-tour logsum in order to log utility expression results."); + + if (s.isInboundStop()) smcLogger + .error(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopDirection=%s, StopId=%d, NumIBStops=%d, StopOrig=%d, AltStopLoc=%d", + s.getTour().getPersonObject().getHouseholdObject() + .getHhId(), s.getTour().getPersonObject() + .getPersonNum(), s.getTour().getPersonObject() + .getPersonType(), s.getTour().getTourPurpose(), s + .getTour().getTourModeChoice(), s.getTour() + .getTourId(), s.getDestPurpose(), "inbound", (s + .getStopId() + 1), + s.getTour().getNumInboundStops() - 1, s.getOrig(), altMgra)); + else smcLogger + .error(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourMode=%d, TourId=%d, StopPurpose=%s, StopDirection=%s, StopId=%d, NumOBStops=%d, StopOrig=%d, AltStopLoc=%d", + s.getTour().getPersonObject().getHouseholdObject() + .getHhId(), s.getTour().getPersonObject() + .getPersonNum(), s.getTour().getPersonObject() + .getPersonType(), s.getTour().getTourPurpose(), s + .getTour().getTourModeChoice(), s.getTour() + .getTourId(), s.getDestPurpose(), "outbound", (s + .getStopId() + 1), s.getTour() + .getNumOutboundStops() - 1, s.getOrig(), altMgra)); + + mcDmuObject.getDmuIndexValues().setDebug(true); + mcDmuObject.getDmuIndexValues().setHHIndex( + s.getTour().getPersonObject().getHouseholdObject().getHhId()); + logsum = logsumHelper.calculateTripMcLogsum(s.getOrig(), altMgra, + s.getStopPeriod(), mcModel, mcDmuObject, smcLogger); + mcDmuObject.getDmuIndexValues().setDebug(false); + + // throw new RuntimeException(); + + } + + } + //value of time; lookup vot, votS2, or votS3 from the UEC depending on chosen mode + UtilityExpressionCalculator uec = mcModel.getUEC(); + + double vot = 0.0; + + if(modelStructure.getTripModeIsS2(selectedModeAlt)){ + int votIndex = uec.lookupVariableIndex("votS2"); + vot = uec.getValueForIndex(votIndex); + }else if (modelStructure.getTripModeIsS3(selectedModeAlt)){ + int votIndex = uec.lookupVariableIndex("votS3"); + vot = uec.getValueForIndex(votIndex); + }else{ + int votIndex = uec.lookupVariableIndex("vot"); + vot = uec.getValueForIndex(votIndex); + } + s.setValueOfTime(vot); + + return selectedModeAlt; + } + + private void setOutboundTripDepartTimes(Stop[] stops) + { + + // these stops are in outbound direction + int halfTourDirection = 0; + + for (int i = 0; i < stops.length; i++) + { + + // if tour depart and arrive periods are the same, set same values + // for the stops + Stop stop = stops[i]; + Tour tour = stop.getTour(); + Person person = tour.getPersonObject(); + Household household = person.getHouseholdObject(); + if (tour.getTourArrivePeriod() == tour.getTourDepartPeriod()) + { + + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Depart Time Model Not Run Since Tour Depart and Arrive Periods are Equal; Stop Depart Period set to Tour Depart Period = " + + tour.getTourDepartPeriod() + " for outbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourModeChoice(), + tour.getTourCategory(), tour.getTourPrimaryPurpose(), + tour.getTourId(), stop.getOrigPurpose(), + stop.getDestPurpose(), (stop.getStopId() + 1), + stops.length)); + tripDepartLogger.info(String.format("tourDepartPeriod=%d, tourArrivePeriod=%d", + tour.getTourDepartPeriod(), tour.getTourArrivePeriod())); + tripDepartLogger.info(""); + } + stop.setStopPeriod(tour.getTourDepartPeriod()); + + } else + { + + int tripIndex = i + 1; + + if (tripIndex == 1) + { + + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Depart Time Model Not Run Since Trip is first trip in sequence, departing from " + + stop.getOrigPurpose() + + "; Stop Depart Period set to Tour Depart Period = " + + tour.getTourDepartPeriod() + " for outbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), tour.getTourId(), + stop.getOrigPurpose(), stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger.info(String.format( + "tourDepartPeriod=%d, tourArrivePeriod=%d", + tour.getTourDepartPeriod(), tour.getTourArrivePeriod())); + tripDepartLogger.info(""); + } + stop.setStopPeriod(tour.getTourDepartPeriod()); + + } else + { + + int prevTripPeriod = stops[i - 1].getStopPeriod(); + + if (prevTripPeriod == tour.getTourArrivePeriod()) + { + + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Depart Time Model Not Run Since Previous Trip Depart and Tour Arrive Periods are Equal; Stop Depart Period set to Tour Arrive Period = " + + tour.getTourArrivePeriod() + + " for outbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), + tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), tour.getTourId(), + stop.getOrigPurpose(), stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger.info(String.format( + "prevTripPeriod=%d, tourDepartPeriod=%d, tourArrivePeriod=%d", + prevTripPeriod, tour.getTourDepartPeriod(), + tour.getTourArrivePeriod())); + tripDepartLogger.info(""); + } + stop.setStopPeriod(tour.getTourDepartPeriod()); + + } else + { + + int tourPrimaryPurposeIndex = tour.getTourPrimaryPurposeIndex(); + + double[] proportions = stopTodModel.getStopTodIntervalProportions( + tourPrimaryPurposeIndex, halfTourDirection, prevTripPeriod, + tripIndex); + + // for inbound trips, the first trip cannot arrive + // earlier than the last outbound trip departs + // if such a case is chosen, re-select. + int invalidCount = 0; + boolean validTripDepartPeriodSet = false; + while (validTripDepartPeriodSet == false) + { + + double rn = household.getHhRandom().nextDouble(); + int choice = getMonteCarloSelection(proportions, rn); + + // check that this stop depart time departs at same + // time or later than the stop object preceding this + // one in the stop sequence. + if (choice >= prevTripPeriod && choice <= tour.getTourArrivePeriod()) + { + validTripDepartPeriodSet = true; + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Depart Time Model for outbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), + person.getPersonNum(), + person.getPersonType(), + tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), + tour.getTourId(), + stop.getOrigPurpose(), + stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger + .info(String + .format("prevTripPeriod=%d, tourDepartPeriod=%d, tourArrivePeriod=%d", + prevTripPeriod, + tour.getTourDepartPeriod(), + tour.getTourArrivePeriod())); + tripDepartLogger.info("tourPrimaryPurposeIndex=" + + tourPrimaryPurposeIndex + ", halfTourDirection=" + + halfTourDirection + ", tripIndex=" + tripIndex); + tripDepartLogger.info(""); + + tripDepartLogger.info(loggerSeparator); + tripDepartLogger.info(String.format("%-4s %-8s %10s %10s", + "alt", "time", "prob", "cumProb")); + double cumProb = 0.0; + for (int p = 1; p < proportions.length; p++) + { + int hr = 4 + (p / 2); + int min = (p % 2) * 30; + cumProb += proportions[p]; + String timeString = ((hr < 10) ? ("0" + hr) + : ("" + hr + ":")) + ((min == 30) ? min : "00"); + tripDepartLogger.info(String.format( + "%-4d %-8s %10.8f %10.8f", p, timeString, + proportions[p], cumProb)); + } + tripDepartLogger.info(loggerSeparator); + tripDepartLogger.info("rn=" + rn + ", choice=" + choice + + ", try=" + invalidCount); + tripDepartLogger.info(""); + } + stop.setStopPeriod(choice); + + } else + { + invalidCount++; + } + + if (invalidCount > MAX_INVALID_FIRST_ARRIVAL_COUNT) + { + tripDepartLogger.warn("Problem in Outbound Trip Depart Time Model."); + tripDepartLogger + .warn("Outbound trip depart time less than previous trip depart time for " + + invalidCount + " times."); + tripDepartLogger.warn("Possible infinite loop?"); + tripDepartLogger + .warn(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), + tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), + tour.getTourId(), stop.getOrigPurpose(), + stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger + .warn(String + .format("prevTripPeriod=%d, tourDepartPeriod=%d, tourArrivePeriod=%d, last choice=%d", + prevTripPeriod, tour.getTourDepartPeriod(), + tour.getTourArrivePeriod(), choice)); + tripDepartLogger.warn("=" + invalidCount + " times."); + + //throw new RuntimeException(); + //instead of throwing an exception, set the stop period to the same period as the last stop + stop.setStopPeriod(prevTripPeriod); + } + + } + + } + + } + + } + + } + + } + + private void setInboundTripDepartTimes(Stop[] stops, int lastOutboundTripDeparts) + { + + // these stops are in inbound direction + int halfTourDirection = 1; + + for (int i = stops.length - 1; i >= 0; i--) + { + + // if tour depart and arrive periods are the same, set same values + // for the stops + Stop stop = stops[i]; + Tour tour = stop.getTour(); + Person person = tour.getPersonObject(); + Household household = person.getHouseholdObject(); + if (tour.getTourArrivePeriod() == tour.getTourDepartPeriod()) + { + + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Arrive Time Model Not Run Since Tour Depart and Arrive Periods are Equal; Stop Arrive Period set to Tour Arrive Period = " + + tour.getTourDepartPeriod() + " for inbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourModeChoice(), + tour.getTourCategory(), tour.getTourPrimaryPurpose(), + tour.getTourId(), stop.getOrigPurpose(), + stop.getDestPurpose(), (stop.getStopId() + 1), + stops.length)); + tripDepartLogger.info(String.format("tourDepartPeriod=%d, tourArrivePeriod=%d", + tour.getTourDepartPeriod(), tour.getTourArrivePeriod())); + tripDepartLogger.info(""); + } + stop.setStopPeriod(tour.getTourArrivePeriod()); + + } else + { + + int tripIndex = stops.length - i; + + if (tripIndex == 1) + { + + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Arrive Time Model Not Run Since Trip is last trip in sequence, arriving at " + + stop.getDestPurpose() + + "; Stop Arrive Period set to Tour Arrive Period = " + + tour.getTourArrivePeriod() + " for inbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), tour.getTourId(), + stop.getOrigPurpose(), stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger.info(String.format( + "tourDepartPeriod=%d, tourArrivePeriod=%d", + tour.getTourDepartPeriod(), tour.getTourArrivePeriod())); + tripDepartLogger.info(""); + } + stop.setStopPeriod(tour.getTourArrivePeriod()); + + } else + { + + int prevTripPeriod = stops[i + 1].getStopPeriod(); + + if (prevTripPeriod == tour.getTourArrivePeriod()) + { + + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Arrive Time Model Not Run Since Previous Trip Arrive and Tour Arrive Periods are Equal; Stop Arrive Period set to Tour Arrive Period = " + + tour.getTourArrivePeriod() + + " for intbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), + tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), tour.getTourId(), + stop.getOrigPurpose(), stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger.info(String.format( + "prevTripPeriod=%d, tourDepartPeriod=%d, tourArrivePeriod=%d", + prevTripPeriod, tour.getTourDepartPeriod(), + tour.getTourArrivePeriod())); + tripDepartLogger.info(""); + } + stop.setStopPeriod(tour.getTourArrivePeriod()); + + } else + { + + int tourPrimaryPurposeIndex = tour.getTourPrimaryPurposeIndex(); + + double[] proportions = stopTodModel.getStopTodIntervalProportions( + tourPrimaryPurposeIndex, halfTourDirection, prevTripPeriod, + tripIndex); + + // for inbound trips, the first trip cannot arrive + // earlier than the last outbound trip departs + // if such a case is chosen, re-select. + int invalidCount = 0; + boolean validTripArrivePeriodSet = false; + while (validTripArrivePeriodSet == false) + { + + double rn = household.getHhRandom().nextDouble(); + int choice = getMonteCarloSelection(proportions, rn); + + // check that this stop arrival time arrives at same + // time or earlier than the stop object following + // this one in the stop sequence. + // also check that this stop arrival is after the + // depart time for the last outbound stop. + if (choice <= prevTripPeriod && choice >= lastOutboundTripDeparts) + { + validTripArrivePeriodSet = true; + if (household.getDebugChoiceModels()) + { + tripDepartLogger + .info("Trip Arrive Time Model for inbound half-tour."); + tripDepartLogger + .info(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), + person.getPersonNum(), + person.getPersonType(), + tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), + tour.getTourId(), + stop.getOrigPurpose(), + stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger.info("tourPrimaryPurposeIndex=" + + tourPrimaryPurposeIndex + ", halfTourDirection=" + + halfTourDirection + ", tripIndex=" + tripIndex + + ", prevTripPeriod=" + prevTripPeriod); + tripDepartLogger + .info(String + .format("prevTripPeriod=%d, tourDepartPeriod=%d, tourArrivePeriod=%d", + prevTripPeriod, + tour.getTourDepartPeriod(), + tour.getTourArrivePeriod())); + tripDepartLogger.info(loggerSeparator); + tripDepartLogger.info(""); + + tripDepartLogger.info(String.format("%-4s %-8s %10s %10s", + "alt", "time", "prob", "cumProb")); + double cumProb = 0.0; + for (int p = 1; p < proportions.length; p++) + { + int hr = 4 + (p / 2); + int min = (p % 2) * 30; + cumProb += proportions[p]; + String timeString = ((hr < 10) ? ("0" + hr) + : ("" + hr + ":")) + ((min == 30) ? min : "00"); + tripDepartLogger.info(String.format( + "%-4d %-8s %10.8f %10.8f", p, timeString, + proportions[p], cumProb)); + } + tripDepartLogger.info(loggerSeparator); + tripDepartLogger.info("rn=" + rn + ", choice=" + choice + + ", try=" + invalidCount); + tripDepartLogger.info(""); + } + stop.setStopPeriod(choice); + } else + { + invalidCount++; + } + + if (invalidCount > MAX_INVALID_FIRST_ARRIVAL_COUNT) + { + tripDepartLogger.warn("Problem in Inbound Trip Arrival Time Model."); + tripDepartLogger + .warn("Inbound trip arrive time greater than tour arrive time chosen for " + + invalidCount + " times."); + tripDepartLogger.warn("Possible infinite loop?"); + tripDepartLogger + .warn(String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourMode=%d, TourCategory=%s, TourPurpose=%s, TourId=%d, StopOrigPurpose=%s, StopDestPurpose=%s, StopId=%d, outboundStopsArray Length=%d", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), + tour.getTourModeChoice(), + tour.getTourCategory(), + tour.getTourPrimaryPurpose(), + tour.getTourId(), stop.getOrigPurpose(), + stop.getDestPurpose(), + (stop.getStopId() + 1), stops.length)); + tripDepartLogger + .warn(String + .format("prevTripPeriod=%d, tourDepartPeriod=%d, tourArrivePeriod=%d, last choice=%d", + prevTripPeriod, tour.getTourDepartPeriod(), + tour.getTourArrivePeriod(), choice)); + tripDepartLogger.warn("=" + invalidCount + " times."); + + //throw new RuntimeException(); + //instead of throwing an exception, set the stop period to the same period as the previous stop + stop.setStopPeriod(lastOutboundTripDeparts); + } + + } + + } + + } + + } + + } + + } + + /** + * + * @param probabilities + * has 1s based indexing + * @param randomNumber + * @return + */ + private int getMonteCarloSelection(double[] probabilities, double randomNumber) + { + + int returnValue = 0; + double sum = probabilities[1]; + // probabilities array passded into this method is 1s based. + for (int i = 1; i < probabilities.length - 1; i++) + { + if (randomNumber <= sum) + { + returnValue = i; + break; + } else + { + sum += probabilities[i + 1]; + returnValue = i + 1; + } + } + return returnValue; + } + + private void zeroOutCpuTimes() + { + soaAutoTime = 0; + soaOtherTime = 0; + slsTime = 0; + sldTime = 0; + slcTime = 0; + todTime = 0; + smcTime = 0; + } + + public long[] getStopTimes() + { + hhTimes[0] = soaAutoTime; + hhTimes[1] = soaOtherTime; + hhTimes[2] = slsTime; + hhTimes[3] = sldTime; + hhTimes[4] = slcTime - (soaAutoTime + soaOtherTime + slsTime); + hhTimes[5] = slcTime; + hhTimes[6] = todTime; + hhTimes[7] = smcTime; + hhTimes[8] = slcTime + sldTime + todTime + smcTime; + + return hhTimes; + } + + // this method is called to determine the parking mgra location if the stop + // location is in parkarea 1 and chosen mode is sov or hov. + private int selectParkingLocation(Household household, Tour tour, Stop stop) + { + + Logger modelLogger = parkLocLogger; + + // if the trip destination mgra is not in parking area 1, it's not + // necessary to make a parking location choice + if (mgraAltLocationIndex.containsKey(stop.getDest()) == false + || mgraAltParkArea.get(stop.getDest()) != 1) return -1; + + // if person worked at home, no reason to make a parking location choice + if (tour.getPersonObject().getFreeParkingAvailableResult() == ParkingProvisionModel.FP_MODEL_NO_REIMBURSEMENT_CHOICE) + return -1; + + // if the person has free parking, set the parking location + if (tour.getPersonObject().getFreeParkingAvailableResult() == 1) return stop.getDest(); + + parkingChoiceDmuObj.setDmuIndexValues(household.getHhId(), stop.getOrig(), stop.getDest(), + household.getDebugChoiceModels()); + + parkingChoiceDmuObj.setPersonType(tour.getPersonObject().getPersonTypeNumber()); + + Stop[] stops = null; + if (stop.isInboundStop()) stops = tour.getInboundStops(); + else stops = tour.getOutboundStops(); + + // determine activity duration in number od departure time intervals + // if no stops on halftour, activity duration is tour duration + int activityIntervals = 0; + if (stops.length == 1) + { + activityIntervals = tour.getTourArrivePeriod() - tour.getTourDepartPeriod(); + } else + { + int stopId = stop.getStopId(); + if (stopId == stops.length - 1) activityIntervals = tour.getTourArrivePeriod() + - stop.getStopPeriod(); + else activityIntervals = stops[stopId + 1].getStopPeriod() - stop.getStopPeriod(); + } + + parkingChoiceDmuObj.setActivityIntervals(activityIntervals); + + parkingChoiceDmuObj.setDestPurpose(stop.getStopPurposeIndex()); + + parkingChoiceDmuObj.setReimbPct(tour.getPersonObject().getParkingReimbursement()); + + int[] sampleIndices = setupParkLocationChoiceAlternativeArrays(stop.getOrig(), + stop.getDest()); + + // if no alternatives in the sample, it's not necessary to make a + // parking location choice + if (sampleIndices == null) return -1; + + if (household.getDebugChoiceModels()) + { + household.logHouseholdObject( + "Pre Parking Location Choice for trip: HH_" + household.getHhId() + ", Pers_" + + tour.getPersonObject().getPersonNum() + ", Tour Purpose_" + + tour.getTourPurpose() + ", Tour_" + tour.getTourId() + + ", Tour Purpose_" + tour.getTourPurpose() + ", Stop_" + + stop.getStopId(), modelLogger); + household.logPersonObject("Pre Parking Location Choice for person " + + tour.getPersonObject().getPersonNum(), modelLogger, tour.getPersonObject()); + household.logTourObject("Pre Parking Location Choice for tour " + tour.getTourId(), + modelLogger, tour.getPersonObject(), tour); + household.logStopObject("Pre Parking Location Choice for stop " + stop.getStopId(), + modelLogger, stop, modelStructure); + } + + Person person = tour.getPersonObject(); + + String choiceModelDescription = ""; + String separator = ""; + String loggerString = ""; + String decisionMakerLabel = ""; + + // log headers to traceLogger if the person making the destination + // choice is from a household requesting trace information + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = "Parking Location Choice Model for trip"; + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourPurpose=%s, TourId=%d, StopPurpose=%s, StopId=%d", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourPurpose(), tour.getTourId(), tour.getTourPurpose(), + stop.getStopId()); + + modelLogger.info(" "); + loggerString = choiceModelDescription + " for " + decisionMakerLabel + "."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + plcModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + plcModel.computeUtilities(parkingChoiceDmuObj, parkingChoiceDmuObj.getDmuIndexValues(), + altParkAvail, altParkSample); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + int chosenIndex = -1; + int parkMgra = 0; + if (plcModel.getAvailabilityCount() > 0) + { + // get the mgra number associated with the chosen alternative + chosen = plcModel.getChoiceResult(rn); + // sampleIndices is 1-based, but the values returned are 0-based, + // parkMgras is 0-based + chosenIndex = sampleIndices[chosen]; + parkMgra = parkMgras[chosenIndex]; + } + + // write choice model alternative info to log file + if (household.getDebugChoiceModels() || chosen < 0) + { + + double[] utilities = plcModel.getUtilities(); + double[] probabilities = plcModel.getProbabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("-------------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + + for (int k = 1; k <= numAltsInSample; k++) + { + int index = sampleIndices[k]; + int altMgra = parkMgras[index]; + cumProb += probabilities[k - 1]; + String altString = String.format("k=%d, index=%d, altMgra=%d", k, index, altMgra); + modelLogger.info(String.format("%-35s%18.6e%18.6e%18.6e", altString, + utilities[k - 1], probabilities[k - 1], cumProb)); + } + + modelLogger.info(" "); + if (chosen < 0) + { + modelLogger.info(String.format("No Alternatives Available For Choice !!!")); + } else + { + String altString = String.format("chosen=%d, chosenIndex=%d, chosenMgra=%d", + chosen, chosenIndex, parkMgra); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + } + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + plcModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + plcModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log file + plcModel.logUECResults(modelLogger, loggerString); + + } + + if (chosen > 0) return parkMgra; + else + { + logger.error(String + .format("Exception caught for HHID=%d, personNum=%d, no available parking location alternatives in tourId=%d to choose from in plcModelApplication.", + household.getHhId(), person.getPersonNum(), tour.getTourId())); + return stop.getDest(); + //throw new RuntimeException(); + } + + } + + // this method is called for trips that require a park location choice -- + // trip destination in parkarea 1 and not a work trip with free onsite + // parking + // return false if no parking location alternatives are in walk distance of + // trip destination; true otherwise. + private int[] setupParkLocationChoiceAlternativeArrays(int tripOrigMgra, int tripDestMgra) + { + + // get the array of mgras within walking distance of the trip + // destination + int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceTo(tripDestMgra); + + // set the distance values for the mgras walkable to the destination + if (walkMgras != null) + { + + // get distances, in feet, and convert to miles + // get distances from destMgra since this is the direction of + // distances read from the data file + int altCount = 0; + for (int wMgra : walkMgras) + { + // if wMgra is in the set of parkarea==1 MGRAs, add to list of + // alternatives for this park location choice + if (mgraAltLocationIndex.containsKey(wMgra)) + { + + double curWalkDist = mgraManager.getMgraToMgraWalkDistTo(wMgra, tripDestMgra) / 5280.0; + + if (curWalkDist > MgraDataManager.MAX_PARKING_WALK_DISTANCE) continue; + + // the hashMap stores a 0-based index + int altIndex = mgraAltLocationIndex.get(wMgra); + //int m = wMgra - 1; + int m=wMgra; + + altSdDistances[altCount + 1] = curWalkDist; + altMgraIndices[altCount + 1] = altIndex; + + altParkingCostsM[altCount + 1] = lsWgtAvgCostM[m]; + altParkingCostsD[altCount + 1] = lsWgtAvgCostD[m]; + altParkingCostsH[altCount + 1] = lsWgtAvgCostH[m]; + altMstallsoth[altCount + 1] = mstallsoth[m]; + altMstallssam[altCount + 1] = mstallssam[m]; + altMparkcost[altCount + 1] = mparkcost[m]; + altDstallsoth[altCount + 1] = dstallsoth[m]; + altDstallssam[altCount + 1] = dstallssam[m]; + altDparkcost[altCount + 1] = dparkcost[m]; + altHstallsoth[altCount + 1] = hstallsoth[m]; + altHstallssam[altCount + 1] = hstallssam[m]; + altHparkcost[altCount + 1] = hparkcost[m]; + altNumfreehrs[altCount + 1] = numfreehrs[m]; + + altParkAvail[altCount + 1] = true; + altParkSample[altCount + 1] = 1; + + altCount++; + } + } + + if (altCount > 0) + { + + for (int i = altCount; i < MAX_PLC_SAMPLE_SIZE; i++) + { + altOsDistances[i + 1] = Double.NaN; + altSdDistances[i + 1] = Double.NaN; + altMgraIndices[i + 1] = Integer.MAX_VALUE; + + altParkingCostsM[i + 1] = Double.NaN; + altParkingCostsD[i + 1] = Double.NaN; + altParkingCostsH[i + 1] = Double.NaN; + altMstallsoth[i + 1] = Integer.MAX_VALUE; + altMstallssam[i + 1] = Integer.MAX_VALUE; + altMparkcost[i + 1] = Float.MAX_VALUE; + altDstallsoth[i + 1] = Integer.MAX_VALUE; + altDstallssam[i + 1] = Integer.MAX_VALUE; + altDparkcost[i + 1] = Float.MAX_VALUE; + altHstallsoth[i + 1] = Integer.MAX_VALUE; + altHstallssam[i + 1] = Integer.MAX_VALUE; + altHparkcost[i + 1] = Float.MAX_VALUE; + altNumfreehrs[i + 1] = Integer.MAX_VALUE; + + altParkAvail[i + 1] = false; + altParkSample[i + 1] = 0; + } + numAltsInSample = altCount; + if (numAltsInSample > maxAltsInSample) maxAltsInSample = numAltsInSample; + } + + return altMgraIndices; + + } + + return null; + + } + + public int getMaxAltsInSample() + { + return maxAltsInSample; + } + + public HashMap getSizeSegmentNameIndexMap() + { + return sizeSegmentNameIndexMap; + } + + public double[][] getSizeSegmentArray() + { + return slcSizeTerms; + } + /** + * This method calculates a cost coefficient based on the following formula: + * + * costCoeff = incomeCoeff * 1/(max(income,1000)^incomeExponent) + * + * + * @param incomeCoeff + * @param incomeExponent + * @return A cost coefficent that should be multiplied by cost variables (cents) in tour mode choice + */ + public double calculateCostCoefficient(double income, double incomeCoeff, double incomeExponent){ + + return incomeCoeff * 1.0/(Math.pow(Math.max(income,1000.0),incomeExponent)); + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/InternalExternalTripChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/InternalExternalTripChoiceDMU.java new file mode 100644 index 0000000..3b00f69 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/InternalExternalTripChoiceDMU.java @@ -0,0 +1,113 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + * @author crf
+ * Started: Apr 14, 2009 11:09:58 AM + */ +public class InternalExternalTripChoiceDMU + implements Serializable, VariableTable +{ + + protected HashMap methodIndexMap; + + private Household hh; + private Person person; + + private double distanceToCordonsLogsum; + private double vehiclesPerHouseholdMember; + + private IndexValues iv; + + public InternalExternalTripChoiceDMU() + { + iv = new IndexValues(); + } + + public void setDmuIndexValues(int hhid, int hhtaz) + { + iv.setHHIndex(hhid); + iv.setZoneIndex(hhtaz); + iv.setDebug(hh.getDebugChoiceModels()); + } + + public IndexValues getDmuIndexValues() + { + return iv; + } + + public void setHouseholdObject(Household hhObj) + { + hh = hhObj; + } + + public void setPersonObject(Person persObj) + { + person = persObj; + } + + public void setDistanceToCordonsLogsum(double value) + { + distanceToCordonsLogsum = value; + } + + public double getDistanceToCordonsLogsum() + { + return distanceToCordonsLogsum; + } + + public void setVehiclesPerHouseholdMember(double value) + { + vehiclesPerHouseholdMember = value; + } + + public double getVehiclesPerHouseholdMember() + { + return vehiclesPerHouseholdMember; + } + + public int getHhIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + public int getAge() + { + return person.getAge(); + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/InternalExternalTripChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/InternalExternalTripChoiceModel.java new file mode 100644 index 0000000..eb856d0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/InternalExternalTripChoiceModel.java @@ -0,0 +1,120 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; + +import org.apache.log4j.Logger; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class InternalExternalTripChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("ie"); + + private static final String IE_CONTROL_FILE_TARGET = "ie.uec.file"; + private static final String IE_DATA_SHEET_TARGET = "ie.data.page"; + private static final String IE_MODEL_SHEET_TARGET = "ie.model.page"; + + public static final int IE_MODEL_NO_ALT = 1; + public static final int IE_MODEL_YES_ALT = 2; + + private ChoiceModelApplication ieModel; + private InternalExternalTripChoiceDMU ieDmuObject; + private ModelStructure modelStructure; + + public InternalExternalTripChoiceModel(HashMap propertyMap,ModelStructure myModelStructure, + CtrampDmuFactoryIf dmuFactory) + { + + logger.info("setting up internal-external trip choice model."); + + + modelStructure = myModelStructure; + // locate the IE choice UEC + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String ieUecFile = uecFileDirectory + propertyMap.get(IE_CONTROL_FILE_TARGET); + + int dataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, IE_DATA_SHEET_TARGET); + int modelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, IE_MODEL_SHEET_TARGET); + + // create the choice model DMU object. + ieDmuObject = dmuFactory.getInternalExternalTripChoiceDMU(); + + // create the choice model object + ieModel = new ChoiceModelApplication(ieUecFile, modelSheet, dataSheet, propertyMap, + (VariableTable) ieDmuObject); + + } + + public void applyModel(Household hhObject, double[] distanceToCordonsLogsums) + { + + int homeTaz = hhObject.getHhTaz(); + ieDmuObject.setDistanceToCordonsLogsum(distanceToCordonsLogsums[homeTaz]); + + ieDmuObject.setHouseholdObject(hhObject); + double vehiclesPerHouseholdMember = hhObject.getAutosOwned() + / hhObject.getHhSize(); + ieDmuObject.setVehiclesPerHouseholdMember(vehiclesPerHouseholdMember); + + Random hhRandom = hhObject.getHhRandom(); + + // person array is 1-based + Person[] person = hhObject.getPersons(); + for (int i = 1; i < person.length; i++) + { + + ieDmuObject.setPersonObject(person[i]); + ieDmuObject.setDmuIndexValues(hhObject.getHhId(), hhObject.getHhTaz()); + + double randomNumber = hhRandom.nextDouble(); + + // compute utilities and choose alternative. + float logsum = (float) ieModel.computeUtilities(ieDmuObject, ieDmuObject.getDmuIndexValues()); + person[i].setIeLogsum(logsum); + + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + if (ieModel.getAvailabilityCount() > 0) + { + chosenAlt = ieModel.getChoiceResult(randomNumber); + } else + { + String decisionMaker = String.format("HHID=%d, PersonNum=%d", hhObject.getHhId(), + person[i].getPersonNum()); + String errorMessage = String + .format("Exception caught for %s, no available internal-external trip choice alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.error(errorMessage); + + ieModel.logUECResults(logger, decisionMaker); + throw new RuntimeException(); + } + + // write choice model alternative info to log file + if (hhObject.getDebugChoiceModels()) + { + String decisionMaker = String.format("HHID=%d, PersonNum=%d", hhObject.getHhId(), + person[i].getPersonNum()); + ieModel.logAlternativesInfo("Internal-External Trip Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d with rn %.8f", + "Internal-External Trip Choice", decisionMaker, chosenAlt, randomNumber)); + ieModel.logUECResults(logger, decisionMaker); + } + + person[i].setInternalExternalTripChoiceResult(chosenAlt); + + + } + + hhObject.setIeRandomCount(hhObject.getHhRandomCount()); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/JointTourModels.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/JointTourModels.java new file mode 100644 index 0000000..c886c22 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/JointTourModels.java @@ -0,0 +1,916 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.net.UnknownHostException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Random; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagHouseholdDataManager; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; + +/** + * Created by IntelliJ IDEA. User: Jim Date: Jul 11, 2008 Time: 9:25:30 AM To + * change this template use File | Settings | File Templates. + */ +public class JointTourModels + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(JointTourModels.class); + private transient Logger tourFreq = Logger.getLogger("tourFreq"); + + // these are public because CtrampApplication creates a + // ChoiceModelAppplication in order to get the alternatives for a log report + public static final String UEC_FILE_PROPERTIES_TARGET = "jtfcp.uec.file"; + public static final String UEC_DATA_PAGE_TARGET = "jtfcp.data.page"; + public static final String UEC_JOINT_TOUR_FREQ_COMP_MODEL_PAGE = "jtfcp.freq.comp.page"; + + private static final String UEC_JOINT_TOUR_PARTIC_MODEL_PAGE = "jtfcp.participate.page"; + + public static final int JOINT_TOUR_COMPOSITION_ADULTS = 1; + public static final int JOINT_TOUR_COMPOSITION_CHILDREN = 2; + public static final int JOINT_TOUR_COMPOSITION_MIXED = 3; + + public static final String[] JOINT_TOUR_COMPOSITION_NAMES = {"", "adult", "child", + "mixed" }; + + public static final int PURPOSE_1_FIELD = 2; + public static final int PURPOSE_2_FIELD = 3; + public static final int PARTY_1_FIELD = 4; + public static final int PARTY_2_FIELD = 5; + + // DMU for the UEC + private JointTourModelsDMU dmuObject; + private AccessibilitiesTable accTable; + + private ChoiceModelApplication jointTourFrequencyModel; + private ChoiceModelApplication jointTourParticipation; + private TableDataSet jointModelsAltsTable; + private HashMap purposeIndexNameMap; + + private int[] invalidCount = new int[5]; + + private String threadName = null; + + public JointTourModels(HashMap propertyMap, AccessibilitiesTable myAccTable, + ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory) + { + + accTable = myAccTable; + + try + { + threadName = "[" + java.net.InetAddress.getLocalHost().getHostName() + ": " + + Thread.currentThread().getName() + "]"; + } catch (UnknownHostException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + setUpModels(propertyMap, modelStructure, dmuFactory); + } + + public void setUpModels(HashMap propertyMap, ModelStructure modelStructure, + CtrampDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up %s tour frequency model on %s", + ModelStructure.JOINT_NON_MANDATORY_CATEGORY, threadName)); + + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + + String uecFileName = propertyMap.get(UEC_FILE_PROPERTIES_TARGET); + uecFileName = uecFileDirectory + uecFileName; + + dmuObject = dmuFactory.getJointTourModelsDMU(); + + purposeIndexNameMap = new HashMap(); + purposeIndexNameMap.put(ModelStructure.SHOPPING_PRIMARY_PURPOSE_INDEX, + ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME); + purposeIndexNameMap.put(ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_INDEX, + ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME); + purposeIndexNameMap.put(ModelStructure.EAT_OUT_PRIMARY_PURPOSE_INDEX, + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME); + purposeIndexNameMap.put(ModelStructure.VISITING_PRIMARY_PURPOSE_INDEX, + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME); + purposeIndexNameMap.put(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_INDEX, + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME); + + int dataSheet = Integer.parseInt(propertyMap.get(UEC_DATA_PAGE_TARGET)); + int freqCompSheet = Integer.parseInt(propertyMap.get(UEC_JOINT_TOUR_FREQ_COMP_MODEL_PAGE)); + int particSheet = Integer.parseInt(propertyMap.get(UEC_JOINT_TOUR_PARTIC_MODEL_PAGE)); + + // set up the models + jointTourFrequencyModel = new ChoiceModelApplication(uecFileName, freqCompSheet, dataSheet, + propertyMap, (VariableTable) dmuObject); + jointModelsAltsTable = jointTourFrequencyModel.getUEC().getAlternativeData(); + modelStructure.setJtfAltLabels(jointTourFrequencyModel.getAlternativeNames()); + + jointTourParticipation = new ChoiceModelApplication(uecFileName, particSheet, dataSheet, + propertyMap, (VariableTable) dmuObject); + } + + public void applyModel(Household household) + { + + // this household does not make joint tours if the CDAP pattern does not + // contain "j". + if (!household.getCoordinatedDailyActivityPattern().contains("j")) return; + + household.calculateTimeWindowOverlaps(); + + try + { + + // joint tour frequency choice is not applied to a household unless + // it has: + // 2 or more persons, each with at least one out-of home activity, + // and at + // least 1 of the persons not a pre-schooler. + + Logger modelLogger = tourFreq; + if (household.getDebugChoiceModels()) + household.logHouseholdObject( + "Pre Joint Tour Frequency Choice HHID=" + household.getHhId() + " Object", + modelLogger); + + // if it's not a valid household for joint tour frequency, keep + // track of + // count for logging later, and return. + int validIndex = household.getValidHouseholdForJointTourFrequencyModel(); + if (validIndex != 1) + { + invalidCount[validIndex]++; + switch (validIndex) + { + case 2: + household.setJointTourFreqResult(-2, "-2_1 person"); + break; + case 3: + household.setJointTourFreqResult(-3, "-3_< 2 travel"); + break; + case 4: + household.setJointTourFreqResult(-4, "-4_only preschool travel"); + break; + } + return; + } + + // set the household id, origin taz, hh taz, and debugFlag=false in + // the dmu + dmuObject.setHouseholdObject(household); + + // set the accessibility values needed based on auto sufficiency + // category for the hh. + if (household.getAutoSufficiency() == 1) + { + dmuObject.setShopHOVAccessibility(accTable.getAggregateAccessibility("shopHov0", + household.getHhMgra())); + dmuObject.setMaintHOVAccessibility(accTable.getAggregateAccessibility("maintHov0", + household.getHhMgra())); + dmuObject.setDiscrHOVAccessibility(accTable.getAggregateAccessibility("discrHov0", + household.getHhMgra())); + } else if (household.getAutoSufficiency() == 2) + { + dmuObject.setShopHOVAccessibility(accTable.getAggregateAccessibility("shopHov1", + household.getHhMgra())); + dmuObject.setMaintHOVAccessibility(accTable.getAggregateAccessibility("maintHov1", + household.getHhMgra())); + dmuObject.setDiscrHOVAccessibility(accTable.getAggregateAccessibility("discrHov1", + household.getHhMgra())); + } else if (household.getAutoSufficiency() == 3) + { + dmuObject.setShopHOVAccessibility(accTable.getAggregateAccessibility("shopHov2", + household.getHhMgra())); + dmuObject.setMaintHOVAccessibility(accTable.getAggregateAccessibility("maintHov2", + household.getHhMgra())); + dmuObject.setDiscrHOVAccessibility(accTable.getAggregateAccessibility("discrHov2", + household.getHhMgra())); + } + + IndexValues index = dmuObject.getDmuIndexValues(); + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = String + .format("Joint Non-Mandatory Tour Frequency Choice Model:"); + decisionMakerLabel = String.format("HH=%d, hhSize=%d.", household.getHhId(), + household.getHhSize()); + + jointTourFrequencyModel.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + loggingHeader = choiceModelDescription + " for " + decisionMakerLabel; + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + } + + float logsum = (float) jointTourFrequencyModel.computeUtilities(dmuObject, index); + household.setJtfLogsum(logsum); + + // get the random number from the household + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosenFreqAlt = -1; + if (jointTourFrequencyModel.getAvailabilityCount() > 0) + { + chosenFreqAlt = jointTourFrequencyModel.getChoiceResult(rn); + household.setJointTourFreqResult(chosenFreqAlt, + jointTourFrequencyModel.getAlternativeNames()[chosenFreqAlt - 1]); + } else + { + logger.error(String + .format("Exception caught for HHID=%d, no available joint tour frequency alternatives to choose from in choiceModelApplication.", + household.getHhId())); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels()) + { + + String[] altNames = jointTourFrequencyModel.getAlternativeNames(); + + double[] utilities = jointTourFrequencyModel.getUtilities(); + double[] probabilities = jointTourFrequencyModel.getProbabilities(); + + modelLogger.info("HHID: " + household.getHhId() + ", HHSize: " + + household.getHhSize()); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("------------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < altNames.length; k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %10s", k + 1, altNames[k]); + modelLogger.info(String.format("%-15s%18.6e%18.6e%18.6e", altString, + utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %10s", chosenFreqAlt, + altNames[chosenFreqAlt - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + jointTourFrequencyModel.logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + jointTourFrequencyModel.logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosenFreqAlt); + + // write UEC calculation results to separate model specific log + // file + jointTourFrequencyModel.logUECResults(modelLogger, loggingHeader); + + } + + createJointTours(household, chosenFreqAlt); + + } catch (Exception e) + { + logger.error(String.format("error joint tour choices model for hhId=%d.", + household.getHhId())); + throw new RuntimeException(); + } + + household.setJtfRandomCount(household.getHhRandomCount()); + + } + + private void jointTourParticipation(Tour jointTour) + { + + // get the Household object for this joint tour + Household household = dmuObject.getHouseholdObject(); + + // get the array of Person objects for this hh + Person[] persons = household.getPersons(); + + // define an ArrayList to hold indices of person objects participating + // in the joint tour + ArrayList jointTourPersonList = null; + + // make sure each joint tour has a valid composition before going to the + // next one. + boolean validParty = false; + + int adults = 0; + int children = 0; + + Logger modelLogger = tourFreq; + + int loopCount = 0; + while (!validParty) + { + + dmuObject.setTourObject(jointTour); + + adults = 0; + children = 0; + + jointTourPersonList = new ArrayList(); + + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + jointTour.setPersonObject(persons[p]); + + if (household.getDebugChoiceModels() || loopCount == 1000) + { + decisionMakerLabel = String.format( + "HH=%d, hhSize=%d, PersonNum=%d, PersonType=%s, tourId=%d.", + household.getHhId(), household.getHhSize(), person.getPersonNum(), + person.getPersonType(), jointTour.getTourId()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + // if person type is inconsistent with tour composition, + // person's + // participation is by definition no, + // so skip making the choice and go to next person + switch (jointTour.getJointTourComposition()) + { + + // adults only in joint tour + case 1: + if (persons[p].getPersonIsAdult() == 1) + { + + // write debug header + if (household.getDebugChoiceModels() || loopCount == 1000) + { + + choiceModelDescription = String + .format("Adult Party Joint Tour Participation Choice Model:"); + jointTourParticipation.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + loggingHeader = choiceModelDescription + " for " + + decisionMakerLabel + "."; + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + } + + jointTourParticipation.computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + + // get the random number from the household + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, make choice. + int chosen = -1; + if (jointTourParticipation.getAvailabilityCount() > 0) chosen = jointTourParticipation + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught for HHID=%d, person p=%d, no available adults only joint tour participation alternatives to choose from in choiceModelApplication.", + jointTour.getHhId(), p)); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels() || loopCount == 1000) + { + + String[] altNames = jointTourParticipation.getAlternativeNames(); + + double[] utilities = jointTourParticipation.getUtilities(); + double[] probabilities = jointTourParticipation.getProbabilities(); + + modelLogger.info("HHID: " + household.getHhId() + ", HHSize: " + + household.getHhSize() + ", tourId: " + + jointTour.getTourId() + ", jointFreqChosen: " + + household.getJointTourFreqChosenAltName()); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("------------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < altNames.length; k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %13s", k + 1, + altNames[k]); + modelLogger.info(String.format("%-18s%18.6e%18.6e%18.6e", + altString, utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %13s", chosen, + altNames[chosen - 1]); + modelLogger.info(String.format( + "Choice: %s, with rn=%.8f, randomCount=%d", altString, rn, + randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug + // log + // file + jointTourParticipation.logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + jointTourParticipation.logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate + // model + // specific log file + jointTourParticipation.logUECResults(modelLogger, loggingHeader); + + if (loopCount == 1000) + { + jointTourFrequencyModel.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + jointTourFrequencyModel.computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + jointTourFrequencyModel.logUECResults(modelLogger, + loggingHeader); + } + + } + + // particpate is alternative 1, not participating is + // alternative 2. + if (chosen == 1) + { + jointTourPersonList.add(p); + adults++; + } + } + break; + + // children only in joint tour + case 2: + if (persons[p].getPersonIsAdult() == 0) + { + + // write debug header + if (household.getDebugChoiceModels() || loopCount == 1000) + { + + choiceModelDescription = String + .format("Child Party Joint Tour Participation Choice Model:"); + jointTourParticipation.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + loggingHeader = choiceModelDescription + " for " + + decisionMakerLabel + "."; + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + } + + jointTourParticipation.computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, make choice. + int chosen = -1; + if (jointTourParticipation.getAvailabilityCount() > 0) chosen = jointTourParticipation + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught for HHID=%d, person p=%d, no available children only joint tour participation alternatives to choose from in choiceModelApplication.", + jointTour.getHhId(), p)); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels() || loopCount == 1000) + { + + String[] altNames = jointTourParticipation.getAlternativeNames(); + + double[] utilities = jointTourParticipation.getUtilities(); + double[] probabilities = jointTourParticipation.getProbabilities(); + + modelLogger.info("HHID: " + household.getHhId() + ", HHSize: " + + household.getHhSize() + ", tourId: " + + jointTour.getTourId()); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("------------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < altNames.length; k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %13s", k + 1, + altNames[k]); + modelLogger.info(String.format("%-18s%18.6e%18.6e%18.6e", + altString, utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %13s", chosen, + altNames[chosen - 1]); + modelLogger.info(String.format( + "Choice: %s, with rn=%.8f, randomCount=%d", altString, rn, + randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug + // log + // file + jointTourParticipation.logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + jointTourParticipation.logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate + // model + // specific log file + jointTourParticipation.logUECResults(modelLogger, loggingHeader); + + if (loopCount == 1000) + { + jointTourFrequencyModel.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + jointTourFrequencyModel.computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + jointTourFrequencyModel.logUECResults(modelLogger, + loggingHeader); + } + } + + // particpate is alternative 1, not participating is + // alternative 2. + if (chosen == 1) + { + jointTourPersonList.add(p); + children++; + } + } + break; + + // mixed, adults and children in joint tour + case 3: + + // write debug header + if (household.getDebugChoiceModels() || loopCount == 1000) + { + + choiceModelDescription = String + .format("Mixed Party Joint Tour Participation Choice Model:"); + jointTourParticipation.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + loggingHeader = choiceModelDescription + " for " + decisionMakerLabel + + "."; + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + } + + jointTourParticipation.computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, make choice. + int chosen = -1; + if (jointTourParticipation.getAvailabilityCount() > 0) chosen = jointTourParticipation + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught for HHID=%d, person p=%d, no available mixed adult/children joint tour participation alternatives to choose from in choiceModelApplication.", + jointTour.getHhId(), p)); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels() || loopCount == 1000) + { + + String[] altNames = jointTourParticipation.getAlternativeNames(); + + double[] utilities = jointTourParticipation.getUtilities(); + double[] probabilities = jointTourParticipation.getProbabilities(); + + modelLogger.info("HHID: " + household.getHhId() + ", HHSize: " + + household.getHhSize() + ", tourId: " + jointTour.getTourId()); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("------------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < altNames.length; k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %13s", k + 1, altNames[k]); + modelLogger.info(String.format("%-18s%18.6e%18.6e%18.6e", + altString, utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %13s", chosen, + altNames[chosen - 1]); + modelLogger.info(String.format( + "Choice: %s, with rn=%.8f, randomCount=%d", altString, rn, + randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log + // file + jointTourParticipation.logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + jointTourParticipation.logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model + // specific log file + jointTourParticipation.logUECResults(modelLogger, loggingHeader); + + if (loopCount == 1000) + { + jointTourFrequencyModel.choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + jointTourFrequencyModel.computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + jointTourFrequencyModel.logUECResults(modelLogger, loggingHeader); + } + } + + // particpate is alternative 1, not participating is + // alternative 2. + if (chosen == 1) + { + jointTourPersonList.add(p); + if (persons[p].getPersonIsAdult() == 1) adults++; + else children++; + } + break; + + } + + } + + // done with all persons, so see if the chosen participation is a + // valid + // composition, and if not, repeat the participation choice. + switch (jointTour.getJointTourComposition()) + { + + case 1: + if (adults > 1 && children == 0) validParty = true; + break; + + case 2: + if (adults == 0 && children > 1) validParty = true; + break; + + case 3: + if (adults > 0 && children > 0) validParty = true; + break; + + } + + if (!validParty) loopCount++; + + if (loopCount > 1000) + { + logger.warn("loop count in joint tour participation model is " + loopCount); + if (loopCount > 2000) + { + logger.warn("joint tour party composition-terminating on excessive loop count."); + //logger.error("terminating on excessive loop count."); + //throw new RuntimeException(); + } + } + + } // end while + + // create an array of person indices for participation in the tour + int[] personNums = new int[jointTourPersonList.size()]; + for (int i = 0; i < personNums.length; i++) + personNums[i] = jointTourPersonList.get(i); + jointTour.setPersonNumArray(personNums); + + if (household.getDebugChoiceModels()) + { + for (int i = 0; i < personNums.length; i++) + { + Person person = household.getPersons()[personNums[i]]; + String decisionMakerLabel = String + .format("Person in Party, HH=%d, hhSize=%d, PersonNum=%d, PersonType=%s, tourId=%d.", + household.getHhId(), household.getHhSize(), person.getPersonNum(), + person.getPersonType(), jointTour.getTourId()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + } + + } + + /** + * creates the tour objects in the Household object given the chosen joint + * tour frequency alternative. + * + * @param chosenAlt + */ + private void createJointTours(Household household, int chosenAlt) + { + + int purposeIndex1 = (int) jointModelsAltsTable.getValueAt(chosenAlt, PURPOSE_1_FIELD); + int purposeIndex2 = (int) jointModelsAltsTable.getValueAt(chosenAlt, PURPOSE_2_FIELD); + + if (purposeIndex1 > 0 && purposeIndex2 > 0) + { + + Tour t1 = new Tour(household, (String) purposeIndexNameMap.get(purposeIndex1), + ModelStructure.JOINT_NON_MANDATORY_CATEGORY, purposeIndex1); + int party1 = (int) jointModelsAltsTable.getValueAt(chosenAlt, PARTY_1_FIELD); + t1.setJointTourComposition(party1); + + Tour t2 = new Tour(household, (String) purposeIndexNameMap.get(purposeIndex2), + ModelStructure.JOINT_NON_MANDATORY_CATEGORY, purposeIndex2); + int party2 = (int) jointModelsAltsTable.getValueAt(chosenAlt, PARTY_2_FIELD); + t2.setJointTourComposition(party2); + + household.createJointTourArray(t1, t2); + + jointTourParticipation(t1); + jointTourParticipation(t2); + + } else + { + + Tour t1 = new Tour(household, (String) purposeIndexNameMap.get(purposeIndex1), + ModelStructure.JOINT_NON_MANDATORY_CATEGORY, purposeIndex1); + int party1 = (int) jointModelsAltsTable.getValueAt(chosenAlt, PARTY_1_FIELD); + t1.setJointTourComposition(party1); + + household.createJointTourArray(t1); + + jointTourParticipation(t1); + + } + + } + + public static void main(String[] args) + { + + // set values for these arguments so an object instance can be created + // and setup run to test integrity of UEC files before running full + // model. + HashMap propertyMap; + + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + ResourceBundle rb = ResourceBundle.getBundle(args[0]); + propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + } + + /* + * + */ + String matrixServerAddress = (String) propertyMap.get("RunModel.MatrixServerAddress"); + String matrixServerPort = (String) propertyMap.get("RunModel.MatrixServerPort"); + + MatrixDataServerIf ms = new MatrixDataServerRmi(matrixServerAddress, + Integer.parseInt(matrixServerPort), MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + TazDataManager tazManager = TazDataManager.getInstance(propertyMap); + + ModelStructure modelStructure = new SandagModelStructure(); + SandagCtrampDmuFactory dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + String projectDirectory = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file"); + AccessibilitiesTable accTable = new AccessibilitiesTable(accFileName); + + String hhHandlerAddress = (String) propertyMap.get("RunModel.HouseholdServerAddress"); + int hhServerPort = Integer.parseInt((String) propertyMap + .get("RunModel.HouseholdServerPort")); + + HouseholdDataManagerIf householdDataManager = new HouseholdDataManagerRmi(hhHandlerAddress, + hhServerPort, SandagHouseholdDataManager.HH_DATA_SERVER_NAME); + + householdDataManager.setPropertyFileValues(propertyMap); + householdDataManager.setHouseholdSampleRate(1.0f, 0); + householdDataManager.setDebugHhIdsFromHashmap(); + householdDataManager.setTraceHouseholdSet(); + + int id = householdDataManager.getArrayIndex(423804); + Household[] hh = householdDataManager.getHhArray(id, id); + + JointTourModels jtfModel = new JointTourModels(propertyMap, accTable, modelStructure, + dmuFactory); + jtfModel.applyModel(hh[0]); + + /* + * Use this block to instantiate a UEC for the joint freq/comp model and + * a UEC for the joint participate model. After checking the UECs are + * instantiated correctly (spelling/typos/dmu methods implemented/etc.), + * test model implementation. String uecFileDirectory = propertyMap.get( + * CtrampApplication.PROPERTIES_UEC_PATH ); + * + * ModelStructure modelStructure = new SandagModelStructure(); + * SandagCtrampDmuFactory dmuFactory = new + * SandagCtrampDmuFactory(modelStructure); + * + * JointTourModelsDMU dmuObject = dmuFactory.getJointTourModelsDMU(); + * File uecFile = new File(uecFileDirectory + propertyMap.get( + * UEC_FILE_PROPERTIES_TARGET )); UtilityExpressionCalculator uec = new + * UtilityExpressionCalculator(uecFile, 1, 0, propertyMap, + * (VariableTable)dmuObject); + * System.out.println("Jount tour freq/comp choice UEC passed."); + * + * uec = new UtilityExpressionCalculator(uecFile, 2, 0, propertyMap, + * (VariableTable)dmuObject); + * System.out.println("Joint tour participation choice UEC passed."); + */ + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/JointTourModelsDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/JointTourModelsDMU.java new file mode 100644 index 0000000..efadb79 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/JointTourModelsDMU.java @@ -0,0 +1,310 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class JointTourModelsDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TourModeChoiceDMU.class); + + protected HashMap methodIndexMap; + + protected Household hh; + protected Tour tour; + protected IndexValues dmuIndex; + + private float shopHOVAccessibility; + private float maintHOVAccessibility; + private float discrHOVAccessibility; + + public JointTourModelsDMU() + { + dmuIndex = new IndexValues(); + } + + public Household getHouseholdObject() + { + return hh; + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + public void setTourObject(Tour tourObject) + { + tour = tourObject; + } + + // DMU methods - define one of these for every @var in the mode choice + // control + // file. + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getActiveCountFullTimeWorkers() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsFullTimeWorker() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getActiveCountPartTimeWorkers() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsPartTimeWorker() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getActiveCountUnivStudents() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsUniversityStudent() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getActiveCountNonWorkers() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsNonWorkingAdultUnder65() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getActiveCountRetirees() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsNonWorkingAdultOver65() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getActiveCountDrivingAgeSchoolChildren() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsStudentDriving() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getActiveCountPreDrivingAgeSchoolChildren() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsStudentNonDriving() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getActiveCountPreSchoolChildren() + { + int count = 0; + for (Person p : hh.getPersons()) + if (p != null && p.getPersonIsPreschoolChild() == 1) + if (!p.getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) count++; + return count; + } + + public int getMaxPairwiseAdultOverlapsHh() + { + return hh.getMaxAdultOverlaps(); + } + + public int getMaxPairwiseChildOverlapsHh() + { + return hh.getMaxChildOverlaps(); + } + + public int getMaxPairwiseMixedOverlapsHh() + { + return hh.getMaxMixedOverlaps(); + } + + public int getMaxPairwiseOverlapOtherAdults() + { + return tour.getPersonObject().getMaxAdultOverlaps(); + } + + public int getMaxPairwiseOverlapOtherChildren() + { + return tour.getPersonObject().getMaxChildOverlaps(); + } + + public int getTravelActiveAdults() + { + return hh.getTravelActiveAdults(); + } + + public int getTravelActiveChildren() + { + return hh.getTravelActiveChildren(); + } + + public int getPersonStaysHome() + { + Person p = tour.getPersonObject(); + return p.getCdapActivity().equalsIgnoreCase("H") ? 1 : 0; + } + + public int getIncomeLessThan30K() + { + return hh.getIncomeInDollars() < 30000 ? 1 : 0; + } + + public int getIncome30Kto60K() + { + int income = hh.getIncomeInDollars(); + return (income >= 30000 && income < 60000) ? 1 : 0; + } + + public int getIncomeMoreThan100K() + { + return hh.getIncomeInDollars() >= 100000 ? 1 : 0; + } + + public int getNumAdults() + { + int num = 0; + Person[] persons = hh.getPersons(); + for (int i = 1; i < persons.length; i++) + num += (persons[i].getPersonIsAdult() == 1 ? 1 : 0); + return num; + } + + public int getNumChildren() + { + int num = 0; + Person[] persons = hh.getPersons(); + for (int i = 1; i < persons.length; i++) + num += (persons[i].getPersonIsAdult() == 0 ? 1 : 0); + return num; + } + + public int getHhWorkers() + { + return hh.getWorkers(); + } + + public int getAutoOwnership() + { + return hh.getAutosOwned(); + } + + public int getTourPurposeIsMaint() + { + return tour.getTourPurpose() + .equalsIgnoreCase(ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME) ? 1 : 0; + } + + public int getTourPurposeIsEat() + { + return tour.getTourPurpose().equalsIgnoreCase(ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME) ? 1 + : 0; + } + + public int getTourPurposeIsVisit() + { + return tour.getTourPurpose().equalsIgnoreCase(ModelStructure.VISITING_PRIMARY_PURPOSE_NAME) ? 1 + : 0; + } + + public int getTourPurposeIsDiscr() + { + return tour.getTourPurpose() + .equalsIgnoreCase(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME) ? 1 : 0; + } + + public int getPersonType() + { + return tour.getPersonObject().getPersonTypeNumber(); + } + + public int getJointTourComposition() + { + return tour.getJointTourComposition(); + } + + public int getJTours() + { + return hh.getJointTourArray().length; + } + + public void setShopHOVAccessibility(float accessibility) + { + shopHOVAccessibility = accessibility; + } + + public float getShopHOVAccessibility() + { + return shopHOVAccessibility; + } + + public void setMaintHOVAccessibility(float accessibility) + { + maintHOVAccessibility = accessibility; + } + + public float getMaintHOVAccessibility() + { + return maintHOVAccessibility; + } + + public void setDiscrHOVAccessibility(float accessibility) + { + discrHOVAccessibility = accessibility; + } + + public float getDiscrHOVAccessibility() + { + return discrHOVAccessibility; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/MandatoryDestChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MandatoryDestChoiceModel.java new file mode 100644 index 0000000..ebc8c62 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MandatoryDestChoiceModel.java @@ -0,0 +1,885 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.IndexSort; + +public class MandatoryDestChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(MandatoryDestChoiceModel.class); + private transient Logger dcManLogger = Logger.getLogger("tourDcMan"); + + // this constant used as a dimension for saving distance and logsums for + // alternatives in samples + private static final int MAXIMUM_SOA_ALTS_FOR_ANY_MODEL = 200; + + private static final int DC_DATA_SHEET = 0; + private static final int DC_WORK_AT_HOME_SHEET = 1; + + private MgraDataManager mgraManager; + private DestChoiceSize dcSizeObj; + + private DestChoiceDMU dcDmuObject; + private DcSoaDMU dcSoaDmuObject; + + private TourModeChoiceModel mcModel; + private DestinationSampleOfAlternativesModel dcSoaModel; + + private String[] segmentNameList; + private HashMap segmentNameIndexMap; + private HashMap workOccupValueSegmentIndexMap; + + private int[] dcModelIndices; + + // A ChoiceModelApplication object and modeAltsAvailable[] is needed for + // each purpose + private ChoiceModelApplication[] locationChoiceModels; + private ChoiceModelApplication locationChoiceModel; + private ChoiceModelApplication worksAtHomeModel; + + private int[] uecSheetIndices; + private int[] soaUecSheetIndices; + + int origMgra; + + private int modelIndex; + private int shadowPricingIteration; + + private double[] sampleAlternativeDistances; + private double[] sampleAlternativeLogsums; + + private double[] mgraDistanceArray; + + private BuildAccessibilities aggAcc; + + public MandatoryDestChoiceModel(int index, HashMap propertyMap, + DestChoiceSize dcSizeObj, BuildAccessibilities aggAcc, MgraDataManager mgraManager, + String dcUecFileName, String soaUecFile, int soaSampleSize, String modeChoiceUecFile, + CtrampDmuFactoryIf dmuFactory, TourModeChoiceModel mcModel) + { + + // set the model structure and the tour purpose list + this.mgraManager = mgraManager; + this.aggAcc = aggAcc; + this.dcSizeObj = dcSizeObj; + this.mcModel = mcModel; + + modelIndex = index; + + dcDmuObject = dmuFactory.getDestChoiceDMU(); + dcDmuObject.setAggAcc(aggAcc); + + dcSoaDmuObject = dmuFactory.getDcSoaDMU(); + dcSoaDmuObject.setAggAcc(aggAcc); + + shadowPricingIteration = 0; + + sampleAlternativeDistances = new double[MAXIMUM_SOA_ALTS_FOR_ANY_MODEL]; + sampleAlternativeLogsums = new double[MAXIMUM_SOA_ALTS_FOR_ANY_MODEL]; + + workOccupValueSegmentIndexMap = aggAcc.getWorkOccupValueIndexMap(); + + } + + public void setupWorkSegments(int[] myUecSheetIndices, int[] mySoaUecSheetIndices) + { + uecSheetIndices = myUecSheetIndices; + soaUecSheetIndices = mySoaUecSheetIndices; + segmentNameList = aggAcc.getWorkSegmentNameList(); + } + + public void setupSchoolSegments() + { + aggAcc.createSchoolSegmentNameIndices(); + uecSheetIndices = aggAcc.getSchoolDcUecSheets(); + soaUecSheetIndices = aggAcc.getSchoolDcSoaUecSheets(); + segmentNameList = aggAcc.getSchoolSegmentNameList(); + } + + public void setupDestChoiceModelArrays(HashMap propertyMap, + String dcUecFileName, String soaUecFile, int soaSampleSize) + { + + segmentNameIndexMap = dcSizeObj.getSegmentNameIndexMap(); + + // create a sample of alternatives choice model object for use in + // selecting a sample + // of all possible destination choice alternatives. + dcSoaModel = new DestinationSampleOfAlternativesModel(soaUecFile, soaSampleSize, + propertyMap, mgraManager, dcSizeObj.getDcSizeArray(), dcSoaDmuObject, + soaUecSheetIndices); + + // create the works-at-home ChoiceModelApplication object + worksAtHomeModel = new ChoiceModelApplication(dcUecFileName, DC_WORK_AT_HOME_SHEET, + DC_DATA_SHEET, propertyMap, (VariableTable) dcDmuObject); + + dcSoaModel.setAvailabilityForSampleOfAlternatives(dcSizeObj.getDcSizeArray()); + + // create a lookup array to map purpose index to model index + dcModelIndices = new int[uecSheetIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int dcModelIndex = 0; + int dcSegmentIndex = 0; + for (int uecIndex : uecSheetIndices) + { + // if the uec sheet for the model segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, dcModelIndex); + dcModelIndices[dcSegmentIndex] = dcModelIndex++; + } else + { + dcModelIndices[dcSegmentIndex] = modelIndexMap.get(uecIndex); + } + + dcSegmentIndex++; + } + // the value of dcModelIndex is the number of ChoiceModelApplication + // objects to create + // the modelIndexMap keys are the uec sheets to use in building + // ChoiceModelApplication objects + + locationChoiceModels = new ChoiceModelApplication[modelIndexMap.size()]; + + int i = 0; + for (int uecIndex : modelIndexMap.keySet()) + { + + int modelIndex = -1; + try + { + modelIndex = modelIndexMap.get(uecIndex); + locationChoiceModels[modelIndex] = new ChoiceModelApplication(dcUecFileName, + uecIndex, DC_DATA_SHEET, propertyMap, (VariableTable) dcDmuObject); + } catch (RuntimeException e) + { + logger.fatal(String + .format("exception caught setting up DC ChoiceModelApplication[%d] for modelIndex=%d of %d models", + i, modelIndex, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + throw new RuntimeException(); + } + + } + + mgraDistanceArray = new double[mgraManager.getMaxMgra() + 1]; + + } + + public void applyWorkLocationChoice(Household hh) + { + + if (hh.getDebugChoiceModels()) + { + String label = String.format("Pre Work Location Choice HHId=%d Object", hh.getHhId()); + hh.logHouseholdObject(label, dcManLogger); + } + + // declare these variables here so their values can be logged if a + // RuntimeException occurs. + int i = -1; + int occupSegmentIndex = -1; + int occup = -1; + String occupSegmentName = ""; + + Person[] persons = hh.getPersons(); + + int tourNum = 0; + for (i = 1; i < persons.length; i++) + { + + Person p = persons[i]; + + // skip person if they are not a worker + if (p.getPersonIsWorker() != 1) + { + p.setWorkLocationSegmentIndex(-1); + p.setWorkLocation(0); + p.setWorkLocDistance(0); + p.setWorkLocLogsum(-999); + continue; + } + + // skip person if their work at home choice was work in the home + // (alternative 2 in choice model) + int worksAtHomeChoice = selectWorksAtHomeChoice(dcDmuObject, hh, p); + if (worksAtHomeChoice == ModelStructure.WORKS_AT_HOME_ALTERNATUVE_INDEX) + { + p.setWorkLocationSegmentIndex(ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR); + p.setWorkLocation(ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR); + p.setWorkLocDistance(0); + p.setWorkLocLogsum(-999); + continue; + } + + // save person information in decision maker label, and log person + // object + if (hh.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", p + .getHouseholdObject().getHhId(), p.getPersonNum(), p.getPersonType()); + hh.logPersonObject(decisionMakerLabel, dcManLogger, p); + } + + double[] results = null; + try + { + + int homeMgra = hh.getHhMgra(); + origMgra = homeMgra; + + occup = p.getPersPecasOccup(); + occupSegmentIndex = workOccupValueSegmentIndexMap.get(occup); + occupSegmentName = segmentNameList[occupSegmentIndex]; + + p.setWorkLocationSegmentIndex(occupSegmentIndex); + + // update the DC dmuObject for this person + dcDmuObject.setHouseholdObject(hh); + dcDmuObject.setPersonObject(p); + dcDmuObject.setDmuIndexValues(hh.getHhId(), homeMgra, origMgra, 0); + + double[] homeMgraSizeArray = dcSizeObj.getDcSizeArray()[occupSegmentIndex]; + mcModel.getAnmSkimCalculator().getAmPkSkimDistancesFromMgra(homeMgra, + mgraDistanceArray); + + // set size array for the tour segment and distance array from + // the home mgra to all destinaion mgras. + dcSoaDmuObject.setDestChoiceSize(homeMgraSizeArray); + dcSoaDmuObject.setDestDistance(mgraDistanceArray); + + dcDmuObject.setDestChoiceSize(homeMgraSizeArray); + dcDmuObject.setDestChoiceDistance(mgraDistanceArray); + + int choiceModelIndex = dcModelIndices[occupSegmentIndex]; + locationChoiceModel = locationChoiceModels[choiceModelIndex]; + + // get the work location alternative chosen from the sample + results = selectLocationFromSampleOfAlternatives("work", -1, p, occupSegmentName, + occupSegmentIndex, tourNum++, homeMgraSizeArray, mgraDistanceArray); + + } catch (RuntimeException e) + { + logger.fatal(String + .format("Exception caught in dcModel selecting location for i=%d, hh.hhid=%d, person i=%d, in work location choice, occup=%d, segmentIndex=%d, segmentName=%s", + i, hh.getHhId(), i, occup, occupSegmentIndex, occupSegmentName)); + logger.fatal("Exception caught:", e); + logger.fatal("calling System.exit(-1) to terminate."); + System.exit(-1); + } + + p.setWorkLocation((int) results[0]); + p.setWorkLocDistance((float) results[1]); + p.setWorkLocLogsum((float) results[2]); + + } + + } + + public void applySchoolLocationChoice(Household hh) + { + + if (hh.getDebugChoiceModels()) + { + String label = String.format("Pre school Location Choice HHId=%d Object", hh.getHhId()); + hh.logHouseholdObject(label, dcManLogger); + } + + // declare these variables here so their values can be logged if a + // RuntimeException occurs. + int i = -1; + + int homeMgra = hh.getHhMgra(); + Person[] persons = hh.getPersons(); + + int tourNum = 0; + for (i = 1; i < persons.length; i++) + { + + Person p = persons[i]; + + int segmentIndex = -1; + int segmentType = -1; + if (p.getPersonIsPreschoolChild() == 1 || p.getPersonIsStudentNonDriving() == 1 + || p.getPersonIsStudentDriving() == 1 || p.getPersonIsUniversityStudent() == 1) + { + + if (p.getPersonIsPreschoolChild() == 1) + { + segmentIndex = segmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.PRESCHOOL_SEGMENT_GROUP_INDEX]); + segmentType = BuildAccessibilities.PRESCHOOL_ALT_INDEX; + } else if (p.getPersonIsGradeSchool() == 1) + { + segmentIndex = aggAcc.getMgraGradeSchoolSegmentIndex(homeMgra); + segmentType = BuildAccessibilities.GRADE_SCHOOL_ALT_INDEX; + } else if (p.getPersonIsHighSchool() == 1) + { + segmentIndex = aggAcc.getMgraHighSchoolSegmentIndex(homeMgra); + segmentType = BuildAccessibilities.HIGH_SCHOOL_ALT_INDEX; + } else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() < 30) + { + segmentIndex = segmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_TYPICAL_SEGMENT_GROUP_INDEX]); + segmentType = BuildAccessibilities.UNIV_TYPICAL_ALT_INDEX; + } else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() >= 30) + { + segmentIndex = segmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_NONTYPICAL_SEGMENT_GROUP_INDEX]); + segmentType = BuildAccessibilities.UNIV_NONTYPICAL_ALT_INDEX; + } + + // if person type is a student but segment index is -1, the + // person is not enrolled + // assume home schooled + if (segmentIndex < 0) + { + p.setSchoolLocationSegmentIndex(ModelStructure.NOT_ENROLLED_SEGMENT_INDEX); + p.setSchoolLoc(ModelStructure.NOT_ENROLLED_SEGMENT_INDEX); + p.setSchoolLocDistance(0); + p.setSchoolLocLogsum(-999); + continue; + } else + { + // if the segment is in the skip shadow pricing set, and the + // iteration is > 0, dont' compute new choice + if (shadowPricingIteration == 0 + || !dcSizeObj.getSegmentIsInSkipSegmentSet(segmentIndex)) + p.setSchoolLocationSegmentIndex(segmentIndex); + } + + if (segmentType < 0) + { + segmentType = ModelStructure.NOT_ENROLLED_SEGMENT_INDEX; + } + } else // not a student person type + { + p.setSchoolLocationSegmentIndex(-1); + p.setSchoolLoc(0); + p.setSchoolLocDistance(0); + p.setSchoolLocLogsum(-999); + continue; + } + + // save person information in decision maker label, and log person + // object + if (hh.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", p + .getHouseholdObject().getHhId(), p.getPersonNum(), p.getPersonType()); + hh.logPersonObject(decisionMakerLabel, dcManLogger, p); + } + + // if the segment is in the skip shadow pricing set, and the + // iteration is > 0, dont' compute new choice + if (shadowPricingIteration > 0 && dcSizeObj.getSegmentIsInSkipSegmentSet(segmentIndex)) + continue; + + double[] results = null; + int modelIndex = 0; + try + { + + origMgra = homeMgra; + + // update the DC dmuObject for this person + dcDmuObject.setHouseholdObject(hh); + dcDmuObject.setPersonObject(p); + dcDmuObject.setDmuIndexValues(hh.getHhId(), homeMgra, origMgra, 0); + + /** + * remove following - don't need non-mandatory accessibility + * since we're doing shadow pricing for school tours // set the + * auto sufficiency dependent non-mandatory accessibility value + * for the household int autoSufficiency = + * hh.getAutoSufficiency(); float accessibility = + * aggAcc.getAggregateAccessibility( + * nonMandatoryAccessibilityTypes[autoSufficiency], + * hh.getHhMgra() ); dcDmuObject.setNonMandatoryAccessibility( + * accessibility ); + */ + + double[] homeMgraSizeArray = dcSizeObj.getDcSizeArray()[segmentIndex]; + mcModel.getAnmSkimCalculator().getAmPkSkimDistancesFromMgra(homeMgra, + mgraDistanceArray); + + // set size array for the tour segment and distance array from + // the home mgra to all destinaion mgras. + dcSoaDmuObject.setDestChoiceSize(homeMgraSizeArray); + dcSoaDmuObject.setDestDistance(mgraDistanceArray); + + dcDmuObject.setDestChoiceSize(homeMgraSizeArray); + dcDmuObject.setDestChoiceDistance(mgraDistanceArray); + + modelIndex = dcModelIndices[segmentIndex]; + locationChoiceModel = locationChoiceModels[modelIndex]; + + // get the school location alternative chosen from the sample + results = selectLocationFromSampleOfAlternatives("school", segmentType, p, + segmentNameList[segmentIndex], segmentIndex, tourNum++, homeMgraSizeArray, + mgraDistanceArray); + + } catch (RuntimeException e) + { + logger.fatal(String + .format("Exception caught in dcModel selecting location for i=%d, hh.hhid=%d, person i=%d, in school location choice, modelIndex=%d, segmentIndex=%d, segmentName=%s", + i, hh.getHhId(), i, modelIndex, segmentIndex, + segmentNameList[segmentIndex])); + logger.fatal("Exception caught:", e); + logger.fatal("calling System.exit(-1) to terminate."); + System.exit(-1); + } + + p.setSchoolLoc((int) results[0]); + p.setSchoolLocDistance((float) results[1]); + p.setSchoolLocLogsum((float) results[2]); + + } + + } + + /** + * + * @return an array with chosen mgra, distance to chosen mgra, and logsum to + * chosen mgra. + */ + private double[] selectLocationFromSampleOfAlternatives(String segmentType, + int segmentTypeIndex, Person person, String segmentName, int sizeSegmentIndex, + int tourNum, double[] homeMgraSizeArray, double[] homeMgraDistanceArray) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcManLogger; + + Household household = person.getHouseholdObject(); + + // compute the sample of alternatives set for the person + dcSoaModel.computeDestinationSampleOfAlternatives(dcSoaDmuObject, null, person, + segmentName, sizeSegmentIndex, household.getHhMgra()); + + // get sample of locations and correction factors for sample + int[] finalSample = dcSoaModel.getSampleOfAlternatives(); + float[] sampleCorrectionFactors = dcSoaModel.getSampleOfAlternativesCorrections(); + + int numAlts = locationChoiceModel.getNumberOfAlternatives(); + + // set the destAltsAvailable array to true for all destination choice + // alternatives for each purpose + boolean[] destAltsAvailable = new boolean[numAlts + 1]; + for (int k = 0; k <= numAlts; k++) + destAltsAvailable[k] = false; + + // set the destAltsSample array to 1 for all destination choice + // alternatives + // for each purpose + int[] destAltsSample = new int[numAlts + 1]; + for (int k = 0; k <= numAlts; k++) + destAltsSample[k] = 0; + + int[] sampleValues = new int[finalSample.length]; + + dcDmuObject.setDestChoiceSize(homeMgraSizeArray); + dcDmuObject.setDestChoiceDistance(homeMgraDistanceArray); + + // for the destinations and sub-zones in the sample, compute mc logsums + // and + // save in DC dmuObject. + // also save correction factor and set availability and sample value for + // the + // sample alternative to true. 1, respectively. + for (int i = 1; i < finalSample.length; i++) + { + + int destMgra = finalSample[i]; + sampleValues[i] = finalSample[i]; + + // get the mode choice logsum for the destination choice sample + // alternative + double logsum = getModeChoiceLogsum(household, person, destMgra, segmentTypeIndex); + + sampleAlternativeLogsums[i] = logsum; + sampleAlternativeDistances[i] = homeMgraDistanceArray[finalSample[i]]; + + // set logsum value in DC dmuObject for the logsum index, sampled + // zone and subzone. + dcDmuObject.setMcLogsum(destMgra, logsum); + + // set sample of alternatives correction factor used in destination + // choice utility for the sampled alternative. + dcDmuObject.setDcSoaCorrections(destMgra, sampleCorrectionFactors[i]); + + // set availaibility and sample values for the purpose, dcAlt. + destAltsAvailable[finalSample[i]] = true; + destAltsSample[finalSample[i]] = 1; + + } + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format( + "Usual %s Location Choice Model for: Segment=%s", segmentType, segmentName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourNum=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tourNum); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Usual " + segmentType + " Location Choice Model for: Segment=" + + segmentName + ", Person Num: " + person.getPersonNum() + ", Person Type: " + + person.getPersonType() + ", TourNum=" + tourNum); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + locationChoiceModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + locationChoiceModel.computeUtilities(dcDmuObject, dcDmuObject.getDmuIndexValues(), + destAltsAvailable, destAltsSample); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (locationChoiceModel.getAvailabilityCount() > 0) + { + chosen = locationChoiceModel.getChoiceResult(rn); + } else + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, no available %s destination choice alternatives to choose from in choiceModelApplication.", + dcDmuObject.getHouseholdObject().getHhId(), dcDmuObject + .getPersonObject().getPersonNum(), segmentName)); + } + + // write choice model alternative info to log file + int selectedIndex = -1; + for (int j = 1; j < finalSample.length; j++) + { + if (finalSample[j] == chosen) + { + selectedIndex = j; + break; + } + } + + if (household.getDebugChoiceModels() || chosen <= 0) + { + + double[] utilities = locationChoiceModel.getUtilities(); + double[] probabilities = locationChoiceModel.getProbabilities(); + boolean[] availabilities = locationChoiceModel.getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb Distance Logsum"); + modelLogger + .info("--------------------- -------------- -------------- -------------- -------------- -------------- --------------"); + + int[] sortedSampleValueIndices = IndexSort.indexSort(sampleValues); + + int sortedSelectedIndex = 0; + double cumProb = 0.0; + for (int j = 1; j < finalSample.length; j++) + { + int k = sortedSampleValueIndices[j]; + int alt = finalSample[k]; + + if (alt == chosen) sortedSelectedIndex = j; + + cumProb += probabilities[alt - 1]; + String altString = String.format("j=%-2d, k=%-2d, mgra=%-5d", j, k, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e%18.6e%18.6e", + altString, availabilities[alt], utilities[alt - 1], probabilities[alt - 1], + cumProb, sampleAlternativeDistances[k], sampleAlternativeLogsums[k])); + } + + if (sortedSelectedIndex >= 0) + { + modelLogger.info(" "); + String altString = String.format("j=%d, mgra=%d", sortedSelectedIndex, chosen); + modelLogger.info(String.format( + "Choice: %s, dist=%.6e, logsum=%.6e with rn=%.8f, randomCount=%d", + altString, sampleAlternativeDistances[selectedIndex], + sampleAlternativeLogsums[selectedIndex], rn, randomCount)); + } else + { + modelLogger.info(" "); + modelLogger.info(String.format( + "j=%d, mgra=None selected, no alternatives available", selectedIndex)); + modelLogger.info(String.format("Choice: %s, rn=%.8f, randomCount=%d", "N/A", rn, + randomCount)); + } + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + locationChoiceModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + locationChoiceModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, + chosen); + + // write UEC calculation results to separate model specific log file + locationChoiceModel.logUECResults(modelLogger, loggingHeader); + + if (chosen < 0) + { + logger.fatal(String + .format("Exception caught for HHID=%d, PersonNum=%d, no available %s destination choice alternatives to choose from in choiceModelApplication.", + dcDmuObject.getHouseholdObject().getHhId(), dcDmuObject + .getPersonObject().getPersonNum(), segmentName)); + logger.fatal("calling System.exit(-1) to terminate."); + System.exit(-1); + } + + } + + double[] returnArray = new double[3]; + + returnArray[0] = chosen; + returnArray[1] = sampleAlternativeDistances[selectedIndex]; + returnArray[2] = sampleAlternativeLogsums[selectedIndex]; + + return returnArray; + + } + + private int selectWorksAtHomeChoice(DestChoiceDMU dcDmuObject, Household household, + Person person) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcManLogger; + + dcDmuObject.setHouseholdObject(household); + dcDmuObject.setPersonObject(person); + dcDmuObject.setDmuIndexValues(household.getHhId(), household.getHhMgra(), origMgra, 0); + + double accessibility = aggAcc.getAccessibilitiesTableObject().getAggregateAccessibility( + "totEmp", household.getHhMgra()); + dcDmuObject.setWorkAccessibility(accessibility); + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format("Usual Work Location Is At Home Choice Model"); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", person + .getHouseholdObject().getHhId(), person.getPersonNum(), person.getPersonType()); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Usual Work Location Is At Home Choice Model: Person Num: " + + person.getPersonNum() + ", Person Type: " + person.getPersonType()); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + worksAtHomeModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + float logsum = (float) worksAtHomeModel.computeUtilities(dcDmuObject, dcDmuObject.getDmuIndexValues()); + person.setWorksFromHomeLogsum(logsum); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (worksAtHomeModel.getAvailabilityCount() > 0) + { + chosen = worksAtHomeModel.getChoiceResult(rn); + } + + // write choice model alternative info to log file + if (household.getDebugChoiceModels() || chosen < 0) + { + + double[] utilities = worksAtHomeModel.getUtilities(); + double[] probabilities = worksAtHomeModel.getProbabilities(); + boolean[] availabilities = worksAtHomeModel.getAvailabilities(); + + String[] altNames = worksAtHomeModel.getAlternativeNames(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- -------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 0; j < utilities.length; j++) + { + cumProb += probabilities[j]; + String altString = String.format("%d, %s", j + 1, altNames[j]); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j + 1], utilities[j], probabilities[j], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("j=%d, alt=%s", chosen, + (chosen < 0 ? "N/A, no available alternatives" : altNames[chosen - 1])); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + worksAtHomeModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + worksAtHomeModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, + chosen); + + // write UEC calculation results to separate model specific log file + worksAtHomeModel.logUECResults(modelLogger, loggingHeader); + + } + + if (chosen < 0) + { + logger.fatal(String + .format("Exception caught for HHID=%d, PersonNum=%d, no available works at home alternatives to choose from in choiceModelApplication.", + dcDmuObject.getHouseholdObject().getHhId(), dcDmuObject + .getPersonObject().getPersonNum())); + logger.fatal("calling System.exit(-1) to terminate."); + System.exit(-1); + } + + return chosen; + + } + + private double getModeChoiceLogsum(Household household, Person person, int sampleDestMgra, + int segmentTypeIndex) + { + + int purposeIndex = 0; + String purpose = ""; + if (segmentTypeIndex < 0) + { + purposeIndex = ModelStructure.WORK_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.WORK_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.PRESCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.GRADE_SCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.HIGH_SCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.UNIV_TYPICAL_ALT_INDEX) + { + purposeIndex = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.UNIV_NONTYPICAL_ALT_INDEX) + { + purposeIndex = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME; + } + + // create a temporary tour to use to calculate mode choice logsum + Tour mcLogsumTour = new Tour(person, 0, purposeIndex); + mcLogsumTour.setTourPurpose(purpose); + mcLogsumTour.setTourOrigMgra(household.getHhMgra()); + mcLogsumTour.setTourDestMgra(sampleDestMgra); + mcLogsumTour.setTourDepartPeriod(Person.DEFAULT_MANDATORY_START_PERIOD); + mcLogsumTour.setTourArrivePeriod(Person.DEFAULT_MANDATORY_END_PERIOD); + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + + if (household.getDebugChoiceModels()) + { + dcManLogger.info(""); + dcManLogger.info(""); + choiceModelDescription = "location choice logsum for segmentTypeIndex=" + + segmentTypeIndex + ", temp tour PurposeIndex=" + purposeIndex; + decisionMakerLabel = "HHID: " + household.getHhId() + ", PersNum: " + + person.getPersonNum(); + household.logPersonObject(choiceModelDescription + ", " + decisionMakerLabel, + dcManLogger, person); + } + + double logsum = -1; + try + { + logsum = mcModel.getModeChoiceLogsum(household, person, mcLogsumTour, dcManLogger, + choiceModelDescription, decisionMakerLabel); + } catch (Exception e) + { + choiceModelDescription = "location choice logsum for segmentTypeIndex=" + + segmentTypeIndex + ", temp tour PurposeIndex=" + purposeIndex; + decisionMakerLabel = "HHID: " + household.getHhId() + ", PersNum: " + + person.getPersonNum(); + logger.fatal("exception caught calculating ModeChoiceLogsum for usual work/school location choice."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + logger.fatal("Exception caught:", e); + System.exit(-1); + } + + return logsum; + } + + public int getModelIndex() + { + return modelIndex; + } + + public void setDcSizeObject(DestChoiceSize dcSizeObj) + { + this.dcSizeObj = dcSizeObj; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/MatrixDataServer.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MatrixDataServer.java new file mode 100644 index 0000000..aa90422 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MatrixDataServer.java @@ -0,0 +1,209 @@ +package org.sandag.abm.ctramp; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagTourBasedModel; + +import com.pb.common.calculator.DataEntry; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; + +/** + * @author Jim Hicks + * + * Class for managing matrix data in a remote process and accessed by + * UECs using RMI. + */ +public class MatrixDataServer + implements MatrixDataServerIf, Serializable +{ + + private static Logger logger = Logger.getLogger(MatrixDataServer.class); + + private Object objectLock; + + private static final String VERSION = "2.3_OMX_Only"; + + // These are used if the server is started manually by running this class's + // main(). If so, these must be defined consistently with + // any class that acts as a client to the server, i.e. the client must know + // the + // address and port as well. + private static final String MATRIX_DATA_SERVER_ADDRESS = "127.0.0.1"; + private static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final String MATRIX_DATA_SERVER_NAME = MatrixDataServer.class + .getCanonicalName(); + private static final String MATRIX_DATA_SERVER_LABEL = "matrix server"; + + private HashMap matrixEntryMap; + private HashMap matrixMap; + + public MatrixDataServer() + { + + // create the HashMap objects to keep track of matrix data read by the server + matrixEntryMap = new HashMap(); + matrixMap = new HashMap(); + + objectLock = new Object(); + } + + public String testRemote(String remoteObjectName) + { + logger.info("testRemote() called by remote process: " + remoteObjectName + "."); + return String.format("testRemote() method in %s called by %s.", this.getClass() + .getCanonicalName(), remoteObjectName); + } + + public String testRemote() + { + logger.info("testRemote() called by remote process."); + return String.format("testRemote() method in %s called.", this.getClass() + .getCanonicalName()); + } + + /* + * Read a matrix. + * + * @param matrixEntry a DataEntry describing the matrix to read + * + * @return a Matrix + */ + public Matrix getMatrix(DataEntry matrixEntry) + { + + Matrix matrix; + + synchronized (objectLock) + { + + String name = matrixEntry.name; + + if (matrixEntryMap.containsKey(name)) + { + matrix = matrixMap.get(name); + } else + { + + //create 64bit matrix reader + String fileName = matrixEntry.fileName; + MatrixReader mr = MatrixReader.createReader(MatrixType.OMX, new File(fileName)); + matrix = mr.readMatrix(matrixEntry.matrixName); + logger.info("Read " + matrixEntry.matrixName + " as " + name + " from " + fileName); + + // Use token name from control file for matrix name (not name + // from underlying matrix) + matrix.setName(matrixEntry.name); + + matrixMap.put(name, matrix); + matrixEntryMap.put(name, matrixEntry); + } + + } + + return matrix; + } + + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + public void writeMatrixFile(String fileName, Matrix[] m) + { + + File outFile = new File(fileName); + MatrixWriter writer = MatrixWriter.createWriter(MatrixType.OMX, outFile); + String[] names = new String[m.length]; + + for (int i = 0; i < m.length; i++) + { + names[i] = m[i].getName(); + } + + writer.writeMatrices(names, m); + } + + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + public void writeMatrixFile(String fileName, Matrix[] m, MatrixType mt) + { + writeMatrixFile(fileName, m); + } + + public void clear() + { + if (matrixMap != null) + { + matrixMap = new HashMap(); + logger.info("MatrixDataServer matrixMap object is cleared."); + } else + { + logger.info("MatrixDataServer.clear() called, but matrixMap object is null."); + } + + if (matrixEntryMap != null) + { + matrixEntryMap = new HashMap(); + logger.info("MatrixDataServer matrixEntryMap object is cleared."); + } else + { + logger.info("MatrixDataServer.clear() called, but matrixEntryMap object is null."); + } + } + + //Empty methods to maintain compatibility + public void start32BitMatrixIoServer(MatrixType mType) {} + public void stop32BitMatrixIoServer() {} + public void setRam(int ram) {} + + public static void main(String[] args) throws Exception + { + + String serverAddress = MATRIX_DATA_SERVER_ADDRESS; + int serverPort = MATRIX_DATA_SERVER_PORT; + String className = MATRIX_DATA_SERVER_NAME; + String serverLabel = MATRIX_DATA_SERVER_LABEL; + int ram = -1; + + for (int i = 0; i < args.length; i++) + { + if (args[i].equalsIgnoreCase("-hostname")) serverAddress = args[i + 1]; + else if (args[i].equalsIgnoreCase("-port")) serverPort = Integer.parseInt(args[i + 1]); + else if (args[i].equalsIgnoreCase("-label")) serverLabel = args[i + 1]; + else if (args[i].equalsIgnoreCase("-ram")) ram = Integer.parseInt(args[i + 1]); + } + + MatrixDataServer matrixServer = new MatrixDataServer(); + + // bind this concrete object with the cajo library objects for managing RMI + Remote.config(serverAddress, serverPort, null, 0); + ItemServer.bind(matrixServer, className); + + // log that the server started + logger.info("server starting on " + (System.getProperty("os.arch")) + + " operating system."); + logger.info(String.format("%s version %s started on: %s:%d", serverLabel, VERSION, + serverAddress, serverPort)); + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/MatrixDataServerRmi.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MatrixDataServerRmi.java new file mode 100644 index 0000000..767b869 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MatrixDataServerRmi.java @@ -0,0 +1,98 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; + +import com.pb.common.calculator.DataEntry; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; + +/** + * @author Jim Hicks + * + * Class for managing matrix data in a remote process and accessed by + * UECs using RMI. + */ +public class MatrixDataServerRmi + implements MatrixDataServerIf, Serializable +{ + + // protected static Logger logger = + // Logger.getLogger(MatrixDataServerRmi.class); + + UtilRmi remote; + String connectString; + + public MatrixDataServerRmi(String hostname, int port, String className) + { + + connectString = String.format("//%s:%d/%s", hostname, port, className); + remote = new UtilRmi(connectString); + + } + + public void clear() + { + Object[] objArray = {}; + remote.method("clear", objArray); + } + + public void writeMatrixFile(String fileName, Matrix[] m, MatrixType mt) + { + Object[] objArray = {fileName, m, mt}; + remote.method("writeMatrixFile", objArray); + } + + public Matrix getMatrix(DataEntry dataEntry) + { + Object[] objArray = {dataEntry}; + return (Matrix) remote.method("getMatrix", objArray); + } + + public void start32BitMatrixIoServer(MatrixType mType) + { + Object[] objArray = {mType}; + remote.method("start32BitMatrixIoServer", objArray); + } + + public void start32BitMatrixIoServer(MatrixType mType, String label) + { + Object[] objArray = {mType, label}; + remote.method("start32BitMatrixIoServer", objArray); + } + + public void stop32BitMatrixIoServer() + { + Object[] objArray = {}; + remote.method("stop32BitMatrixIoServer", objArray); + } + + public void stop32BitMatrixIoServer(String label) + { + Object[] objArray = {label}; + remote.method("stop32BitMatrixIoServer", objArray); + } + + public String testRemote(String remoteObjectName) + { + Object[] objArray = {remoteObjectName}; + return (String) remote.method("testRemote", objArray); + } + + public String testRemote() + { + Object[] objArray = {}; + return (String) remote.method("testRemote", objArray); + } + + /** + * This method is included in the Interface this class implements, but is not used anywhere by the SANDAG model. + * It is included hear to satisfy the interface only. + */ + @Override + public void writeMatrixFile(String fileName, Matrix[] m) { + // TODO Auto-generated method stub + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/McLogsumsCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/McLogsumsCalculator.java new file mode 100644 index 0000000..2699a7b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/McLogsumsCalculator.java @@ -0,0 +1,754 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.BestTransitPathCalculator; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; + +import com.pb.common.newmodel.Alternative; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.ConcreteAlternative; +import com.pb.common.newmodel.LogitModel; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.calculator.IndexValues; + + +public class McLogsumsCalculator implements Serializable +{ + + private transient Logger autoSkimLogger = Logger.getLogger(McLogsumsCalculator.class); + + public static final String PROPERTIES_UEC_TOUR_MODE_CHOICE = "tourModeChoice.uec.file"; + public static final String PROPERTIES_UEC_TRIP_MODE_CHOICE = "tripModeChoice.uec.file"; + + + public static final int WTW = 0; + public static final int WTD = 1; + public static final int DTW = 2; + public static final int NUM_ACC_EGR = 3; + + public static final int OUT = 0; + public static final int IN = 1; + public static final int NUM_DIR = 2; + + private BestTransitPathCalculator bestPathUEC; + private double[] tripModeChoiceSegmentStoredProbabilities; + private double[] tripModeChoiceSegmentStoredVOTs; + private float tripModeChoiceSegmentStoredParkingCost; + + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private double[] lsWgtAvgCostM; + private double[] lsWgtAvgCostD; + private double[] lsWgtAvgCostH; + private int[] parkingArea; + + private double[][] bestWtwTapPairsOut; + private double[][] bestWtwTapPairsIn; + private double[][] bestWtdTapPairsOut; + private double[][] bestWtdTapPairsIn; + private double[][] bestDtwTapPairsOut; + private double[][] bestDtwTapPairsIn; + + private double[][] bestWtwTripTapPairs; + private double[][] bestWtdTripTapPairs; + private double[][] bestDtwTripTapPairs; + + private AutoAndNonMotorizedSkimsCalculator anm; + + private int setTourMcLogsumDmuAttributesTotalTime = 0; + private int setTripMcLogsumDmuAttributesTotalTime = 0; + + + + public McLogsumsCalculator() + { + if (mgraManager == null) + mgraManager = MgraDataManager.getInstance(); + + if (tazManager == null) + tazManager = TazDataManager.getInstance(); + + this.lsWgtAvgCostM = mgraManager.getLsWgtAvgCostM(); + this.lsWgtAvgCostD = mgraManager.getLsWgtAvgCostD(); + this.lsWgtAvgCostH = mgraManager.getLsWgtAvgCostH(); + this.parkingArea = mgraManager.getMgraParkAreas(); + + tripModeChoiceSegmentStoredVOTs = new double[3]; + } + + + public BestTransitPathCalculator getBestTransitPathCalculator() + { + return bestPathUEC; + } + + + public void setupSkimCalculators(HashMap rbMap) + { + bestPathUEC = new BestTransitPathCalculator(rbMap); + anm = new AutoAndNonMotorizedSkimsCalculator(rbMap); + } + + public void setTazDistanceSkimArrays( double[][][] storedFromTazDistanceSkims, double[][][] storedToTazDistanceSkims ) { + anm.setTazDistanceSkimArrays( storedFromTazDistanceSkims, storedToTazDistanceSkims ); + } + + + public AutoAndNonMotorizedSkimsCalculator getAnmSkimCalculator() + { + return anm; + } + + public void setTourMcDmuAttributes( TourModeChoiceDMU mcDmuObject, int origMgra, int destMgra, int departPeriod, int arrivePeriod, boolean debug ) + { + + setNmTourMcDmuAttributes( mcDmuObject, origMgra, destMgra, departPeriod, arrivePeriod, debug ); + setWtwTourMcDmuAttributes( mcDmuObject, origMgra, destMgra, departPeriod, arrivePeriod, debug ); + setDtwTourMcDmuAttributes( mcDmuObject, origMgra, destMgra, departPeriod, arrivePeriod, debug ); + setWtdTourMcDmuAttributes( mcDmuObject, origMgra, destMgra, departPeriod, arrivePeriod, debug ); + + // set the land use data items in the DMU for the origin + mcDmuObject.setOrigDuDen( mgraManager.getDuDenValue( origMgra ) ); + mcDmuObject.setOrigEmpDen( mgraManager.getEmpDenValue( origMgra ) ); + mcDmuObject.setOrigTotInt( mgraManager.getTotIntValue( origMgra ) ); + + // set the land use data items in the DMU for the destination + mcDmuObject.setDestDuDen( mgraManager.getDuDenValue( destMgra ) ); + mcDmuObject.setDestEmpDen( mgraManager.getEmpDenValue( destMgra ) ); + mcDmuObject.setDestTotInt( mgraManager.getTotIntValue( destMgra ) ); + + mcDmuObject.setLsWgtAvgCostM( lsWgtAvgCostM[destMgra] ); + mcDmuObject.setLsWgtAvgCostD( lsWgtAvgCostD[destMgra] ); + mcDmuObject.setLsWgtAvgCostH( lsWgtAvgCostH[destMgra] ); + + int tourOrigTaz = mgraManager.getTaz(origMgra); + int tourDestTaz = mgraManager.getTaz(destMgra); + + mcDmuObject.setPTazTerminalTime( tazManager.getOriginTazTerminalTime(tourOrigTaz) ); + mcDmuObject.setATazTerminalTime( tazManager.getDestinationTazTerminalTime(tourDestTaz) ); + + Person person = mcDmuObject.getPersonObject(); + + double reimbursePct=0; + if(person!=null) { + reimbursePct = person.getParkingReimbursement(); + } + + mcDmuObject.setReimburseProportion( reimbursePct ); + mcDmuObject.setParkingArea(parkingArea[destMgra]); + + + } + + + public double calculateTourMcLogsum(int origMgra, int destMgra, int departPeriod, int arrivePeriod, + ChoiceModelApplication mcModel, TourModeChoiceDMU mcDmuObject) + { + + long currentTime = System.currentTimeMillis(); + setTourMcDmuAttributes( mcDmuObject, origMgra, destMgra, departPeriod, arrivePeriod, mcDmuObject.getDmuIndexValues().getDebug() ); + setTourMcLogsumDmuAttributesTotalTime += ( System.currentTimeMillis() - currentTime ); + + // mode choice UEC references highway skim matrices directly, so set index orig/dest to O/D TAZs. + IndexValues mcDmuIndex = mcDmuObject.getDmuIndexValues(); + int tourOrigTaz = mgraManager.getTaz(origMgra); + int tourDestTaz = mgraManager.getTaz(destMgra); + mcDmuIndex.setOriginZone(tourOrigTaz); + mcDmuIndex.setDestZone(tourDestTaz); + mcDmuObject.setOriginMgra(origMgra); + mcDmuObject.setDestMgra(destMgra); + + mcModel.computeUtilities(mcDmuObject, mcDmuIndex); + double logsum = mcModel.getLogsum(); + + return logsum; + + } + + public void setWalkTransitLogSumUnavailable( TripModeChoiceDMU tripMcDmuObject ) { + tripMcDmuObject.setTransitLogSum( WTW, bestPathUEC.NA ); + } + + public void setDriveTransitLogSumUnavailable( TripModeChoiceDMU tripMcDmuObject, boolean isInbound ) { + + // set drive transit skim attributes to unavailable + if ( ! isInbound ) { + tripMcDmuObject.setTransitLogSum( DTW, bestPathUEC.NA); + } + else { + tripMcDmuObject.setTransitLogSum( WTD, bestPathUEC.NA); + } + + } + + + public double calculateTripMcLogsum(int origMgra, int destMgra, int departPeriod, ChoiceModelApplication mcModel, TripModeChoiceDMU mcDmuObject, Logger myLogger) + { + long currentTime = System.currentTimeMillis(); + setNmTripMcDmuAttributes( mcDmuObject, origMgra, destMgra, departPeriod, mcDmuObject.getHouseholdObject().getDebugChoiceModels() ); + + mcDmuObject.setTripPeriod(departPeriod); + + // set the land use data items in the DMU for the origin + mcDmuObject.setOrigDuDen( mgraManager.getDuDenValue( origMgra ) ); + mcDmuObject.setOrigEmpDen( mgraManager.getEmpDenValue( origMgra ) ); + mcDmuObject.setOrigTotInt( mgraManager.getTotIntValue( origMgra ) ); + + // set the land use data items in the DMU for the destination + mcDmuObject.setDestDuDen( mgraManager.getDuDenValue( destMgra ) ); + mcDmuObject.setDestEmpDen( mgraManager.getEmpDenValue( destMgra ) ); + mcDmuObject.setDestTotInt( mgraManager.getTotIntValue( destMgra ) ); + + // mode choice UEC references highway skim matrices directly, so set index orig/dest to O/D TAZs. + IndexValues mcDmuIndex = mcDmuObject.getDmuIndexValues(); + mcDmuIndex.setOriginZone(mgraManager.getTaz(origMgra)); + mcDmuIndex.setDestZone(mgraManager.getTaz(destMgra)); + mcDmuObject.setOriginMgra(origMgra); + mcDmuObject.setDestMgra(destMgra); + + setTripMcLogsumDmuAttributesTotalTime += ( System.currentTimeMillis() - currentTime ); + mcDmuObject.setPTazTerminalTime( tazManager.getOriginTazTerminalTime(mgraManager.getTaz(origMgra)) ); + mcDmuObject.setATazTerminalTime( tazManager.getDestinationTazTerminalTime(mgraManager.getTaz(destMgra)) ); + + + mcModel.computeUtilities(mcDmuObject, mcDmuIndex); + double logsum = mcModel.getLogsum(); + tripModeChoiceSegmentStoredProbabilities = Arrays.copyOf( mcModel.getCumulativeProbabilities(), mcModel.getNumberOfAlternatives() ); + + //also save the VOTs from the model + UtilityExpressionCalculator uec = mcModel.getUEC(); + + ModelStructure modelStructure = mcDmuObject.modelStructure; + + tripModeChoiceSegmentStoredVOTs[0] = uec.getValueForIndex(uec.lookupVariableIndex("vot")); + tripModeChoiceSegmentStoredVOTs[1] = uec.getValueForIndex(uec.lookupVariableIndex("votS2")); + tripModeChoiceSegmentStoredVOTs[2] = uec.getValueForIndex(uec.lookupVariableIndex("votS3")); + + tripModeChoiceSegmentStoredParkingCost = (float) uec.getValueForIndex(uec.lookupVariableIndex("parkingCost")); + + if ( mcDmuObject.getHouseholdObject().getDebugChoiceModels() ) + mcModel.logUECResults(myLogger, "Trip Mode Choice Utility Expressions for mgras: " + origMgra + " to " + destMgra + " for HHID: " + mcDmuIndex.getHHIndex() ); + + return logsum; + + } + + + /** + * return the array of mode choice model cumulative probabilities determined while + * computing the mode choice logsum for the trip segmen during stop location choice. + * These probabilities arrays are stored for each sampled stop location so that when + * the selected sample stop location is known, the mode choice can be drawn from the + * already computed probabilities. + * + * @return mode choice cumulative probabilities array + */ + public double[] getStoredSegmentCumulativeProbabilities() { + return tripModeChoiceSegmentStoredProbabilities; + } + + public double[] getStoredSegmentVOTs() { + return tripModeChoiceSegmentStoredVOTs; + } + public double[][] getBestWtwTapsOut() + { + return bestWtwTapPairsOut; + } + + public double[][] getBestWtwTapsIn() + { + return bestWtwTapPairsIn; + } + + public double[][] getBestWtdTapsOut() + { + return bestWtdTapPairsOut; + } + + public double[][] getBestWtdTapsIn() + { + return bestWtdTapPairsIn; + } + + public double[][] getBestDtwTapsOut() + { + return bestDtwTapPairsOut; + } + + public double[][] getBestDtwTapsIn() + { + return bestDtwTapPairsIn; + } + + public double[][] getBestWtwTripTaps() + { + return bestWtwTripTapPairs; + } + + public double[][] getBestDtwTripTaps() + { + return bestDtwTripTapPairs; + } + + public double[][] getBestWtdTripTaps() + { + return bestWtdTripTapPairs; + } + + + private void setNmTourMcDmuAttributes( TourModeChoiceDMU mcDmuObject, int origMgra, int destMgra, int departPeriod, int arrivePeriod, boolean loggingEnabled ) + { + // non-motorized, outbound then inbound + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + departPeriod = skimPeriodIndex; + double[] nmSkimsOut = anm.getNonMotorizedSkims(origMgra, destMgra, departPeriod, loggingEnabled, autoSkimLogger); + if (loggingEnabled) + anm.logReturnedSkims(origMgra, destMgra, departPeriod, nmSkimsOut, "non-motorized outbound", autoSkimLogger); + + skimPeriodIndex = ModelStructure.getSkimPeriodIndex(arrivePeriod); + arrivePeriod = skimPeriodIndex; + double[] nmSkimsIn = anm.getNonMotorizedSkims(destMgra, origMgra, arrivePeriod, loggingEnabled, autoSkimLogger); + if (loggingEnabled) anm.logReturnedSkims(destMgra, origMgra, arrivePeriod, nmSkimsIn, "non-motorized inbound", autoSkimLogger); + + int walkIndex = anm.getNmWalkTimeSkimIndex(); + mcDmuObject.setNmWalkTimeOut( nmSkimsOut[walkIndex] ); + mcDmuObject.setNmWalkTimeIn( nmSkimsIn[walkIndex] ); + + int bikeIndex = anm.getNmBikeTimeSkimIndex(); + mcDmuObject.setNmBikeTimeOut( nmSkimsOut[bikeIndex] ); + mcDmuObject.setNmBikeTimeIn( nmSkimsIn[bikeIndex] ); + + } + + private void setWtwTourMcDmuAttributes( TourModeChoiceDMU mcDmuObject, int origMgra, int destMgra, int departPeriod, int arrivePeriod, boolean loggingEnabled ) + { + + //setup best path dmu variables + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + // walk access, walk egress transit, outbound + int skimPeriodIndexOut = ModelStructure.getSkimPeriodIndex(departPeriod); + int pTaz = mgraManager.getTaz(origMgra); + int aTaz = mgraManager.getTaz(destMgra); + float odDistance = (float) anm.getTazDistanceFromTaz(pTaz, ModelStructure.AM_SKIM_PERIOD_INDEX)[aTaz]; + bestWtwTapPairsOut = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, WTW, origMgra, destMgra, skimPeriodIndexOut, loggingEnabled, autoSkimLogger, odDistance); + + if (bestWtwTapPairsOut[0] == null) { + mcDmuObject.setTransitLogSum( WTW, false, bestPathUEC.NA ); + } else { + // calculate logsum + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + walkDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + walkDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + driveDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + driveDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + + //catch issues where the trip mode choice DMU was set up without a household or person object + if(mcDmuObject.getHouseholdObject()!=null){ + walkDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? walkDmu.getPersonType() : mcDmuObject.getPersonType()); + driveDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? driveDmu.getPersonType() : mcDmuObject.getPersonType()); + } + + bestWtwTapPairsOut = bestPathUEC.calcPersonSpecificUtilities(bestWtwTapPairsOut, walkDmu, driveDmu, WTW, origMgra, destMgra, skimPeriodIndexOut, loggingEnabled, autoSkimLogger, odDistance); + double logsumOut = bestPathUEC.calcTripLogSum(bestWtwTapPairsOut, loggingEnabled, autoSkimLogger); + mcDmuObject.setTransitLogSum( WTW, false, logsumOut); + } + + //setup best path dmu variables + walkDmu = new TransitWalkAccessDMU(); + driveDmu = new TransitDriveAccessDMU(); + + // walk access, walk egress transit, inbound + int skimPeriodIndexIn = ModelStructure.getSkimPeriodIndex(arrivePeriod); + bestWtwTapPairsIn = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, WTW, destMgra, origMgra, skimPeriodIndexIn, loggingEnabled, autoSkimLogger, odDistance); + + if (bestWtwTapPairsIn[0] == null) { + mcDmuObject.setTransitLogSum( WTW, true, bestPathUEC.NA ); + } else { + // calculate logsum + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + walkDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + walkDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + driveDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + driveDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + + //catch issues where the trip mode choice DMU was set up without a household or person object + if(mcDmuObject.getHouseholdObject()!=null){ + walkDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? walkDmu.getPersonType() : mcDmuObject.getPersonType()); + driveDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? driveDmu.getPersonType() : mcDmuObject.getPersonType()); + } + + bestWtwTapPairsIn = bestPathUEC.calcPersonSpecificUtilities(bestWtwTapPairsIn, walkDmu, driveDmu, WTW, destMgra, origMgra, skimPeriodIndexIn, loggingEnabled, autoSkimLogger, odDistance); + double logsumIn = bestPathUEC.calcTripLogSum(bestWtwTapPairsIn, loggingEnabled, autoSkimLogger); + mcDmuObject.setTransitLogSum( WTW, true, logsumIn); + } + } + + private void setWtdTourMcDmuAttributes( TourModeChoiceDMU mcDmuObject, int origMgra, int destMgra, int departPeriod, int arrivePeriod, boolean loggingEnabled ) + { + + //setup best path dmu variables + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + // logsum for WTD outbound is never used -> set to NA + mcDmuObject.setTransitLogSum( WTD, false, bestPathUEC.NA ); + /* TODO: - remove this section of code after successful testing + // walk access, drive egress transit, outbound + int skimPeriodIndexOut = ModelStructure.getSkimPeriodIndex(departPeriod); + bestWtdTapPairsOut = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, WTD, origMgra, destMgra, skimPeriodIndexOut, loggingEnabled, autoSkimLogger); + + if (bestWtdTapPairsOut[0] == null) { + mcDmuObject.setTransitLogSum( WTD, false, bestPathUEC.NA ); + } else { + // calculate logsum + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + walkDmu.setTourCategoryIsJoint(mcDmuObject.getTourCategoryJoint()); + walkDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? walkDmu.personType : mcDmuObject.getPersonType()); + walkDmu.setValueOfTime((float)mcDmuObject.getValueOfTime()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + driveDmu.setTourCategoryIsJoint(mcDmuObject.getTourCategoryJoint()); + driveDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? driveDmu.personType : mcDmuObject.getPersonType()); + driveDmu.setValueOfTime((float)mcDmuObject.getValueOfTime()); + + bestWtdTapPairsOut = bestPathUEC.calcPersonSpecificUtilities(bestWtdTapPairsOut, walkDmu, driveDmu, WTD, origMgra, destMgra, skimPeriodIndexOut, loggingEnabled, autoSkimLogger); + double logsumOut = bestPathUEC.calcTripLogSum(bestWtdTapPairsOut, loggingEnabled, autoSkimLogger); + mcDmuObject.setTransitLogSum( WTD, false, logsumOut); + } + */ + + // walk access, drive egress transit, inbound + int skimPeriodIndexIn = ModelStructure.getSkimPeriodIndex(arrivePeriod); + int pTaz = mgraManager.getTaz(origMgra); + int aTaz = mgraManager.getTaz(destMgra); + float odDistance = (float) anm.getTazDistanceFromTaz(pTaz, ModelStructure.AM_SKIM_PERIOD_INDEX)[aTaz]; + + bestWtdTapPairsIn = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, WTD, destMgra, origMgra, skimPeriodIndexIn, loggingEnabled, autoSkimLogger, odDistance); + + if (bestWtdTapPairsIn[0] == null) { + mcDmuObject.setTransitLogSum( WTD, true, bestPathUEC.NA ); + } else { + // calculate logsum + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + walkDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + walkDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + driveDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + driveDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + //catch issues where the trip mode choice DMU was set up without a household or person object + if(mcDmuObject.getHouseholdObject()!=null){ + walkDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? walkDmu.getPersonType() : mcDmuObject.getPersonType()); + driveDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? driveDmu.getPersonType() : mcDmuObject.getPersonType()); + } + bestWtdTapPairsIn = bestPathUEC.calcPersonSpecificUtilities(bestWtdTapPairsIn, walkDmu, driveDmu, WTD, destMgra, origMgra, skimPeriodIndexIn, loggingEnabled, autoSkimLogger, odDistance); + double logsumIn = bestPathUEC.calcTripLogSum(bestWtdTapPairsIn, loggingEnabled, autoSkimLogger); + mcDmuObject.setTransitLogSum( WTD, true, logsumIn); + } + } + + private void setDtwTourMcDmuAttributes( TourModeChoiceDMU mcDmuObject, int origMgra, int destMgra, int departPeriod, int arrivePeriod, boolean loggingEnabled ) + { + //setup best path dmu variables + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + // drive access, walk egress transit, outbound + int skimPeriodIndexOut = ModelStructure.getSkimPeriodIndex(departPeriod); + int pTaz = mgraManager.getTaz(origMgra); + int aTaz = mgraManager.getTaz(destMgra); + float odDistance = (float) anm.getTazDistanceFromTaz(pTaz, ModelStructure.AM_SKIM_PERIOD_INDEX)[aTaz]; + + bestDtwTapPairsOut = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, DTW, origMgra, destMgra, skimPeriodIndexOut, loggingEnabled, autoSkimLogger, odDistance); + + if (bestDtwTapPairsOut[0] == null) { + mcDmuObject.setTransitLogSum( DTW, false, bestPathUEC.NA ); + } else { + // calculate logsum + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + walkDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + walkDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + driveDmu.setIvtCoeff( (float) mcDmuObject.getIvtCoeff()); + driveDmu.setCostCoeff( (float) mcDmuObject.getCostCoeff()); + + //catch issues where the trip mode choice DMU was set up without a household or person object + if(mcDmuObject.getHouseholdObject()!=null){ + walkDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? walkDmu.getPersonType() : mcDmuObject.getPersonType()); + driveDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? driveDmu.getPersonType() : mcDmuObject.getPersonType()); + } + + bestDtwTapPairsOut = bestPathUEC.calcPersonSpecificUtilities(bestDtwTapPairsOut, walkDmu, driveDmu, DTW, origMgra, destMgra, skimPeriodIndexOut, loggingEnabled, autoSkimLogger, odDistance); + double logsumOut = bestPathUEC.calcTripLogSum(bestDtwTapPairsOut, loggingEnabled, autoSkimLogger); + mcDmuObject.setTransitLogSum( DTW, false, logsumOut); + } + + // logsum for DTW inbound is never used -> set to NA + mcDmuObject.setTransitLogSum( DTW, true, bestPathUEC.NA ); + + /* TODO: remove this section of code after successful testing + //setup best path dmu variables + walkDmu = new TransitWalkAccessDMU(); + driveDmu = new TransitDriveAccessDMU(); + + // drive access, walk egress transit, inbound + int skimPeriodIndexIn = ModelStructure.getSkimPeriodIndex(arrivePeriod); + bestDtwTapPairsIn = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, DTW, destMgra, origMgra, skimPeriodIndexIn, loggingEnabled, autoSkimLogger); + + if (bestDtwTapPairsIn[0] == null) { + mcDmuObject.setTransitLogSum( DTW, true, bestPathUEC.NA ); + } else { + // calculate logsum + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + walkDmu.setTourCategoryIsJoint(mcDmuObject.getTourCategoryJoint()); + walkDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? walkDmu.personType : mcDmuObject.getPersonType()); + walkDmu.setValueOfTime((float)mcDmuObject.getValueOfTime()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TOURMC); + driveDmu.setTourCategoryIsJoint(mcDmuObject.getTourCategoryJoint()); + driveDmu.setPersonType(mcDmuObject.getTourCategoryJoint()==1 ? driveDmu.personType : mcDmuObject.getPersonType()); + driveDmu.setValueOfTime((float)mcDmuObject.getValueOfTime()); + + bestDtwTapPairsIn = bestPathUEC.calcPersonSpecificUtilities(bestDtwTapPairsIn, walkDmu, driveDmu, DTW, destMgra, origMgra, skimPeriodIndexIn, loggingEnabled, autoSkimLogger); + double logsumIn = bestPathUEC.calcTripLogSum(bestDtwTapPairsIn, loggingEnabled, autoSkimLogger); + mcDmuObject.setTransitLogSum( DTW, true, logsumIn); + } + */ + } + + public void setNmTripMcDmuAttributes( TripModeChoiceDMU tripMcDmuObject, int origMgra, int destMgra, int departPeriod, boolean loggingEnabled ) + { + + double[] nmSkims = null; + + // non-motorized, outbound then inbound + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + departPeriod = skimPeriodIndex; + nmSkims = anm.getNonMotorizedSkims(origMgra, destMgra, departPeriod, loggingEnabled, autoSkimLogger); + if (loggingEnabled) + anm.logReturnedSkims(origMgra, destMgra, departPeriod, nmSkims, "non-motorized trip mode choice skims", autoSkimLogger); + + int walkIndex = anm.getNmWalkTimeSkimIndex(); + tripMcDmuObject.setNonMotorizedWalkTime(nmSkims[walkIndex] ); + + int bikeIndex = anm.getNmBikeTimeSkimIndex(); + tripMcDmuObject.setNonMotorizedBikeTime(nmSkims[bikeIndex] ); + + } + + public void setWtwTripMcDmuAttributesForBestTapPairs( TripModeChoiceDMU tripMcDmuObject, int origMgra, int destMgra, int departPeriod, double[][] bestTapPairs, boolean loggingEnabled) + { + + if (bestTapPairs == null) { + if(loggingEnabled){ + autoSkimLogger.info("Attempting to set WTW Trip MC DMU Attributes for null best TAP pairs array"); + } + tripMcDmuObject.setTransitLogSum( WTW, bestPathUEC.NA ); + bestWtwTripTapPairs = bestTapPairs; + return; + } + + // calculate logsum + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + double logsum = bestPathUEC.calcTripLogSum(bestTapPairs, loggingEnabled, autoSkimLogger); + tripMcDmuObject.setTransitLogSum( WTW, logsum); + bestWtwTripTapPairs = bestTapPairs; + + } + + public void setDtwTripMcDmuAttributesForBestTapPairs( TripModeChoiceDMU tripMcDmuObject, int origMgra, int destMgra, int departPeriod, double[][] bestTapPairs, boolean loggingEnabled ) + { + + if (bestTapPairs == null) { + if(loggingEnabled){ + autoSkimLogger.info("Attempting to set DTW Trip MC DMU Attributes for null best TAP pairs array"); + } + tripMcDmuObject.setTransitLogSum( DTW, bestPathUEC.NA ); + bestDtwTripTapPairs = bestTapPairs; + return; + } + + // calculate logsum + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + double logsum = bestPathUEC.calcTripLogSum(bestTapPairs, loggingEnabled, autoSkimLogger); + + if(loggingEnabled) + autoSkimLogger.info("Setting DTW logsum in trip MC DMU object to "+logsum); + + tripMcDmuObject.setTransitLogSum( DTW, logsum); + bestDtwTripTapPairs = bestTapPairs; + + } + + public void setWtdTripMcDmuAttributesForBestTapPairs( TripModeChoiceDMU tripMcDmuObject, int origMgra, int destMgra, int departPeriod, double[][] bestTapPairs, boolean loggingEnabled ) + { + + if (bestTapPairs == null) { + if(loggingEnabled){ + autoSkimLogger.info("Attempting to set WTD Trip MC DMU Attributes for null best TAP pairs array"); + } + tripMcDmuObject.setTransitLogSum( WTD, bestPathUEC.NA ); + bestWtdTripTapPairs = bestTapPairs; + return; + } + + // calculate logsum + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + double logsum = bestPathUEC.calcTripLogSum(bestTapPairs, loggingEnabled, autoSkimLogger); + tripMcDmuObject.setTransitLogSum( WTD, logsum); + bestWtdTripTapPairs = bestTapPairs; + + } + + public void setWtwTripMcDmuAttributes( TripModeChoiceDMU tripMcDmuObject, int origMgra, int destMgra, int departPeriod, boolean loggingEnabled ) + { + //setup best path dmu variables + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + // walk access and walk egress for transit segment + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + int pTaz = mgraManager.getTaz(origMgra); + int aTaz = mgraManager.getTaz(destMgra); + float odDistance = (float) anm.getTazDistanceFromTaz(pTaz, ModelStructure.AM_SKIM_PERIOD_INDEX)[aTaz]; + + // store best tap pairs for walk-transit-walk + bestWtwTripTapPairs = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, WTW, origMgra, destMgra, skimPeriodIndex, loggingEnabled, autoSkimLogger, odDistance ); + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TRIPMC); + walkDmu.setIvtCoeff( (float) tripMcDmuObject.getIvtCoeff()); + walkDmu.setCostCoeff( (float) tripMcDmuObject.getCostCoeff()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TRIPMC); + driveDmu.setIvtCoeff( (float) tripMcDmuObject.getIvtCoeff()); + driveDmu.setCostCoeff( (float) tripMcDmuObject.getCostCoeff()); + + //catch issues where the trip mode choice DMU was set up without a household or person object + if(tripMcDmuObject.getHouseholdObject()!=null){ + walkDmu.setPersonType(tripMcDmuObject.getTourCategoryJoint()==1 ? walkDmu.getPersonType() : tripMcDmuObject.getPersonType()); + driveDmu.setPersonType(tripMcDmuObject.getTourCategoryJoint()==1 ? driveDmu.getPersonType() : tripMcDmuObject.getPersonType()); + } + // calculate logsum + bestWtwTripTapPairs = bestPathUEC.calcPersonSpecificUtilities(bestWtwTripTapPairs, walkDmu, driveDmu, WTW, origMgra, destMgra, skimPeriodIndex, loggingEnabled, autoSkimLogger, odDistance); + double logsum = bestPathUEC.calcTripLogSum(bestWtwTripTapPairs, loggingEnabled, autoSkimLogger); + tripMcDmuObject.setTransitLogSum( WTW, logsum); + + } + + public void setWtdTripMcDmuAttributes( TripModeChoiceDMU tripMcDmuObject, int origMgra, int destMgra, int departPeriod, boolean loggingEnabled ) + { + //setup best path dmu variables + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + // walk access, drive egress transit, outbound + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + int pTaz = mgraManager.getTaz(origMgra); + int aTaz = mgraManager.getTaz(destMgra); + float odDistance = (float) anm.getTazDistanceFromTaz(pTaz, ModelStructure.AM_SKIM_PERIOD_INDEX)[aTaz]; + + // store best tap pairs using outbound direction array + bestWtdTripTapPairs = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, WTD, origMgra, destMgra, skimPeriodIndex, loggingEnabled, autoSkimLogger, odDistance); + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TRIPMC); + walkDmu.setIvtCoeff( (float) tripMcDmuObject.getIvtCoeff()); + walkDmu.setCostCoeff( (float) tripMcDmuObject.getCostCoeff()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TRIPMC); + driveDmu.setIvtCoeff( (float) tripMcDmuObject.getIvtCoeff()); + driveDmu.setCostCoeff( (float) tripMcDmuObject.getCostCoeff()); + + //catch issues where the trip mode choice DMU was set up without a household or person object + if(tripMcDmuObject.getHouseholdObject()!=null){ + walkDmu.setPersonType(tripMcDmuObject.getTourCategoryJoint()==1 ? walkDmu.getPersonType() : tripMcDmuObject.getPersonType()); + driveDmu.setPersonType(tripMcDmuObject.getTourCategoryJoint()==1 ? driveDmu.getPersonType() : tripMcDmuObject.getPersonType()); + } + + // calculate logsum + bestWtdTripTapPairs = bestPathUEC.calcPersonSpecificUtilities(bestWtdTripTapPairs, walkDmu, driveDmu, WTD, origMgra, destMgra, skimPeriodIndex, loggingEnabled, autoSkimLogger, odDistance); + double logsum = bestPathUEC.calcTripLogSum(bestWtdTripTapPairs, loggingEnabled, autoSkimLogger); + tripMcDmuObject.setTransitLogSum( WTD, logsum); + + } + + public void setDtwTripMcDmuAttributes( TripModeChoiceDMU tripMcDmuObject, int origMgra, int destMgra, int departPeriod, boolean loggingEnabled ) + { + //setup best path dmu variables + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + + // drive access, walk egress transit, outbound + int skimPeriodIndex = ModelStructure.getSkimPeriodIndex(departPeriod); + int pTaz = mgraManager.getTaz(origMgra); + int aTaz = mgraManager.getTaz(destMgra); + float odDistance = (float) anm.getTazDistanceFromTaz(pTaz, ModelStructure.AM_SKIM_PERIOD_INDEX)[aTaz]; + + // store best tap pairs using outbound direction array + bestDtwTripTapPairs = bestPathUEC.getBestTapPairs(walkDmu, driveDmu, DTW, origMgra, destMgra, skimPeriodIndex, loggingEnabled, autoSkimLogger, odDistance); + + //set person specific variables and re-calculate best tap pair utilities + walkDmu.setApplicationType(bestPathUEC.APP_TYPE_TRIPMC); + walkDmu.setIvtCoeff( (float) tripMcDmuObject.getIvtCoeff()); + walkDmu.setCostCoeff( (float) tripMcDmuObject.getCostCoeff()); + + driveDmu.setApplicationType(bestPathUEC.APP_TYPE_TRIPMC); + driveDmu.setIvtCoeff( (float) tripMcDmuObject.getIvtCoeff()); + driveDmu.setCostCoeff( (float) tripMcDmuObject.getCostCoeff()); + + //catch issues where the trip mode choice DMU was set up without a household or person object + if(tripMcDmuObject.getHouseholdObject()!=null){ + walkDmu.setPersonType(tripMcDmuObject.getTourCategoryJoint()==1 ? walkDmu.getPersonType() : tripMcDmuObject.getPersonType()); + driveDmu.setPersonType(tripMcDmuObject.getTourCategoryJoint()==1 ? driveDmu.getPersonType() : tripMcDmuObject.getPersonType()); + } + // calculate logsum + bestDtwTripTapPairs = bestPathUEC.calcPersonSpecificUtilities(bestDtwTripTapPairs, walkDmu, driveDmu, DTW, origMgra, destMgra, skimPeriodIndex, loggingEnabled, autoSkimLogger, odDistance); + double logsum = bestPathUEC.calcTripLogSum(bestDtwTripTapPairs, loggingEnabled, autoSkimLogger); + tripMcDmuObject.setTransitLogSum( DTW, logsum); + + } + + //select best transit path from N-path for trip + public int chooseTripPath(double rnum, double[][] bestTapPairs, boolean myTrace, Logger myLogger) { + return bestPathUEC.chooseTripPath(rnum, bestTapPairs, myTrace, myLogger); + } + + + public float getTripModeChoiceSegmentStoredParkingCost() { + return tripModeChoiceSegmentStoredParkingCost; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/MicromobilityChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MicromobilityChoiceDMU.java new file mode 100644 index 0000000..356b914 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MicromobilityChoiceDMU.java @@ -0,0 +1,119 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + */ +public class MicromobilityChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(MicromobilityChoiceDMU.class); + + protected HashMap methodIndexMap; + + private IndexValues dmuIndex; + protected double ivtCoeff; + protected double costCoeff; + protected float walkTime; + protected boolean isTransit; + protected boolean microTransitAvailable; + + + public MicromobilityChoiceDMU() + { + dmuIndex = new IndexValues(); + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + } + + + public double getIvtCoeff() { + return ivtCoeff; + } + + public void setIvtCoeff(double ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + public double getCostCoeff() { + return costCoeff; + } + + public void setCostCoeff(double costCoeff) { + this.costCoeff = costCoeff; + } + + public float getWalkTime() { + return walkTime; + } + + public void setWalkTime(float walkTime) { + this.walkTime = walkTime; + } + + public boolean isTransit() { + return isTransit; + } + + public void setTransit(boolean isTransit) { + this.isTransit = isTransit; + } + + public boolean isMicroTransitAvailable() { + return microTransitAvailable; + } + + public void setMicroTransitAvailable(boolean microTransitAvailable) { + this.microTransitAvailable = microTransitAvailable; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/MicromobilityChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MicromobilityChoiceModel.java new file mode 100644 index 0000000..724da7a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MicromobilityChoiceModel.java @@ -0,0 +1,449 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class MicromobilityChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("micromobility"); + + private static final String MM_CONTROL_FILE_TARGET = "micromobility.uec.file"; + private static final String MM_DATA_SHEET_TARGET = "micromobility.data.page"; + private static final String MM_MODEL_SHEET_TARGET = "micromobility.model.page"; + private static final String MT_TAP_FILE_TARGET = "active.microtransit.tap.file"; + private static final String MT_MAZ_FILE_TARGET = "active.microtransit.mgra.file"; + + public static final int MM_MODEL_WALK_ALT = 0; + public static final int MM_MODEL_MICROMOBILITY_ALT = 1; + public static final int MM_MODEL_MICROTRANSIT_ALT = 2; + + + private ChoiceModelApplication mmModel; + private MicromobilityChoiceDMU mmDmuObject; + + // following arrays used to store ivt coefficients, and income coefficients, income exponents to calculate cost coefficient, by tour purpose + double[] ivtCoeffs; + double[] incomeCoeffs; + double[] incomeExponents; + + private static final String PROPERTIES_TRIP_UTILITY_IVT_COEFFS = "trip.utility.ivt.coeffs"; + private static final String PROPERTIES_TRIP_UTILITY_INCOME_COEFFS = "trip.utility.income.coeffs"; + private static final String PROPERTIES_TRIP_UTILITY_INCOME_EXPONENTS = "trip.utility.income.exponents"; + private ModelStructure modelStructure; + private MgraDataManager mgraDataManager; + + private HashSet microtransitTaps; + private HashSet microtransitMazs; + + + public MicromobilityChoiceModel(HashMap propertyMap, + ModelStructure myModelStructure, CtrampDmuFactoryIf dmuFactory) + { + + setupMicromobilityChoiceModelApplication(propertyMap, myModelStructure, dmuFactory); + } + + private void setupMicromobilityChoiceModelApplication(HashMap propertyMap, + ModelStructure myModelStructure, CtrampDmuFactoryIf dmuFactory) + { + logger.info("setting up micromobility choice model."); + + modelStructure = myModelStructure; + + // locate the micromobility choice UEC + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mmUecFile = uecFileDirectory + propertyMap.get(MM_CONTROL_FILE_TARGET); + + int dataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, MM_DATA_SHEET_TARGET); + int modelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, MM_MODEL_SHEET_TARGET); + + // create the micromobility choice model DMU object. + mmDmuObject = dmuFactory.getMicromobilityChoiceDMU(); + + // create the transponder choice model object + mmModel = new ChoiceModelApplication(mmUecFile, modelSheet, dataSheet, propertyMap, + (VariableTable) mmDmuObject); + + + //get the coefficients for ivt and the coefficients to calculate the cost coefficient + ivtCoeffs = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TRIP_UTILITY_IVT_COEFFS); + incomeCoeffs = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TRIP_UTILITY_INCOME_COEFFS); + incomeExponents = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TRIP_UTILITY_INCOME_EXPONENTS); + + mgraDataManager = MgraDataManager.getInstance(); + + String projectDirectory = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String microTransitTapFile = projectDirectory + propertyMap.get(MT_TAP_FILE_TARGET); + String microTransitMazFile = projectDirectory + propertyMap.get(MT_MAZ_FILE_TARGET); + + TableDataSet microTransitTapData = Util.readTableDataSet(microTransitTapFile); + TableDataSet microTransitMazData = Util.readTableDataSet(microTransitMazFile); + + microtransitTaps = new HashSet(); + microtransitMazs = new HashSet(); + + for(int i=1;i<=microTransitTapData.getRowCount();++i) { + + int tap = (int) microTransitTapData.getValueAt(i,"TAP"); + microtransitTaps.add(tap); + } + + for(int i=1;i<=microTransitMazData.getRowCount();++i) { + + int maz = (int) microTransitMazData.getValueAt(i,"MGRA"); + microtransitMazs.add(maz); + } + + + } + + + /** + * Apply model to all trips for the household. + * + * @param household + */ + public void applyModel(Household household) { + + for(Person person : household.getPersons()) { + + if(person==null) + continue; + + //work tours + if(person.getListOfWorkTours()!=null) { + + for(Tour tour:person.getListOfWorkTours()) + applyModel(household, person, tour); + } + + //school tours + if(person.getListOfSchoolTours()!=null) { + + for(Tour tour:person.getListOfSchoolTours()) + applyModel(household, person, tour); + } + + //non-mandatory tours + if(person.getListOfIndividualNonMandatoryTours()!=null) { + + for(Tour tour:person.getListOfIndividualNonMandatoryTours()) + applyModel(household, person, tour); + } + + //at-work sub tours + if(person.getListOfAtWorkSubtours()!=null) { + + for(Tour tour:person.getListOfAtWorkSubtours()) + applyModel(household, person, tour); + } + + } + + + } + + public void applyModel(Household household, Person person, Tour tour) { + + //apply to outbound stops + if(tour.getOutboundStops()!=null) { + + for(Stop s: tour.getOutboundStops()) + applyModel(household, person, tour, s); + } + + //apply to inbound stops + if(tour.getInboundStops()!=null) { + + for(Stop s: tour.getInboundStops()) + applyModel(household, person, tour, s); + } + + + } + + public void applyModel(Household household, Person person, Tour tour, Stop s) + { + + if(tour==null) + return; + + + if(!modelStructure.getTourModeIsWalk(s.getMode()) && !modelStructure.getTourModeIsWalkTransit(s.getMode())&& !modelStructure.getTourModeIsDriveTransit(s.getMode())) + return; + + int homeMaz = household.getHhMgra(); + double income = (double) household.getIncomeInDollars(); + + int category = IntermediateStopChoiceModels.PURPOSE_CATEGORIES[tour.getTourPrimaryPurposeIndex()]; + double ivtCoeff = ivtCoeffs[category]; + double incomeCoeff = incomeCoeffs[category]; + double incomeExpon = incomeExponents[category]; + double costCoeff = calculateCostCoefficient(income, incomeCoeff,incomeExpon); + double timeFactor = 1.0f; + if(tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + timeFactor = tour.getJointTourTimeFactor(); + else if(tour.getTourPrimaryPurposeIndex()==ModelStructure.WORK_PRIMARY_PURPOSE_INDEX) + timeFactor = person.getTimeFactorWork(); + else + timeFactor = person.getTimeFactorNonWork(); + + mmDmuObject.setIvtCoeff(ivtCoeff * timeFactor); + mmDmuObject.setCostCoeff(costCoeff); + int originMaz = s.getOrig(); + int destMaz = s.getDest(); + + if(modelStructure.getTourModeIsWalk(s.getMode())) + mmDmuObject.setTransit(false); + else + mmDmuObject.setTransit(true); + + if(modelStructure.getTourModeIsWalk(s.getMode())) { + + float walkTime = mgraDataManager.getMgraToMgraWalkTime(originMaz, destMaz); + mmDmuObject.setWalkTime(walkTime); + + if(microtransitMazs.contains(originMaz) && microtransitMazs.contains(destMaz)) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + + //set destination to origin so that Z can be used to find origin zone access to mode in mgra data file in UEC + mmDmuObject.setDmuIndexValues(household.getHhId(), originMaz, originMaz, originMaz); + + // compute utilities and choose micromobility choice alternative. + float logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + s.setMicromobilityWalkLogsum(logsum); + + // if the choice model has at least one available alternative, make choice + byte chosenAlt = (byte) getChoice(household, person, tour, s); + s.setMicromobilityWalkMode(chosenAlt); + + // write choice model alternative info to log file + if (household.getDebugChoiceModels()) + { + String decisionMaker = String.format("Household " + household.getHhId()+ "Person " + person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + //String decisionMaker = String.format("Household %d", household.getHhId()+ "Person %d", person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Micromobility Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + + }else if(modelStructure.getTourModeIsWalkTransit(s.getMode())) { + + //access + int tapPosition = mgraDataManager.getTapPosition(originMaz, s.boardTap); + if(tapPosition==-1) { + logger.warn("Problem with hh "+household.getHhId()+" Person "+person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + logger.warn("Origin MAZ "+originMaz+ " Board TAP "+s.boardTap+ " Alight TAP "+s.alightTap+" Destination MAZ "+destMaz); + logger.warn("Can't find walk connection from origin to board TAP; skipping micromobility choice"); + return; + } + float walkTime = mgraDataManager.getMgraToTapWalkTime(originMaz, tapPosition); + mmDmuObject.setWalkTime(walkTime); + + if(microtransitMazs.contains(originMaz) && microtransitTaps.contains(s.boardTap)) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + + //set destination to origin so that Z can be used to find origin zone access to mode in mgra data file in UEC + mmDmuObject.setDmuIndexValues(household.getHhId(), originMaz, originMaz, originMaz); + + // compute utilities and choose micromobility choice alternative. + float logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + s.setMicromobilityAccessLogsum(logsum); + + // if the choice model has at least one available alternative, make choice + byte chosenAlt = (byte) getChoice(household, person, tour, s); + s.setMicromobilityAccessMode(chosenAlt); + + // write choice model alternative info to log file + if (household.getDebugChoiceModels()) + { + String decisionMaker = String.format("Household " + household.getHhId()+ "Person " + person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + //String decisionMaker = String.format("Household %d", household.getHhId()+ "Person %d", person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()+ " access choice"); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Micromobility Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + //egress + tapPosition = mgraDataManager.getTapPosition(destMaz, s.alightTap); + if(tapPosition==-1) { + logger.warn("Problem with hh "+household.getHhId()+" Person "+person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + logger.warn("Origin MAZ "+originMaz+ " Board TAP "+s.boardTap+ " Alight TAP "+s.alightTap+" Destination MAZ "+destMaz); + logger.warn("Can't find walk connection from alight TAP to destination; skipping micromobility choice"); + return; + } + walkTime = mgraDataManager.getMgraToTapWalkTime(destMaz, tapPosition); + mmDmuObject.setWalkTime(walkTime); + + if(microtransitMazs.contains(destMaz) && microtransitTaps.contains(s.alightTap)) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + //set destination to closest mgra to alighting TAP so that Z can be used to find access to mode in mgra data file in UEC + int closestMazToAlightTap = mgraDataManager.getClosestMgra(s.alightTap); + mmDmuObject.setDmuIndexValues(household.getHhId(), closestMazToAlightTap, closestMazToAlightTap, closestMazToAlightTap); + + // compute utilities and choose micromobility choice alternative. + logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + s.setMicromobilityEgressLogsum(logsum); + + // if the choice model has at least one available alternative, make choice + chosenAlt = (byte) getChoice(household, person, tour, s); + s.setMicromobilityEgressMode(chosenAlt); + + // write choice model alternative info to log file + if (household.getDebugChoiceModels()) + { + String decisionMaker = String.format("Household " + household.getHhId()+ "Person " + person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + //String decisionMaker = String.format("Household %d", household.getHhId()+ "Person %d", person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()+ " egress choice"); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Micromobility Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + + + } else if( modelStructure.getTourModeIsDriveTransit(s.getMode()) ) { //drive-transit. Choose non-drive direction + + int tapPosition = 0; + float walkTime = 9999; + + if(s.isInboundStop()) { //inbound, so access mode is walk + tapPosition = mgraDataManager.getTapPosition(originMaz, s.boardTap); + if(tapPosition==-1) { + logger.warn("Problem with hh "+household.getHhId()+" Person "+person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + logger.warn("Origin MAZ "+originMaz+ " Board TAP "+s.boardTap+ " Alight TAP "+s.alightTap+" Destination MAZ "+destMaz); + logger.warn("Can't find walk connection from origin to board TAP; skipping micromobility choice"); + return; + } + + walkTime = mgraDataManager.getMgraToTapWalkTime(originMaz, tapPosition); + //set destination to origin so that Z can be used to find origin zone access to mode in mgra data file in UEC + mmDmuObject.setDmuIndexValues(household.getHhId(), originMaz, originMaz, originMaz); + + if(microtransitMazs.contains(originMaz) && microtransitTaps.contains(s.boardTap)) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + }else { //outbound so egress mode is walk. + tapPosition = mgraDataManager.getTapPosition(destMaz, s.alightTap); + if(tapPosition==-1) { + logger.warn("Problem with hh "+household.getHhId()+" Person "+person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + logger.warn("Origin MAZ "+originMaz+ " Board TAP "+s.boardTap+ " Alight TAP "+s.alightTap+" Destination MAZ "+destMaz); + logger.warn("Can't find walk connection from destination MAZ to alight TAP; skipping micromobility choice"); + return; + } + walkTime = mgraDataManager.getMgraToTapWalkTime(destMaz, tapPosition); + //set destination to closest mgra to alighting TAP so that Z can be used to find access to mode in mgra data file in UEC + int closestMazToAlightTap = mgraDataManager.getClosestMgra(s.alightTap); + mmDmuObject.setDmuIndexValues(household.getHhId(), closestMazToAlightTap, closestMazToAlightTap, closestMazToAlightTap); + + if(microtransitMazs.contains(destMaz) && microtransitTaps.contains(s.alightTap)) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + } + mmDmuObject.setWalkTime(walkTime); + + // compute utilities and choose micromobility choice alternative. + float logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + + // if the choice model has at least one available alternative, make choice + byte chosenAlt = (byte) getChoice(household, person, tour, s); + + if(s.isInboundStop()) { //inbound, set access + s.setMicromobilityAccessMode(chosenAlt); + s.setMicromobilityAccessLogsum(logsum); + }else { //outound, set egress + s.setMicromobilityEgressMode(chosenAlt); + s.setMicromobilityEgressLogsum(logsum); + } + + // write choice model alternative info to log file + if (household.getDebugChoiceModels()) + { + String decisionMaker = String.format("Household " + household.getHhId()+ "Person " + person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + //String decisionMaker = String.format("Household %d", household.getHhId()+ "Person %d", person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Micromobility Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + + } + + } + + + /** + * Select the micromobility mode from the UEC. This is helper code for applyModel(), where utilities have already been calculated. + * + * @param household + * @param person + * @param tour + * @param s + * @return The micromobility mode. + */ + private int getChoice(Household household, Person person, Tour tour, Stop s) { + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + Random hhRandom = household.getHhRandom(); + if (mmModel.getAvailabilityCount() > 0) + { + double randomNumber = hhRandom.nextDouble(); + chosenAlt = mmModel.getChoiceResult(randomNumber); + return chosenAlt; + } else + { + String decisionMaker = String.format("Household " + household.getHhId()+ "Person " + person.getPersonNum()+" "+tour.getTourCategory()+" tour ID "+tour.getTourId()+ "stop "+s.getStopId()+ " mode " +s.getMode()); + String errorMessage = String + .format("Exception caught for %s, no available micromobility choice alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.info(errorMessage); + logger.info("Setting mode to walk"); + + mmModel.logUECResults(logger, decisionMaker); + return MM_MODEL_WALK_ALT; + } + + } + + /** + * This method calculates a cost coefficient based on the following formula: + * + * costCoeff = incomeCoeff * 1/(max(income,1000)^incomeExponent) + * + * + * @param incomeCoeff + * @param incomeExponent + * @return A cost coefficent that should be multiplied by cost variables (cents) in tour mode choice + */ + public double calculateCostCoefficient(double income, double incomeCoeff, double incomeExponent){ + + return incomeCoeff * 1.0/(Math.pow(Math.max(income,1000.0),incomeExponent)); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/ModelStructure.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ModelStructure.java new file mode 100644 index 0000000..db7b60e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ModelStructure.java @@ -0,0 +1,600 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; + +/** + * Holds the tour purpose list as well as the market segments for each tour. + * + * @author D. Ory + * + */ +public abstract class ModelStructure + implements Serializable +{ + + public static final String[] DC_SIZE_AREA_TYPE_BASED_SEGMENTS = {"CBD", + "URBAN", "SUBURBAN", "RURAL" }; + + public static final String MANDATORY_CATEGORY = "MANDATORY"; + public static final String JOINT_NON_MANDATORY_CATEGORY = "JOINT_NON_MANDATORY"; + public static final String INDIVIDUAL_NON_MANDATORY_CATEGORY = "INDIVIDUAL_NON_MANDATORY"; + public static final String AT_WORK_CATEGORY = "AT_WORK"; + + public static final String MANDATORY_PATTERN = "M"; + public static final String NONMANDATORY_PATTERN = "N"; + public static final String HOME_PATTERN = "H"; + + public static final int FIRST_DEPART_HOUR = 4; + public static final int LAST_DEPART_HOUR = 24; + public static final int FIRST_TOD_INTERVAL_HOUR = 430; + public static final int LAST_TOD_INTERVAL_HOUR = 2400; + public static final float TOD_INTERVAL_IN_MINUTES = 30.0f; + public static final int MAX_TOD_INTERVAL = 40; + protected String[] TOD_INTERVAL_LABELS; + + public static final int EA_SKIM_PERIOD_INDEX = 0; + public static final int AM_SKIM_PERIOD_INDEX = 1; + public static final int MD_SKIM_PERIOD_INDEX = 2; + public static final int PM_SKIM_PERIOD_INDEX = 3; + public static final int EV_SKIM_PERIOD_INDEX = 4; + public static final int[] SKIM_PERIOD_INDICES = { + EA_SKIM_PERIOD_INDEX, AM_SKIM_PERIOD_INDEX, MD_SKIM_PERIOD_INDEX, PM_SKIM_PERIOD_INDEX, + EV_SKIM_PERIOD_INDEX }; + + public static final int[] PERIODCODES = { EA_SKIM_PERIOD_INDEX, AM_SKIM_PERIOD_INDEX, + MD_SKIM_PERIOD_INDEX, PM_SKIM_PERIOD_INDEX, EV_SKIM_PERIOD_INDEX }; + + public static final String[] SKIM_PERIOD_STRINGS = {"EA", + "AM", "MD", "PM", "EV" }; + + // define indices associated with valid skim period combinations + public static final int EA_EA = 0; + public static final int EA_AM = 1; + public static final int EA_MD = 2; + public static final int EA_PM = 3; + public static final int EA_EV = 4; + // AM cannot be before EA + public static final int AM_EA = -1; + public static final int AM_AM = 5; + public static final int AM_MD = 6; + public static final int AM_PM = 7; + public static final int AM_EV = 8; + // MD cannot be before EA or AM + public static final int MD_EA = -1; + public static final int MD_AM = -1; + public static final int MD_MD = 9; + public static final int MD_PM = 10; + public static final int MD_EV = 11; + // PM cannot be before EA, AM or PM + public static final int PM_EA = -1; + public static final int PM_AM = -1; + public static final int PM_MD = -1; + public static final int PM_PM = 12; + public static final int PM_EV = 13; + // EV cannot be before EA, AM, MD or PM + public static final int EV_EA = -1; + public static final int EV_AM = -1; + public static final int EV_MD = -1; + public static final int EV_PM = -1; + public static final int EV_EV = 14; + + // define an array that contains the set of the valid skim period + // combination indices + public static final int[] SKIM_PERIOD_COMBINATION_INDICES = {EA_EA, + EA_AM, EA_MD, EA_PM, EA_EV, AM_AM, AM_MD, AM_PM, AM_EV, MD_MD, MD_PM, MD_EV, PM_PM, + PM_EV, EV_EV }; + + // define a 2-D array for the set of skim period combinations associatedf + // with each skim period index value + public static final int[][] SKIM_PERIOD_COMBINATIONS = { + {EA_EA, EA_AM, EA_MD, EA_PM, EA_EV}, {AM_EA, AM_AM, AM_MD, AM_PM, AM_EV}, + {MD_EA, MD_AM, MD_MD, MD_PM, MD_EV}, {PM_EA, PM_AM, PM_MD, PM_PM, PM_EV}, + {EV_EA, EV_AM, EV_MD, EV_PM, EV_EV} }; + + // define model period labels associated with each model period index + public static final String[] MODEL_PERIOD_LABELS = {"EA", + "AM", "MD", "PM", "EV" }; + + // the upper TOD interval index for each model period (EA:1-3, AM:6-9, + // MD:10-22, PM:23-29, EV:30-40) + public static final int UPPER_EA = 3; + public static final int UPPER_AM = 9; + public static final int UPPER_MD = 22; + public static final int UPPER_PM = 29; + + public static final int[] PERIOD_ENDS = {UPPER_EA,UPPER_AM,UPPER_MD,UPPER_PM, 40}; + + private HashMap indexTimePeriodMap; + private HashMap timePeriodIndexMap; + + public static final int WORKS_AT_HOME_ALTERNATUVE_INDEX = 2; + public static final int WORKS_AT_HOME_LOCATION_INDICATOR = 99999; + public static final int NOT_ENROLLED_SEGMENT_INDEX = 88888; + + private HashMap primaryTourPurposeNameIndexMap = new HashMap(); + private HashMap indexPrimaryTourPurposeNameMap = new HashMap(); + + public static final String WORK_PRIMARY_PURPOSE_NAME = "Work"; + public static final String UNIVERSITY_PRIMARY_PURPOSE_NAME = "University"; + public static final String SCHOOL_PRIMARY_PURPOSE_NAME = "School"; + public static final String ESCORT_PRIMARY_PURPOSE_NAME = "Escort"; + public static final String SHOPPING_PRIMARY_PURPOSE_NAME = "Shop"; + public static final String OTH_MAINT_PRIMARY_PURPOSE_NAME = "Maintenance"; + public static final String EAT_OUT_PRIMARY_PURPOSE_NAME = "Eating Out"; + public static final String VISITING_PRIMARY_PURPOSE_NAME = "Visiting"; + public static final String OTH_DISCR_PRIMARY_PURPOSE_NAME = "Discretionary"; + public static final String WORK_BASED_PRIMARY_PURPOSE_NAME = "Work-Based"; + + public static final int WORK_PRIMARY_PURPOSE_INDEX = 1; + public static final int UNIVERSITY_PRIMARY_PURPOSE_INDEX = 2; + public static final int SCHOOL_PRIMARY_PURPOSE_INDEX = 3; + public static final int ESCORT_PRIMARY_PURPOSE_INDEX = 4; + public static final int SHOPPING_PRIMARY_PURPOSE_INDEX = 5; + public static final int OTH_MAINT_PRIMARY_PURPOSE_INDEX = 6; + public static final int EAT_OUT_PRIMARY_PURPOSE_INDEX = 7; + public static final int VISITING_PRIMARY_PURPOSE_INDEX = 8; + public static final int OTH_DISCR_PRIMARY_PURPOSE_INDEX = 9; + public static final int WORK_BASED_PRIMARY_PURPOSE_INDEX = 10; + public static final int NUM_PRIMARY_PURPOSES = 10; + + public static final int WORK_STOP_PURPOSE_INDEX = 1; + public static final int UNIV_STOP_PURPOSE_INDEX = 2; + public static final int ESCORT_STOP_PURPOSE_INDEX = 4; + public static final int SHOP_STOP_PURPOSE_INDEX = 5; + public static final int MAINT_STOP_PURPOSE_INDEX = 6; + public static final int EAT_OUT_STOP_PURPOSE_INDEX = 7; + public static final int VISIT_STOP_PURPOSE_INDEX = 8; + public static final int DISCR_STOP_PURPOSE_INDEX = 9; + + public static final byte ESCORT_STOP_TYPE_DROPOFF = 1; + public static final byte ESCORT_STOP_TYPE_PICKUP = 2; + public static final int RIDE_SHARING_TYPE = 1; + public static final int PURE_ESCORTING_TYPE = 2; + + public static final int MAX_STOPS_PER_DIRECTION = 4; + + public String WORK_PURPOSE_NAME; + public String UNIVERSITY_PURPOSE_NAME; + public String SCHOOL_PURPOSE_NAME; + public String ESCORT_PURPOSE_NAME; + public String SHOPPING_PURPOSE_NAME; + public String EAT_OUT_PURPOSE_NAME; + public String OTH_MAINT_PURPOSE_NAME; + public String SOCIAL_PURPOSE_NAME; + public String OTH_DISCR_PURPOSE_NAME; + public String AT_WORK_PURPOSE_NAME; + public String AT_WORK_EAT_PURPOSE_NAME; + public String AT_WORK_BUSINESS_PURPOSE_NAME; + public String AT_WORK_MAINT_PURPOSE_NAME; + + public int AT_WORK_PURPOSE_INDEX_EAT; + public int AT_WORK_PURPOSE_INDEX_BUSINESS; + public int AT_WORK_PURPOSE_INDEX_MAINT; + + public String[] ESCORT_SEGMENT_NAMES; + public String[] AT_WORK_SEGMENT_NAMES; + + protected HashMap workSegmentNameIndexMap; + protected HashMap schoolSegmentNameIndexMap; + protected HashMap workSegmentIndexNameMap; + protected HashMap schoolSegmentIndexNameMap; + + // TODO: Determine which of the following can be eliminated + protected HashMap dcSoaUecIndexMap; + protected HashMap dcUecIndexMap; + protected HashMap tourModeChoiceUecIndexMap; + + protected HashMap dcSizeDcModelPurposeMap; + protected HashMap dcModelDcSizePurposeMap; + + protected HashMap dcModelPurposeIndexMap; // segments + // for + // which + // dc + // soa alternative models + // are applied + protected HashMap dcModelIndexPurposeMap; // segments + // for + // which + // dc + // soa alternative models + // are applied + + protected HashMap dcSizeSegmentIndexMap; // segments + // for + // which + // separate dc size + // coefficients are + // specified + protected HashMap dcSizeIndexSegmentMap; + protected HashMap dcSizeArrayPurposeIndexMap; // segments + // for + // which + // dc + // size terms are stored + protected HashMap dcSizeArrayIndexPurposeMap; + protected HashMap> dcSizePurposeSegmentMap; + + private String dcSizeCoeffPurposeFieldName = "purpose"; + private String dcSizeCoeffSegmentFieldName = "segment"; + + // TODO meld with what jim is doing on this front + protected String[] mandatoryDcModelPurposeNames; + protected String[] jointDcModelPurposeNames; + protected String[] nonMandatoryDcModelPurposeNames; + protected String[] atWorkDcModelPurposeNames; + + protected String workPurposeName; + protected String universityPurposeName; + protected String schoolPurposeName; + + protected String[] workPurposeSegmentNames; + protected String[] universityPurposeSegmentNames; + protected String[] schoolPurposeSegmentNames; + + protected HashMap stopFreqUecIndexMap; + protected HashMap stopLocUecIndexMap; + protected HashMap tripModeChoiceUecIndexMap; + + protected String[] jtfAltLabels; + protected String[] awfAltLabels; + + /** + * Assume name of the columns in the destination size coefficients file that + * contain the purpose strings is "purpose" and the column that contains the + * segment strings is "segment" + */ + public ModelStructure() + { + + workSegmentNameIndexMap = new HashMap(); + schoolSegmentNameIndexMap = new HashMap(); + workSegmentIndexNameMap = new HashMap(); + schoolSegmentIndexNameMap = new HashMap(); + + dcModelPurposeIndexMap = new HashMap(); + dcModelIndexPurposeMap = new HashMap(); + dcSoaUecIndexMap = new HashMap(); + dcUecIndexMap = new HashMap(); + tourModeChoiceUecIndexMap = new HashMap(); + stopFreqUecIndexMap = new HashMap(); + stopLocUecIndexMap = new HashMap(); + tripModeChoiceUecIndexMap = new HashMap(); + + // create a mapping between primary purpose + // names and purpose indices + createPrimaryPurposeMappings(); + + createIndexTimePeriodMap(); + + } + + public abstract HashMap getWorkSegmentNameIndexMap(); + + public abstract HashMap getSchoolSegmentNameIndexMap(); + + public abstract HashMap getWorkSegmentIndexNameMap(); + + public abstract HashMap getSchoolSegmentIndexNameMap(); + + // a derived class must implement these methods to retrieve purpose names + // for + // various personTypes making mandatory tours. + public abstract String getWorkPurpose(int incomeCategory); + + public abstract String getWorkPurpose(boolean isPtWorker, int incomeCategory); + + public abstract String getUniversityPurpose(); + + public abstract String getSchoolPurpose(int age); + + public abstract boolean getTourModeIsSov(int tourMode); + + public abstract boolean getTourModeIsSovOrHov(int tourMode); + + public abstract boolean getTourModeIsS2(int tourMode); + + public abstract boolean getTourModeIsS3(int tourMode); + + public abstract boolean getTourModeIsHov(int tourMode); + + public abstract boolean getTourModeIsNonMotorized(int tourMode); + + public abstract boolean getTourModeIsBike(int tourMode); + + public abstract boolean getTourModeIsWalk(int tourMode); + + public abstract boolean getTourModeIsTransit(int tourMode); + + public abstract boolean getTourModeIsWalkTransit(int tourMode); + + public abstract boolean getTourModeIsDriveTransit(int tourMode); + + public abstract boolean getTourModeIsPnr(int tourMode); + + public abstract boolean getTourModeIsKnr(int tourMode); + + public abstract boolean getTourModeIsSchoolBus(int tourMode); + + public abstract boolean getTourModeIsTncTransit(int tripMode); + + public abstract boolean getTourModeIsMaas(int tripMode); + + public abstract boolean getTripModeIsSovOrHov(int tripMode); + + public abstract boolean getTripModeIsWalkTransit(int tripMode); + + public abstract boolean getTripModeIsPnrTransit(int tripMode); + + public abstract boolean getTripModeIsKnrTransit(int tripMode); + + public abstract boolean getTripModeIsTransit(int tripMode); + + public abstract boolean getTripModeIsS2(int tripMode); + + public abstract boolean getTripModeIsS3(int tripMode); + + public abstract double[][] getCdap6PlusProps(); + + public abstract int getDefaultAmPeriod(); + + public abstract int getDefaultPmPeriod(); + + public abstract int getDefaultMdPeriod(); + + public abstract int getMaxTourModeIndex(); + + public abstract String getModelPeriodLabel(int period); + + public abstract int[] getSkimPeriodCombinationIndices(); + + public abstract int getSkimPeriodCombinationIndex(int startPeriod, int endPeriod); + + public abstract String getSkimMatrixPeriodString(int period); + + public abstract HashMap> getDcSizePurposeSegmentMap(); + + public abstract String[] getJtfAltLabels(); + + public abstract void setJtfAltLabels(String[] labels); + + private void createPrimaryPurposeMappings() + { + + primaryTourPurposeNameIndexMap.put(WORK_PRIMARY_PURPOSE_NAME, WORK_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(WORK_PRIMARY_PURPOSE_INDEX, WORK_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(UNIVERSITY_PRIMARY_PURPOSE_NAME, + UNIVERSITY_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(UNIVERSITY_PRIMARY_PURPOSE_INDEX, + UNIVERSITY_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(SCHOOL_PRIMARY_PURPOSE_NAME, + SCHOOL_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(SCHOOL_PRIMARY_PURPOSE_INDEX, + SCHOOL_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(ESCORT_PRIMARY_PURPOSE_NAME, + ESCORT_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(ESCORT_PRIMARY_PURPOSE_INDEX, + ESCORT_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(SHOPPING_PRIMARY_PURPOSE_NAME, + SHOPPING_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(SHOPPING_PRIMARY_PURPOSE_INDEX, + SHOPPING_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(OTH_MAINT_PRIMARY_PURPOSE_NAME, + OTH_MAINT_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(OTH_MAINT_PRIMARY_PURPOSE_INDEX, + OTH_MAINT_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(EAT_OUT_PRIMARY_PURPOSE_NAME, + EAT_OUT_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(EAT_OUT_PRIMARY_PURPOSE_INDEX, + EAT_OUT_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(VISITING_PRIMARY_PURPOSE_NAME, + VISITING_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(VISITING_PRIMARY_PURPOSE_INDEX, + VISITING_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(OTH_DISCR_PRIMARY_PURPOSE_NAME, + OTH_DISCR_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(OTH_DISCR_PRIMARY_PURPOSE_INDEX, + OTH_DISCR_PRIMARY_PURPOSE_NAME); + primaryTourPurposeNameIndexMap.put(WORK_BASED_PRIMARY_PURPOSE_NAME, + WORK_BASED_PRIMARY_PURPOSE_INDEX); + indexPrimaryTourPurposeNameMap.put(WORK_BASED_PRIMARY_PURPOSE_INDEX, + WORK_BASED_PRIMARY_PURPOSE_NAME); + + } + + /** + * @return the HashMap object that maps primary tour purpose + * names common to all CTRAMP implementations to indices (1-10). + */ + public HashMap getPrimaryPurposeNameIndexMap() + { + return primaryTourPurposeNameIndexMap; + } + + /** + * @return the HashMap object that maps indices (1-10) to + * primary tour purpose names common to all CTRAMP implementations. + */ + public HashMap getIndexPrimaryPurposeNameMap() + { + return indexPrimaryTourPurposeNameMap; + } + + /** + * @param purposeKey + * is the "purpose" name used as a key for the map to get the + * associated UEC tab number. + * @return the tab number of the UEC control file for the purpose + */ + public int getSoaUecIndexForPurpose(String purposeKey) + { + return dcSoaUecIndexMap.get(purposeKey); + } + + /** + * @param purposeKey + * is the "purpose" name used as a key for the map to get the + * associated UEC tab number. + * @return the tab number of the UEC control file for the purpose + */ + public int getDcUecIndexForPurpose(String purposeKey) + { + return dcUecIndexMap.get(purposeKey); + } + + /** + * @param purposeKey + * is the "purpose" name used as a key for the map to get the + * associated UEC tab number. + * @return the tab number of the UEC control file for the purpose + */ + public int getTourModeChoiceUecIndexForPurpose(String purposeKey) + { + return tourModeChoiceUecIndexMap.get(purposeKey); + } + + public String[] getDcModelPurposeList(String tourCategory) + { + if (tourCategory.equalsIgnoreCase(MANDATORY_CATEGORY)) return mandatoryDcModelPurposeNames; + else if (tourCategory.equalsIgnoreCase(JOINT_NON_MANDATORY_CATEGORY)) return jointDcModelPurposeNames; + else if (tourCategory.equalsIgnoreCase(INDIVIDUAL_NON_MANDATORY_CATEGORY)) return nonMandatoryDcModelPurposeNames; + else if (tourCategory.equalsIgnoreCase(AT_WORK_CATEGORY)) return atWorkDcModelPurposeNames; + else return null; + } + + public String getDcSizeCoeffPurposeFieldName() + { + return dcSizeCoeffPurposeFieldName; + } + + public String getDcSizeCoeffSegmentFieldName() + { + return this.dcSizeCoeffSegmentFieldName; + } + + public String getAtWorkEatPurposeName() + { + return AT_WORK_EAT_PURPOSE_NAME; + } + + public String[] getAtWorkSegmentNames() + { + return AT_WORK_SEGMENT_NAMES; + } + + public String getAtWorkBusinessPurposeName() + { + return AT_WORK_BUSINESS_PURPOSE_NAME; + } + + public String getAtWorkMaintPurposeName() + { + return AT_WORK_MAINT_PURPOSE_NAME; + } + + public int getAtWorkEatPurposeIndex() + { + return AT_WORK_PURPOSE_INDEX_EAT; + } + + public int getAtWorkBusinessPurposeIndex() + { + return AT_WORK_PURPOSE_INDEX_BUSINESS; + } + + public int getAtWorkMaintPurposeIndex() + { + return AT_WORK_PURPOSE_INDEX_MAINT; + } + + /** + * @param departPeriod + * is the model TOD interval for the departure period (for tour + * or trip) + * @return the skim period index associated with the departure interval + */ + public static int getSkimPeriodIndex(int departPeriod) + { + + int skimPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) skimPeriodIndex = EA_SKIM_PERIOD_INDEX; + else if (departPeriod <= UPPER_AM) skimPeriodIndex = AM_SKIM_PERIOD_INDEX; + else if (departPeriod <= UPPER_MD) skimPeriodIndex = MD_SKIM_PERIOD_INDEX; + else if (departPeriod <= UPPER_PM) skimPeriodIndex = PM_SKIM_PERIOD_INDEX; + else skimPeriodIndex = EV_SKIM_PERIOD_INDEX; + + return skimPeriodIndex; + + } + + /** + * @param departPeriod + * is the model TOD interval for the departure period (for tour + * or trip) + * @return the model period index associated with the departure interval + * Model periods: 0=EA, 1=AM, 2=MD, 3=PM, 4=EV + */ + public static int getModelPeriodIndex(int departPeriod) + { + + int modelPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) modelPeriodIndex = 0; + else if (departPeriod <= UPPER_AM) modelPeriodIndex = 1; + else if (departPeriod <= UPPER_MD) modelPeriodIndex = 2; + else if (departPeriod <= UPPER_PM) modelPeriodIndex = 3; + else modelPeriodIndex = 4; + + return modelPeriodIndex; + + } + + private void createIndexTimePeriodMap() + { + indexTimePeriodMap = new HashMap(); + timePeriodIndexMap = new HashMap(); + + int numHours = LAST_DEPART_HOUR - FIRST_DEPART_HOUR; + int numHalfHours = numHours * 2; + + TOD_INTERVAL_LABELS = new String[numHalfHours + 1]; + + for (int i = 1; i <= numHalfHours; i++) + { + int time = ((int) (i / 2) + FIRST_DEPART_HOUR) * 100 + (i % 2) * 30; + indexTimePeriodMap.put(i, time); + timePeriodIndexMap.put(time, i); + TOD_INTERVAL_LABELS[i] = Integer.toString(time); + } + } + + public String[] getTimePeriodLabelArray() + { + return TOD_INTERVAL_LABELS; + } + + public String getTimePeriodLabel(int timePeriodIndex) + { + return TOD_INTERVAL_LABELS[timePeriodIndex]; + } + + // time argument is specified as: 500 for 5 am, 530 for 5:30 am, 1530 for + // 3:30 pm, etc. + public int getTimePeriodIndexForTime(int time) + { + return timePeriodIndexMap.get(time); + } + + public int getNumberOfTimePeriods() + { + return TOD_INTERVAL_LABELS.length - 1; + } + + public String[] getAwfAltLabels() + { + return awfAltLabels; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/MyLogit.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MyLogit.java new file mode 100644 index 0000000..29fc670 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/MyLogit.java @@ -0,0 +1,115 @@ +package org.sandag.abm.ctramp; + +import com.pb.common.math.MathUtil; +import com.pb.common.model.Alternative; +import com.pb.common.model.LogitModel; +import com.pb.common.model.ModelException; + +public class MyLogit + extends LogitModel +{ + + private static final int MAX_EXP_ARGUMENT = 400; + + private double[] utilities; + private double[] util; + private double[] constant; + private String[] altName; + + public MyLogit(String n, int numberOfAlternatives) + { + super(n, numberOfAlternatives); + + utilities = new double[numberOfAlternatives]; + util = new double[numberOfAlternatives]; + constant = new double[numberOfAlternatives]; + altName = new String[numberOfAlternatives]; + + nf.setMaximumFractionDigits(8); + nf.setMinimumFractionDigits(8); + } + + /** + * Overrides the base class getUtility() method to call a method to return + * the array of exponentiated utilities, having passed to it an array of + * utilities. + * + * @return The composite utility (logsum value) of all the alternatives. + */ + public double getUtility() throws ModelException + { + + double sum = 0; + double base = 0; + + // get the array of utility values to be exponentiated from the + // alternatives + // objects. + int i = 0; + for (int alt = 0; alt < alternatives.size(); ++alt) + { + Alternative thisAlt = (Alternative) alternatives.get(alt); + if (thisAlt.isAvailable()) + { + + // assign attributes of the alternatives + util[i] = thisAlt.getUtility(); + constant[i] = thisAlt.getConstant(); + altName[i] = thisAlt.getName(); + + // if alternative has a very large negative utility, it isn't + // available + if (util[i] + constant[i] < -MAX_EXP_ARGUMENT) + { + utilities[i] = -MAX_EXP_ARGUMENT; + } else + { + utilities[i] = dispersionParameter * (util[i] + constant[i]); + setAvailability(true); + } + + i++; + } else + { + utilities[i++] = -MAX_EXP_ARGUMENT; + } + } + + // exponentiate the utilities array and save result in expUtilities. + MathUtil.expArray(utilities, expUtilities); + + // sum the exponentiated utilities + for (i = 0; i < expUtilities.length; i++) + sum += expUtilities[i]; + + // if debug, and the alternatives is elemental, log the utility values + if (debug) + { + for (i = 0; i < expUtilities.length; i++) + { + Boolean elemental = (Boolean) isElementalAlternative.get(i); + if (elemental.equals(Boolean.TRUE)) + logger.info(String.format("%-20s", altName[i]) + "\t\t" + nf.format(util[i]) + + "\t\t\t" + nf.format(constant[i]) + "\t\t\t" + + nf.format(Math.exp(utilities[i]))); + } + } + + if (isAvailable()) + { + base = (1 / dispersionParameter) * MathUtil.log(sum); + + if (Double.isNaN(base)) throw new ModelException(ModelException.INVALID_UTILITY); + + if (debug) + logger.info(String.format("%-20s", getName() + " logsum:") + "\t\t" + + nf.format(base)); + + return base; + } + + // if nothing avaiable, return a bad utilty + return -999; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/NonMandatoryDestChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/NonMandatoryDestChoiceModel.java new file mode 100644 index 0000000..04a5ecc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/NonMandatoryDestChoiceModel.java @@ -0,0 +1,1527 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.Random; +import java.util.ResourceBundle; + +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.IndexSort; +import com.pb.common.util.ResourceUtil; +import com.pb.common.newmodel.ChoiceModelApplication; +import org.apache.log4j.Logger; + +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import org.sandag.abm.accessibilities.NonTransitUtilities; +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagHouseholdDataManager; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampDmuFactoryIf; +import org.sandag.abm.ctramp.DcSoaDMU; +import org.sandag.abm.ctramp.DestChoiceDMU; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Tour; +import org.sandag.abm.ctramp.DestinationSampleOfAlternativesModel; +import org.sandag.abm.ctramp.TourModeChoiceDMU; +import org.sandag.abm.ctramp.TourModeChoiceModel; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.visitor.VisitorTour; +public class NonMandatoryDestChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(NonMandatoryDestChoiceModel.class); + private transient Logger dcNonManLogger = Logger.getLogger("tourDcNonMan"); + private transient Logger todMcLogger = Logger.getLogger("todMcLogsum"); + + // TODO eventually remove this target + private static final String PROPERTIES_DC_UEC_FILE = "nmdc.uec.file"; + private static final String PROPERTIES_DC_UEC_FILE2 = "nmdc.uec.file2"; + private static final String PROPERTIES_DC_SOA_UEC_FILE = "nmdc.soa.uec.file"; + + private static final String USE_NEW_SOA_METHOD_PROPERTY_KEY = "nmdc.use.new.soa"; + + private static final String PROPERTIES_DC_SOA_NON_MAND_SAMPLE_SIZE_KEY = "nmdc.soa.SampleSize"; + + private static final String PROPERTIES_DC_DATA_SHEET = "nmdc.data.page"; + + private static final String PROPERTIES_DC_ESCORT_MODEL_SHEET = "nmdc.escort.model.page"; + private static final String PROPERTIES_DC_SHOP_MODEL_SHEET = "nmdc.shop.model.page"; + private static final String PROPERTIES_DC_MAINT_MODEL_SHEET = "nmdc.maint.model.page"; + private static final String PROPERTIES_DC_EATOUT_MODEL_SHEET = "nmdc.eat.model.page"; + private static final String PROPERTIES_DC_VISIT_MODEL_SHEET = "nmdc.visit.model.page"; + private static final String PROPERTIES_DC_DISCR_MODEL_SHEET = "nmdc.discr.model.page"; + + private static final String PROPERTIES_DC_SOA_ESCORT_MODEL_SHEET = "nmdc.soa.escort.model.page"; + private static final String PROPERTIES_DC_SOA_SHOP_MODEL_SHEET = "nmdc.soa.shop.model.page"; + private static final String PROPERTIES_DC_SOA_MAINT_MODEL_SHEET = "nmdc.soa.maint.model.page"; + private static final String PROPERTIES_DC_SOA_EATOUT_MODEL_SHEET = "nmdc.soa.eat.model.page"; + private static final String PROPERTIES_DC_SOA_VISIT_MODEL_SHEET = "nmdc.soa.visit.model.page"; + private static final String PROPERTIES_DC_SOA_DISCR_MODEL_SHEET = "nmdc.soa.discr.model.page"; + + private static final String PROPERTIES_DC_SAMPLE_TOD_PERIOD = "nmdc.SampleTODPeriod"; + private static final String PROPERTIES_SAMPLE_TOD_PERIOD_FILE = "nmdc.SampleTODPeriod.file"; + private boolean sampleTODPeriod = false; + private double[][] cumProbability; // by purpose, alternative: cumulative probability distribution + private int[][] outboundPeriod; // by purpose, alternative: outbound period + private int[][] returnPeriod; // by purpose, alternative: return period + + + private static final String[] TOUR_PURPOSE_NAMES = { + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME, + ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME, + ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME, + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME, + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME, + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME }; + + // set priority ranking for non-mandatory purposes - include 0 values for 0 + // element and mandatory purposes + private static final int[] TOUR_PURPOSE_PRIORITIES = {0, + 0, 0, 0, 1, 3, 2, 6, 4, 5 }; + + private static final String[] DC_MODEL_SHEET_KEYS = { + PROPERTIES_DC_ESCORT_MODEL_SHEET, PROPERTIES_DC_SHOP_MODEL_SHEET, + PROPERTIES_DC_MAINT_MODEL_SHEET, PROPERTIES_DC_EATOUT_MODEL_SHEET, + PROPERTIES_DC_VISIT_MODEL_SHEET, PROPERTIES_DC_DISCR_MODEL_SHEET }; + + private static final String[] DC_SOA_MODEL_SHEET_KEYS = { + PROPERTIES_DC_SOA_ESCORT_MODEL_SHEET, PROPERTIES_DC_SOA_SHOP_MODEL_SHEET, + PROPERTIES_DC_SOA_MAINT_MODEL_SHEET, PROPERTIES_DC_SOA_EATOUT_MODEL_SHEET, + PROPERTIES_DC_SOA_VISIT_MODEL_SHEET, PROPERTIES_DC_SOA_DISCR_MODEL_SHEET }; + + // all three subtour purposes use the same SOA sheet + private final int[] sizeSheetIndices = { + BuildAccessibilities.ESCORT_INDEX, BuildAccessibilities.SHOP_INDEX, + BuildAccessibilities.OTH_MAINT_INDEX, BuildAccessibilities.EATOUT_INDEX, + BuildAccessibilities.VISIT_INDEX, BuildAccessibilities.OTH_DISCR_INDEX }; + + // set default depart periods that represents each model period + private static final int EA = 1; + private static final int AM = 8; + private static final int MD = 16; + private static final int PM = 26; + private static final int EV = 36; + + private static final int[][][] PERIOD_COMBINATIONS = { + { {AM, AM}, {MD, MD}, {PM, PM}}, { {MD, MD}, {PM, PM}, {EV, EV}}, + { {AM, MD}, {MD, PM}, {PM, EV}}, { {MD, MD}, {PM, PM}, {EV, EV}}, + { {MD, MD}, {PM, PM}, {EV, EV}}, { {AM, MD}, {MD, PM}, {PM, EV}} }; + + private static final double[][] PERIOD_COMBINATION_COEFFICIENTS = { + {-1.065820, -0.871051, -1.439514}, {-0.467154, -1.411351, -2.044826}, + {-0.941865, -0.813977, -1.789714}, {-1.007316, -0.968856, -1.365375}, + {-1.081531, -1.121260, -1.093461}, {-1.258919, -1.155085, -0.913773} }; + + private ModelStructure modelStructure; + + private int[] dcModelIndices; + private HashMap purposeNameIndexMap; + HashMap nonMandatorySegmentNameIndexMap; + HashMap nonMandatorySizeSegmentNameIndexMap; + + private double[][] dcSizeArray; + + private TourModeChoiceDMU mcDmuObject; + private DestChoiceDMU dcDmuObject; + private DestChoiceTwoStageModelDMU dcDistSoaDmuObject; + private DcSoaDMU dcSoaDmuObject; + + private boolean[] needToComputeLogsum; + private double[] modeChoiceLogsums; + + private TourModeChoiceModel mcModel; + private DestinationSampleOfAlternativesModel dcSoaModel; + private ChoiceModelApplication[] dcModel; + private ChoiceModelApplication[] dcModel2; + + private boolean[] dcModel2AltsAvailable; + private int[] dcModel2AltsSample; + private int[] dcModel2SampleValues; + + private double[] mgraDistanceArray; + + private BuildAccessibilities aggAcc; + + private TazDataManager tazs; + private MgraDataManager mgraManager; + + private DestChoiceTwoStageModel dcSoaTwoStageObject; + + private boolean useNewSoaMethod; + + private int soaSampleSize; + + private long soaRunTime; + + public NonMandatoryDestChoiceModel(HashMap propertyMap, + ModelStructure myModelStructure, BuildAccessibilities myAggAcc, + CtrampDmuFactoryIf dmuFactory, TourModeChoiceModel myMcModel) + { + + logger.info("setting up Non-Mandatory tour destination choice model."); + + // set the model structure and the tour purpose list + this.modelStructure = myModelStructure; + this.mcModel = myMcModel; + aggAcc = myAggAcc; + + mgraManager = MgraDataManager.getInstance(); + tazs = TazDataManager.getInstance(); + + soaSampleSize = Util.getIntegerValueFromPropertyMap(propertyMap, + PROPERTIES_DC_SOA_NON_MAND_SAMPLE_SIZE_KEY); + + useNewSoaMethod = Util.getBooleanValueFromPropertyMap(propertyMap, + USE_NEW_SOA_METHOD_PROPERTY_KEY); + + if (useNewSoaMethod) + dcSoaTwoStageObject = new DestChoiceTwoStageModel(propertyMap, soaSampleSize); + + // create an array of ChoiceModelApplication objects for each choice + // purpose + setupDestChoiceModelArrays(propertyMap, dmuFactory); + + sampleTODPeriod = Util.getBooleanValueFromPropertyMap(propertyMap, PROPERTIES_DC_SAMPLE_TOD_PERIOD); + String directory = Util.getStringValueFromPropertyMap(propertyMap, "Project.Directory"); + String diurnalFile = Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_SAMPLE_TOD_PERIOD_FILE); + diurnalFile = directory + diurnalFile; + + if(sampleTODPeriod) + readTODFile(diurnalFile); + } + + /** + * Read the TOD distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readTODFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating tour TOD probability distribution"); + + int purposes = PERIOD_COMBINATIONS.length; // start at 0 + int periods = ModelStructure.MAX_TOD_INTERVAL; // start at 1 + int periodCombinations = periods * (periods + 1) / 2; + + cumProbability = new double[purposes][periodCombinations]; + outboundPeriod = new int[purposes][periodCombinations]; + returnPeriod = new int[purposes][periodCombinations]; + + // fill up arrays + int rowCount = probabilityTable.getRowCount(); + int lastPurpose = -99; + double cumProb = 0; + int alt = 0; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose") - 4; //4 mandatory purposes, first non-mand purpose is escort - 4 + int outPer = (int) probabilityTable.getValueAt(row, "OutboundPeriod"); + int retPer = (int) probabilityTable.getValueAt(row, "ReturnPeriod"); + + // continue if return period before outbound period + if (retPer < outPer) continue; + + // reset if new purpose + if (purpose != lastPurpose) + { + + // log cumulative probability just in case + if (lastPurpose != -99) + logger.info("Cumulative probability for purpose " + purpose + " is " + cumProb); + cumProb = 0; + alt = 0; + } + + // calculate cumulative probability and store in array + cumProb += probabilityTable.getValueAt(row, "Percent"); + cumProbability[purpose][alt] = cumProb; + outboundPeriod[purpose][alt] = outPer; + returnPeriod[purpose][alt] = retPer; + + ++alt; + + lastPurpose = purpose; + } + + logger.info("End calculating tour TOD probability distribution"); + + } + + /** + * Calculate tour time of day for the tour. + * + * @param tour + * A tour (with purpose) + */ + public double sampleTODPeriodAndCalculateDCLogsum(Person person, Tour tour, int sampleDestMgra) + { + + Logger modelLogger = todMcLogger; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + Household household = person.getHouseholdObject(); + + if (household.getDebugChoiceModels()) + { + choiceModelDescription = String + .format("Non-Mandatory sample TOD logsum calculations for %s Location Choice", + tour.getTourPurpose()); + decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d non-mand tours", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourId(), person.getListOfIndividualNonMandatoryTours().size()); + + } + + + double random = household.getHhRandom().nextDouble(); + int purpose = purposeNameIndexMap.get(tour.getTourPurpose()); + + int depart = -1; + int arrive = -1; + if (household.getDebugChoiceModels()) + { + logger.info("Choosing tour time of day for purpose " + + tour.getTourPurpose() + " using random number " + random); + tour.logTourObject(logger, 100); + } + + for (int i = 0; i < cumProbability[purpose].length; ++i) + { + + //Wu added to prevent large random number resulting in invalid choice + if (random>0.999999) { + depart = outboundPeriod[purpose][cumProbability[purpose].length-1]; + arrive = returnPeriod[purpose][cumProbability[purpose].length-1]; + break; + } + if (random < cumProbability[purpose][i]) + { + depart = outboundPeriod[purpose][i]; + arrive = returnPeriod[purpose][i]; + break; + } + } + if((depart ==-1)||(arrive==-1)){ + logger.fatal("Error: did not find outbound or return period for tour"); + logger.fatal("Depart period, arrive period = "+depart+","+arrive); + logger.fatal("Random number: "+random); + tour.logTourObject(logger,100); + throw new RuntimeException(); + } + + String periodString = modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(depart)) + + " to " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(arrive)); + + if (household.getDebugChoiceModels()) + { + logger.info(""); + logger.info("Chose depart period " + depart + " and arrival period " + + arrive); + logger.info(""); + } + + // set the mode choice attributes needed by @variables in the UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, depart, arrive, sampleDestMgra); + + double logsum = -999; + try + { + logsum = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel+","+periodString); + } catch (Exception e) + { + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + tour.getTourPrimaryPurpose() + " tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + e.printStackTrace(); + throw new RuntimeException(e); + } + + if (household.getDebugChoiceModels()) + modelLogger.info("Mode choice logsum for sampled mgra = " + logsum); + + return logsum; + + } + + + private void setupDestChoiceModelArrays(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + + String dcUecFileName = propertyMap.get(PROPERTIES_DC_UEC_FILE); + dcUecFileName = uecFileDirectory + dcUecFileName; + + String dcUecFileName2 = propertyMap.get(PROPERTIES_DC_UEC_FILE2); + dcUecFileName2 = uecFileDirectory + dcUecFileName2; + + String soaUecFileName = propertyMap.get(PROPERTIES_DC_SOA_UEC_FILE); + soaUecFileName = uecFileDirectory + soaUecFileName; + + int dcModelDataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, + PROPERTIES_DC_DATA_SHEET); + + dcDmuObject = dmuFactory.getDestChoiceDMU(); + dcDmuObject.setAggAcc(aggAcc); + dcDmuObject.setAccTable(aggAcc.getAccessibilitiesTableObject()); + + if (useNewSoaMethod) + { + dcDistSoaDmuObject = dmuFactory.getDestChoiceSoaTwoStageDMU(); + dcDistSoaDmuObject.setAggAcc(aggAcc); + dcDistSoaDmuObject.setAccTable(aggAcc.getAccessibilitiesTableObject()); + } + + dcSoaDmuObject = dmuFactory.getDcSoaDMU(); + dcSoaDmuObject.setAggAcc(aggAcc); + + mcDmuObject = dmuFactory.getModeChoiceDMU(); + + int numLogsumIndices = modelStructure.getSkimPeriodCombinationIndices().length; + needToComputeLogsum = new boolean[numLogsumIndices]; + modeChoiceLogsums = new double[numLogsumIndices]; + + // create the arrays of dc model and soa model indices + int[] uecSheetIndices = new int[TOUR_PURPOSE_NAMES.length]; + int[] soaUecSheetIndices = new int[TOUR_PURPOSE_NAMES.length]; + + purposeNameIndexMap = new HashMap(TOUR_PURPOSE_NAMES.length); + + int i = 0; + for (String purposeName : TOUR_PURPOSE_NAMES) + { + int uecIndex = Util.getIntegerValueFromPropertyMap(propertyMap, DC_MODEL_SHEET_KEYS[i]); + int soaUecIndex = Util.getIntegerValueFromPropertyMap(propertyMap, + DC_SOA_MODEL_SHEET_KEYS[i]); + purposeNameIndexMap.put(purposeName, i); + uecSheetIndices[i] = uecIndex; + soaUecSheetIndices[i] = soaUecIndex; + i++; + } + + // create a lookup array to map purpose index to model index + dcModelIndices = new int[uecSheetIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int dcModelIndex = 0; + int dcSegmentIndex = 0; + for (int uecIndex : uecSheetIndices) + { + // if the uec sheet for the model segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, dcModelIndex); + dcModelIndices[dcSegmentIndex] = dcModelIndex++; + } else + { + dcModelIndices[dcSegmentIndex] = modelIndexMap.get(uecIndex); + } + + dcSegmentIndex++; + } + + // the size term array in aggAcc gives mgra*purpose - need an array of + // all mgras for one purpose + double[][] aggAccDcSizeArray = aggAcc.getSizeTerms(); + nonMandatorySegmentNameIndexMap = new HashMap(); + nonMandatorySizeSegmentNameIndexMap = new HashMap(); + for (int k = 0; k < TOUR_PURPOSE_NAMES.length; k++) + { + nonMandatorySegmentNameIndexMap.put(TOUR_PURPOSE_NAMES[k], k); + nonMandatorySizeSegmentNameIndexMap.put(TOUR_PURPOSE_NAMES[k], sizeSheetIndices[k]); + } + + dcSizeArray = new double[TOUR_PURPOSE_NAMES.length][aggAccDcSizeArray.length]; + for (i = 0; i < aggAccDcSizeArray.length; i++) + { + for (int m : nonMandatorySegmentNameIndexMap.values()) + { + int s = sizeSheetIndices[m]; + dcSizeArray[m][i] = aggAccDcSizeArray[i][s]; + } + } + + dcModel = new ChoiceModelApplication[modelIndexMap.size()]; + + if (useNewSoaMethod) + { + dcModel2 = new ChoiceModelApplication[modelIndexMap.size()]; + dcModel2AltsAvailable = new boolean[soaSampleSize + 1]; + dcModel2AltsSample = new int[soaSampleSize + 1]; + dcModel2SampleValues = new int[soaSampleSize]; + } else + { + // create a sample of alternatives choice model object for use in + // selecting a sample + // of all possible destination choice alternatives. + dcSoaModel = new DestinationSampleOfAlternativesModel(soaUecFileName, soaSampleSize, + propertyMap, mgraManager, dcSizeArray, dcSoaDmuObject, soaUecSheetIndices); + } + + i = 0; + for (int uecIndex : modelIndexMap.keySet()) + { + + try + { + dcModel[i] = new ChoiceModelApplication(dcUecFileName, uecIndex, dcModelDataSheet, + propertyMap, (VariableTable) dcDmuObject); + + if (useNewSoaMethod) + { + dcModel2[i] = new ChoiceModelApplication(dcUecFileName2, uecIndex, + dcModelDataSheet, propertyMap, (VariableTable) dcDistSoaDmuObject); + } + + i++; + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught setting up DC ChoiceModelApplication[%d] for model index=%d of %d models", + i, i, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + + mgraDistanceArray = new double[mgraManager.getMaxMgra() + 1]; + } + + public void applyIndivModel(Household hh) + { + + soaRunTime = 0; + + if (useNewSoaMethod) dcSoaTwoStageObject.resetSoaRunTime(); + else dcSoaModel.resetSoaRunTime(); + + // declare these variables here so their values can be logged if a + // RuntimeException occurs. + int i = -1; + + Person[] persons = hh.getPersons(); + + for (i = 1; i < persons.length; i++) + { + + Person p = persons[i]; + + // get the individual non-mandatory tours for this person and choose + // a destination for each. + ArrayList tourList = getPriorityOrderedTourList(p + .getListOfIndividualNonMandatoryTours()); + + int currentTourNum = 0; + for (Tour tour : tourList) + { + + if(tour.getEscortTypeOutbound()==ModelStructure.RIDE_SHARING_TYPE||tour.getEscortTypeOutbound()==ModelStructure.PURE_ESCORTING_TYPE|| + tour.getEscortTypeInbound()==ModelStructure.RIDE_SHARING_TYPE||tour.getEscortTypeInbound()==ModelStructure.PURE_ESCORTING_TYPE) + continue; + + int chosen = -1; + try + { + + int homeTaz = hh.getHhTaz(); + int origMgra = tour.getTourOrigMgra(); + + // update the MC dmuObject for this person + mcDmuObject.setHouseholdObject( hh ); + mcDmuObject.setPersonObject( p ); + mcDmuObject.setTourObject( tour ); + mcDmuObject.setDmuIndexValues( hh.getHhId(), homeTaz, origMgra, 0, hh.getDebugChoiceModels() ); + mcDmuObject.setOriginMgra(origMgra); + + // update the DC dmuObject for this person + dcDmuObject.setHouseholdObject(hh); + dcDmuObject.setPersonObject(p); + dcDmuObject.setTourObject(tour); + dcDmuObject.setDmuIndexValues(hh.getHhId(), homeTaz, origMgra, 0); + + if (useNewSoaMethod) + { + dcDistSoaDmuObject.setHouseholdObject(hh); + dcDistSoaDmuObject.setPersonObject(p); + dcDistSoaDmuObject.setTourObject(tour); + dcDistSoaDmuObject.setDmuIndexValues(hh.getHhId(), homeTaz, origMgra, 0); + } + + // for individual non-mandatory DC, just count remaining + // individual non-mandatory tours + int toursLeftCount = tourList.size() - currentTourNum; + dcDmuObject.setToursLeftCount(toursLeftCount); + if (useNewSoaMethod) dcDistSoaDmuObject.setToursLeftCount(toursLeftCount); + + // get the tour location alternative chosen from the sample + if (useNewSoaMethod) + { + chosen = selectLocationFromTwoStageSampleOfAlternatives(tour, mcDmuObject); + soaRunTime += dcSoaTwoStageObject.getSoaRunTime(); + } else + { + chosen = selectLocationFromSampleOfAlternatives(tour, dcDmuObject, + dcSoaDmuObject, mcDmuObject); + soaRunTime += dcSoaModel.getSoaRunTime(); + } + + } catch (RuntimeException e) + { + logger.fatal(String + .format("exception caught selecting individual non-mandatory tour destination choice for hh.hhid=%d, personNum=%d, tourId=%d, purposeName=%s", + hh.getHhId(), p.getPersonNum(), tour.getTourId(), + tour.getTourPurpose())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(e); + } + + // set chosen values in tour object + tour.setTourDestMgra(chosen); + + currentTourNum++; + } + + } + + hh.setInmtlRandomCount(hh.getHhRandomCount()); + + } + + public void applyJointModel(Household hh) + { + + soaRunTime = 0; + + if (useNewSoaMethod) dcSoaTwoStageObject.resetSoaRunTime(); + else dcSoaModel.resetSoaRunTime(); + + // if no joint non-mandatory tours, nothing to do for this household. + Tour[] jointTours = hh.getJointTourArray(); + if (jointTours == null || jointTours.length == 0) return; + + // get the individual non-mandatory tours for this person and choose a + // destination for each. + ArrayList tourList = getPriorityOrderedTourList(jointTours); + + int currentTourNum = 0; + for (Tour tour : tourList) + { + + int chosen = -1; + try + { + + int homeTaz = hh.getHhTaz(); + int origMgra = tour.getTourOrigMgra(); + + // update the MC dmuObject for this person + mcDmuObject.setHouseholdObject( hh ); + mcDmuObject.setPersonObject( null ); + mcDmuObject.setTourObject( tour ); + mcDmuObject.setDmuIndexValues( hh.getHhId(), homeTaz, origMgra, 0, hh.getDebugChoiceModels() ); + mcDmuObject.setOriginMgra(origMgra); + + // update the DC dmuObject for this person + dcDmuObject.setHouseholdObject(hh); + dcDmuObject.setPersonObject(null); + dcDmuObject.setTourObject(tour); + dcDmuObject.setDmuIndexValues(hh.getHhId(), homeTaz, origMgra, 0); + + if (useNewSoaMethod) + { + dcDistSoaDmuObject.setHouseholdObject(hh); + dcDistSoaDmuObject.setPersonObject(null); + dcDistSoaDmuObject.setTourObject(tour); + dcDistSoaDmuObject.setDmuIndexValues(hh.getHhId(), homeTaz, origMgra, 0); + } + + // for individual non-mandatory DC, just count remaining + // individual non-mandatory tours + int toursLeftCount = tourList.size() - currentTourNum; + dcDmuObject.setToursLeftCount(toursLeftCount); + if (useNewSoaMethod) dcDistSoaDmuObject.setToursLeftCount(toursLeftCount); + + // get the tour location alternative chosen from the sample + if (useNewSoaMethod) + { + chosen = selectLocationFromTwoStageSampleOfAlternatives(tour, mcDmuObject); + soaRunTime += dcSoaTwoStageObject.getSoaRunTime(); + } else + { + chosen = selectLocationFromSampleOfAlternatives(tour, dcDmuObject, + dcSoaDmuObject, mcDmuObject); + soaRunTime += dcSoaModel.getSoaRunTime(); + } + + } catch (RuntimeException e) + { + logger.fatal(String + .format("exception caught selecting joint non-mandatory tour destination choice for hh.hhid=%d, tourId=%d, purposeName=%s", + hh.getHhId(), tour.getTourId(), tour.getTourPurpose())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + // set chosen values in tour object + tour.setTourDestMgra(chosen); + + currentTourNum++; + } + + hh.setJtlRandomCount(hh.getHhRandomCount()); + + } + + /** + * + * @return chosen mgra. + */ + private int selectLocationFromSampleOfAlternatives(Tour tour, DestChoiceDMU dcDmuObject, + DcSoaDMU dcSoaDmuObject, TourModeChoiceDMU mcDmuObject) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcNonManLogger; + + // get the Household object for the person making this non-mandatory + // tour + Person person = tour.getPersonObject(); + + // get the Household object for the person making this non-mandatory + // tour + Household household = person.getHouseholdObject(); + + // get the tour purpose name + String tourPurposeName = tour.getTourPurpose(); + int tourPurposeIndex = purposeNameIndexMap.get(tourPurposeName); + + int sizeIndex = nonMandatorySizeSegmentNameIndexMap.get(tourPurposeName); + dcSoaDmuObject.setDestChoiceSize(dcSizeArray[sizeIndex]); + + // double[] homeMgraDistanceArray = + // mandAcc.calculateDistancesForAllMgras( household.getHhMgra() ); + mcModel.getAnmSkimCalculator().getOpSkimDistancesFromMgra(household.getHhMgra(), + mgraDistanceArray); + dcSoaDmuObject.setDestDistance(mgraDistanceArray); + + dcDmuObject.setDestChoiceSize(dcSizeArray[sizeIndex]); + dcDmuObject.setDestChoiceDistance(mgraDistanceArray); + + // compute the sample of alternatives set for the person + dcSoaModel.computeDestinationSampleOfAlternatives(dcSoaDmuObject, tour, person, + tourPurposeName, tourPurposeIndex, household.getHhMgra()); + + // get sample of locations and correction factors for sample + int[] finalSample = dcSoaModel.getSampleOfAlternatives(); + float[] sampleCorrectionFactors = dcSoaModel.getSampleOfAlternativesCorrections(); + + int m = dcModelIndices[tourPurposeIndex]; + int numAlts = dcModel[m].getNumberOfAlternatives(); + + // set the destAltsAvailable array to true for all destination choice + // alternatives for each purpose + boolean[] destAltsAvailable = new boolean[numAlts + 1]; + for (int k = 0; k <= numAlts; k++) + destAltsAvailable[k] = false; + + // set the destAltsSample array to 1 for all destination choice + // alternatives + // for each purpose + int[] destAltsSample = new int[numAlts + 1]; + for (int k = 0; k <= numAlts; k++) + destAltsSample[k] = 0; + + int[] sampleValues = new int[finalSample.length]; + + // for the destinations and sub-zones in the sample, compute mc logsums + // and + // save in DC dmuObject. + // also save correction factor and set availability and sample value for + // the + // sample alternative to true. 1, respectively. + for (int i = 1; i < finalSample.length; i++) + { + + int destMgra = finalSample[i]; + sampleValues[i] = finalSample[i]; + + // set logsum value in DC dmuObject for the logsum index, sampled + // zone and subzone. + double logsum = -999; + if(sampleTODPeriod) + logsum = sampleTODPeriodAndCalculateDCLogsum(person, tour, destMgra); + else + logsum = calculateSimpleTODChoiceLogsum(person, tour, destMgra, i); + + dcDmuObject.setMcLogsum(destMgra, logsum); + + // set sample of alternatives correction factor used in destination + // choice utility for the sampled alternative. + dcDmuObject.setDcSoaCorrections(destMgra, sampleCorrectionFactors[i]); + + // set availaibility and sample values for the purpose, dcAlt. + destAltsAvailable[finalSample[i]] = true; + destAltsSample[finalSample[i]] = 1; + + } + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format( + "Non-Mandatory Location Choice Model for: tour purpose=%s", tourPurposeName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourId()); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Non-Mandatory Location Choice Model for tour purpose=" + + tourPurposeName + ", Person Num: " + person.getPersonNum() + + ", Person Type: " + person.getPersonType() + ", TourId=" + tour.getTourId()); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + dcModel[m].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + float modelLogsum = (float) dcModel[m].computeUtilities(dcDmuObject, dcDmuObject.getDmuIndexValues(), + destAltsAvailable, destAltsSample); + + tour.setTourDestinationLogsum(modelLogsum); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (dcModel[m].getAvailabilityCount() > 0) + { + try + { + chosen = dcModel[m].getChoiceResult(rn); + } catch (Exception e) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, in %s destination choice.", + dcDmuObject.getHouseholdObject().getHhId(), dcDmuObject + .getPersonObject().getPersonNum(), tour.getTourId(), + tourPurposeName)); + throw new RuntimeException(); + } + } + + // write choice model alternative info to log file + int selectedIndex = -1; + for (int j = 1; j < finalSample.length; j++) + { + if (finalSample[j] == chosen) + { + selectedIndex = j; + break; + } + } + + if (household.getDebugChoiceModels() || chosen <= 0) + { + + double[] utilities = dcModel[m].getUtilities(); + double[] probabilities = dcModel[m].getProbabilities(); + boolean[] availabilities = dcModel[m].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- -------------- -------------- -------------- --------------"); + + int[] sortedSampleValueIndices = IndexSort.indexSort(sampleValues); + + double cumProb = 0.0; + for (int j = 1; j < finalSample.length; j++) + { + int k = sortedSampleValueIndices[j]; + int alt = finalSample[k]; + + if (finalSample[k] == chosen) selectedIndex = j; + + cumProb += probabilities[alt - 1]; + String altString = String.format("j=%d, mgra=%d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[alt], utilities[alt - 1], probabilities[alt - 1], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("j=%d, mgra=%d", selectedIndex, chosen); + modelLogger.info(String.format("Choice: %s with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + dcModel[m].logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + dcModel[m].logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log file + dcModel[m].logUECResults(modelLogger, loggingHeader); + + if (chosen < 0) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, tourPurpose=%d, no available %s destination choice alternatives to choose from in ChoiceModelApplication.", + dcDmuObject.getHouseholdObject().getHhId(), dcDmuObject + .getPersonObject().getPersonNum(), tour.getTourId(), + tourPurposeName)); + throw new RuntimeException(); + } + + } + + return chosen; + + } + + /** + * + * @return chosen mgra. + */ + private int selectLocationFromTwoStageSampleOfAlternatives(Tour tour, + TourModeChoiceDMU mcDmuObject) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcNonManLogger; + + // get the Household object for the person making this non-mandatory + // tour + Person person = tour.getPersonObject(); + + // get the Household object for the person making this non-mandatory + // tour + Household household = person.getHouseholdObject(); + + // get the tour purpose name + String tourPurposeName = tour.getTourPurpose(); + int tourPurposeIndex = purposeNameIndexMap.get(tourPurposeName); + + // get sample of locations and correction factors for sample using the + // alternate method + // for non-mandatory tour destination choice, the sizeSegmentType INdex + // and sizeSegmentIndex are the same values. + dcSoaTwoStageObject.chooseSample(mgraManager.getTaz(tour.getTourOrigMgra()), + tourPurposeIndex, tourPurposeIndex, soaSampleSize, household.getHhRandom(), + household.getDebugChoiceModels()); + int[] finalSample = dcSoaTwoStageObject.getUniqueSampleMgras(); + double[] sampleCorrectionFactors = dcSoaTwoStageObject + .getUniqueSampleMgraCorrectionFactors(); + int numUniqueAlts = dcSoaTwoStageObject.getNumberofUniqueMgrasInSample(); + + int m = dcModelIndices[tourPurposeIndex]; + int numAlts = dcModel2[m].getNumberOfAlternatives(); + + Arrays.fill(dcModel2AltsAvailable, false); + Arrays.fill(dcModel2AltsSample, 0); + Arrays.fill(dcModel2SampleValues, 999999); + + mcModel.getAnmSkimCalculator().getOpSkimDistancesFromMgra(household.getHhMgra(), + mgraDistanceArray); + dcDistSoaDmuObject.setMgraDistanceArray(mgraDistanceArray); + + int sizeIndex = nonMandatorySizeSegmentNameIndexMap.get(tourPurposeName); + dcDistSoaDmuObject.setMgraSizeArray(dcSizeArray[sizeIndex]); + + // set sample of alternatives correction factors used in destination + // choice utility for the sampled alternatives. + dcDistSoaDmuObject.setDcSoaCorrections(sampleCorrectionFactors); + + // for the destination mgras in the sample, compute mc logsums and save + // in dmuObject. + // also save correction factor and set availability and sample value for + // the + // sample alternative to true. 1, respectively. + for (int i = 0; i < numUniqueAlts; i++) + { + + int destMgra = finalSample[i]; + dcModel2SampleValues[i] = finalSample[i]; + + // set logsum value in DC dmuObject for the logsum index, sampled + // zone and subzone. + double logsum = -999; + if(sampleTODPeriod) + logsum = sampleTODPeriodAndCalculateDCLogsum(person, tour, destMgra); + else + logsum = calculateSimpleTODChoiceLogsum(person, tour, destMgra, i); + dcDistSoaDmuObject.setMcLogsum(i, logsum); + + // set availaibility and sample values for the purpose, dcAlt. + dcModel2AltsAvailable[i + 1] = true; + dcModel2AltsSample[i + 1] = 1; + + } + + dcDistSoaDmuObject.setSampleArray(dcModel2SampleValues); + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format( + "Non-Mandatory Location Choice Model for: tour purpose=%s", tourPurposeName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourId()); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Non-Mandatory Location Choice Model for tour purpose=" + + tourPurposeName + ", Person Num: " + person.getPersonNum() + + ", Person Type: " + person.getPersonType() + ", TourId=" + tour.getTourId()); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + dcModel2[m].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + float logsum = (float) dcModel2[m].computeUtilities(dcDistSoaDmuObject, dcDistSoaDmuObject.getDmuIndexValues(), + dcModel2AltsAvailable, dcModel2AltsSample); + + tour.setTourDestinationLogsum(logsum); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (dcModel2[m].getAvailabilityCount() > 0) + { + try + { + chosen = dcModel2[m].getChoiceResult(rn); + } catch (Exception e) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, in %s destination choice.", + dcDistSoaDmuObject.getHouseholdObject().getHhId(), + dcDistSoaDmuObject.getPersonObject().getPersonNum(), + tour.getTourId(), tourPurposeName)); + throw new RuntimeException(); + } + } + + if (household.getDebugChoiceModels() || chosen <= 0) + { + + double[] utilities = dcModel2[m].getUtilities(); + double[] probabilities = dcModel2[m].getProbabilities(); + boolean[] availabilities = dcModel2[m].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- -------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 0; j < finalSample.length; j++) + { + int alt = finalSample[j]; + cumProb += probabilities[j]; + String altString = String.format("j=%d, mgra=%d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j + 1], utilities[j], probabilities[j], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("j=%d, mgra=%d", chosen - 1, finalSample[chosen - 1]); + modelLogger.info(String.format("Choice: %s with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + dcModel2[m].logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + dcModel2[m].logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log file + dcModel2[m].logUECResults(modelLogger, loggingHeader); + + if (chosen < 0) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, tourPurpose=%d, no available %s destination choice alternatives to choose from in ChoiceModelApplication.", + dcDistSoaDmuObject.getHouseholdObject().getHhId(), + dcDistSoaDmuObject.getPersonObject().getPersonNum(), + tour.getTourId(), tourPurposeName)); + throw new RuntimeException(); + } + + } + + return chosen; + + } + + private void setModeChoiceDmuAttributes(Household household, Person person, Tour t, + int startPeriod, int endPeriod, int sampleDestMgra) + { + + t.setTourDestMgra(sampleDestMgra); + t.setTourDepartPeriod(startPeriod); + t.setTourArrivePeriod(endPeriod); + + // update the MC dmuObjects for this person + mcDmuObject.setHouseholdObject(household); + mcDmuObject.setPersonObject(person); + mcDmuObject.setTourObject(t); + mcDmuObject.setDmuIndexValues(household.getHhId(), t.getTourOrigMgra(), + t.getTourOrigMgra(), sampleDestMgra, household.getDebugChoiceModels()); + + mcDmuObject.setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(t + .getTourOrigMgra()))); + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager + .getTaz(sampleDestMgra))); + mcDmuObject.setOriginMgra(t.getTourOrigMgra()); + mcDmuObject.setDestMgra(t.getTourDestMgra()); + + } + + + /** + * This method calculates TOD choice logsum for the person, tour and sampled destination. + * @param person + * @param tour + * @param sampleDestMgra + * @param sampleNum + * @return The logsum. + */ + private double calculateSimpleTODChoiceLogsum(Person person, Tour tour, int sampleDestMgra, + int sampleNum) + { + + Household household = person.getHouseholdObject(); + + Arrays.fill(needToComputeLogsum, true); + Arrays.fill(modeChoiceLogsums, -999); + + Logger modelLogger = todMcLogger; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + choiceModelDescription = String + .format("Non-Mandatory Simplified TOD logsum calculations for %s Location Choice, Sample Number %d", + tour.getTourPurpose(), sampleNum); + decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d non-mand tours", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourId(), person.getListOfIndividualNonMandatoryTours().size()); + loggingHeader = String.format("%s %s", choiceModelDescription, decisionMakerLabel); + + } + + int i = 0; + int tourPurposeIndex = purposeNameIndexMap.get(tour.getTourPurpose()); + double totalExpUtility = 0.0; + for (int[] combo : PERIOD_COMBINATIONS[tourPurposeIndex]) + { + int startPeriod = combo[0]; + int endPeriod = combo[1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + if (needToComputeLogsum[index]) + { + + String periodString = modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(startPeriod)) + + " to " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(endPeriod)); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, startPeriod, endPeriod, + sampleDestMgra); + + if (household.getDebugChoiceModels()) + { + modelLogger.info(""); + modelLogger.info(""); + household.logTourObject(loggingHeader + ", " + periodString, modelLogger, + person, tour); + } + + try + { + modeChoiceLogsums[index] = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel + ", " + + periodString); + } catch (Exception e) + { + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + periodString + " " + tour.getTourPrimaryPurpose() + " tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + e.printStackTrace(); + //System.exit(-1); + throw new RuntimeException(e); + } + needToComputeLogsum[index] = false; + } + + double expUtil = Math.exp(modeChoiceLogsums[index] + + PERIOD_COMBINATION_COEFFICIENTS[tourPurposeIndex][i]); + totalExpUtility += expUtil; + + if (household.getDebugChoiceModels()) + modelLogger + .info("i = " + + i + + ", purpose = " + + tourPurposeIndex + + ", " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(startPeriod)) + + " to " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(endPeriod)) + + " MCLS = " + + modeChoiceLogsums[index] + + ", ASC = " + + PERIOD_COMBINATION_COEFFICIENTS[tourPurposeIndex][i] + + ", (MCLS + ASC) = " + + (modeChoiceLogsums[index] + PERIOD_COMBINATION_COEFFICIENTS[tourPurposeIndex][i]) + + ", exp(MCLS + ASC) = " + expUtil + ", cumExpUtility = " + + totalExpUtility); + + i++; + } + + double logsum = Math.log(totalExpUtility); + + if (household.getDebugChoiceModels()) + modelLogger.info("final simplified TOD logsum = " + logsum); + + return logsum; + } + + /** + * takes an ArrayList of tours + * + * @return a new ArrayList ordered by priority + */ + private ArrayList getPriorityOrderedTourList(ArrayList toursIn) + { + + int[] tourPriorities = new int[toursIn.size()]; + + int i = 0; + for (Tour tour : toursIn) + { + String purposeName = tour.getTourPurpose(); + int purposeIndex = purposeNameIndexMap.get(purposeName); + int purposePriority = TOUR_PURPOSE_PRIORITIES[purposeIndex]; + tourPriorities[i] = purposePriority; + } + + int[] sortedIndices = IndexSort.indexSort(tourPriorities); + ArrayList toursOut = new ArrayList(toursIn.size()); + + for (i = 0; i < toursIn.size(); i++) + toursOut.add(toursIn.get(sortedIndices[i])); + + return toursOut; + } + + /** + * takes an ArrayList of tours + * + * @return a new ArrayList ordered by priority + */ + private ArrayList getPriorityOrderedTourList(Tour[] toursIn) + { + + int[] tourPriorities = new int[toursIn.length]; + + int i = 0; + for (Tour tour : toursIn) + { + String purposeName = tour.getTourPurpose(); + int purposeIndex = purposeNameIndexMap.get(purposeName); + int purposePriority = TOUR_PURPOSE_PRIORITIES[purposeIndex]; + tourPriorities[i] = purposePriority; + } + + int[] sortedIndices = IndexSort.indexSort(tourPriorities); + ArrayList toursOut = new ArrayList(toursIn.length); + + for (i = 0; i < toursIn.length; i++) + toursOut.add(toursIn[sortedIndices[i]]); + + return toursOut; + } + + public void setNonMandatorySoaProbs(double[][][] soaDistProbs, double[][][] soaSizeProbs) + { + if (useNewSoaMethod) + { + dcSoaTwoStageObject.setTazDistProbs(soaDistProbs); + dcSoaTwoStageObject.setMgraSizeProbs(soaSizeProbs); + } + } + + public long getSoaRunTime() + { + return soaRunTime; + } + + public void resetSoaRunTime() + { + soaRunTime = 0; + } + + public static void main(String[] args) + { + + // set values for these arguments so an object instance can be created + // and setup run to test integrity of UEC files before running full + // model. + HashMap propertyMap; + + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + ResourceBundle rb = ResourceBundle.getBundle(args[0]); + propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + } + + String matrixServerAddress = (String) propertyMap.get("RunModel.MatrixServerAddress"); + String matrixServerPort = (String) propertyMap.get("RunModel.MatrixServerPort"); + + MatrixDataServerIf ms = new MatrixDataServerRmi(matrixServerAddress, + Integer.parseInt(matrixServerPort), MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + + ModelStructure modelStructure = new SandagModelStructure(); + SandagCtrampDmuFactory dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + TazDataManager tazManager = TazDataManager.getInstance(propertyMap); + + BuildAccessibilities aggAcc = BuildAccessibilities.getInstance(); + if (!aggAcc.getAccessibilitiesAreBuilt()) + { + aggAcc.setupBuildAccessibilities(propertyMap, false); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateConstants(); + // aggAcc.buildAccessibilityComponents(propertyMap); + + boolean readAccessibilities = Util.getBooleanValueFromPropertyMap(propertyMap, + CtrampApplication.READ_ACCESSIBILITIES); + if (readAccessibilities) + { + + // output data + String projectDirectory = propertyMap + .get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file"); + + aggAcc.readAccessibilityTableFromFile(accFileName); + + } else + { + + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + } + + } + + double[][] expConstants = aggAcc.getExpConstants(); + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + + double[][][] sovExpUtilities = null; + double[][][] hovExpUtilities = null; + double[][][] nMotorExpUtilities = null; + double[][][] maasExpUtilities = null; + + NonTransitUtilities ntUtilities = new NonTransitUtilities(propertyMap, sovExpUtilities, + hovExpUtilities, nMotorExpUtilities,maasExpUtilities); + + MandatoryAccessibilitiesCalculator mandAcc = new MandatoryAccessibilitiesCalculator( + propertyMap, ntUtilities, expConstants, logsumHelper.getBestTransitPathCalculator()); + + HouseholdIndividualNonMandatoryTourFrequencyModel inmtfModel = new HouseholdIndividualNonMandatoryTourFrequencyModel( + propertyMap, dmuFactory, aggAcc.getAccessibilitiesTableObject(), mandAcc); + + TourModeChoiceModel inmmcModel = new TourModeChoiceModel(propertyMap, modelStructure, + "Non-Mandatory", dmuFactory, logsumHelper); + + NonMandatoryDestChoiceModel testObject = new NonMandatoryDestChoiceModel(propertyMap, + modelStructure, aggAcc, dmuFactory, inmmcModel); + + String hhHandlerAddress = (String) propertyMap.get("RunModel.HouseholdServerAddress"); + int hhServerPort = Integer.parseInt((String) propertyMap + .get("RunModel.HouseholdServerPort")); + + HouseholdDataManagerIf householdDataManager = new HouseholdDataManagerRmi(hhHandlerAddress, + hhServerPort, SandagHouseholdDataManager.HH_DATA_SERVER_NAME); + + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population + // files and apply its tables to objects mapping method. + boolean restartHhServer = false; + try + { + // possible values for the following can be none, ao, cdap, imtf, + // imtod, awf, awl, awtod, jtf, jtl, jtod, inmtf, inmtl, inmtod, + // stf, stl + String restartModel = (String) propertyMap.get("RunModel.RestartWithHhServer"); + if (restartModel.equalsIgnoreCase("none")) restartHhServer = true; + else if (restartModel.equalsIgnoreCase("uwsl") || restartModel.equalsIgnoreCase("ao") + || restartModel.equalsIgnoreCase("fp") || restartModel.equalsIgnoreCase("cdap") + || restartModel.equalsIgnoreCase("imtf") + || restartModel.equalsIgnoreCase("imtod") + || restartModel.equalsIgnoreCase("awf") || restartModel.equalsIgnoreCase("awl") + || restartModel.equalsIgnoreCase("awtod") + || restartModel.equalsIgnoreCase("jtf") || restartModel.equalsIgnoreCase("jtl") + || restartModel.equalsIgnoreCase("jtod") + || restartModel.equalsIgnoreCase("inmtf") + || restartModel.equalsIgnoreCase("inmtl") + || restartModel.equalsIgnoreCase("inmtod") + || restartModel.equalsIgnoreCase("stf") || restartModel.equalsIgnoreCase("stl")) + restartHhServer = false; + } catch (MissingResourceException e) + { + restartHhServer = true; + } + + if (restartHhServer) + { + + householdDataManager.setDebugHhIdsFromHashmap(); + + String inputHouseholdFileName = (String) propertyMap + .get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = (String) propertyMap + .get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(0.2f, 0); + householdDataManager.setupHouseholdDataManager(modelStructure, inputHouseholdFileName, + inputPersonFileName); + + } else + { + + householdDataManager.setHouseholdSampleRate(0.2f, 0); + householdDataManager.setDebugHhIdsFromHashmap(); + householdDataManager.setTraceHouseholdSet(); + + } + + int id = householdDataManager.getArrayIndex(1033380); + Household[] hh = householdDataManager.getHhArray(id, id); + + testObject.applyIndivModel(hh[0]); + testObject.applyJointModel(hh[0]); + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/NonMandatoryTourDepartureAndDurationTime.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/NonMandatoryTourDepartureAndDurationTime.java new file mode 100644 index 0000000..fb4cfec --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/NonMandatoryTourDepartureAndDurationTime.java @@ -0,0 +1,1448 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.Random; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagHouseholdDataManager; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; + +/** + * Created by IntelliJ IDEA. User: Jim Date: Jul 11, 2008 Time: 9:25:30 AM To + * change this template use File | Settings | File Templates. + */ +public class NonMandatoryTourDepartureAndDurationTime + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(NonMandatoryTourDepartureAndDurationTime.class); + private transient Logger todLogger = Logger.getLogger("todLogger"); + private transient Logger tourMCNonManLogger = Logger.getLogger("tourMcNonMan"); + + private static final String IMTOD_UEC_FILE_TARGET = "departTime.uec.file"; + private static final String IMTOD_UEC_DATA_TARGET = "departTime.data.page"; + private static final String IMTOD_UEC_ESCORT_MODEL_TARGET = "departTime.escort.page"; + private static final String IMTOD_UEC_SHOP_MODEL_TARGET = "departTime.shop.page"; + private static final String IMTOD_UEC_MAINT_MODEL_TARGET = "departTime.maint.page"; + private static final String IMTOD_UEC_EAT_MODEL_TARGET = "departTime.eat.page"; + private static final String IMTOD_UEC_VISIT_MODEL_TARGET = "departTime.visit.page"; + private static final String IMTOD_UEC_DISCR_MODEL_TARGET = "departTime.discr.page"; + + private static final String[] TOUR_PURPOSE_NAMES = { + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME, + ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME, + ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME, + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME, + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME, + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME }; + + private static final String[] DC_MODEL_SHEET_KEYS = { + IMTOD_UEC_ESCORT_MODEL_TARGET, IMTOD_UEC_SHOP_MODEL_TARGET, + IMTOD_UEC_MAINT_MODEL_TARGET, IMTOD_UEC_EAT_MODEL_TARGET, IMTOD_UEC_VISIT_MODEL_TARGET, + IMTOD_UEC_DISCR_MODEL_TARGET }; + + // process non-mandatory tours in order by priority purpose: + // 4=escort, 6=oth maint, 5=shop, 8=visiting, 9=oth discr, 7=eat out, + private static final int[] TOUR_PURPOSE_INDEX_ORDER = {4, 6, 5, 8, 9, 7}; + + private ArrayList[] purposeTourLists; + + private int[] todModelIndices; + private HashMap purposeNameIndexMap; + + private int[] tourDepartureTimeChoiceSample; + + // DMU for the UEC + private TourDepartureTimeAndDurationDMU todDmuObject; + private TourModeChoiceDMU mcDmuObject; + + // model structure to compare the .properties time of day with the UECs + private ModelStructure modelStructure; + + // private double[][] dcSizeArray; + + private TazDataManager tazs; + private MgraDataManager mgraManager; + + private ChoiceModelApplication[] todModels; + private TourModeChoiceModel mcModel; + + private int[] altStarts; + private int[] altEnds; + + private boolean[] needToComputeLogsum; + private double[] modeChoiceLogsums; + + private int noAltChoice = 1; + + private long jointModeChoiceTime; + private long indivModeChoiceTime; + + public NonMandatoryTourDepartureAndDurationTime(HashMap propertyMap, + ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory, + TourModeChoiceModel mcModel) + { + + // set the model structure + this.modelStructure = modelStructure; + this.mcModel = mcModel; + + logger.info("setting up Non-Mandatory time-of-day choice model."); + + setupTodChoiceModels(propertyMap, dmuFactory); + } + + private void setupTodChoiceModels(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + + tazs = TazDataManager.getInstance(); + mgraManager = MgraDataManager.getInstance(); + + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + + String todUecFileName = propertyMap.get(IMTOD_UEC_FILE_TARGET); + todUecFileName = uecFileDirectory + todUecFileName; + + todDmuObject = dmuFactory.getTourDepartureTimeAndDurationDMU(); + + mcDmuObject = dmuFactory.getModeChoiceDMU(); + + int numLogsumIndices = modelStructure.getSkimPeriodCombinationIndices().length; + needToComputeLogsum = new boolean[numLogsumIndices]; + modeChoiceLogsums = new double[numLogsumIndices]; + + // create the array of tod model indices + int[] uecSheetIndices = new int[TOUR_PURPOSE_NAMES.length]; + + purposeNameIndexMap = new HashMap(TOUR_PURPOSE_NAMES.length); + + int i = 0; + for (String purposeName : TOUR_PURPOSE_NAMES) + { + int uecIndex = Util.getIntegerValueFromPropertyMap(propertyMap, DC_MODEL_SHEET_KEYS[i]); + purposeNameIndexMap.put(purposeName, i); + uecSheetIndices[i] = uecIndex; + i++; + } + + // create a lookup array to map purpose index to model index + todModelIndices = new int[uecSheetIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int todModelIndex = 0; + for (int uecIndex : uecSheetIndices) + { + // if the uec sheet for the model segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, todModelIndex); + todModelIndices[todModelIndex] = todModelIndex++; + } else + { + todModelIndices[todModelIndex++] = modelIndexMap.get(uecIndex); + } + } + + todModels = new ChoiceModelApplication[modelIndexMap.size()]; + int todModelDataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, + IMTOD_UEC_DATA_TARGET); + + for (int uecIndex : modelIndexMap.keySet()) + { + int modelIndex = modelIndexMap.get(uecIndex); + try + { + todModels[modelIndex] = new ChoiceModelApplication(todUecFileName, uecIndex, + todModelDataSheet, propertyMap, (VariableTable) todDmuObject); + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught setting up NonMandatory TOD ChoiceModelApplication[%d] for modelIndex=%d, num choice models=%d", + modelIndex, modelIndex, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + + // get the alternatives table from the work tod UEC. + TableDataSet altsTable = todModels[0].getUEC().getAlternativeData(); + + altStarts = altsTable.getColumnAsInt(CtrampApplication.START_FIELD_NAME); + altEnds = altsTable.getColumnAsInt(CtrampApplication.END_FIELD_NAME); + todDmuObject.setTodAlts(altStarts, altEnds); + + int numDepartureTimeChoiceAlternatives = todModels[0].getNumberOfAlternatives(); + tourDepartureTimeChoiceSample = new int[numDepartureTimeChoiceAlternatives + 1]; + Arrays.fill(tourDepartureTimeChoiceSample, 1); + + // allocate an array of ArrayList objects to hold tour lists by purpose + // - tour lists will be processed + // in priority purpose order. + int maxPurposeIndex = 0; + for (i = 0; i < TOUR_PURPOSE_INDEX_ORDER.length; i++) + if (TOUR_PURPOSE_INDEX_ORDER[i] > maxPurposeIndex) + maxPurposeIndex = TOUR_PURPOSE_INDEX_ORDER[i]; + + purposeTourLists = new ArrayList[maxPurposeIndex + 1]; + for (i = 0; i < TOUR_PURPOSE_INDEX_ORDER.length; i++) + { + int index = TOUR_PURPOSE_INDEX_ORDER[i]; + purposeTourLists[index] = new ArrayList(); + } + + } + + public void applyIndivModel(Household hh, boolean runTODChoice, boolean runModeChoice) + { + + indivModeChoiceTime = 0; + + Logger modelLogger = todLogger; + + // get the person objects for this household + Person[] persons = hh.getPersons(); + + if(!runTODChoice) { + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + // if no individual non-mandatory tours, nothing to do. + if (person.getListOfIndividualNonMandatoryTours().size() == 0) continue; + + // arrange the individual non-mandatory tours for this person in an + // array of ArrayLists by purpose + getPriorityOrderedTourList(person.getListOfIndividualNonMandatoryTours()); + + for (int i = 0; i < TOUR_PURPOSE_INDEX_ORDER.length; i++) { + int tourPurposeIndex = TOUR_PURPOSE_INDEX_ORDER[i]; + for (Tour t : purposeTourLists[tourPurposeIndex]) + try { + runModeChoice(hh,person,t,t.getTourDepartPeriod(),t.getTourArrivePeriod()); + + }catch(Exception e) { + String errorMessage = String + .format("Exception caught for HHID=%d, personNum=%d, individual non-mandatory mode choice, tour ArrayList index=%d.", + hh.getHhId(), person.getPersonNum(), tourPurposeIndex); + String decisionMakerLabel = String + .format("Final Individual Non-Mandatory Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + hh.getHhId(), person.getPersonNum(), person.getPersonType()); + hh.logPersonObject(decisionMakerLabel, modelLogger, person); + logger.error(errorMessage, e); + throw new RuntimeException(e); + + } + } + } + return; + + } + + + + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + // if no individual non-mandatory tours, nothing to do. + if (person.getListOfIndividualNonMandatoryTours().size() == 0) continue; + + // arrange the individual non-mandatory tours for this person in an + // array of ArrayLists by purpose + getPriorityOrderedTourList(person.getListOfIndividualNonMandatoryTours()); + + // define variables to hold depart/arrive periods selected for the + // most recent tour. + // if a tour has no non-overlapping period available, set the + // periods to either the depart or arrive of the most recently + // determined + // if none has been selected yet, set to the first of last interval + int previouslySelectedDepartPeriod = -1; + int previouslySelectedArrivePeriod = -1; + + for (int i = 0; i < TOUR_PURPOSE_INDEX_ORDER.length; i++) + { + + int tourPurposeIndex = TOUR_PURPOSE_INDEX_ORDER[i]; + + // process each individual non-mandatory tour from the list + int m = -1; + int tourPurpNum = 1; + int noWindowCountFirstTemp = 0; + int noWindowCountLastTemp = 0; + int noLaterAlternativeCountTemp = 0; + + for (Tour t : purposeTourLists[tourPurposeIndex]) + { + + //store the tour depart time and arrival time if it is an escort tour; that way mode choice + //logsums can be calculated for the tour and stored when the actual tour dep/arr period isn't chosen. + int escortTourDepartPeriod=0; + int escortTourArrivePeriod=0; + if(t.getEscortTypeOutbound()>0 || t.getEscortTypeInbound()>0){ + escortTourDepartPeriod = t.getTourDepartPeriod(); + escortTourArrivePeriod = t.getTourArrivePeriod(); + continue; + } + try + { + + // get the choice model for the tour purpose + String tourPurposeName = t.getTourPurpose(); + m = todModelIndices[purposeNameIndexMap.get(tourPurposeName)]; + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (hh.getDebugChoiceModels()) + { + + choiceModelDescription = String + .format("Individual Non-Mandatory Tour Departure Time Choice Model for: Purpose=%s", + tourPurposeName); + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, tourId=%d, num=%d of %d %s tours", + hh.getHhId(), person.getPersonNum(), + person.getPersonType(), t.getTourId(), tourPurpNum, + purposeTourLists[tourPurposeIndex].size(), + tourPurposeName); + + todModels[m].choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = "Individual Non-Mandatory Tour Departure Time Choice Model: Debug Statement for Household ID: " + + hh.getHhId() + + ", Person Num: " + + person.getPersonNum() + + ", Person Type: " + + person.getPersonType() + + ", Tour Id: " + + t.getTourId() + + ", num " + + tourPurpNum + + " of " + + purposeTourLists[tourPurposeIndex].size() + + " " + + tourPurposeName + " tours."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + loggingHeader = String.format("%s for %s", choiceModelDescription, + decisionMakerLabel); + + } + + // set the dmu object + todDmuObject.setHousehold(hh); + todDmuObject.setPerson(person); + todDmuObject.setTour(t); + + // check for multiple tours for this person, by purpose + // set the first or second switch if multiple tours for + // person, by purpose + if (purposeTourLists[tourPurposeIndex].size() == 1) + { + // not a multiple tour pattern + todDmuObject.setFirstTour(0); + todDmuObject.setSubsequentTour(0); + todDmuObject.setTourNumber(1); + todDmuObject.setEndOfPreviousScheduledTour(0); + } else if (purposeTourLists[tourPurposeIndex].size() > 1) + { + // Two-plus tour multiple tour pattern + if (tourPurpNum == 1) + { + // first of 2+ tours + todDmuObject.setFirstTour(1); + todDmuObject.setSubsequentTour(0); + todDmuObject.setTourNumber(tourPurpNum); + todDmuObject.setEndOfPreviousScheduledTour(0); + } else + { + // 2nd or greater tours + todDmuObject.setFirstTour(0); + todDmuObject.setSubsequentTour(1); + todDmuObject.setTourNumber(tourPurpNum); + // the ArrayList is 0-based, and we want the + // previous tour, so subtract 2 from tourPurpNum + // to get the right index + int otherTourEndHour = purposeTourLists[tourPurposeIndex].get( + tourPurpNum - 2).getTourArrivePeriod(); + todDmuObject.setEndOfPreviousScheduledTour(otherTourEndHour); + } + } + + // set the choice availability and sample + boolean[] departureTimeChoiceAvailability = person.getAvailableTimeWindows( + altStarts, altEnds); + Arrays.fill(tourDepartureTimeChoiceSample, 1); + + if (departureTimeChoiceAvailability.length != tourDepartureTimeChoiceSample.length) + { + logger.error(String + .format("error in individual non-mandatory departure time choice model for hhId=%d, personNum=%d, tour purpose index=%d, tour ArrayList index=%d.", + hh.getHhId(), person.getPersonNum(), tourPurposeIndex, + tourPurpNum - 1)); + logger.error(String + .format("length of the availability array determined by the number of alternatives set in the person scheduler=%d", + departureTimeChoiceAvailability.length)); + logger.error(String + .format("does not equal the length of the sample array determined by the number of alternatives in the individual non-mandatory tour UEC=%d.", + tourDepartureTimeChoiceSample.length)); + throw new RuntimeException(); + } + + // if all time windows for this person have already been + // scheduled, choose either the first and last + // alternatives and keep track of the number of times + // this condition occurs. + int alternativeAvailable = -1; + for (int a = 0; a < departureTimeChoiceAvailability.length; a++) + { + if (departureTimeChoiceAvailability[a]) + { + alternativeAvailable = a; + break; + } + } + + int chosen = -1; + int chosenStartPeriod = -1; + int chosenEndPeriod = -1; + + // alternate making the first and last periods chosen if + // no alternatives are available + if (alternativeAvailable < 0) + { + + if (noAltChoice == 1) + { + if (previouslySelectedDepartPeriod < 0) + { + chosenStartPeriod = altStarts[noAltChoice - 1]; + chosenEndPeriod = altEnds[noAltChoice - 1]; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, and no non-mandatory tour scheduled yet, depart AND arrive set to first period=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + "."); + } else + { + chosenStartPeriod = previouslySelectedArrivePeriod; + chosenEndPeriod = previouslySelectedArrivePeriod; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to arrive period of most recent scheduled non-mandatory tour=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + "."); + } + noWindowCountFirstTemp++; + noAltChoice = departureTimeChoiceAvailability.length - 1; + } else + { + if (previouslySelectedDepartPeriod < 0) + { + chosenStartPeriod = altStarts[noAltChoice - 1]; + chosenEndPeriod = altEnds[noAltChoice - 1]; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, and no non-mandatory tour scheduled yet, depart AND arrive set to last period=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + "."); + } else + { + chosenStartPeriod = previouslySelectedArrivePeriod; + chosenEndPeriod = previouslySelectedArrivePeriod; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to arrive period of most recent scheduled non-mandatory tour=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + "."); + } + noWindowCountLastTemp++; + noAltChoice = 1; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to work tour arrive period=" + + chosenEndPeriod + "."); + } + + // schedule the chosen alternative + person.scheduleWindow(chosenStartPeriod, chosenEndPeriod); + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + previouslySelectedDepartPeriod = chosenStartPeriod; + previouslySelectedArrivePeriod = chosenEndPeriod; + + if (runModeChoice) + { + + runModeChoice( hh, person,t,t.getTourDepartPeriod(),t.getTourArrivePeriod()); + } + + } else + { + + // calculate and store the mode choice logsum for + // the usual work location for this worker at the + // various + // departure time and duration alternativees + setTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(t, + departureTimeChoiceAvailability); + + if (hh.getDebugChoiceModels()) + { + hh.logTourObject(loggingHeader, modelLogger, person, t); + } + + todDmuObject.setOriginZone(mgraManager.getTaz(t.getTourOrigMgra())); + todDmuObject + .setDestinationZone(mgraManager.getTaz(t.getTourDestMgra())); + + float logsum = (float) todModels[m].computeUtilities(todDmuObject, + todDmuObject.getIndexValues(), departureTimeChoiceAvailability, + tourDepartureTimeChoiceSample); + + t.setTimeOfDayLogsum(logsum); + + Random hhRandom = hh.getHhRandom(); + int randomCount = hh.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available + // alternative, make choice. + if (todModels[m].getAvailabilityCount() > 0) + { + chosen = todModels[m].getChoiceResult(rn); + + // debug output + if (hh.getDebugChoiceModels()) + { + + double[] utilities = todModels[m].getUtilities(); + double[] probabilities = todModels[m].getProbabilities(); + boolean[] availabilities = todModels[m].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + + personTypeString + ", Tour Id: " + t.getTourId() + + ", Tour num: " + tourPurpNum + " of " + + purposeTourLists[tourPurposeIndex].size() + " " + + tourPurposeName + " tours."); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("-------------------- ------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < todModels[m].getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d out=%-3d, in=%-3d", + k + 1, altStarts[k], altEnds[k]); + modelLogger.info(String.format( + "%-20s%15s%18.6e%18.6e%18.6e", altString, + availabilities[k + 1], utilities[k], + probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d out=%-3d, in=%-3d", + chosen, altStarts[chosen - 1], altEnds[chosen - 1]); + modelLogger.info(String.format( + "Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to + // debug log file + todModels[m].logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + todModels[m].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate + // model specific log file + loggingHeader = String.format("%s for %s", + choiceModelDescription, decisionMakerLabel); + todModels[m].logUECResults(modelLogger, loggingHeader); + + } + + } else + { + + // since there were no alternatives with valid + // utility, assuming previous + // tour of this type scheduled up to the last + // period, so no periods left + // for this tour. + + // TODO: do a formal check for this so we can + // still flag other reasons why there's + // no valid utility for any alternative + chosen = departureTimeChoiceAvailability.length - 1; + noLaterAlternativeCountTemp++; + + } + + // schedule the chosen alternative + chosenStartPeriod = altStarts[chosen - 1]; + chosenEndPeriod = altEnds[chosen - 1]; + person.scheduleWindow(chosenStartPeriod, chosenEndPeriod); + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + previouslySelectedDepartPeriod = chosenStartPeriod; + previouslySelectedArrivePeriod = chosenEndPeriod; + + if (runModeChoice) + { + + runModeChoice(hh,person,t,t.getTourDepartPeriod(),t.getTourArrivePeriod()); + } + + } + + } catch (Exception e) + { + String errorMessage = String + .format("Exception caught for HHID=%d, personNum=%d, individual non-mandatory Departure time choice, tour ArrayList index=%d.", + hh.getHhId(), person.getPersonNum(), tourPurpNum - 1); + String decisionMakerLabel = String + .format("Final Individual Non-Mandatory Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + hh.getHhId(), person.getPersonNum(), person.getPersonType()); + hh.logPersonObject(decisionMakerLabel, modelLogger, person); + todModels[m].logUECResults(modelLogger, errorMessage); + + logger.error(errorMessage, e); + throw new RuntimeException(e); + } + + tourPurpNum++; + + } + + if (hh.getDebugChoiceModels()) + { + String decisionMakerLabel = String + .format("Final Individual Non-Mandatory Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + hh.getHhId(), person.getPersonNum(), person.getPersonType()); + hh.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + } + + } + + hh.setInmtodRandomCount(hh.getHhRandomCount()); + + } + + + public void runModeChoice(Household hh, Person person, Tour t, int chosenStartPeriod, int chosenEndPeriod) { + if (hh.getDebugChoiceModels()) + hh.logHouseholdObject( + "Pre Non-Mandatory Tour Mode Choice Household " + + hh.getHhId() + + ", Tour " + + t.getTourId() + + " of " + + person.getListOfIndividualNonMandatoryTours() + .size(), tourMCNonManLogger); + + // set the mode choice attributes needed by + // @variables in the UEC spreadsheets + setModeChoiceDmuAttributes(hh, person, t, chosenStartPeriod, + chosenEndPeriod); + + // use the mcModel object already setup for + // computing logsums and get + // the mode choice, where the selected + // worklocation and subzone an departure time + // and duration are set + // for this work tour. + int chosenMode = mcModel.getModeChoice(mcDmuObject, + t.getTourPrimaryPurpose()); + t.setTourModeChoice(chosenMode); + + } + public void applyJointModel(Household hh,boolean runTODChoice, boolean runModeChoice) + { + + jointModeChoiceTime = 0; + + // if no joint non-mandatory tours, nothing to do for this household. + Tour[] jointTours = hh.getJointTourArray(); + if (jointTours == null || jointTours.length == 0) return; + + Logger modelLogger = todLogger; + + // arrange the joint non-mandatory tours for this househol in an array + // of ArrayLists by purpose + getPriorityOrderedTourList(jointTours); + + // process tour lists by priority purpose + if(!runTODChoice) { + for (int i = 0; i < TOUR_PURPOSE_INDEX_ORDER.length; i++) + { + + int tourPurposeIndex = TOUR_PURPOSE_INDEX_ORDER[i]; + for (Tour t : purposeTourLists[tourPurposeIndex]) + runModeChoice(hh,t,t.getTourDepartPeriod(),t.getTourArrivePeriod()); + } + return; + } + + + // define variables to hold depart/arrive periods selected for the most + // recent tour. + // if a tour has no non-overlapping period available, set the periods to + // either the depart or arrive of the most recently determined + // if none has been selected yet, set to the first of last interval + int previouslySelectedDepartPeriod = -1; + int previouslySelectedArrivePeriod = -1; + + for (int i = 0; i < TOUR_PURPOSE_INDEX_ORDER.length; i++) + { + + int tourPurposeIndex = TOUR_PURPOSE_INDEX_ORDER[i]; + + // process each individual non-mandatory tour from the list + int m = -1; + int tourPurpNum = 1; + int noWindowCountFirstTemp = 0; + int noWindowCountLastTemp = 0; + int noLaterAlternativeCountTemp = 0; + for (Tour t : purposeTourLists[tourPurposeIndex]) + { + + try + { + + // get the choice model for the tour purpose + String tourPurposeName = t.getTourPurpose(); + m = todModelIndices[purposeNameIndexMap.get(tourPurposeName)]; + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (hh.getDebugChoiceModels()) + { + + String personNumsInJointTour = "Person Nums: ["; + for (int n : t.getPersonNumArray()) + personNumsInJointTour += " " + n; + personNumsInJointTour += " ]"; + + choiceModelDescription = String + .format("Joint Non-Mandatory Tour Departure Time Choice Model for: Purpose=%s", + tourPurposeName); + decisionMakerLabel = String.format( + "HH=%d, tourId=%d, %s, num=%d of %d %s tours", hh.getHhId(), + t.getTourId(), personNumsInJointTour, tourPurpNum, + purposeTourLists[tourPurposeIndex].size(), tourPurposeName); + + todModels[m].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + loggingHeader = String.format("%s for %s", choiceModelDescription, + decisionMakerLabel); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + } + + // set the dmu object + todDmuObject.setHousehold(hh); + todDmuObject.setTour(t); + + // check for multiple tours for this person, by purpose + // set the first or second switch if multiple tours for + // person, by purpose + if (purposeTourLists[tourPurposeIndex].size() == 1) + { + // not a multiple tour pattern + todDmuObject.setFirstTour(0); + todDmuObject.setSubsequentTour(0); + todDmuObject.setTourNumber(1); + todDmuObject.setEndOfPreviousScheduledTour(0); + } else if (purposeTourLists[tourPurposeIndex].size() > 1) + { + // Two-plus tour multiple tour pattern + if (tourPurpNum == 1) + { + // first of 2+ tours + todDmuObject.setFirstTour(1); + todDmuObject.setSubsequentTour(0); + todDmuObject.setTourNumber(tourPurpNum); + todDmuObject.setEndOfPreviousScheduledTour(0); + } else + { + // 2nd or greater tours + todDmuObject.setFirstTour(0); + todDmuObject.setSubsequentTour(1); + todDmuObject.setTourNumber(tourPurpNum); + // the ArrayList is 0-based, and we want the + // previous tour, so subtract 2 from tourPurpNum to + // get the right index + int otherTourEndHour = purposeTourLists[tourPurposeIndex].get( + tourPurpNum - 2).getTourArrivePeriod(); + todDmuObject.setEndOfPreviousScheduledTour(otherTourEndHour); + } + } + + // set the choice availability and sample + boolean[] departureTimeChoiceAvailability = hh + .getAvailableJointTourTimeWindows(t, altStarts, altEnds); + Arrays.fill(tourDepartureTimeChoiceSample, 1); + + if (departureTimeChoiceAvailability.length != tourDepartureTimeChoiceSample.length) + { + logger.error(String + .format("error in joint non-mandatory departure time choice model for hhId=%d, tour purpose index=%d, tour ArrayList index=%d.", + hh.getHhId(), tourPurposeIndex, tourPurpNum - 1)); + logger.error(String + .format("length of the availability array determined by the number of alternatives set in the person schedules=%d", + departureTimeChoiceAvailability.length)); + logger.error(String + .format("does not equal the length of the sample array determined by the number of alternatives in the joint non-mandatory tour UEC=%d.", + tourDepartureTimeChoiceSample.length)); + throw new RuntimeException(); + } + + // if all time windows for this person have already been + // scheduled, choose either the first and last + // alternatives and keep track of the number of times this + // condition occurs. + int alternativeAvailable = -1; + for (int a = 0; a < departureTimeChoiceAvailability.length; a++) + { + if (departureTimeChoiceAvailability[a]) + { + alternativeAvailable = a; + break; + } + } + + int chosen = -1; + int chosenStartPeriod = -1; + int chosenEndPeriod = -1; + + // alternate making the first and last periods chosen if no + // alternatives are available + if (alternativeAvailable < 0) + { + + if (noAltChoice == 1) + { + if (previouslySelectedDepartPeriod < 0) + { + chosenStartPeriod = altStarts[noAltChoice - 1]; + chosenEndPeriod = altEnds[noAltChoice - 1]; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, and no joint non-mandatory tour scheduled yet, depart AND arrive set to first period=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + + "."); + } else + { + chosenStartPeriod = previouslySelectedArrivePeriod; + chosenEndPeriod = previouslySelectedArrivePeriod; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to arrive period of most recent scheduled joint non-mandatory tour=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + + "."); + } + noWindowCountFirstTemp++; + noAltChoice = departureTimeChoiceAvailability.length - 1; + } else + { + if (previouslySelectedDepartPeriod < 0) + { + chosenStartPeriod = altStarts[noAltChoice - 1]; + chosenEndPeriod = altEnds[noAltChoice - 1]; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, and no joint non-mandatory tour scheduled yet, depart AND arrive set to last period=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + + "."); + } else + { + chosenStartPeriod = previouslySelectedArrivePeriod; + chosenEndPeriod = previouslySelectedArrivePeriod; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to arrive period of most recent scheduled joint non-mandatory tour=" + + chosenStartPeriod + + ", " + + chosenEndPeriod + + "."); + } + noWindowCountLastTemp++; + noAltChoice = 1; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to work tour arrive period=" + + chosenEndPeriod + "."); + } + + // schedule the chosen alternative + hh.scheduleJointTourTimeWindows(t, chosenStartPeriod, chosenEndPeriod); + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + previouslySelectedDepartPeriod = chosenStartPeriod; + previouslySelectedArrivePeriod = chosenEndPeriod; + + if (runModeChoice) + { + runModeChoice(hh,t,chosenStartPeriod,chosenEndPeriod); + + } + + } else + { + + // calculate and store the mode choice logsum for the + // usual work location for this worker at the various + // departure time and duration alternativees + setTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(t, + departureTimeChoiceAvailability); + + if (hh.getDebugChoiceModels()) + { + for (int p = 1; p < hh.getPersons().length; p++) + { + Person pers = hh.getPersons()[p]; + hh.logTourObject(loggingHeader, modelLogger, pers, t); + } + } + + todDmuObject.setOriginZone(mgraManager.getTaz(t.getTourOrigMgra())); + todDmuObject.setDestinationZone(mgraManager.getTaz(t.getTourDestMgra())); + + float logsum = (float) todModels[m].computeUtilities(todDmuObject, todDmuObject.getIndexValues(), + departureTimeChoiceAvailability, tourDepartureTimeChoiceSample); + t.setTimeOfDayLogsum(logsum); + + Random hhRandom = hh.getHhRandom(); + int randomCount = hh.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available + // alternative, make choice. + if (todModels[m].getAvailabilityCount() > 0) + { + chosen = todModels[m].getChoiceResult(rn); + + // debug output + if (hh.getDebugChoiceModels()) + { + + double[] utilities = todModels[m].getUtilities(); + double[] probabilities = todModels[m].getProbabilities(); + boolean[] availabilities = todModels[m].getAvailabilities(); + + modelLogger.info("Tour Id: " + t.getTourId() + ", Tour num: " + + tourPurpNum + " of " + + purposeTourLists[tourPurposeIndex].size() + " " + + tourPurposeName + " tours."); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("-------------------- ------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < todModels[m].getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d out=%-3d, in=%-3d", + k + 1, altStarts[k], altEnds[k]); + modelLogger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", + altString, availabilities[k + 1], utilities[k], + probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d out=%-3d, in=%-3d", chosen, + altStarts[chosen - 1], altEnds[chosen - 1]); + modelLogger.info(String.format( + "Choice: %s, with rn=%.8f, randomCount=%d", altString, rn, + randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug + // log file + todModels[m].logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + todModels[m].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate + // model specific log file + loggingHeader = String.format("%s for %s", choiceModelDescription, + decisionMakerLabel); + todModels[m].logUECResults(modelLogger, loggingHeader); + + } + + } else + { + + // since there were no alternatives with valid + // utility, assuming previous + // tour of this type scheduled up to the last + // period, so no periods left + // for this tour. + + // TODO: do a formal check for this so we can still + // flag other reasons why there's + // no valid utility for any alternative + chosen = departureTimeChoiceAvailability.length - 1; + noLaterAlternativeCountTemp++; + + } + + // schedule the chosen alternative + chosenStartPeriod = altStarts[chosen - 1]; + chosenEndPeriod = altEnds[chosen - 1]; + hh.scheduleJointTourTimeWindows(t, chosenStartPeriod, chosenEndPeriod); + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + previouslySelectedDepartPeriod = chosenStartPeriod; + previouslySelectedArrivePeriod = chosenEndPeriod; + + if (runModeChoice) + { + + runModeChoice(hh,t,chosenStartPeriod,chosenEndPeriod); + + } + + } + + } catch (Exception e) + { + String errorMessage = String + .format("Exception caught for HHID=%d, joint non-mandatory Departure time choice, tour ArrayList index=%d.", + hh.getHhId(), tourPurpNum - 1); + String decisionMakerLabel = "Final Joint Non-Mandatory Departure Time Person Objects:"; + for (int p = 1; p < hh.getPersons().length; p++) + { + Person pers = hh.getPersons()[p]; + hh.logPersonObject(decisionMakerLabel, modelLogger, pers); + todModels[m].logUECResults(modelLogger, errorMessage); + } + + logger.error(errorMessage, e); + throw new RuntimeException(); + } + + tourPurpNum++; + + } + + if (hh.getDebugChoiceModels()) + { + for (int p = 1; p < hh.getPersons().length; p++) + { + Person pers = hh.getPersons()[p]; + String decisionMakerLabel = String + .format("Final Joint Non-Mandatory Departure Time Person Objects: HH=%d, PersonNum=%d, PersonType=%s", + hh.getHhId(), pers.getPersonNum(), pers.getPersonType()); + hh.logPersonObject(decisionMakerLabel, modelLogger, pers); + } + } + + } + + hh.setJtodRandomCount(hh.getHhRandomCount()); + + } + + /** + * For joint tours + * @param hh + * @param t + * @param chosenStartPeriod + * @param chosenEndPeriod + */ + private void runModeChoice(Household hh, Tour t, int chosenStartPeriod, int chosenEndPeriod) { + + long check = System.nanoTime(); + + if (hh.getDebugChoiceModels()) + hh.logHouseholdObject( + "Pre Joint Non-Mandatory Tour Mode Choice Household " + + hh.getHhId() + ", Tour " + t.getTourId()+1 + " of " + + hh.getJointTourArray().length, + tourMCNonManLogger); + + // set the mode choice attributes needed by + // @variables in the UEC spreadsheets + setModeChoiceDmuAttributes(hh, null, t, chosenStartPeriod, + chosenEndPeriod); + + // use the mcModel object already setup for + // computing logsums and get + // the mode choice, where the selected + // worklocation and subzone an departure time and + // duration are set + // for this work tour. + int chosenMode = mcModel.getModeChoice(mcDmuObject, + t.getTourPrimaryPurpose()); + t.setTourModeChoice(chosenMode); + jointModeChoiceTime += (System.nanoTime() - check); + + } + + + + + + private void setModeChoiceDmuAttributes(Household household, Person person, Tour t, + int startPeriod, int endPeriod) + { + + t.setTourDepartPeriod(startPeriod); + t.setTourArrivePeriod(endPeriod); + + // update the MC dmuObjects for this person + mcDmuObject.setHouseholdObject(household); + mcDmuObject.setPersonObject(person); + mcDmuObject.setTourObject(t); + mcDmuObject.setDmuIndexValues(household.getHhId(), t.getTourOrigMgra(), + t.getTourOrigMgra(), t.getTourDestMgra(), household.getDebugChoiceModels()); + + + + mcDmuObject.setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(t + .getTourOrigMgra()))); + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager.getTaz(t + .getTourDestMgra()))); + + mcDmuObject.setOriginMgra(t.getTourOrigMgra()); + mcDmuObject.setDestMgra(t.getTourDestMgra()); + + } + + private void setTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(Tour tour, + boolean[] altAvailable) + { + + Person person = tour.getPersonObject(); + Household household = person.getHouseholdObject(); + + Arrays.fill(needToComputeLogsum, true); + Arrays.fill(modeChoiceLogsums, -999); + + Logger modelLogger = todLogger; + String choiceModelDescription = String.format( + "NonMandatory Tour Mode Choice Logsum calculation for %s Departure Time Choice", + tour.getTourPurpose()); + String decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), person + .getPersonNum(), person.getPersonType(), tour.getTourId(), person + .getListOfWorkTours().size()); + String loggingHeader = String + .format("%s %s", choiceModelDescription, decisionMakerLabel); + + for (int a = 1; a <= altStarts.length; a++) + { + + // if the depart/arrive alternative is unavailable, no need to check + // to see if a logsum has been calculated + if (!altAvailable[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + if (needToComputeLogsum[index]) + { + + String periodString = modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(startPeriod)) + + " to " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(endPeriod)); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, startPeriod, endPeriod); + + if (household.getDebugChoiceModels()) + household.logTourObject(loggingHeader + ", " + periodString, modelLogger, + person, mcDmuObject.getTourObject()); + + try + { + modeChoiceLogsums[index] = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel + ", " + + periodString); + } catch (Exception e) + { + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + periodString + " work tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + throw new RuntimeException(e); + } + needToComputeLogsum[index] = false; + } + + } + + todDmuObject.setModeChoiceLogsums(modeChoiceLogsums); + + mcDmuObject.getTourObject().setTourDepartPeriod(0); + mcDmuObject.getTourObject().setTourArrivePeriod(0); + } + + /** + * takes an ArrayList of individual non-mandatory tours creates an array of + * ArrayLists of tours by purpose + */ + private void getPriorityOrderedTourList(ArrayList toursIn) + { + + // clear the ArrayLists + for (int i = 0; i < purposeTourLists.length; i++) + { + if (purposeTourLists[i] != null) purposeTourLists[i].clear(); + } + + // go through the list of non-mandatory tours, and put each into an + // array of ArrayLists, by purpose. + for (Tour tour : toursIn) + { + int purposeIndex = tour.getTourPrimaryPurposeIndex(); + purposeTourLists[purposeIndex].add(tour); + } + + } + + /** + * takes an array of joint non-mandatory tours creates an array of + * ArrayLists of tours by purpose + */ + private void getPriorityOrderedTourList(Tour[] toursIn) + { + + // clear the ArrayLists + for (int i = 0; i < purposeTourLists.length; i++) + { + if (purposeTourLists[i] != null) purposeTourLists[i].clear(); + } + + // go through the list of non-mandatory tours, and put each into an + // array of ArrayLists, by purpose. + for (Tour tour : toursIn) + { + int purposeIndex = tour.getTourPrimaryPurposeIndex(); + purposeTourLists[purposeIndex].add(tour); + } + + } + + public long getJointModeChoiceTime() + { + return jointModeChoiceTime; + } + + public long getIndivModeChoiceTime() + { + return indivModeChoiceTime; + } + + public static void main(String[] args) + { + + // set values for these arguments so an object instance can be created + // and setup run to test integrity of UEC files before running full + // model. + HashMap propertyMap; + + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + ResourceBundle rb = ResourceBundle.getBundle(args[0]); + propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + } + + String matrixServerAddress = (String) propertyMap.get("RunModel.MatrixServerAddress"); + String matrixServerPort = (String) propertyMap.get("RunModel.MatrixServerPort"); + + MatrixDataServerIf ms = new MatrixDataServerRmi(matrixServerAddress, + Integer.parseInt(matrixServerPort), MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + + ModelStructure modelStructure = new SandagModelStructure(); + SandagCtrampDmuFactory dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + TazDataManager tazManager = TazDataManager.getInstance(propertyMap); + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + + String hhHandlerAddress = (String) propertyMap.get("RunModel.HouseholdServerAddress"); + int hhServerPort = Integer.parseInt((String) propertyMap + .get("RunModel.HouseholdServerPort")); + + HouseholdDataManagerIf householdDataManager = new HouseholdDataManagerRmi(hhHandlerAddress, + hhServerPort, SandagHouseholdDataManager.HH_DATA_SERVER_NAME); + + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population + // files and apply its tables to objects mapping method. + boolean restartHhServer = false; + try + { + // possible values for the following can be none, ao, cdap, imtf, + // imtod, awf, awl, awtod, jtf, jtl, jtod, inmtf, inmtl, inmtod, + // stf, stl + String restartModel = (String) propertyMap.get("RunModel.RestartWithHhServer"); + if (restartModel.equalsIgnoreCase("none")) restartHhServer = true; + else if (restartModel.equalsIgnoreCase("uwsl") || restartModel.equalsIgnoreCase("ao") + || restartModel.equalsIgnoreCase("fp") || restartModel.equalsIgnoreCase("cdap") + || restartModel.equalsIgnoreCase("imtf") + || restartModel.equalsIgnoreCase("imtod") + || restartModel.equalsIgnoreCase("awf") || restartModel.equalsIgnoreCase("awl") + || restartModel.equalsIgnoreCase("awtod") + || restartModel.equalsIgnoreCase("jtf") || restartModel.equalsIgnoreCase("jtl") + || restartModel.equalsIgnoreCase("jtod") + || restartModel.equalsIgnoreCase("inmtf") + || restartModel.equalsIgnoreCase("inmtl") + || restartModel.equalsIgnoreCase("inmtod") + || restartModel.equalsIgnoreCase("stf") || restartModel.equalsIgnoreCase("stl")) + restartHhServer = false; + } catch (MissingResourceException e) + { + restartHhServer = true; + } + + if (restartHhServer) + { + + householdDataManager.setDebugHhIdsFromHashmap(); + + String inputHouseholdFileName = (String) propertyMap + .get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = (String) propertyMap + .get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(1.0f, 0); + householdDataManager.setupHouseholdDataManager(modelStructure, inputHouseholdFileName, + inputPersonFileName); + + } else + { + + householdDataManager.setHouseholdSampleRate(1.0f, 0); + householdDataManager.setDebugHhIdsFromHashmap(); + householdDataManager.setTraceHouseholdSet(); + + } + + // int id = householdDataManager.getArrayIndex( 1033380 ); + // int id = householdDataManager.getArrayIndex( 1033331 ); + int id = householdDataManager.getArrayIndex(423804); + Household[] hh = householdDataManager.getHhArray(id, id); + + TourModeChoiceModel inmmcModel = new TourModeChoiceModel(propertyMap, modelStructure, + ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY, dmuFactory, logsumHelper); + + NonMandatoryTourDepartureAndDurationTime testObject = new NonMandatoryTourDepartureAndDurationTime( + propertyMap, modelStructure, dmuFactory, inmmcModel); + + testObject.applyIndivModel(hh[0], true, true); + testObject.applyJointModel(hh[0], true, true); + + /** + * used this block of code to test for typos and implemented dmu + * methiods in the TOD choice UECs + * + * String uecFileDirectory = propertyMap.get( + * CtrampApplication.PROPERTIES_UEC_PATH ); String todUecFileName = + * propertyMap.get( IMTOD_UEC_FILE_TARGET ); todUecFileName = + * uecFileDirectory + todUecFileName; + * + * ModelStructure modelStructure = new SandagModelStructure(); + * SandagCtrampDmuFactory dmuFactory = new + * SandagCtrampDmuFactory(modelStructure); + * TourDepartureTimeAndDurationDMU todDmuObject = + * dmuFactory.getTourDepartureTimeAndDurationDMU(); + * + * int[] indices = { 0, 1, 2, 3, 4, 5 }; for (int i : indices ) { int + * uecIndex = i + 4; File uecFile = new File(todUecFileName); + * UtilityExpressionCalculator uec = new + * UtilityExpressionCalculator(uecFile, uecIndex, 0, propertyMap, + * (VariableTable) todDmuObject); } + */ + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingChoiceDMU.java new file mode 100644 index 0000000..8cbfa08 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingChoiceDMU.java @@ -0,0 +1,332 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + * @author crf
+ * Started: Apr 14, 2009 1:34:03 PM + */ +public class ParkingChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(ParkingChoiceDMU.class); + + protected HashMap methodIndexMap; + + private IndexValues dmuIndex; + + private int personType; + private int activityIntervals; + private int destPurpose; + private double reimbPct; + + private double[] distancesOrigAlt; + private double[] distancesAltDest; + + private double[] altParkingCostsM; + private int[] altMstallsoth; + private int[] altMstallssam; + private float[] altMparkcost; + private int[] altDstallsoth; + private int[] altDstallssam; + private float[] altDparkcost; + private int[] altHstallsoth; + private int[] altHstallssam; + private float[] altHparkcost; + private int[] altNumfreehrs; + + private int[] parkAreaMgras; + private int[] altMgraIndices; + + public ParkingChoiceDMU() + { + dmuIndex = new IndexValues(); + } + + public void setDmuIndexValues(int hhId, int origMgra, int destMgra, boolean hhDebug) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setOriginZone(origMgra); + dmuIndex.setDestZone(destMgra); + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + + if (hhDebug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug Parking Choice UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public void setPersonType(int value) + { + personType = value; + } + + public void setActivityIntervals(int value) + { + activityIntervals = value; + } + + public void setDestPurpose(int value) + { + destPurpose = value; + } + + public void setReimbPct(double value) + { + reimbPct = value; + } + + /** + * @param mgras + * is the array of MGRAs in parking area from + * "plc.alts.corresp.file". This is a 0-based array + */ + public void setParkAreaMgraArray(int[] mgras) + { + parkAreaMgras = mgras; + } + + /** + * @param indices + * is an array of indices representing this person's park + * location choice sample. the index value in this array points + * to the parkAreaMgras element, and the corresponding mgra + * value. This is a 0-based array + */ + public void setSampleIndicesArray(int[] indices) + { + altMgraIndices = indices; + } + + public void setDistancesOrigAlt(double[] distances) + { + distancesOrigAlt = distances; + } + + public void setDistancesAltDest(double[] distances) + { + distancesAltDest = distances; + } + + public void setParkingCostsM(double[] values) + { + altParkingCostsM = values; + } + + public void setMstallsoth(int[] values) + { + altMstallsoth = values; + } + + public void setMstallssam(int[] values) + { + altMstallssam = values; + } + + public void setMparkCost(float[] values) + { + altMparkcost = values; + } + + public void setDstallsoth(int[] values) + { + altDstallsoth = values; + } + + public void setDstallssam(int[] values) + { + altDstallssam = values; + } + + public void setDparkCost(float[] values) + { + altDparkcost = values; + } + + public void setHstallsoth(int[] values) + { + altHstallsoth = values; + } + + public void setHstallssam(int[] values) + { + altHstallssam = values; + } + + public void setHparkCost(float[] values) + { + altHparkcost = values; + } + + public void setNumfreehrs(int[] values) + { + altNumfreehrs = values; + } + + public int getPersonType() + { + return personType; + } + + public int getActivityIntervals() + { + return activityIntervals; + } + + public int getTripDestPurpose() + { + return destPurpose; + } + + public double getReimbPct() + { + return reimbPct; + } + + /** + * @param alt + * is the index value in the alternatives array (0,...,num alts). + * @return the distance between the trip origin mgra and the alternative + * park mgra. + */ + public double getDistanceTripOrigToParkAlt(int alt) + { + return distancesOrigAlt[alt]; + } + + /** + * @param alt + * is the index value in the alternatives array (0,...,num alts). + * @return the distance between the alternative park mgra and the trip + * destination mgra. + */ + public double getDistanceTripDestFromParkAlt(int alt) + { + return distancesAltDest[alt]; + } + + /** + * @param alt + * is the index value in the alternatives array (0,...,num alts). + * @return the cost for this person to park at the alternative park mgra. + */ + public double getLsWgtAvgCostM(int alt) + { + return altParkingCostsM[alt]; + } + + public int getMstallsoth(int alt) + { + return altMstallsoth[alt]; + } + + public int getMstallssam(int alt) + { + return altMstallssam[alt]; + } + + public float getMparkcost(int alt) + { + return altMparkcost[alt]; + } + + public int getDstallsoth(int alt) + { + return altDstallsoth[alt]; + } + + public int getDstallssam(int alt) + { + return altDstallssam[alt]; + } + + public float getDparkcost(int alt) + { + return altDparkcost[alt]; + } + + public int getHstallsoth(int alt) + { + return altHstallsoth[alt]; + } + + public int getHstallssam(int alt) + { + return altHstallssam[alt]; + } + + public float getHparkcost(int alt) + { + return altHparkcost[alt]; + } + + public int getNumfreehrs(int alt) + { + return altNumfreehrs[alt]; + } + + /** + * @return 1 if the altMgra attribute that was set equals the trip + * destination + */ + public int getDestSameAsParkAlt(int alt) + { + int index = altMgraIndices[alt]; + int altMgra = parkAreaMgras[index]; + return altMgra == dmuIndex.getDestZone() ? 1 : 0; + } + + /** + * @return the altMgra attribute for this alternative + */ + public int getParkMgraAlt(int alt) + { + int index = altMgraIndices[alt]; + int altMgra = parkAreaMgras[index]; + return altMgra; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingProvisionChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingProvisionChoiceDMU.java new file mode 100644 index 0000000..cde7ed7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingProvisionChoiceDMU.java @@ -0,0 +1,256 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + * @author crf
+ * Started: Apr 14, 2009 11:09:58 AM + */ +public class ParkingProvisionChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(ParkingProvisionChoiceDMU.class); + + protected HashMap methodIndexMap; + + private Household hh; + private Person person; + private IndexValues dmuIndex; + + private int mgraParkArea; + private int numFreeHours; + private int mstallsoth; + private int mstallssam; + private float mparkcost; + private int dstallsoth; + private int dstallssam; + private float dparkcost; + private int hstallsoth; + private int hstallssam; + private float hparkcost; + + private double lsWgtAvgCostM; + private double lsWgtAvgCostD; + private double lsWgtAvgCostH; + + public ParkingProvisionChoiceDMU() + { + dmuIndex = new IndexValues(); + } + + /** need to set hh and home taz before using **/ + public void setPersonObject(Person person) + { + hh = person.getHouseholdObject(); + this.person = person; + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug Free Parking UEC"); + } + } + + public void setMgraParkArea(int value) + { + mgraParkArea = value; + } + + public void setNumFreeHours(int value) + { + numFreeHours = value; + } + + public void setLsWgtAvgCostM(double cost) + { + lsWgtAvgCostM = cost; + } + + public void setLsWgtAvgCostD(double cost) + { + lsWgtAvgCostD = cost; + } + + public void setLsWgtAvgCostH(double cost) + { + lsWgtAvgCostH = cost; + } + + public void setMStallsOth(int value) + { + mstallsoth = value; + } + + public void setMStallsSam(int value) + { + mstallssam = value; + } + + public void setMParkCost(float value) + { + mparkcost = value; + } + + public void setDStallsOth(int value) + { + dstallsoth = value; + } + + public void setDStallsSam(int value) + { + dstallssam = value; + } + + public void setDParkCost(float value) + { + dparkcost = value; + } + + public void setHStallsOth(int value) + { + hstallsoth = value; + } + + public void setHStallsSam(int value) + { + hstallssam = value; + } + + public void setHParkCost(float value) + { + hparkcost = value; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /* dmu @ functions */ + + public int getIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + public double getLsWgtAvgCostM() + { + return lsWgtAvgCostM; + } + + public double getLsWgtAvgCostD() + { + return lsWgtAvgCostD; + } + + public double getLsWgtAvgCostH() + { + return lsWgtAvgCostH; + } + + public int getMgraParkArea() + { + return mgraParkArea; + } + + public int getNumFreeHours() + { + return numFreeHours; + } + + public int getMStallsOth() + { + return mstallsoth; + } + + public int getMStallsSam() + { + return mstallssam; + } + + public float getMParkCost() + { + return mparkcost; + } + + public int getDStallsOth() + { + return dstallsoth; + } + + public int getDStallsSam() + { + return dstallssam; + } + + public float getDParkCost() + { + return dparkcost; + } + + public int getHStallsOth() + { + return hstallsoth; + } + + public int getHStallsSam() + { + return hstallssam; + } + + public float getHParkCost() + { + return hparkcost; + } + + public int getWorkLocMgra() + { + return person.getWorkLocation(); + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingProvisionModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingProvisionModel.java new file mode 100644 index 0000000..e283792 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/ParkingProvisionModel.java @@ -0,0 +1,216 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class ParkingProvisionModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("fp"); + + private static final String FP_CONTROL_FILE_TARGET = "fp.uec.file"; + private static final String FP_DATA_SHEET_TARGET = "fp.data.page"; + private static final String FP_MODEL_SHEET_TARGET = "fp.model.page"; + + public static final int FP_MODEL_NO_REIMBURSEMENT_CHOICE = -1; + public static final int FP_MODEL_FREE_ALT = 1; + public static final int FP_MODEL_PAY_ALT = 2; + public static final int FP_MODEL_REIMB_ALT = 3; + + private static final String REIMBURSEMENT_MEAN = "park.cost.reimb.mean"; + private static final String REIMBURSEMENT_STD_DEV = "park.cost.reimb.std.dev"; + + private MgraDataManager mgraManager; + + private double meanReimb; + private double stdDevReimb; + + private int[] mgraParkArea; + private int[] numfreehrs; + private int[] hstallsoth; + private int[] hstallssam; + private float[] hparkcost; + private int[] dstallsoth; + private int[] dstallssam; + private float[] dparkcost; + private int[] mstallsoth; + private int[] mstallssam; + private float[] mparkcost; + + private double[] lsWgtAvgCostM; + private double[] lsWgtAvgCostD; + private double[] lsWgtAvgCostH; + + private ChoiceModelApplication fpModel; + private ParkingProvisionChoiceDMU fpDmuObject; + + public ParkingProvisionModel(HashMap propertyMap, CtrampDmuFactoryIf dmuFactory) + { + mgraManager = MgraDataManager.getInstance(propertyMap); + setupFreeParkingChoiceModelApplication(propertyMap, dmuFactory); + } + + private void setupFreeParkingChoiceModelApplication(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + logger.info("setting up free parking choice model."); + + // locate the free parking UEC + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String fpUecFile = uecFileDirectory + propertyMap.get(FP_CONTROL_FILE_TARGET); + + int dataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, FP_DATA_SHEET_TARGET); + int modelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, FP_MODEL_SHEET_TARGET); + + // create the auto ownership choice model DMU object. + fpDmuObject = dmuFactory.getFreeParkingChoiceDMU(); + + // create the auto ownership choice model object + fpModel = new ChoiceModelApplication(fpUecFile, modelSheet, dataSheet, propertyMap, + (VariableTable) fpDmuObject); + + meanReimb = Float.parseFloat(propertyMap.get(REIMBURSEMENT_MEAN)); + stdDevReimb = Float.parseFloat(propertyMap.get(REIMBURSEMENT_STD_DEV)); + + mgraParkArea = mgraManager.getMgraParkAreas(); + numfreehrs = mgraManager.getNumFreeHours(); + lsWgtAvgCostM = mgraManager.getLsWgtAvgCostM(); + lsWgtAvgCostD = mgraManager.getLsWgtAvgCostD(); + lsWgtAvgCostH = mgraManager.getLsWgtAvgCostH(); + mstallsoth = mgraManager.getMStallsOth(); + mstallssam = mgraManager.getMStallsSam(); + mparkcost = mgraManager.getMParkCost(); + dstallsoth = mgraManager.getDStallsOth(); + dstallssam = mgraManager.getDStallsSam(); + dparkcost = mgraManager.getDParkCost(); + hstallsoth = mgraManager.getHStallsOth(); + hstallssam = mgraManager.getHStallsSam(); + hparkcost = mgraManager.getHParkCost(); + + } + + public void applyModel(Household hhObject) + { + + Random hhRandom = hhObject.getHhRandom(); + + // person array is 1-based + Person[] person = hhObject.getPersons(); + for (int i = 1; i < person.length; i++) + { + + int workLoc = person[i].getWorkLocation(); + if (workLoc == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + + person[i].setFreeParkingAvailableResult(FP_MODEL_NO_REIMBURSEMENT_CHOICE); + person[i].setParkingReimbursement(FP_MODEL_NO_REIMBURSEMENT_CHOICE); + + } else if (workLoc > 0 && mgraParkArea[workLoc] == MgraDataManager.PARK_AREA_ONE) + { + + double randomNumber = hhRandom.nextDouble(); + int chosen = getParkingChoice(person[i], randomNumber); + person[i].setFreeParkingAvailableResult(chosen); + + if (chosen == FP_MODEL_REIMB_ALT) + { + double logReimbPct = meanReimb + hhRandom.nextGaussian() * stdDevReimb; + person[i].setParkingReimbursement(Math.exp(logReimbPct)); + } else if (chosen == FP_MODEL_FREE_ALT) + { + person[i].setParkingReimbursement(0.0); + } else if (chosen == FP_MODEL_PAY_ALT) + { + person[i].setParkingReimbursement(0.0); + } + + } else + { + + person[i].setFreeParkingAvailableResult(FP_MODEL_NO_REIMBURSEMENT_CHOICE); + person[i].setParkingReimbursement(0.0); + + } + } + + hhObject.setFpRandomCount(hhObject.getHhRandomCount()); + } + + private int getParkingChoice(Person personObj, double randomNumber) + { + + // get the corresponding household object + Household hhObj = personObj.getHouseholdObject(); + fpDmuObject.setPersonObject(personObj); + + fpDmuObject.setMgraParkArea(mgraParkArea[personObj.getWorkLocation()]); + fpDmuObject.setNumFreeHours(numfreehrs[personObj.getWorkLocation()]); + fpDmuObject.setLsWgtAvgCostM(lsWgtAvgCostM[personObj.getWorkLocation()]); + fpDmuObject.setLsWgtAvgCostD(lsWgtAvgCostD[personObj.getWorkLocation()]); + fpDmuObject.setLsWgtAvgCostH(lsWgtAvgCostH[personObj.getWorkLocation()]); + fpDmuObject.setMStallsOth(mstallsoth[personObj.getWorkLocation()]); + fpDmuObject.setMStallsSam(mstallssam[personObj.getWorkLocation()]); + fpDmuObject.setMParkCost(mparkcost[personObj.getWorkLocation()]); + fpDmuObject.setDStallsSam(dstallssam[personObj.getWorkLocation()]); + fpDmuObject.setDStallsOth(dstallsoth[personObj.getWorkLocation()]); + fpDmuObject.setDParkCost(dparkcost[personObj.getWorkLocation()]); + fpDmuObject.setHStallsOth(hstallsoth[personObj.getWorkLocation()]); + fpDmuObject.setHStallsSam(hstallssam[personObj.getWorkLocation()]); + fpDmuObject.setHParkCost(hparkcost[personObj.getWorkLocation()]); + + // set the zone and dest attributes to the person's work location + fpDmuObject.setDmuIndexValues(hhObj.getHhId(), personObj.getWorkLocation(), + hhObj.getHhTaz(), personObj.getWorkLocation()); + + // compute utilities and choose auto ownership alternative. + float logsum = (float) fpModel.computeUtilities(fpDmuObject, fpDmuObject.getDmuIndexValues()); + personObj.setParkingProvisionLogsum(logsum); + + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + if (fpModel.getAvailabilityCount() > 0) + { + try { + chosenAlt = fpModel.getChoiceResult(randomNumber); + }catch(Exception e) { + + logger.fatal("Error trying to get parking location for HHID="+hhObj.getHhId()+", PERSID="+ + personObj.getPersonId() +" Destination MGRA="+personObj.getWorkLocation()); + throw new RuntimeException(e); + } + } else + { + String decisionMaker = String.format("HHID=%d, PERSID=%d", hhObj.getHhId(), + personObj.getPersonId()); + String errorMessage = String + .format("Exception caught for %s, no available free parking alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.error(errorMessage); + + fpModel.logUECResults(logger, decisionMaker); + throw new RuntimeException(); + } + + // write choice model alternative info to log file + if (hhObj.getDebugChoiceModels()) + { + String decisionMaker = String.format("HHID=%d, PERSID=%d", hhObj.getHhId(), + personObj.getPersonId()); + fpModel.logAlternativesInfo("Free parking Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d with rn %.8f", + "Free parking Choice", decisionMaker, chosenAlt, randomNumber)); + fpModel.logUECResults(logger, decisionMaker); + } + + return chosenAlt; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/Person.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Person.java new file mode 100644 index 0000000..9ce7486 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Person.java @@ -0,0 +1,2032 @@ +package org.sandag.abm.ctramp; + +import java.util.ArrayList; +import org.apache.log4j.Logger; + +public class Person + implements java.io.Serializable +{ + + // 8 am default departure period + public static final int DEFAULT_MANDATORY_START_PERIOD = 8; + // 10 am default departure period + public static final int DEFAULT_NON_MANDATORY_START_PERIOD = 12; + // 12 pm default departure period + public static final int DEFAULT_AT_WORK_SUBTOUR_START_PERIOD = 16; + // 5 pm default arrival period + public static final int DEFAULT_MANDATORY_END_PERIOD = 26; + // 3 pm default arrival period + public static final int DEFAULT_NON_MANDATORY_END_PERIOD = 22; + // 2 pm default arrival period + public static final int DEFAULT_AT_WORK_SUBTOUR_END_PERIOD = 20; + + public static final int MIN_ADULT_AGE = 19; + public static final int MIN_STUDENT_AGE = 5; + + + // person type strings used for data summaries + public static final String PERSON_TYPE_FULL_TIME_WORKER_NAME = "Full-time worker"; + public static final String PERSON_TYPE_PART_TIME_WORKER_NAME = "Part-time worker"; + public static final String PERSON_TYPE_UNIVERSITY_STUDENT_NAME = "University student"; + public static final String PERSON_TYPE_NON_WORKER_NAME = "Non-worker"; + public static final String PERSON_TYPE_RETIRED_NAME = "Retired"; + public static final String PERSON_TYPE_STUDENT_DRIVING_NAME = "Student of driving age"; + public static final String PERSON_TYPE_STUDENT_NON_DRIVING_NAME = "Student of non-driving age"; + public static final String PERSON_TYPE_PRE_SCHOOL_CHILD_NAME = "Child too young for school"; + public static final int PERSON_TYPE_FULL_TIME_WORKER_INDEX = 1; + public static final int PERSON_TYPE_PART_TIME_WORKER_INDEX = 2; + public static final int PERSON_TYPE_UNIVERSITY_STUDENT_INDEX = 3; + public static final int PERSON_TYPE_NON_WORKER_INDEX = 4; + public static final int PERSON_TYPE_RETIRED_INDEX = 5; + public static final int PERSON_TYPE_STUDENT_DRIVING_INDEX = 6; + public static final int PERSON_TYPE_STUDENT_NON_DRIVING_INDEX = 7; + public static final int PERSON_TYPE_PRE_SCHOOL_CHILD_INDEX = 8; + public static final int MALE_INDEX = 1; + public static final int FEMALE_INDEX = 2; + public static final String[] PERSON_TYPE_NAME_ARRAY = { + PERSON_TYPE_FULL_TIME_WORKER_NAME, PERSON_TYPE_PART_TIME_WORKER_NAME, + PERSON_TYPE_UNIVERSITY_STUDENT_NAME, PERSON_TYPE_NON_WORKER_NAME, + PERSON_TYPE_RETIRED_NAME, PERSON_TYPE_STUDENT_DRIVING_NAME, + PERSON_TYPE_STUDENT_NON_DRIVING_NAME, PERSON_TYPE_PRE_SCHOOL_CHILD_NAME}; + + // Employment category (1-employed FT, 2-employed PT, 3-not employed, + // 4-under age + // 16) + // Student category (1 - student in grade or high school; 2 - student in + // college + // or higher; 3 - not a student) + + public static final String EMPLOYMENT_CATEGORY_FULL_TIME_WORKER_NAME = "Full-time worker"; + public static final String EMPLOYMENT_CATEGORY_PART_TIME_WORKER_NAME = "Part-time worker"; + public static final String EMPLOYMENT_CATEGORY_NOT_EMPLOYED_NAME = "Not employed"; + public static final String EMPLOYMENT_CATEGORY_UNDER_AGE_16_NAME = "Under age 16"; + + public static final String[] EMPLOYMENT_CATEGORY_NAME_ARRAY = { + EMPLOYMENT_CATEGORY_FULL_TIME_WORKER_NAME, EMPLOYMENT_CATEGORY_PART_TIME_WORKER_NAME, + EMPLOYMENT_CATEGORY_NOT_EMPLOYED_NAME, EMPLOYMENT_CATEGORY_UNDER_AGE_16_NAME}; + + public static final String STUDENT_CATEGORY_GRADE_OR_HIGH_SCHOOL_NAME = "Grade or high school"; + public static final String STUDENT_CATEGORY_COLLEGE_OR_HIGHER_NAME = "College or higher"; + public static final String STUDENT_CATEGORY_NOT_STUDENT_NAME = "Not student"; + + public static final String[] STUDENT_CATEGORY_NAME_ARRAY = { + STUDENT_CATEGORY_GRADE_OR_HIGH_SCHOOL_NAME, STUDENT_CATEGORY_COLLEGE_OR_HIGHER_NAME, + STUDENT_CATEGORY_NOT_STUDENT_NAME }; + + private Household hhObj; + + private int persNum; + private int persId; + private short persAge; + private short persGender; + private short persPecasOccup; + private short persActivityCode; + private short persEmploymentCategory; + private short persStudentCategory; + private short personType; + private boolean gradeSchool; + private boolean highSchool; + private boolean highSchoolGraduate; + private boolean hasBachelors; + + // individual value-of-time in $/hr + private float persValueOfTime; + + private int workLocation; + private int workLocSegmentIndex; + private float workLocDistance; + private float workLocLogsum; + private int schoolLoc; + private int schoolLocSegmentIndex; + private float schoolLocDistance; + private float schoolLocLogsum; + + private float timeFactorWork; + private float timeFactorNonWork; + + private short freeParkingAvailable; + private short internalExternalTripChoice = 1; + private float reimbursePercent; + + private float worksFromHomeLogsum; + private float parkingProvisionLogsum; + private float telecommuteLogsum; + private float ieLogsum; + private float cdapLogsum; + private float imtfLogsum; + private float inmtfLogsum; + + private String cdapActivity; + private short imtfChoice; + private short inmtfChoice; + + private int maxAdultOverlaps; + private int maxChildOverlaps; + + private short telecommuteChoice; + + private ArrayList workTourArrayList; + private ArrayList schoolTourArrayList; + private ArrayList indNonManTourArrayList; + private ArrayList atWorkSubtourArrayList; + + // private Scheduler scheduler; + // windows[] is 1s based - indexed from 1 to number of intervals. + private short[] windows; + + private int windowBeforeFirstMandJointTour; + private int windowBetweenFirstLastMandJointTour; + private int windowAfterLastMandJointTour; + + private ModelStructure modelStructure; + + public Person(Household hhObj, int persNum, ModelStructure modelStructure) + { + this.hhObj = hhObj; + this.persNum = persNum; + this.workTourArrayList = new ArrayList(); + this.schoolTourArrayList = new ArrayList(); + this.indNonManTourArrayList = new ArrayList(); + this.atWorkSubtourArrayList = new ArrayList(); + this.modelStructure = modelStructure; + + initializeWindows(); + + freeParkingAvailable = ParkingProvisionModel.FP_MODEL_REIMB_ALT; + reimbursePercent = 0.43f; + } + + public Household getHouseholdObject() + { + return hhObj; + } + + public ArrayList getListOfWorkTours() + { + return workTourArrayList; + } + + public ArrayList getListOfSchoolTours() + { + return schoolTourArrayList; + } + + public ArrayList getListOfIndividualNonMandatoryTours() + { + return indNonManTourArrayList; + } + + public ArrayList getListOfAtWorkSubtours() + { + return atWorkSubtourArrayList; + } + + public short[] getTimeWindows() + { + return windows; + } + + public String getTimePeriodLabel(int windowIndex) + { + return modelStructure.getTimePeriodLabel(windowIndex); + } + + public void initializeWindows() + { + windows = new short[modelStructure.getNumberOfTimePeriods() + 1]; + } + + public void resetTimeWindow(int startPeriod, int endPeriod) + { + for (int i = startPeriod; i <= endPeriod; i++) + { + windows[i] = 0; + } + } + + public void resetTimeWindow() + { + for (int i = 0; i < windows.length; i++) + { + windows[i] = 0; + } + } + + /** + * code the time window array for this tour being scheduled. 0: unscheduled, + * 1: scheduled, middle of tour, 2: scheduled, start of tour, 3: scheduled, + * end of tour, 4: scheduled, end of previous tour, start of current tour or + * end of current tour, start of subsequent tour; or current tour start/end + * same period. + * + * @param start + * is the departure period index for the tour + * @param end + * is the arrival period index for the tour + */ + public void scheduleWindow(int start, int end) + { + + /* + * This is the logic used in ARC/MTC, but for SANDAG, we don't allow + * overlapping tours + * + * + * if (start == end) { windows[start] = 4; } else { if (windows[start] + * == 3) windows[start] = 4; else if (windows[start] == 0) + * windows[start] = 2; + * + * if (windows[end] == 2) windows[end] = 4; else if (windows[end] == 0) + * windows[end] = 3; } + * + * for (int h = start + 1; h < end; h++) { windows[h] = 1; } + */ + + for (int h = start; h <= end; h++) + { + windows[h] = 1; + } + + } + + public boolean[] getAvailableTimeWindows(int[] altStarts, int[] altEnds) + { + + // availability array is used by UEC based choice model, which uses + // 1-based + // indexing + boolean[] availability = new boolean[altStarts.length + 1]; + + for (int i = 1; i <= altStarts.length; i++) + { + int start = altStarts[i - 1]; + int end = altEnds[i - 1]; + availability[i] = isWindowAvailable(start, end); + } + + return availability; + } + + public boolean isWindowAvailable(int start, int end) + { + + /* + * This is the logic used in ARC/MTC, but for SANDAG, we don't allow + * overlapping tours + * + * + * // check start period, if window is 0, it is unscheduled; // if + * window is 3, it is the last period of another tour, and available // + * as the first period of this tour. if (windows[start] == 1) return + * false; else if (windows[start] == 2 && start != end) return false; + * + * // check end period, if window is 0, it is unscheduled; // if window + * is 2, it is the first period of another tour, and available // as the + * last period of this tour. if (windows[end] == 1) return false; else + * if (windows[end] == 3 && start != end) return false; + * + * // the alternative is available if start and end are available, and + * all periods // from start+1,...,end-1 are available. for (int h = + * start + 1; h < end; h++) { if (windows[h] > 0) return false; } + * + * return true; + */ + + // the alternative is available if all intervals between start and end, + // inclusive, are available + for (int h = start; h <= end; h++) + { + if (windows[h] > 0) return false; + } + + return true; + + } + + /** + * @return true if the window for the argument is the end of a previously + * scheduled tour and this period does not overlap with any other + * tour. + */ + public boolean isPreviousArrival(int period) + { + + if (windows[period] == 3 || windows[period] == 4) return true; + else return false; + + } + + /** + * @return true if the window for the argument is the start of a previously + * scheduled tour and this period does not overlap with any other + * tour. + */ + public boolean isPreviousDeparture(int period) + { + + if (windows[period] == 2 || windows[period] == 4) return true; + else return false; + + } + + public boolean isPeriodAvailable(int period) + { + // if windows[index] == 0, the period is available. + + // if window[index] is 0 (available), 2 (start of another tour), 3 (end + // of + // another tour), 4 available for this period only, the period is + // available; + // otherwise, if window[index] is 1 (middle of another tour), it is not + // available. + if (windows[period] == 1) return false; + else return true; + } + + public void setPersId(int id) + { + persId = id; + } + + public void setFreeParkingAvailableResult(int chosenAlt) + { + freeParkingAvailable = (short) chosenAlt; + } + + /** + * set the chosen alternative number: 1=no, 2=yes + * + * @param chosenAlt + */ + public void setInternalExternalTripChoiceResult(int chosenAlt) + { + internalExternalTripChoice = (short) chosenAlt; + } + + public void setParkingReimbursement(double pct) + { + reimbursePercent = (float) pct; + } + + public void setWorkLocationSegmentIndex(int workSegment) + { + workLocSegmentIndex = workSegment; + } + + public void setSchoolLocationSegmentIndex(int schoolSegment) + { + schoolLocSegmentIndex = schoolSegment; + } + + public void setPersAge(int age) + { + persAge = (short) age; + } + + public void setPersGender(int gender) + { + persGender = (short) gender; + } + + public void setPersPecasOccup(int occup) + { + persPecasOccup = (short) occup; + } + + public void setPersActivityCode(int actCode) + { + persActivityCode = (short) actCode; + } + + public void setPersEmploymentCategory(int category) + { + persEmploymentCategory = (short) category; + } + + public void setPersStudentCategory(int category) + { + persStudentCategory = (short) category; + } + + public void setPersonTypeCategory(int personTypeCategory) + { + personType = (short) personTypeCategory; + } + + public void setValueOfTime(float vot) + { + persValueOfTime = vot; + } + + public void setWorkLocation(int aWorkLocationMgra) + { + workLocation = aWorkLocationMgra; + } + + public void setWorkLocDistance(float distance) + { + workLocDistance = distance; + } + + public void setWorkLocLogsum(float logsum) + { + workLocLogsum = logsum; + } + + public void setSchoolLoc(int loc) + { + schoolLoc = loc; + } + + public void setSchoolLocDistance(float distance) + { + schoolLocDistance = distance; + } + + public void setSchoolLocLogsum(float logsum) + { + schoolLocLogsum = logsum; + } + + public void setImtfChoice(int choice) + { + imtfChoice = (short) choice; + } + + public void setInmtfChoice(int choice) + { + inmtfChoice = (short) choice; + } + + public int getImtfChoice() + { + return imtfChoice; + } + + public int getInmtfChoice() + { + return inmtfChoice; + } + + public void clearIndividualNonMandatoryToursArray() + { + indNonManTourArrayList.clear(); + } + + public void createIndividualNonMandatoryTours(int numberOfTours, String primaryPurposeName) + { + + /* + * // if purpose is escort, need to determine if household has kids or + * not String purposeName = primaryPurposeName; if ( + * purposeName.equalsIgnoreCase( modelStructure.ESCORT_PURPOSE_NAME ) ) + * { if ( hhObj.getNumChildrenUnder19() > 0 ) purposeName += "_" + + * modelStructure.ESCORT_SEGMENT_NAMES[0]; else purposeName += "_" + + * modelStructure.ESCORT_SEGMENT_NAMES[1]; } int purposeIndex = + * modelStructure.getDcModelPurposeIndex( purposeName ); + */ + + int id = indNonManTourArrayList.size(); + + int primaryIndex = modelStructure.getPrimaryPurposeNameIndexMap().get(primaryPurposeName); + + for (int i = 0; i < numberOfTours; i++) + { + Tour tempTour = new Tour(id++, this.hhObj, this, primaryPurposeName, + ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY, primaryIndex); + + tempTour.setTourOrigMgra(this.hhObj.getHhMgra()); + tempTour.setTourDestMgra(0); + + tempTour.setTourPurpose(primaryPurposeName); + + tempTour.setTourDepartPeriod(DEFAULT_NON_MANDATORY_START_PERIOD); + tempTour.setTourArrivePeriod(DEFAULT_NON_MANDATORY_END_PERIOD); + + indNonManTourArrayList.add(tempTour); + } + + } + + public void createWorkTours(int numberOfTours, int startId, String tourPurpose, + int tourPurposeIndex) + { + + workTourArrayList.clear(); + + for (int i = 0; i < numberOfTours; i++) + { + int id = startId + i; + Tour tempTour = new Tour(this, id, tourPurposeIndex); + + tempTour.setTourOrigMgra(hhObj.getHhMgra()); + + if (workLocation == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) tempTour + .setTourDestMgra(hhObj.getHhMgra()); + else tempTour.setTourDestMgra(workLocation); + + tempTour.setTourPurpose(tourPurpose); + + tempTour.setTourDepartPeriod(-1); + tempTour.setTourArrivePeriod(-1); + // tempTour.setTourDepartPeriod(DEFAULT_MANDATORY_START_PERIOD); + // tempTour.setTourArrivePeriod(DEFAULT_MANDATORY_END_PERIOD); + + workTourArrayList.add(tempTour); + } + + } + + public void clearAtWorkSubtours() + { + + atWorkSubtourArrayList.clear(); + + } + + public void createAtWorkSubtour(int id, int choice, int workMgra, String subtourPurpose) + { + + /* + * String segmentedPurpose = modelStructure.AT_WORK_PURPOSE_NAME + "_" + + * tourPurpose; int purposeIndex = + * modelStructure.getDcModelPurposeIndex( segmentedPurpose ); + */ + + Tour tempTour = new Tour(id, this.hhObj, this, + ModelStructure.WORK_BASED_PRIMARY_PURPOSE_NAME, ModelStructure.AT_WORK_CATEGORY, + ModelStructure.WORK_BASED_PRIMARY_PURPOSE_INDEX); + + tempTour.setTourOrigMgra(workMgra); + tempTour.setTourDestMgra(0); + + tempTour.setTourPurpose(ModelStructure.WORK_BASED_PRIMARY_PURPOSE_NAME); + tempTour.setSubTourPurpose(subtourPurpose); + + tempTour.setTourDepartPeriod(DEFAULT_AT_WORK_SUBTOUR_START_PERIOD); + tempTour.setTourArrivePeriod(DEFAULT_AT_WORK_SUBTOUR_END_PERIOD); + + atWorkSubtourArrayList.add(tempTour); + + } + + public void createSchoolTours(int numberOfTours, int startId, String tourPurpose, + int tourPurposeIndex) + { + + schoolTourArrayList.clear(); + + for (int i = 0; i < numberOfTours; i++) + { + int id = startId + i; + Tour tempTour = new Tour(this, id, tourPurposeIndex); + + tempTour.setTourOrigMgra(this.hhObj.getHhMgra()); + + if (schoolLoc == ModelStructure.NOT_ENROLLED_SEGMENT_INDEX) tempTour + .setTourDestMgra(hhObj.getHhMgra()); + else tempTour.setTourDestMgra(schoolLoc); + + tempTour.setTourPurpose(tourPurpose); + + tempTour.setTourDepartPeriod(-1); + tempTour.setTourArrivePeriod(-1); + // tempTour.setTourDepartPeriod(DEFAULT_MANDATORY_START_PERIOD); + // tempTour.setTourArrivePeriod(DEFAULT_MANDATORY_END_PERIOD); + + schoolTourArrayList.add(tempTour); + } + } + + public int getWorkLocationSegmentIndex() + { + return workLocSegmentIndex; + } + + public int getSchoolLocationSegmentIndex() + { + return schoolLocSegmentIndex; + } + + public void setDailyActivityResult(String activity) + { + this.cdapActivity = activity; + } + + public int getPersonIsChildUnder16WithHomeOrNonMandatoryActivity() + { + + // check the person type + if (persIsStudentNonDrivingAge() == 1 || persIsPreschoolChild() == 1) + { + + // check the activity type + if (cdapActivity.equalsIgnoreCase(ModelStructure.HOME_PATTERN)) return (1); + + if (cdapActivity.equalsIgnoreCase(ModelStructure.MANDATORY_PATTERN)) return (1); + + } + + return (0); + } + + /** + * @return 1 if M, 2 if N, 3 if H + */ + public int getCdapIndex() + { + + // return the activity type + if (cdapActivity.equalsIgnoreCase(ModelStructure.MANDATORY_PATTERN)) return 1; + + if (cdapActivity.equalsIgnoreCase(ModelStructure.NONMANDATORY_PATTERN)) return 2; + + if (cdapActivity.equalsIgnoreCase(ModelStructure.HOME_PATTERN)) return 3; + + return (0); + } + + public int getPersonIsChild6To18WithoutMandatoryActivity() + { + + // check the person type + if (persIsStudentDrivingAge() == 1 || persIsStudentNonDrivingAge() == 1) + { + + // check the activity type + if (cdapActivity.equalsIgnoreCase(ModelStructure.MANDATORY_PATTERN)) return 0; + else return 1; + + } + + return 0; + } + + // methods DMU will use to get info from household object + + public int getAge() + { + return (int) persAge; + } + + public int getHomemaker() + { + return persIsHomemaker(); + } + + public int getGender() + { + return (int) persGender; + } + + public int getPersonIsFemale() + { + if (persGender == 2) return 1; + return 0; + } + + public int getPersonIsMale() + { + if (persGender == 1) return 1; + return 0; + } + + public int getPersonId() + { + return this.persId; + } + + public int getPersonNum() + { + return this.persNum; + } + + public String getPersonType() + { + return PERSON_TYPE_NAME_ARRAY[personType - 1]; + } + + public void setPersonIsHighSchool(boolean flag) + { + highSchool = flag; + } + + public int getPersonIsHighSchool() + { + return highSchool ? 1 : 0; + } + + public void setPersonIsGradeSchool(boolean flag) + { + gradeSchool = flag; + } + + public int getPersonIsGradeSchool() + { + return gradeSchool ? 1 : 0; + } + + public int getPersonIsHighSchoolGraduate() + { + return highSchoolGraduate ? 1 : 0; + } + + public void setPersonIsHighSchoolGraduate(boolean hsGrad) + { + highSchoolGraduate = hsGrad; + } + + public void setPersonHasBachelors(boolean hasBS) + { + hasBachelors = hasBS; + } + + public int getPersonTypeNumber() + { + return personType; + } + + public int getPersPecasOccup() + { + return (int) persPecasOccup; + } + + public int getPersActivityCode() + { + return (int) persActivityCode; + } + + public int getPersonEmploymentCategoryIndex() + { + return (int) persEmploymentCategory; + } + + public String getPersonEmploymentCategory() + { + return EMPLOYMENT_CATEGORY_NAME_ARRAY[persEmploymentCategory - 1]; + } + + public int getPersonStudentCategoryIndex() + { + return persStudentCategory; + } + + public String getPersonStudentCategory() + { + return STUDENT_CATEGORY_NAME_ARRAY[persStudentCategory - 1]; + } + + public float getValueOfTime() + { + return persValueOfTime; + } + + public int getWorkLocation() + { + return workLocation; + } + + public int getPersonSchoolLocationZone() + { + return schoolLoc; + } + + public int getFreeParkingAvailableResult() + { + return freeParkingAvailable; + } + + public int getInternalExternalTripChoiceResult() + { + return internalExternalTripChoice; + } + + public double getParkingReimbursement() + { + return reimbursePercent; + } + + public String getCdapActivity() + { + return cdapActivity; + } + + public float getWorkLocationDistance() + { + return workLocDistance; + } + + public float getWorkLocationLogsum() + { + return workLocLogsum; + } + + public int getUsualSchoolLocation() + { + return schoolLoc; + } + + public float getSchoolLocationDistance() + { + return schoolLocDistance; + } + + public float getSchoolLocationLogsum() + { + return schoolLocLogsum; + } + + public int getHasBachelors() + { + return hasBachelors ? 1 : 0; + } + + public int getNumWorkTours() + { + ArrayList workTours = getListOfWorkTours(); + if (workTours != null) return workTours.size(); + else return 0; + } + + public int getNumSchoolTours() + { + ArrayList schoolTours = getListOfSchoolTours(); + if (schoolTours != null) return schoolTours.size(); + else return 0; + } + + public int getNumIndividualEscortTours() + { + int num = 0; + for (Tour tour : getListOfIndividualNonMandatoryTours()) + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.ESCORT_PURPOSE_NAME)) num++; + return num; + } + + public int getNumIndividualShoppingTours() + { + int num = 0; + for (Tour tour : getListOfIndividualNonMandatoryTours()) + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.SHOPPING_PURPOSE_NAME)) + num++; + return num; + } + + public int getNumIndividualEatOutTours() + { + int num = 0; + for (Tour tour : getListOfIndividualNonMandatoryTours()) + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.EAT_OUT_PURPOSE_NAME)) num++; + return num; + } + + public int getNumIndividualOthMaintTours() + { + int num = 0; + for (Tour tour : getListOfIndividualNonMandatoryTours()) + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.OTH_MAINT_PURPOSE_NAME)) + num++; + return num; + } + + public int getNumIndividualSocialTours() + { + int num = 0; + for (Tour tour : getListOfIndividualNonMandatoryTours()) + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.SOCIAL_PURPOSE_NAME)) num++; + return num; + } + + public int getNumIndividualOthDiscrTours() + { + int num = 0; + for (Tour tour : getListOfIndividualNonMandatoryTours()) + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.OTH_DISCR_PURPOSE_NAME)) + num++; + return num; + } + + public int getNumMandatoryTours() + { + int numTours = 0; + ArrayList workTours = getListOfWorkTours(); + if (workTours != null) numTours += workTours.size(); + + ArrayList schoolTours = getListOfSchoolTours(); + if (schoolTours != null) numTours += schoolTours.size(); + + return numTours; + } + + public int getNumNonMandatoryTours() + { + ArrayList nonMandTours = getListOfIndividualNonMandatoryTours(); + if (nonMandTours == null) return 0; + else return nonMandTours.size(); + } + + public int getNumSubtours() + { + ArrayList subtours = getListOfAtWorkSubtours(); + if (subtours == null) return 0; + else return subtours.size(); + } + + public int getNumTotalIndivTours() + { + return getNumMandatoryTours() + getNumNonMandatoryTours() + getNumSubtours(); + } + + public int getNumJointShoppingTours() + { + return getNumJointToursForPurpose(modelStructure.SHOPPING_PURPOSE_NAME); + } + + public int getNumJointOthMaintTours() + { + return getNumJointToursForPurpose(modelStructure.OTH_MAINT_PURPOSE_NAME); + } + + public int getNumJointEatOutTours() + { + return getNumJointToursForPurpose(modelStructure.EAT_OUT_PURPOSE_NAME); + } + + public int getNumJointSocialTours() + { + return getNumJointToursForPurpose(modelStructure.SOCIAL_PURPOSE_NAME); + } + + public int getNumJointOthDiscrTours() + { + return getNumJointToursForPurpose(modelStructure.OTH_DISCR_PURPOSE_NAME); + } + + private int getNumJointToursForPurpose(String purposeName) + { + int count = 0; + Tour[] jt = hhObj.getJointTourArray(); + if (jt == null) return 0; + + for (int i = 0; i < jt.length; i++) + { + if (jt[i] == null) continue; + String jtPurposeName = jt[i].getTourPurpose(); + int[] personNumsParticipating = jt[i].getPersonNumArray(); + for (int p : personNumsParticipating) + { + if (p == persNum) + { + if (jtPurposeName.equalsIgnoreCase(purposeName)) count++; + break; + } + } + } + + return count; + } + + public void computeIdapResidualWindows() + { + + // find the start of the earliest mandatory or joint tour for this + // person + // and end of last one. + int firstTourStart = 9999; + int lastTourEnd = -1; + int firstTourEnd = 0; + int lastTourStart = 0; + + // first check mandatory tours + for (Tour tour : workTourArrayList) + { + int tourDeparts = tour.getTourDepartPeriod(); + int tourArrives = tour.getTourArrivePeriod(); + + if (tourDeparts < firstTourStart) + { + firstTourStart = tourDeparts; + firstTourEnd = tourArrives; + } + + if (tourArrives > lastTourEnd) + { + lastTourStart = tourDeparts; + lastTourEnd = tourArrives; + } + } + + for (Tour tour : schoolTourArrayList) + { + int tourDeparts = tour.getTourDepartPeriod(); + int tourArrives = tour.getTourArrivePeriod(); + + if (tourDeparts < firstTourStart) + { + firstTourStart = tourDeparts; + firstTourEnd = tourArrives; + } + + if (tourArrives > lastTourEnd) + { + lastTourStart = tourDeparts; + lastTourEnd = tourArrives; + } + } + + // now check joint tours + Tour[] jointTourArray = hhObj.getJointTourArray(); + if (jointTourArray != null) + { + for (Tour tour : jointTourArray) + { + + if (tour == null) continue; + + // see if this person is in the joint tour or not + if (tour.getPersonInJointTour(this)) + { + + int tourDeparts = tour.getTourDepartPeriod(); + int tourArrives = tour.getTourArrivePeriod(); + + if (tourDeparts < firstTourStart) + { + firstTourStart = tourDeparts; + firstTourEnd = tourArrives; + } + + if (tourArrives > lastTourEnd) + { + lastTourStart = tourDeparts; + lastTourEnd = tourArrives; + } + + } + + } + } + + if (firstTourStart > modelStructure.getNumberOfTimePeriods() - 1 && lastTourEnd < 0) + { + int numPeriods = windows.length; + windowBeforeFirstMandJointTour = numPeriods; + windowAfterLastMandJointTour = numPeriods; + windowBetweenFirstLastMandJointTour = numPeriods; + } else + { + + // since first tour first period and last tour last period are + // available, + // account for them. + windowBeforeFirstMandJointTour = firstTourStart + 1; + windowAfterLastMandJointTour = modelStructure.getNumberOfTimePeriods() - lastTourEnd; + + // find the number of unscheduled periods between end of first tour + // and + // start of last tour + windowBetweenFirstLastMandJointTour = 0; + for (int i = firstTourEnd; i <= lastTourStart; i++) + { + if (isPeriodAvailable(i)) windowBetweenFirstLastMandJointTour++; + } + } + + } + + public int getWindowBeforeFirstMandJointTour() + { + return windowBeforeFirstMandJointTour; + } + + public int getWindowBetweenFirstLastMandJointTour() + { + return windowBetweenFirstLastMandJointTour; + } + + public int getWindowAfterLastMandJointTour() + { + return windowAfterLastMandJointTour; + } + + // public int getNumberOfMandatoryWorkTours( String workPurposeName ){ + // + // int numberOfTours = 0; + // for(int i=0;i= MIN_ADULT_AGE + && persEmploymentCategory == EmployStatus.NOT_EMPLOYED.ordinal()) return 1; + else return 0; + } + + public int notEmployed() + { + if (persEmploymentCategory == EmployStatus.NOT_EMPLOYED.ordinal()) return 1; + else return 0; + } + + private int persIsWorker() + { + if (persEmploymentCategory == EmployStatus.FULL_TIME.ordinal() + || persEmploymentCategory == EmployStatus.PART_TIME.ordinal()) return 1; + else return 0; + } + + private int persIsStudent() + { + if (persStudentCategory == StudentStatus.STUDENT_HIGH_SCHOOL_OR_LESS.ordinal() + || persStudentCategory == StudentStatus.STUDENT_COLLEGE_OR_HIGHER.ordinal()) + { + return 1; + } else + { + return 0; + } + } + + private int persIsFullTimeWorker() + { + if (persEmploymentCategory == EmployStatus.FULL_TIME.ordinal()) return 1; + else return 0; + } + + private int persIsPartTimeWorker() + { + if (persEmploymentCategory == EmployStatus.PART_TIME.ordinal()) return 1; + else return 0; + } + + private int persTypeIsFullTimeWorker() + { + if (personType == PersonType.FT_worker_age_16plus.ordinal()) return 1; + else return 0; + } + + private int persTypeIsPartTimeWorker() + { + if (personType == PersonType.PT_worker_nonstudent_age_16plus.ordinal()) return 1; + else return 0; + } + + private int persIsUniversity() + { + if (personType == PersonType.University_student.ordinal()) return 1; + else return 0; + } + + private int persIsStudentDrivingAge() + { + if (personType == PersonType.Student_age_16_19_not_FT_wrkr_or_univ_stud.ordinal()) return 1; + else return 0; + } + + private int persIsStudentNonDrivingAge() + { + if (personType == PersonType.Student_age_6_15_schpred.ordinal()) return 1; + else return 0; + } + + private int persIsPreschoolChild() + { + if (personType == PersonType.Preschool_under_age_6.ordinal()) return 1; + else return 0; + + } + + private int persIsNonWorkingAdultUnder65() + { + if (personType == PersonType.Nonworker_nonstudent_age_16_64.ordinal()) return 1; + else return 0; + } + + private int persIsNonWorkingAdultOver65() + { + if (personType == PersonType.Nonworker_nonstudent_age_65plus.ordinal()) + { + return 1; + } else + { + return 0; + } + } + + /** + * return maximum periods of overlap between this person and other adult + * persons in the household. + * + * @return the most number of periods mutually available between this person + * and other adult household members + */ + public int getMaxAdultOverlaps() + { + return maxAdultOverlaps; + } + + /** + * set maximum periods of overlap between this person and other adult + * persons in the household. + * + * @param overlaps + * are the most number of periods mutually available between this + * person and other adult household members + */ + public void setMaxAdultOverlaps(int overlaps) + { + maxAdultOverlaps = overlaps; + } + + /** + * return maximum periods of overlap between this person and other children + * in the household. + * + * @return the most number of periods mutually available between this person + * and other child household members + */ + public int getMaxChildOverlaps() + { + return maxChildOverlaps; + } + + /** + * set maximum periods of overlap between this person and other children in + * the household. + * + * @param overlaps + * are the most number of periods mutually available between this + * person and other child household members + */ + public void setMaxChildOverlaps(int overlaps) + { + maxChildOverlaps = overlaps; + } + + /** + * return available time window for this person in the household. + * + * @return the total number of periods available for this person + */ + public int getAvailableWindow() + { + int numPeriodsAvailable = 0; + for (int i = 1; i < windows.length; i++) + if (windows[i] != 1) numPeriodsAvailable++; + + return numPeriodsAvailable; + } + + /** + * determine the maximum consecutive available time window for the person + * + * @return the length of the maximum available window in units of time + * intervals + */ + public int getMaximumContinuousAvailableWindow() + { + int maxWindow = 0; + int currentWindow = 0; + for (int i = 1; i < windows.length; i++) + { + if (windows[i] == 0) + { + currentWindow++; + } else + { + if (currentWindow > maxWindow) maxWindow = currentWindow; + currentWindow = 0; + } + } + if (currentWindow > maxWindow) maxWindow = currentWindow; + + return maxWindow; + } + + /** + * determine the maximum consecutive pairwise available time window for this + * person and the person for which a window was passed + * + * @return the length of the maximum pairwise available window in units of + * time intervals + */ + public int getMaximumContinuousPairwiseAvailableWindow(short[] otherWindow) + { + int maxWindow = 0; + int currentWindow = 0; + for (int i = 1; i < windows.length; i++) + { + if (windows[i] == 0 && otherWindow[i] == 0) + { + currentWindow++; + } else + { + if (currentWindow > maxWindow) maxWindow = currentWindow; + currentWindow = 0; + } + } + if (currentWindow > maxWindow) maxWindow = currentWindow; + + return maxWindow; + } + + public void setTimeWindows(short[] win) + { + windows = win; + } + + public void initializeForAoRestart() + { + + cdapActivity = "-"; + imtfChoice = 0; + inmtfChoice = 0; + + maxAdultOverlaps = 0; + maxChildOverlaps = 0; + + workTourArrayList.clear(); + schoolTourArrayList.clear(); + indNonManTourArrayList.clear(); + atWorkSubtourArrayList.clear(); + + initializeWindows(); + + windowBeforeFirstMandJointTour = 0; + windowBetweenFirstLastMandJointTour = 0; + windowAfterLastMandJointTour = 0; + + } + + public void initializeForImtfRestart() + { + + imtfChoice = 0; + inmtfChoice = 0; + + maxAdultOverlaps = 0; + maxChildOverlaps = 0; + + workTourArrayList.clear(); + schoolTourArrayList.clear(); + indNonManTourArrayList.clear(); + atWorkSubtourArrayList.clear(); + + initializeWindows(); + + windowBeforeFirstMandJointTour = 0; + windowBetweenFirstLastMandJointTour = 0; + windowAfterLastMandJointTour = 0; + + } + + /** + * initialize the person attributes and tour objects for restarting the + * model at joint tour frequency + */ + public void initializeForJtfRestart() + { + + inmtfChoice = 0; + + indNonManTourArrayList.clear(); + atWorkSubtourArrayList.clear(); + + for (int i = 0; i < workTourArrayList.size(); i++) + { + Tour t = workTourArrayList.get(i); + scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + for (int i = 0; i < schoolTourArrayList.size(); i++) + { + Tour t = schoolTourArrayList.get(i); + scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + + windowBeforeFirstMandJointTour = 0; + windowBetweenFirstLastMandJointTour = 0; + windowAfterLastMandJointTour = 0; + + } + + /** + * initialize the person attributes and tour objects for restarting the + * model at individual non-mandatory tour frequency. + */ + public void initializeForInmtfRestart() + { + + inmtfChoice = 0; + + indNonManTourArrayList.clear(); + atWorkSubtourArrayList.clear(); + + for (int i = 0; i < workTourArrayList.size(); i++) + { + Tour t = workTourArrayList.get(i); + scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + for (int i = 0; i < schoolTourArrayList.size(); i++) + { + Tour t = schoolTourArrayList.get(i); + scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + + windowBeforeFirstMandJointTour = 0; + windowBetweenFirstLastMandJointTour = 0; + windowAfterLastMandJointTour = 0; + + } + + /** + * initialize the person attributes and tour objects for restarting the + * model at at-work sub-tour frequency. + */ + public void initializeForAwfRestart() + { + + atWorkSubtourArrayList.clear(); + + for (int i = 0; i < workTourArrayList.size(); i++) + { + Tour t = workTourArrayList.get(i); + scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + for (int i = 0; i < schoolTourArrayList.size(); i++) + { + Tour t = schoolTourArrayList.get(i); + scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + for (int i = 0; i < indNonManTourArrayList.size(); i++) + { + Tour t = indNonManTourArrayList.get(i); + scheduleWindow(t.getTourDepartPeriod(), t.getTourArrivePeriod()); + t.clearStopModelResults(); + } + + } + + /** + * initialize the person attributes and tour objects for restarting the + * model at stop frequency. + */ + public void initializeForStfRestart() + { + + for (int i = 0; i < workTourArrayList.size(); i++) + { + Tour t = workTourArrayList.get(i); + t.clearStopModelResults(); + } + for (int i = 0; i < schoolTourArrayList.size(); i++) + { + Tour t = schoolTourArrayList.get(i); + t.clearStopModelResults(); + } + for (int i = 0; i < atWorkSubtourArrayList.size(); i++) + { + Tour t = atWorkSubtourArrayList.get(i); + t.clearStopModelResults(); + } + for (int i = 0; i < indNonManTourArrayList.size(); i++) + { + Tour t = indNonManTourArrayList.get(i); + t.clearStopModelResults(); + } + + } + + public float getParkingProvisionLogsum() { + return parkingProvisionLogsum; + } + + public void setParkingProvisionLogsum(float parkingProvisionLogsum) { + this.parkingProvisionLogsum = parkingProvisionLogsum; + } + + public float getIeLogsum() { + return ieLogsum; + } + + public void setIeLogsum(float ieLogsum) { + this.ieLogsum = ieLogsum; + } + + public float getCdapLogsum() { + return cdapLogsum; + } + + public void setCdapLogsum(float cdapLogsum) { + this.cdapLogsum = cdapLogsum; + } + + + public float getImtfLogsum() { + return imtfLogsum; + } + + public void setImtfLogsum(float imtfLogsum) { + this.imtfLogsum = imtfLogsum; + } + + public float getInmtfLogsum() { + return inmtfLogsum; + } + + public void setInmtfLogsum(float inmtfLogsum) { + this.inmtfLogsum = inmtfLogsum; + } + + public float getWorksFromHomeLogsum() { + return worksFromHomeLogsum; + } + + public void setWorksFromHomeLogsum(float worksFromHomeLogsum) { + this.worksFromHomeLogsum = worksFromHomeLogsum; + } + + public void logPersonObject(Logger logger, int totalChars) + { + + Household.logHelper(logger, "persNum: ", persNum, totalChars); + Household.logHelper(logger, "persId: ", persId, totalChars); + Household.logHelper(logger, "persAge: ", persAge, totalChars); + Household.logHelper(logger, "persGender: ", persGender, totalChars); + Household.logHelper(logger, "persEmploymentCategory: ", persEmploymentCategory, totalChars); + Household.logHelper(logger, "persStudentCategory: ", persStudentCategory, totalChars); + Household.logHelper(logger, "personType: ", personType, totalChars); + Household.logHelper(logger, "workLoc: ", workLocation, totalChars); + Household.logHelper(logger, "schoolLoc: ", schoolLoc, totalChars); + Household.logHelper(logger, "workLocSegmentIndex: ", workLocSegmentIndex, totalChars); + Household.logHelper(logger, "schoolLocSegmentIndex: ", schoolLocSegmentIndex, totalChars); + + Household.logHelper(logger, "timeFactorWork: ", String.format("%.2f",timeFactorWork), totalChars); + Household.logHelper(logger, "timeFactorNonWork: ", String.format("%.2f",timeFactorNonWork), totalChars); + Household.logHelper(logger, "freeParkingAvailable: ", freeParkingAvailable, totalChars); + Household.logHelper(logger, "reimbursementPct: ", + String.format("%.2f%%", (100 * reimbursePercent)), totalChars); + Household.logHelper(logger, "cdapActivity: ", cdapActivity, totalChars); + Household.logHelper(logger, "imtfChoice: ", imtfChoice, totalChars); + Household.logHelper(logger, "inmtfChoice: ", inmtfChoice, totalChars); + Household.logHelper(logger, "maxAdultOverlaps: ", maxAdultOverlaps, totalChars); + Household.logHelper(logger, "maxChildOverlaps: ", maxChildOverlaps, totalChars); + Household.logHelper(logger, "windowBeforeFirstMandJointTour: ", + windowBeforeFirstMandJointTour, totalChars); + Household.logHelper(logger, "windowBetweenFirstLastMandJointTour: ", + windowBetweenFirstLastMandJointTour, totalChars); + Household.logHelper(logger, "windowAfterLastMandJointTour: ", windowAfterLastMandJointTour, + totalChars); + + String header1 = " Index: |"; + String header2 = " Period: |"; + String windowString = " Window: |"; + String periodString = ""; + for (int i = 1; i < windows.length; i++) + { + header1 += String.format(" %2d |", i); + header2 += String.format("%4s|", modelStructure.getTimePeriodLabel(i)); + switch (windows[i]) + { + case 0: + periodString = " "; + break; + case 1: + periodString = "XXXX"; + break; + } + windowString += String.format("%4s|", periodString); + } + + logger.info(header1); + logger.info(header2); + logger.info(windowString); + + if (workTourArrayList.size() > 0) + { + for (Tour tour : workTourArrayList) + { + int id = tour.getTourId(); + logger.info(tour.getTourWindow(String.format("W%d", id))); + } + } + if (atWorkSubtourArrayList.size() > 0) + { + for (Tour tour : atWorkSubtourArrayList) + { + int id = tour.getTourId(); + String alias = ""; + String purposeName = tour.getSubTourPurpose(); + if (purposeName.equalsIgnoreCase(modelStructure.AT_WORK_BUSINESS_PURPOSE_NAME)) alias = "aB"; + else if (purposeName.equalsIgnoreCase(modelStructure.AT_WORK_EAT_PURPOSE_NAME)) alias = "aE"; + else if (purposeName.equalsIgnoreCase(modelStructure.AT_WORK_MAINT_PURPOSE_NAME)) + alias = "aM"; + logger.info(tour.getTourWindow(String.format("%s%d", alias, id))); + } + } + if (schoolTourArrayList.size() > 0) + { + for (Tour tour : schoolTourArrayList) + { + int id = tour.getTourId(); + String alias = "S"; + logger.info(tour.getTourWindow(String.format("%s%d", alias, id))); + } + } + if (hhObj.getJointTourArray() != null && hhObj.getJointTourArray().length > 0) + { + for (Tour tour : hhObj.getJointTourArray()) + { + if (tour == null) continue; + + // log this persons time window if they are in the joint tour + // party. + int[] persNumArray = tour.getPersonNumArray(); + if (persNumArray != null) + { + for (int num : persNumArray) + { + if (num == persNum) + { + + Person person = hhObj.getPersons()[num]; + tour.setPersonObject(person); + + int id = tour.getTourId(); + String alias = ""; + if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME)) alias = "jE"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME)) alias = "jS"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME)) alias = "jM"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME)) alias = "jV"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME)) alias = "jD"; + logger.info(tour.getTourWindow(String.format("%s%d", alias, id))); + } + } + } + } + } + if (indNonManTourArrayList.size() > 0) + { + for (Tour tour : indNonManTourArrayList) + { + int id = tour.getTourId(); + String alias = ""; + if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME)) alias = "ie"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME)) alias = "iE"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME)) alias = "iS"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME)) alias = "iM"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME)) alias = "iV"; + else if (tour.getTourPurpose().equalsIgnoreCase( + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME)) alias = "iD"; + logger.info(tour.getTourWindow(String.format("%s%d", alias, id))); + } + } + + } + + public void logTourObject(Logger logger, int totalChars, Tour tour) + { + tour.logTourObject(logger, totalChars); + } + + public void logEntirePersonObject(Logger logger) + { + + int totalChars = 60; + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "-"; + + Household.logHelper(logger, "persNum: ", persNum, totalChars); + Household.logHelper(logger, "persId: ", persId, totalChars); + Household.logHelper(logger, "persAge: ", persAge, totalChars); + Household.logHelper(logger, "persGender: ", persGender, totalChars); + Household.logHelper(logger, "persEmploymentCategory: ", persEmploymentCategory, totalChars); + Household.logHelper(logger, "persStudentCategory: ", persStudentCategory, totalChars); + Household.logHelper(logger, "personType: ", personType, totalChars); + Household.logHelper(logger, "workLoc: ", workLocation, totalChars); + Household.logHelper(logger, "schoolLoc: ", schoolLoc, totalChars); + Household.logHelper(logger, "workLocSegmentIndex: ", workLocSegmentIndex, totalChars); + Household.logHelper(logger, "schoolLocSegmentIndex: ", schoolLocSegmentIndex, totalChars); + Household.logHelper(logger, "freeParkingAvailable: ", freeParkingAvailable, totalChars); + Household.logHelper(logger, "reimbursementPct: ", + String.format("%.2f%%", (100 * reimbursePercent)), totalChars); + Household.logHelper(logger, "cdapActivity: ", cdapActivity, totalChars); + Household.logHelper(logger, "imtfChoice: ", imtfChoice, totalChars); + Household.logHelper(logger, "inmtfChoice: ", inmtfChoice, totalChars); + Household.logHelper(logger, "maxAdultOverlaps: ", maxAdultOverlaps, totalChars); + Household.logHelper(logger, "maxChildOverlaps: ", maxChildOverlaps, totalChars); + Household.logHelper(logger, "windowBeforeFirstMandJointTour: ", + windowBeforeFirstMandJointTour, totalChars); + Household.logHelper(logger, "windowBetweenFirstLastMandJointTour: ", + windowBetweenFirstLastMandJointTour, totalChars); + Household.logHelper(logger, "windowAfterLastMandJointTour: ", windowAfterLastMandJointTour, + totalChars); + + String header = " Period: |"; + String windowString = " Window: |"; + for (int i = 1; i < windows.length; i++) + { + header += String.format("%4s|", modelStructure.getTimePeriodLabel(i)); + windowString += String.format("%4s|", windows[i] == 0 ? " " : "XXXX"); + } + + logger.info(header); + logger.info(windowString); + + if (workTourArrayList.size() > 0) + { + for (Tour tour : workTourArrayList) + { + int id = tour.getTourId(); + logger.info(tour.getTourWindow(String.format("W%d", id))); + } + } + if (schoolTourArrayList.size() > 0) + { + for (Tour tour : schoolTourArrayList) + { + logger.info(tour + .getTourWindow(tour.getTourPurpose().equalsIgnoreCase("university") ? "U" + : "S")); + } + } + if (indNonManTourArrayList.size() > 0) + { + for (Tour tour : indNonManTourArrayList) + { + logger.info(tour.getTourWindow("N")); + } + } + if (atWorkSubtourArrayList.size() > 0) + { + for (Tour tour : atWorkSubtourArrayList) + { + logger.info(tour.getTourWindow("A")); + } + } + if (hhObj.getJointTourArray() != null && hhObj.getJointTourArray().length > 0) + { + for (Tour tour : hhObj.getJointTourArray()) + { + if (tour != null) logger.info(tour.getTourWindow("J")); + } + } + + logger.info(separater); + + logger.info("Work Tours:"); + if (workTourArrayList.size() > 0) + { + for (Tour tour : workTourArrayList) + { + tour.logEntireTourObject(logger); + } + } else + { + logger.info(" No work tours"); + } + + logger.info("School Tours:"); + if (schoolTourArrayList.size() > 0) + { + for (Tour tour : schoolTourArrayList) + { + tour.logEntireTourObject(logger); + } + } else + { + logger.info(" No school tours"); + } + + logger.info("Individual Non-mandatory Tours:"); + if (indNonManTourArrayList.size() > 0) + { + for (Tour tour : indNonManTourArrayList) + { + tour.logEntireTourObject(logger); + } + } else + { + logger.info(" No individual non-mandatory tours"); + } + + logger.info("Work based subtours Tours:"); + if (atWorkSubtourArrayList.size() > 0) + { + for (Tour tour : atWorkSubtourArrayList) + { + tour.logEntireTourObject(logger); + } + } else + { + logger.info(" No work based subtours"); + } + + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public double getTimeFactorWork() { + return (double) timeFactorWork; + } + + public void setTimeFactorWork(double timeFactorWork) { + this.timeFactorWork = (float) timeFactorWork; + } + + public double getTimeFactorNonWork() { + return (double) timeFactorNonWork; + } + + public void setTimeFactorNonWork(double timeFactorNonWork) { + this.timeFactorNonWork = (float) timeFactorNonWork; + } + + public enum EmployStatus + { + nul, FULL_TIME, PART_TIME, NOT_EMPLOYED, UNDER16 + } + + public enum StudentStatus + { + nul, STUDENT_HIGH_SCHOOL_OR_LESS, STUDENT_COLLEGE_OR_HIGHER, NON_STUDENT + } + + public enum PersonType + { + nul, FT_worker_age_16plus, PT_worker_nonstudent_age_16plus, University_student, Nonworker_nonstudent_age_16_64, Nonworker_nonstudent_age_65plus, Student_age_16_19_not_FT_wrkr_or_univ_stud, Student_age_6_15_schpred, Preschool_under_age_6 + } + + /** + * Returns true if this person is an active adult, else returns false. Active adult + * is defined as full-time worker, part-time worker, university student, + * non-working adult or retired person who has an activity pattern other than H. + * + * @return true if active adult, else false. + */ + public boolean isActiveAdult(){ + boolean activeAdult=false; + if((getPersonTypeNumber()==Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX)||(getPersonTypeNumber()==Person.PERSON_TYPE_PART_TIME_WORKER_INDEX)|| + (getPersonTypeNumber()==Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX)||(getPersonTypeNumber()==Person.PERSON_TYPE_NON_WORKER_INDEX)|| + (getPersonTypeNumber()==Person.PERSON_TYPE_RETIRED_INDEX)) + if(!getCdapActivity().equalsIgnoreCase(ModelStructure.HOME_PATTERN)) + activeAdult=true; + return activeAdult; + } + + public short getTelecommuteChoice() { + return telecommuteChoice; + } + + public void setTelecommuteChoice(short telecommuteChoice) { + this.telecommuteChoice = telecommuteChoice; + } + + public float getTelecommuteLogsum() { + return telecommuteLogsum; + } + + public void setTelecommuteLogsum(float telecommuteLogsum) { + this.telecommuteLogsum = telecommuteLogsum; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortChauffeurResult.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortChauffeurResult.java new file mode 100644 index 0000000..32f93ef --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortChauffeurResult.java @@ -0,0 +1,67 @@ +/* +* The school-escort model was designed by PB (Gupta, Vovsha, et al) +* as part of the Maricopa Association of Governments (MAG) +* Activity-based Travel Model Development project. +* +* This source code, which implements the school escort model, +* was written exclusively for and funded by MAG as part of the +* same project; therefore, per their contract, the +* source code belongs to MAG and can only be used with their +* permission. +* +* It is being adapted for the Southern Oregon ABM by PB & RSG +* with permission from MAG and all references to +* the school escort model as well as source code adapted from this +* original code should credit MAG's role in its development. +* +* The escort model and source code should not be transferred to or +* adapted for other agencies or used in other projects without +* expressed permission from MAG. +* +* The source code has been substantially revised to fit within the +* SANDAG\MTC\ODOT CT-RAMP model structure by RSG (2015). +*/ + +package org.sandag.abm.ctramp; + +import java.io.Serializable; + +public class SchoolEscortChauffeurResult implements Serializable { + + private static final long serialVersionUID = 1L; + + private final int pid; + private final short dir; + private final short bundle; + private final short escortType; + private final short[] childPnums; + + public SchoolEscortChauffeurResult( int pid, short dir, short bundle, short escortType, short[] childPnums ) { + this.pid = pid; + this.dir = dir; + this.bundle = bundle; + this.escortType = escortType; + this.childPnums = childPnums; + } + + public int getPid() { + return pid; + } + + public short getDirection() { + return dir; + } + + public short getBundle() { + return bundle; + } + + public short getEscortType() { + return escortType; + } + + public short[] getChildPnums() { + return childPnums; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortChildResult.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortChildResult.java new file mode 100644 index 0000000..cfa6098 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortChildResult.java @@ -0,0 +1,68 @@ +/* +* The school-escort model was designed by PB (Gupta, Vovsha, et al) +* as part of the Maricopa Association of Governments (MAG) +* Activity-based Travel Model Development project. +* +* This source code, which implements the school escort model, +* was written exclusively for and funded by MAG as part of the +* same project; therefore, per their contract, the +* source code belongs to MAG and can only be used with their +* permission. +* +* It is being adapted for the Southern Oregon ABM by PB & RSG +* with permission from MAG and all references to +* the school escort model as well as source code adapted from this +* original code should credit MAG's role in its development. +* +* The escort model and source code should not be transferred to or +* adapted for other agencies or used in other projects without +* expressed permission from MAG. +* +* The source code has been substantially revised to fit within the +* SANDAG\MTC\ODOT CT-RAMP model structure by RSG (2015). +* +*/ + +package org.sandag.abm.ctramp; + +import java.io.Serializable; + +public class SchoolEscortChildResult implements Serializable { + + private static final long serialVersionUID = 1L; + + private final int pid; + private final short dir; + private final short bundle; + private final short escortType; + private final short adultPnum; + + public SchoolEscortChildResult( int pid, short dir, short bundle, short escortType, short adultPnum ) { + this.pid = pid; + this.dir = dir; + this.bundle = bundle; + this.escortType = escortType; + this.adultPnum = adultPnum; + } + + public int getPid() { + return pid; + } + + public short getDirection() { + return dir; + } + + public short getBundle() { + return bundle; + } + + public short getEscortType() { + return escortType; + } + + public short getAdultPnum() { + return adultPnum; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingBundle.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingBundle.java new file mode 100644 index 0000000..ee37952 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingBundle.java @@ -0,0 +1,499 @@ +/* +* The school-escort model was designed by PB (Gupta, Vovsha, et al) +* as part of the Maricopa Association of Governments (MAG) +* Activity-based Travel Model Development project. +* +* This source code, which implements the school escort model, +* was written exclusively for and funded by MAG as part of the +* same project; therefore, per their contract, the +* source code belongs to MAG and can only be used with their +* permission. +* +* It is being adapted for the Southern Oregon ABM by PB & RSG +* with permission from MAG and all references to +* the school escort model as well as source code adapted from this +* original code should credit MAG's role in its development. +* +* The escort model and source code should not be transferred to or +* adapted for other agencies or used in other projects without +* expressed permission from MAG. +* +* The source code has been substantially revised to fit within the +* SANDAG\MTC\ODOT CT-RAMP model structure by RSG (2015). +*/ + +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.List; +import java.util.StringTokenizer; + +import org.apache.log4j.Logger; + + +public class SchoolEscortingBundle implements Serializable { + + private static final long serialVersionUID = 1L; + + private int id; + private int dir; + private final int alt; + private final int bundle; + private final int type; + private final int chaufId; + private int chaufPnum; + private int chaufPersType; + private int chaufPid; + private int[] childIds; + private int[] childPnums; + private int[] schoolMazs; + private float[] schoolDists; + private int workOrSchoolMaz; + private int departHome; + private int arriveWork; + private int departWork; + private int arriveHome; + private int departPrimaryInterval = -1; + + private SchoolEscortingBundle( int alt, int bundle, int chaufId, int type, int[] childIds, int[] childPnums ) { + this.alt = alt; + this.bundle = bundle; + this.chaufId = chaufId; + this.type = type; + this.childIds = childIds; + this.childPnums = childPnums; + } + + + /** + * Get an Arraylist of SchoolEscortingBundles, dimensioned by: + * 0: max chauffeurs (2) + * 1: max bundles (3) + * + * @param alt The alternative number + * @param altBundleIncidence + * @return An array of SchoolEscortingBundles (dimensioned by 2, for each chauffeur) + */ + public static List[] constructAltBundles( int alt, int[][] altBundleIncidence ) { + + //first dimension of results array is dimensioned by number of chauffeurs + 1 + List[] results = new List[ SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1 ]; + + //for each potential bundle (3) + for ( int i=1; i <= SchoolEscortingModel.NUM_BUNDLES; i++ ) { + + //for each potential chauffeur (2) + for ( int j=1; j <= SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH; j++ ) { + + // for each escort type (rideshare vs pure escort) + for ( int k=1; k <= SchoolEscortingModel.NUM_ESCORT_TYPES; k++ ) { + + //if an arraylist hasn't been created for this chauffeur, create one. + if ( results[j] == null ) + results[j] = new ArrayList(SchoolEscortingModel.NUM_BUNDLES); + + //childIdList initial capacity is max escortees (3); for each potential escortee + List childIdList = new ArrayList(SchoolEscortingModel.NUM_ESCORTEES_PER_HH); + for ( int l=1; l <= SchoolEscortingModel.NUM_ESCORTEES_PER_HH; l++ ) { + int columnIndex = (i-1) * (SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH * SchoolEscortingModel.NUM_ESCORT_TYPES * SchoolEscortingModel.NUM_ESCORTEES_PER_HH) + + (j-1) * (SchoolEscortingModel.NUM_ESCORT_TYPES * SchoolEscortingModel.NUM_ESCORTEES_PER_HH) + + (k-1) * (SchoolEscortingModel.NUM_ESCORTEES_PER_HH) + + (l-1) + 1; + //if child number l belongs to this bundle\chauffeur\escort type combination, add l to the childIdList + if ( altBundleIncidence[alt][columnIndex] > 0 ) + childIdList.add( l ); + } + + //if children are in this bundle\chauffeur\escort type combination + if ( childIdList.size() > 0 ) { + int[] childIds = new int[childIdList.size()]; + int[] childPnums = new int[childIdList.size()]; + for ( int l=0; l < childIdList.size(); l++ ) { + childIds[l] = childIdList.get( l ); + } + //add a new bundle to the chauffeur element. The bundle contains the number of the bundle, the number of the chauffeur, the + //escort type (rideshare versus pure), the child ids (1 through 3) and an empty array of person numbers for each child. + results[j].add( new SchoolEscortingBundle( alt, i, j, k, childIds, childPnums ) ); + } + + } + + } + + } + + return results; + + } + + public void setId( int id ) { + this.id = id; + } + + public int getId() { + return id; + } + + public void setDir( int dir ) { + this.dir = dir; + } + + public int getDir() { + return dir; + } + + public int getAlt() { + return alt; + } + + public int getBundle() { + return bundle; + } + + public int getChaufId() { + return chaufId; + } + + public void setChaufPnum( int pnum ) { + chaufPnum = pnum; + } + + public int getChaufPnum() { + return chaufPnum; + } + + public void setChaufPersType( int ptype ) { + chaufPersType = ptype; + } + + public int getChaufPersType() { + return chaufPersType; + } + + public void setChaufPid( int pid ) { + chaufPid = pid; + } + + public int getChaufPid() { + return chaufPid; + } + + public int getEscortType() { + return type; + } + + public void setSchoolMazs( int[] schoolMazs ) { + this.schoolMazs = schoolMazs; + } + + public int[] getSchoolMazs() { + return schoolMazs; + } + + public void setSchoolDists( float[] schoolDists ) { + this.schoolDists = schoolDists; + } + + public float[] getSchoolDists() { + return schoolDists; + } + + public void setChildIds( int[] childIds ) { + this.childIds = childIds; + } + + public int[] getChildIds() { + return childIds; + } + + public void setChildPnums( int[] childPnums ) { + this.childPnums = childPnums; + } + + public int[] getChildPnums() { + return childPnums; + } + + public void setDepartHome( int depart ) { + departHome = depart; + } + + public int getDepartHome() { + return departHome; + } + + /* + public void setArriveHome( int arrive ) { + arriveHome = Math.min( arrive, TourTodDmu.NUM_TOD_INTERVALS ); + } +*/ + /** + * Arrive home; modified JEF to remove taking the minimum of arrive and number of TOD intervals. + * @param arrive + */ + public void setArriveHome( int arrive ) { + arriveHome = arrive; + } + + + public int getArriveHome() { + return arriveHome; + } + + public void setDepartWork( int depart ) { + departWork = depart; + } + + public int getDepartWork() { + return departWork; + } + + public void setArriveWork( int arrive ) { + arriveWork = arrive; + } + + public int getArriveWork() { + return arriveWork; + } + + public void setWorkOrSchoolMaz( int maz ) { + workOrSchoolMaz = maz; + } + + public int getWorkOrSchoolMaz() { + return workOrSchoolMaz; + } + + public void setDepartPrimaryInterval( int interval ) { + departPrimaryInterval = interval; + } + + public int getDepartPrimaryInterval() { + return departPrimaryInterval; + } + + + public String toString() { + + String childIdString = "["; + String childPnumString = "["; + String schoolString = "["; + String distsString = "["; + if ( childIds.length > 0 ) { + childIdString += childIds[0]; + childPnumString += childPnums[0]; + schoolString += schoolMazs[0]; + distsString += String.format( "%.5f", schoolDists[0] ); + for ( int i=1; i < childIds.length; i++ ) { + childIdString += "," + childIds[i]; + childPnumString += "," + childPnums[i]; + schoolString += "," + schoolMazs[i]; + distsString += "," + String.format( "%.5f", schoolDists[i] ); + } + } + childIdString += "]"; + childPnumString += "]"; + schoolString += "]"; + distsString += "]"; + + String outputString = + "\tid = " + id + "\n" + + "\tdir = " + (dir == SchoolEscortingModel.DIR_OUTBOUND ? "outbound" : "inbound" ) + "\n" + + "\talt = " + alt + "\n" + + "\tbundle = " + bundle + "\n" + + "\tchaufPnum = " + chaufPnum + "\n" + + "\tchaufPid = " + chaufPid + "\n" + + "\tchaufPtype = " + chaufPersType + "\n" + + "\tescort type = " + (type == ModelStructure.RIDE_SHARING_TYPE ? "ride sharing" : "pure escort" ) + "\n" + + "\tchildIds = " + childIdString + "\n" + + "\tchildPnums = " + childPnumString + "\n" + + "\tschoolMazs = " + schoolString + "\n" + + "\tschoolDists = " + distsString + "\n" + + "\tdepartHome = " + departHome + "\n" + + "\tarriveHome = " + arriveHome + "\n" + + "\tdepartWork = " + departWork + "\n" + + "\tarriveWork = " + arriveWork + "\n\n"; + + return outputString; + + } + + public static String getExportHeaderString() { + String header = "id,dir,alt,bundle,type,chaufId,chaufPnum,chaufPersType,chaufPid,departHome,arriveHome,departWork,arriveWork,childIds,childPnums,schoolMazs,schoolDists"; + return header; + } + + public String getExportString() { + + String childIdString = "["; + String childPnumString = "["; + String schoolString = "["; + String distsString = "["; + if ( childIds.length > 0 ) { + childIdString += childIds[0]; + childPnumString += childPnums[0]; + schoolString += schoolMazs[0]; + distsString += String.format( "%.5f", schoolDists[0] ); + for ( int i=1; i < childIds.length; i++ ) { + childIdString += "," + childIds[i]; + childPnumString += "," + childPnums[i]; + schoolString += "," + schoolMazs[i]; + distsString += "," + String.format( "%.5f", schoolDists[i] ); + } + } + childIdString += "]"; + childPnumString += "]"; + schoolString += "]"; + distsString += "]"; + + String outputString = + id + "," + + dir + "," + + alt + "," + + bundle + "," + + type + "," + + chaufId + "," + + chaufPnum + "," + + chaufPersType + "," + + chaufPid + "," + + departHome + "," + + arriveHome + "," + + departWork + "," + + arriveWork + "," + + childIdString + "," + + childPnumString + "," + + schoolString + "," + + distsString; + + return outputString; + + } + + public void logBundle(Logger logger){ + + String childIdString = "["; + String childPnumString = "["; + String schoolString = "["; + String distsString = "["; + if ( childIds.length > 0 ) { + childIdString += childIds[0]; + childPnumString += childPnums[0]; + schoolString += schoolMazs[0]; + distsString += String.format( "%.5f", schoolDists[0] ); + for ( int i=1; i < childIds.length; i++ ) { + childIdString += "," + childIds[i]; + childPnumString += "," + childPnums[i]; + schoolString += "," + schoolMazs[i]; + distsString += "," + String.format( "%.5f", schoolDists[i] ); + } + } + childIdString += "]"; + childPnumString += "]"; + schoolString += "]"; + distsString += "]"; + logger.info("***********************************************"); + logger.info("id = " + id); + logger.info("dir = " + (dir == SchoolEscortingModel.DIR_OUTBOUND ? "outbound" : "inbound" ) ); + logger.info("alt = " + alt ); + logger.info("bundle = " + bundle ); + logger.info("chaufPnum = " + chaufPnum ); + logger.info("chaufPid = " + chaufPid ); + logger.info("chaufPtype = " + chaufPersType ); + logger.info("escort type = " + (type == ModelStructure.RIDE_SHARING_TYPE ? "ride sharing" : "pure escort" ) ); + logger.info("childIds = " + childIdString ); + logger.info("childPnums = " + childPnumString ); + logger.info("schoolMazs = " + schoolString ); + logger.info("schoolDists = " + distsString ); + logger.info("departHome = " + departHome ); + logger.info("arriveHome = " + arriveHome ); + logger.info("departWork = " + departWork ); + logger.info("arriveWork = " + arriveWork ); + logger.info("***********************************************"); + + + } + +/* + public static SchoolEscortingBundle restoreSchoolEscortingBundleFromExportString( String exportString ) throws Exception { + + StringTokenizer st = new StringTokenizer( exportString, "," ); + + String stringValue = st.nextToken().trim(); + int idValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int dirValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int altValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int bundleValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int typeValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int chaufIdValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int chaufPnumValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int chaufPtypeValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int chaufPidValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int departHomeValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int arriveHomeValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int departWorkValue = Integer.parseInt( stringValue ); + + stringValue = st.nextToken().trim(); + int arriveWorkValue = Integer.parseInt( stringValue ); + + int startCharIndex = exportString.indexOf("[") + 1; + int endCharIndex = exportString.indexOf("]"); + String valuesOnlyString = exportString.substring( startCharIndex, endCharIndex ); + int[] childIdValues = Parsing.getOneDimensionalIntArrayValuesFromExportString( valuesOnlyString ); + Integer.par + startCharIndex = exportString.indexOf("[", endCharIndex) + 1; + endCharIndex = exportString.indexOf("]", startCharIndex); + valuesOnlyString = exportString.substring( startCharIndex, endCharIndex ); + int[] childPnumValues = Parsing.getOneDimensionalIntArrayValuesFromExportString( valuesOnlyString ); + + startCharIndex = exportString.indexOf("[", endCharIndex) + 1; + endCharIndex = exportString.indexOf("]", startCharIndex); + valuesOnlyString = exportString.substring( startCharIndex, endCharIndex ); + int[] schoolMazsValues = Parsing.getOneDimensionalIntArrayValuesFromExportString( valuesOnlyString ); + + startCharIndex = exportString.indexOf("[", endCharIndex) + 1; + endCharIndex = exportString.indexOf("]", startCharIndex); + valuesOnlyString = exportString.substring( startCharIndex, endCharIndex ); + float[] schoolDistValues = Parsing.getOneDimensionalFloatArrayValuesFromExportString( valuesOnlyString ); + + + SchoolEscortingBundle newBundle = new SchoolEscortingBundle( altValue, bundleValue, chaufIdValue, typeValue, childIdValues, childPnumValues ); + newBundle.setId( idValue ); + newBundle.setDir( dirValue ); + newBundle.setChaufPnum( chaufPnumValue ); + newBundle.setChaufPersType( chaufPtypeValue ); + newBundle.setChaufPid( chaufPidValue ); + newBundle.setSchoolMazs( schoolMazsValues ); + newBundle.setSchoolDists( schoolDistValues ); + newBundle.setDepartHome( departHomeValue ); + newBundle.setArriveHome( arriveHomeValue ); + newBundle.setDepartWork( departWorkValue ); + newBundle.setArriveWork( arriveWorkValue ); + + return newBundle; + + } + */ +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingDmu.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingDmu.java new file mode 100644 index 0000000..f8c76fb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingDmu.java @@ -0,0 +1,1716 @@ +/* +* The school-escort model was designed by PB (Gupta, Vovsha, et al) +* as part of the Maricopa Association of Governments (MAG) +* Activity-based Travel Model Development project. +* +* This source code, which implements the school escort model, +* was written exclusively for and funded by MAG as part of the +* same project; therefore, per their contract, the +* source code belongs to MAG and can only be used with their +* permission. +* +* It is being adapted for the Southern Oregon ABM by PB & RSG +* with permission from MAG and all references to +* the school escort model as well as source code adapted from this +* original code should credit MAG's role in its development. +* +* The escort model and source code should not be transferred to or +* adapted for other agencies or used in other projects without +* expressed permission from MAG. +*/ + +package org.sandag.abm.ctramp; + +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.matrix.Matrix; +import com.pb.common.util.IndexSort; + + + + +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; + + + +public class SchoolEscortingDmu implements VariableTable { + + private Logger logger = Logger.getLogger( SchoolEscortingDmu.class ); + + private static final float DROP_OFF_DURATION = 5.0f; + private static final float PICK_UP_DURATION = 10.0f; + private static final float MINUTES_PER_MILE = 2.0f; + + + private Household hhObj; + + private float[] distHomeSchool; + private float[] timeHomeSchool; + private float[] distSchoolHome; + private float[] timeSchoolHome; + + //for each cheaffeur + private float[] distHomeMandatory; + private float[] timeHomeMandatory; + private float[] distMandatoryHome; + private float[] timeMandatoryHome; + + private float[][] distSchoolSchool; + private float[][] distSchoolMandatory; + private float[][] distMandatorySchool; + + private Person[] escortees; + + + private int[] escorteeIds; + private int[] escorteePnums; + private int[] escorteeAge; + + private int[] escorteeSchoolLoc; + private int[] escorteeSchoolAtHome; + private int[] escorteeDepartForSchool; + private int[] escorteeDepartFromSchool; + private int numChildrenTravelingToSchool; + + private Person[] chauffers; + private int[] chauffeurPnums; + private int[] chauffeurPids; + private int[] chauffeurAge; + private int[] chauffeurGender; + private int[] chauffeurPersonType; + private int[] chauffeurDap; + private int[] chauffeurMandatoryLoc; + private int[] chauffeurDepartForMandatory; + private int[] chauffeurDepartFromMandatory; + private int numPotentialChauffeurs; + + private int[][][] chaufExtents; + + private int chosenObEscortType1; + private int chosenObEscortType2; + private int chosenObEscortType3; + private int chosenObChauf1; + private int chosenObChauf2; + private int chosenObChauf3; + private int potentialObChauf1; + private int potentialObChauf2; + + private int chosenIbEscortType1; + private int chosenIbEscortType2; + private int chosenIbEscortType3; + private int chosenIbChauf1; + private int chosenIbChauf2; + private int chosenIbChauf3; + private int potentialIbChauf1; + private int potentialIbChauf2; + + private MgraDataManager mgraDataManager; + + private double[][] distanceArray; + + private int[][] altBundleIncidence; + + private Map methodIndexMap; + + + + /** + * Create the DMU by passing in... + * @param MgraDataManager mgraDataManager + * @param Matrix distanceMatrix + */ + public SchoolEscortingDmu(MgraDataManager mgraDataManager, double[][] distanceArray) { + + this.mgraDataManager = mgraDataManager; + this.distanceArray = distanceArray; + + chauffeurPnums = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurPids = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurAge = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurGender = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurPersonType = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurDap = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurMandatoryLoc = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurDepartForMandatory = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + chauffeurDepartFromMandatory = new int[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + distHomeMandatory = new float[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + timeHomeMandatory = new float[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + distMandatoryHome = new float[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + timeMandatoryHome = new float[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + + escorteeIds = new int[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + escorteePnums = new int[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + escorteeAge = new int[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + escorteeSchoolLoc = new int[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + escorteeSchoolAtHome = new int[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + escorteeDepartForSchool = new int[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + escorteeDepartFromSchool = new int[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + distHomeSchool = new float[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + timeHomeSchool = new float[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + distSchoolHome = new float[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + timeSchoolHome = new float[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + + distSchoolSchool = new float[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1][SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + distSchoolMandatory = new float[SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1][SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1]; + distMandatorySchool = new float[SchoolEscortingModel.NUM_CHAUFFEURS_PER_HH+1][SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1]; + + setupMethodIndexMap(); + } + + + public void setAltTableBundleIncidence( int[][] altBundleIncidence ) { + + this.altBundleIncidence = altBundleIncidence; + + } + + /** + * Set attributes of the potential chauffeurs + * @param numPotential Number of potential chauffeurs (size of adults array) + * @param adults Ordered array of chauffeurs + * @param mandatoryMazs Array size of chauffeurs, holding MAZ of last mandatory tour + * @param mandatoryDeparts Array size of chauffeurs, holding home departure period of last mandatory tour + * @param mandatoryReturns Array size of chauffeurs, holding work departure period of last mandatory tour + * @param chaufExtents Array size of chauffeurs, + */ + public void setChaufferAttributes( int numPotential, Person[] adults, int[] mandatoryMazs, int[] mandatoryDeparts, int[] mandatoryReturns, int[][][] chaufExtents ) { + + this.chaufExtents = chaufExtents; + + chauffers = adults; + numPotentialChauffeurs = numPotential; + + for ( int i=1; i < chauffers.length; i++ ) { + if ( chauffers[i] == null ) { + chauffeurAge[i] = 0; + chauffeurGender[i] = 0; + chauffeurPersonType[i] = 0; + chauffeurDap[i] = 0; + chauffeurMandatoryLoc[i] = 0; + chauffeurDepartForMandatory[i] = 0; + chauffeurDepartFromMandatory[i] = 0; + chauffeurPnums[i] = 0; + chauffeurPids[i] = 0; + } + else { + chauffeurPnums[i] = chauffers[i].getPersonNum(); + chauffeurPids[i] = chauffers[i].getPersonId(); + chauffeurAge[i] = chauffers[i].getAge(); + chauffeurGender[i] = chauffers[i].getGender(); + chauffeurPersonType[i] = chauffers[i].getPersonTypeNumber(); + chauffeurDap[i] = chauffers[i].getCdapIndex(); + if ( mandatoryMazs[i] == 0 ) { + chauffeurMandatoryLoc[i] = 0; + chauffeurDepartForMandatory[i] = 0; + chauffeurDepartFromMandatory[i] = 0; + } + else { + chauffeurMandatoryLoc[i] = mandatoryMazs[i]; + chauffeurDepartForMandatory[i] = mandatoryDeparts[i]; + chauffeurDepartFromMandatory[i] = mandatoryReturns[i]; + } + } + } + } + + /** + * Set attributes for escortees. + * + * @param numPotential Number of potential escortees (children traveling to school). + * @param children Person array of potential escortees + * @param schoolAtHome An array for each person indicating if they are schooled at home + * @param schoolMazs An array of school MAZs for each person + * @param schoolDeparts An array of school tour outbound periods + * @param schoolReturns an array of school tour return periods + */ + public void setEscorteeAttributes( int numPotential, Person[] children, int[] schoolAtHome, int[] schoolMazs, int[] schoolDeparts, int[] schoolReturns ) { + + escortees = children; + numChildrenTravelingToSchool = numPotential; + + for ( int i=1; i < escortees.length; i++ ) { + if ( escortees[i] == null || schoolMazs[i] == 0 ) { + escorteeIds[i] = 0; + escorteePnums[i] = 0; + escorteeAge[i] = 0; + escorteeSchoolLoc[i] = 0; + escorteeSchoolAtHome[i] = 0; + escorteeDepartForSchool[i] = 0; + escorteeDepartFromSchool[i] = 0; + } + else { + escorteeIds[i] = i; + escorteePnums[i] = escortees[i].getPersonNum(); + escorteeAge[i] = escortees[i].getAge(); + escorteeSchoolLoc[i] = schoolMazs[i]; + escorteeSchoolAtHome[i] = schoolAtHome[i]; + escorteeDepartForSchool[i] = schoolDeparts[i]; + escorteeDepartFromSchool[i] = schoolReturns[i]; + } + + } + + } + + /** + * Sets distance time attributes for combinations of chauffeur mandatory locations and escortee school locations. + * @param hhObj + * @param distanceArray + */ + public void setDistanceTimeAttributes( Household hhObj, double[][] distanceArray ) { + + this.hhObj = hhObj; + + int homeMaz = hhObj.getHhTaz(); + int homeTaz = mgraDataManager.getTaz(homeMaz); + + // compute times and distances from "home to work" and from "work to home" by traversing the chain of business locations for work tours + // to/from the primary work location for work tours and the chain that may include a work location for school tours. + + //for each chauffeur + for ( int i=1; i < chauffers.length; i++ ) { + if ( chauffers[i] == null ) { + distHomeMandatory[i] = 0; + timeHomeMandatory[i] = 0; + distMandatoryHome[i] = 0; + timeMandatoryHome[i] = 0; + } + else { + if ( chauffeurMandatoryLoc[i] > 0 ) { + + distHomeMandatory[i] = 0; + timeHomeMandatory[i] = 0; + distMandatoryHome[i] = 0; + timeMandatoryHome[i] = 0; + + //the MAG model would traverse all the activities on the tour, skipping non-work and non-school tours, and skipping + //non-work activities, and sum up the distance from home to each work activity. In the case of ORRAMP, only the work + //primary destination is known, so the method has been re-written accordingly to use work primary destination for workers. + + int mandatoryMaz = chauffeurMandatoryLoc[i]; + int mandatoryTaz = mgraDataManager.getTaz(mandatoryMaz); + + distHomeMandatory[i] = (float) distanceArray[homeTaz][ mandatoryTaz]; + timeHomeMandatory[i] = MINUTES_PER_MILE * (float) distanceArray[homeTaz][mandatoryTaz]; + distMandatoryHome[i] = (float) distanceArray[mandatoryTaz][homeTaz]; + timeMandatoryHome[i] = MINUTES_PER_MILE * (float) distanceArray[mandatoryTaz][homeTaz]; + + } + else { + distHomeMandatory[i] = 0; + timeHomeMandatory[i] = 0; + distMandatoryHome[i] = 0; + timeMandatoryHome[i] = 0; + } + } + } + + //iterating through potential escortees (i) + for ( int i=1; i < escortees.length; i++ ) { + if ( escortees[i] == null ) { + distHomeSchool[i] = 0; + timeHomeSchool[i] = 0; + distSchoolHome[i] = 0; + timeSchoolHome[i] = 0; + for ( int j=1; j < chauffeurPnums.length; j++ ) { + distSchoolMandatory[i][j] = 0; + distMandatorySchool[j][i] = 0; + } + for ( int j=1; j < escorteePnums.length; j++ ) + distSchoolSchool[i][j] = 0; + } + else { + if ( escorteeSchoolLoc[i] > 0 ) { + + int schoolTaz = mgraDataManager.getTaz(escorteeSchoolLoc[i]); + + distHomeSchool[i] = (float) distanceArray[homeTaz][schoolTaz]; + timeHomeSchool[i] = MINUTES_PER_MILE * (float) distanceArray[homeTaz][schoolTaz]; + distSchoolHome[i] = (float) distanceArray[schoolTaz][ homeTaz]; + timeSchoolHome[i] = MINUTES_PER_MILE * (float) distanceArray[schoolTaz][homeTaz]; + + //iterating through potential chauffeurs (j) + for ( int j=1; j < chauffeurPnums.length; j++ ) { + distSchoolMandatory[i][j] = 0; + distMandatorySchool[j][i] = 0; + if ( chauffeurMandatoryLoc[j] > 0 ) { + int mandatoryMaz = chauffeurMandatoryLoc[j]; + int mandatoryTaz = mgraDataManager.getTaz(mandatoryMaz); + distSchoolMandatory[i][j] = (float) distanceArray[schoolTaz][mandatoryTaz]; + distMandatorySchool[j][i] = (float) distanceArray[mandatoryTaz][schoolTaz]; + } + } + + for ( int j=1; j < escorteePnums.length; j++ ) { + distSchoolSchool[i][j] = 0; + if ( escorteeSchoolLoc[j] > 0 && escorteeSchoolLoc[j] != escorteeSchoolLoc[i] ) { + int schoolTazJ = mgraDataManager.getTaz(escorteeSchoolLoc[j]); + distSchoolSchool[i][j] = (float) distanceArray[schoolTaz][schoolTazJ]; + } + } + } + else { + distHomeSchool[i] = 0; + timeHomeSchool[i] = 0; + distSchoolHome[i] = 0; + timeSchoolHome[i] = 0; + for ( int j=1; j < chauffeurPnums.length; j++ ) { + distSchoolMandatory[i][j] = 0; + distMandatorySchool[j][i] = 0; + } + for ( int j=1; j < escorteePnums.length; j++ ) + distSchoolSchool[i][j] = 0; + } + } + + } + + } + + + public void setOutboundEscortType1( int chosenObEscortType ) { + chosenObEscortType1 = chosenObEscortType; + } + + public void setOutboundEscortType2( int chosenObEscortType ) { + chosenObEscortType2 = chosenObEscortType; + } + + public void setOutboundEscortType3( int chosenObEscortType ) { + chosenObEscortType3 = chosenObEscortType; + } + + public void setOutboundChauffeur1( int chosenObChauf ) { + chosenObChauf1 = chosenObChauf; + } + + public void setOutboundChauffeur2( int chosenObChauf ) { + chosenObChauf2 = chosenObChauf; + } + + public void setOutboundChauffeur3( int chosenObChauf ) { + chosenObChauf3 = chosenObChauf; + } + + public void setOutboundPotentialChauffeur1( int chaufPnum ) { + potentialObChauf1 = chaufPnum; + } + + public void setOutboundPotentialChauffeur2( int chaufPnum ) { + potentialObChauf2 = chaufPnum; + } + + + + public void setInboundEscortType1( int chosenIbEscortType ) { + chosenIbEscortType1 = chosenIbEscortType; + } + + public void setInboundEscortType2( int chosenIbEscortType ) { + chosenIbEscortType2 = chosenIbEscortType; + } + + public void setInboundEscortType3( int chosenIbEscortType ) { + chosenIbEscortType3 = chosenIbEscortType; + } + + public void setInboundChauffeur1( int chosenIbChauf ) { + chosenIbChauf1 = chosenIbChauf; + } + + public void setInboundChauffeur2( int chosenIbChauf ) { + chosenIbChauf2 = chosenIbChauf; + } + + public void setInboundChauffeur3( int chosenIbChauf ) { + chosenIbChauf3 = chosenIbChauf; + } + + public void setInboundPotentialChauffeur1( int chaufPnum ) { + potentialIbChauf1 = chaufPnum; + } + + public void setInboundPotentialChauffeur2( int chaufPnum ) { + potentialIbChauf2 = chaufPnum; + } + + public int[] getChauffeurPnums() { + return chauffeurPnums; + } + + public int[] getChauffeurDepartForMandatory() { + return chauffeurDepartForMandatory; + } + + public int[] getChauffeurDepartFromMandatory() { + return chauffeurDepartFromMandatory; + } + + public int[] getEscorteePnums() { + return escorteePnums; + } + + public int[] getEscorteeDepartForSchool() { + return escorteeDepartForSchool; + } + + public int[] getEscorteeDepartFromSchool() { + return escorteeDepartFromSchool; + } + + public int[] getEscorteeSchoolAtHome() { + return escorteeSchoolAtHome; + } + + public int[] getEscorteeDistToSchool() { + int[] tempDist = new int[distHomeSchool.length]; + for ( int i=1; i < distHomeSchool.length; i++ ) + tempDist[i] = (int)(distHomeSchool[i] * 100); + return tempDist; + } + + public int[] getEscorteeDistFromSchool() { + int[] tempDist = new int[distSchoolHome.length]; + for ( int i=1; i < distSchoolHome.length; i++ ) + tempDist[i] = (int)(distSchoolHome[i] * 100); + return tempDist; + } + + + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put( "getChild1Pnum", 1 ); + methodIndexMap.put( "getChild2Pnum", 2 ); + methodIndexMap.put( "getChild3Pnum", 3 ); + methodIndexMap.put( "getAdult1Pnum", 4 ); + methodIndexMap.put( "getAdult2Pnum", 5 ); + methodIndexMap.put( "getAgeChild1", 6 ); + methodIndexMap.put( "getAgeChild2", 7 ); + methodIndexMap.put( "getAgeChild3", 8 ); + methodIndexMap.put( "getSchoolMazChild1", 9 ); + methodIndexMap.put( "getSchoolMazChild2", 10 ); + methodIndexMap.put( "getSchoolMazChild3", 11 ); + methodIndexMap.put( "getDistHomeSchool1", 12 ); + methodIndexMap.put( "getDistHomeSchool2", 13 ); + methodIndexMap.put( "getDistHomeSchool3", 14 ); + methodIndexMap.put( "getDistSchoolHome1", 15 ); + methodIndexMap.put( "getDistSchoolHome2", 16 ); + methodIndexMap.put( "getDistSchoolHome3", 17 ); + methodIndexMap.put( "getTimeHomeSchool1", 18 ); + methodIndexMap.put( "getTimeHomeSchool2", 19 ); + methodIndexMap.put( "getTimeHomeSchool3", 20 ); + methodIndexMap.put( "getTimeSchoolHome1", 21 ); + methodIndexMap.put( "getTimeSchoolHome2", 22 ); + methodIndexMap.put( "getTimeSchoolHome3", 23 ); + methodIndexMap.put( "getDepartHomeSchool1", 24 ); + methodIndexMap.put( "getDepartHomeSchool2", 25 ); + methodIndexMap.put( "getDepartHomeSchool3", 26 ); + methodIndexMap.put( "getDepartSchoolHome1", 27 ); + methodIndexMap.put( "getDepartSchoolHome2", 28 ); + methodIndexMap.put( "getDepartSchoolHome3", 29 ); + methodIndexMap.put( "getGenderAdult1", 30 ); + methodIndexMap.put( "getGenderAdult2", 31 ); + methodIndexMap.put( "getPersonTypeAdult1", 32 ); + methodIndexMap.put( "getPersonTypeAdult2", 33 ); + methodIndexMap.put( "getAgeAdult1", 34 ); + methodIndexMap.put( "getAgeAdult2", 35 ); + methodIndexMap.put( "getDepartHomeWorkAdult1", 36 ); + methodIndexMap.put( "getDepartHomeWorkAdult2", 37 ); + methodIndexMap.put( "getDepartWorkHomeAdult1", 38 ); + methodIndexMap.put( "getDepartWorkHomeAdult2", 39 ); + methodIndexMap.put( "getDapAdult1", 40 ); + methodIndexMap.put( "getDapAdult2", 41 ); + methodIndexMap.put( "getDistHomeWork1", 42 ); + methodIndexMap.put( "getDistHomeWork2", 43 ); + methodIndexMap.put( "getTimeHomeWork1", 44 ); + methodIndexMap.put( "getTimeHomeWork2", 45 ); + methodIndexMap.put( "getDistWorkHome1", 46 ); + methodIndexMap.put( "getDistWorkHome2", 47 ); + methodIndexMap.put( "getTimeWorkHome1", 48 ); + methodIndexMap.put( "getTimeWorkHome2", 49 ); + methodIndexMap.put( "getDistSchool1School2", 50 ); + methodIndexMap.put( "getDistSchool1School3", 51 ); + methodIndexMap.put( "getDistSchool2School3", 52 ); + methodIndexMap.put( "getDistSchool1Work1", 53 ); + methodIndexMap.put( "getDistSchool1Work2", 54 ); + methodIndexMap.put( "getDistSchool2Work1", 55 ); + methodIndexMap.put( "getDistSchool2Work2", 56 ); + methodIndexMap.put( "getDistSchool3Work1", 57 ); + methodIndexMap.put( "getDistSchool3Work2", 58 ); + methodIndexMap.put( "getDistWork1School1", 59 ); + methodIndexMap.put( "getDistWork2School1", 60 ); + methodIndexMap.put( "getDistWork1School2", 61 ); + methodIndexMap.put( "getDistWork2School2", 62 ); + methodIndexMap.put( "getDistWork1School3", 63 ); + methodIndexMap.put( "getDistWork2School3", 64 ); + methodIndexMap.put( "getIncome", 65 ); + methodIndexMap.put( "getNumAutosInHH", 66 ); + methodIndexMap.put( "getNumWorkersInHH", 67 ); + methodIndexMap.put( "getNumChildrenWithSchoolOutsideOfHomeAndDap1", 68 ); + methodIndexMap.put( "getNumAdultsinHHDap12", 69 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild1Chauffeur1", 70 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild1Chauffeur2", 71 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild2Chauffeur1", 72 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild2Chauffeur2", 73 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild3Chauffeur1", 74 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild3Chauffeur2", 75 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild12Chauffeur1", 76 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild12Chauffeur2", 77 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild13Chauffeur1", 78 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild13Chauffeur2", 79 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild23Chauffeur1", 80 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild23Chauffeur2", 81 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild123Chauffeur1", 82 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceOutboundChild123Chauffeur2", 83 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild1Chauffeur1", 84 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild1Chauffeur2", 85 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild2Chauffeur1", 86 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild2Chauffeur2", 87 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild3Chauffeur1", 88 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild3Chauffeur2", 89 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild12Chauffeur1", 90 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild12Chauffeur2", 91 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild13Chauffeur1", 92 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild13Chauffeur2", 93 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild23Chauffeur1", 94 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild23Chauffeur2", 95 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild123Chauffeur1", 96 ); + methodIndexMap.put( "getAbsoluteDeviationDistanceInboundChild123Chauffeur2", 97 ); + methodIndexMap.put( "getInboundEscortType1", 98 ); + methodIndexMap.put( "getInboundEscortType2", 99 ); + methodIndexMap.put( "getInboundEscortType3", 100 ); + methodIndexMap.put( "getInboundChauffeur1", 101 ); + methodIndexMap.put( "getInboundChauffeur2", 102 ); + methodIndexMap.put( "getInboundChauffeur3", 103 ); + methodIndexMap.put( "getOutboundEscortType1", 104 ); + methodIndexMap.put( "getOutboundEscortType2", 105 ); + methodIndexMap.put( "getOutboundEscortType3", 106 ); + methodIndexMap.put( "getOutboundChauffeur1", 107 ); + methodIndexMap.put( "getOutboundChauffeur2", 108 ); + methodIndexMap.put( "getOutboundChauffeur3", 109 ); + methodIndexMap.put( "getInboundPotentialChauffeur1", 110 ); + methodIndexMap.put( "getInboundPotentialChauffeur2", 111 ); + methodIndexMap.put( "getOutboundPotentialChauffeur1", 112 ); + methodIndexMap.put( "getOutboundPotentialChauffeur2", 113 ); + methodIndexMap.put( "getTravelTimeWork1School1", 114 ); + methodIndexMap.put( "getTravelTimeWork2School1", 115 ); + methodIndexMap.put( "getTravelTimeWork1School2", 116 ); + methodIndexMap.put( "getTravelTimeWork2School2", 117 ); + methodIndexMap.put( "getTravelTimeWork1School3", 118 ); + methodIndexMap.put( "getTravelTimeWork2School3", 119 ); + methodIndexMap.put( "getTravelTimeWork1Home", 120 ); + methodIndexMap.put( "getTravelTimeWork2Home", 121 ); + methodIndexMap.put( "getAvailabilityForMultipleBundlesOutbound", 122 ); + methodIndexMap.put( "getAvailabilityForMultipleBundlesInbound", 123 ); + methodIndexMap.put( "getAvailabilityForInboundChauf1WithOutboundBundles", 124); + methodIndexMap.put( "getAvailabilityForInboundChauf2WithOutboundBundles", 125); + methodIndexMap.put( "getTravelTimeHomeSchool1", 126 ); + methodIndexMap.put( "getTravelTimeHomeSchool2", 127 ); + methodIndexMap.put( "getTravelTimeHomeSchool3", 128 ); + methodIndexMap.put( "getTravelTimeSchool1Home", 129 ); + methodIndexMap.put( "getTravelTimeSchool2Home", 130 ); + methodIndexMap.put( "getTravelTimeSchool3Home", 131 ); + methodIndexMap.put( "getAvailabilityForOutboundChauf1WithInboundBundles", 132); + methodIndexMap.put( "getAvailabilityForOutboundChauf2WithInboundBundles", 133); + + } + + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 1: + return escorteePnums[1]; + case 2: + return escorteePnums[2]; + case 3: + return escorteePnums[3]; + case 4: + return chauffeurPnums[1]; + case 5: + return chauffeurPnums[2]; + case 6: + return escorteeAge[1]; + case 7: + return escorteeAge[2]; + case 8: + return escorteeAge[3]; + case 9: + return escorteeSchoolLoc[1]; + case 10: + return escorteeSchoolLoc[2]; + case 11: + return escorteeSchoolLoc[3]; + case 12: + return distHomeSchool[1]; + case 13: + return distHomeSchool[2]; + case 14: + return distHomeSchool[3]; + case 15: + return distSchoolHome[1]; + case 16: + return distSchoolHome[2]; + case 17: + return distSchoolHome[3]; + case 18: + return timeHomeSchool[1]; + case 19: + return timeHomeSchool[2]; + case 20: + return timeHomeSchool[3]; + case 21: + return timeSchoolHome[1]; + case 22: + return timeSchoolHome[2]; + case 23: + return timeSchoolHome[3]; + case 24: + return escorteeDepartForSchool[1]; + case 25: + return escorteeDepartForSchool[2]; + case 26: + return escorteeDepartForSchool[3]; + case 27: + return escorteeDepartFromSchool[1]; + case 28: + return escorteeDepartFromSchool[2]; + case 29: + return escorteeDepartFromSchool[3]; + case 30: + return chauffeurGender[1]; + case 31: + return chauffeurGender[2]; + case 32: + return chauffeurPersonType[1]; + case 33: + return chauffeurPersonType[2]; + case 34: + return chauffeurAge[1]; + case 35: + return chauffeurAge[2]; + case 36: + return chauffeurDepartForMandatory[1]; + case 37: + return chauffeurDepartForMandatory[2]; + case 38: + return chauffeurDepartFromMandatory[1]; + case 39: + return chauffeurDepartFromMandatory[2]; + case 40: + return chauffeurDap[1]; + case 41: + return chauffeurDap[2]; + case 42: + return distHomeMandatory[1]; + case 43: + return distHomeMandatory[2]; + case 44: + return timeHomeMandatory[1]; + case 45: + return timeHomeMandatory[2]; + case 46: + return distMandatoryHome[1]; + case 47: + return distMandatoryHome[2]; + case 48: + return timeMandatoryHome[1]; + case 49: + return timeMandatoryHome[2]; + case 50: + return distSchoolSchool[1][2]; + case 51: + return distSchoolSchool[1][3]; + case 52: + return distSchoolSchool[2][3]; + case 53: + return distSchoolMandatory[1][1]; + case 54: + return distSchoolMandatory[1][2]; + case 55: + return distSchoolMandatory[2][1]; + case 56: + return distSchoolMandatory[2][2]; + case 57: + return distSchoolMandatory[3][1]; + case 58: + return distSchoolMandatory[3][2]; + case 59: + return distMandatorySchool[1][1]; + case 60: + return distMandatorySchool[1][2]; + case 61: + return distMandatorySchool[1][3]; + case 62: + return distMandatorySchool[2][1]; + case 63: + return distMandatorySchool[2][2]; + case 64: + return distMandatorySchool[2][3]; + case 65: + return hhObj.getIncomeInDollars(); + case 66: + return hhObj.getAutosOwned(); + case 67: + return hhObj.getWorkers(); + case 68: + return numChildrenTravelingToSchool; + case 69: + return numPotentialChauffeurs; + case 70: + return Math.max( distHomeSchool[1] + distSchoolMandatory[1][1] - distHomeMandatory[1], 0 ); + case 71: + return Math.max( distHomeSchool[1] + distSchoolMandatory[1][2] - distHomeMandatory[2], 0 ); + case 72: + return Math.max( distHomeSchool[2] + distSchoolMandatory[2][1] - distHomeMandatory[1], 0 ); + case 73: + return Math.max( distHomeSchool[2] + distSchoolMandatory[2][2] - distHomeMandatory[2], 0 ); + case 74: + return Math.max( distHomeSchool[3] + distSchoolMandatory[3][1] - distHomeMandatory[1], 0 ); + case 75: + return Math.max( distHomeSchool[3] + distSchoolMandatory[3][2] - distHomeMandatory[2], 0 ); + case 76: + return getAbsoluteDeviationDistanceOutboundChild12Chauffeur1(); + case 77: + return getAbsoluteDeviationDistanceOutboundChild12Chauffeur2(); + case 78: + return getAbsoluteDeviationDistanceOutboundChild13Chauffeur1(); + case 79: + return getAbsoluteDeviationDistanceOutboundChild13Chauffeur2(); + case 80: + return getAbsoluteDeviationDistanceOutboundChild23Chauffeur1(); + case 81: + return getAbsoluteDeviationDistanceOutboundChild23Chauffeur2(); + case 82: + return getAbsoluteDeviationDistanceOutboundChild123Chauffeur1(); + case 83: + return getAbsoluteDeviationDistanceOutboundChild123Chauffeur2(); + case 84: + return Math.max( distMandatorySchool[1][1] + distSchoolHome[1] - distMandatoryHome[1], 0 ); + case 85: + return Math.max( distMandatorySchool[2][1] + distSchoolHome[1] - distMandatoryHome[2], 0 ); + case 86: + return Math.max( distMandatorySchool[1][2] + distSchoolHome[2] - distMandatoryHome[1], 0 ); + case 87: + return Math.max( distMandatorySchool[2][2] + distSchoolHome[2] - distMandatoryHome[2], 0 ); + case 88: + return Math.max( distMandatorySchool[1][3] + distSchoolHome[3] - distMandatoryHome[1], 0 ); + case 89: + return Math.max( distMandatorySchool[2][3] + distSchoolHome[3] - distMandatoryHome[2], 0 ); + case 90: + return getAbsoluteDeviationDistanceInboundChild12Chauffeur1(); + case 91: + return getAbsoluteDeviationDistanceInboundChild12Chauffeur2(); + case 92: + return getAbsoluteDeviationDistanceInboundChild13Chauffeur1(); + case 93: + return getAbsoluteDeviationDistanceInboundChild13Chauffeur2(); + case 94: + return getAbsoluteDeviationDistanceInboundChild23Chauffeur1(); + case 95: + return getAbsoluteDeviationDistanceInboundChild23Chauffeur2(); + case 96: + return getAbsoluteDeviationDistanceInboundChild123Chauffeur1(); + case 97: + return getAbsoluteDeviationDistanceInboundChild123Chauffeur2(); + case 98: + return chosenIbEscortType1; + case 99: + return chosenIbEscortType2; + case 100: + return chosenIbEscortType3; + case 101: + return chosenIbChauf1; + case 102: + return chosenIbChauf2; + case 103: + return chosenIbChauf3; + case 104: + return chosenObEscortType1; + case 105: + return chosenObEscortType2; + case 106: + return chosenObEscortType3; + case 107: + return chosenObChauf1; + case 108: + return chosenObChauf2; + case 109: + return chosenObChauf3; + case 110: + return potentialIbChauf1; + case 111: + return potentialIbChauf2; + case 112: + return potentialObChauf1; + case 113: + return potentialObChauf2; + case 114: + return (int)( ( ( distMandatorySchool[1][1] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 115: + return (int)( ( ( distMandatorySchool[2][1] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 116: + return (int)( ( ( distMandatorySchool[1][2] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 117: + return (int)( ( ( distMandatorySchool[2][2] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 118: + return (int)( ( ( distMandatorySchool[1][3] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 119: + return (int)( ( ( distMandatorySchool[2][3] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 120: + return (int)( ( ( distMandatoryHome[1] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 121: + return (int)( ( ( distMandatoryHome[2] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 122: + return getAvailabilityForMultipleBundlesOutbound( arrayIndex ); + case 123: + return getAvailabilityForMultipleBundlesInbound( arrayIndex ); + case 124: + return getAvailabilityForInboundChauf1WithOutboundBundles( arrayIndex ); + case 125: + return getAvailabilityForInboundChauf2WithOutboundBundles( arrayIndex ); + case 126: + return (int)( ( ( distHomeSchool[1] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 127: + return (int)( ( ( distHomeSchool[2] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 128: + return (int)( ( ( distHomeSchool[3] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 129: + return (int)( ( ( distSchoolHome[1] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 130: + return (int)( ( ( distSchoolHome[2] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 131: + return (int)( ( ( distSchoolHome[3] * MINUTES_PER_MILE ) / ModelStructure.TOD_INTERVAL_IN_MINUTES ) + 0.99999 ); + case 132: + return getAvailabilityForOutboundChauf1WithInboundBundles( arrayIndex ); + case 133: + return getAvailabilityForOutboundChauf2WithInboundBundles( arrayIndex ); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + + + private float getAbsoluteDeviationDistanceOutboundChild12Chauffeur1() { + float d1 = distHomeSchool[1] + distSchoolSchool[1][2] + distSchoolMandatory[2][1]; + float d2 = distHomeSchool[2] + distSchoolSchool[2][1] + distSchoolMandatory[1][1]; + return Math.min( d1, d2 ) - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceInboundChild12Chauffeur1() { + float d1 = distMandatorySchool[1][1] + distSchoolSchool[1][2] + distSchoolHome[2]; + float d2 = distMandatorySchool[1][2] + distSchoolSchool[2][1] + distSchoolHome[1]; + return Math.min( d1, d2 ) - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceOutboundChild12Chauffeur2() { + float d1 = distHomeSchool[1] + distSchoolSchool[1][2] + distSchoolMandatory[2][2]; + float d2 = distHomeSchool[2] + distSchoolSchool[2][1] + distSchoolMandatory[1][2]; + return Math.min( d1, d2 ) - distHomeMandatory[2]; + } + + private float getAbsoluteDeviationDistanceInboundChild12Chauffeur2() { + float d1 = distMandatorySchool[2][1] + distSchoolSchool[1][2] + distSchoolHome[2]; + float d2 = distMandatorySchool[2][2] + distSchoolSchool[2][1] + distSchoolHome[1]; + return Math.min( d1, d2 ) - distHomeMandatory[2]; + } + + private float getAbsoluteDeviationDistanceOutboundChild13Chauffeur1() { + float d1 = distHomeSchool[1] + distSchoolSchool[1][3] + distSchoolMandatory[3][1]; + float d2 = distHomeSchool[3] + distSchoolSchool[3][1] + distSchoolMandatory[1][1]; + return Math.min( d1, d2 ) - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceInboundChild13Chauffeur1() { + float d1 = distMandatorySchool[1][1] + distSchoolSchool[1][3] + distSchoolHome[3]; + float d2 = distMandatorySchool[1][3] + distSchoolSchool[3][1] + distSchoolHome[1]; + return Math.min( d1, d2 ) - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceOutboundChild13Chauffeur2() { + float d1 = distHomeSchool[1] + distSchoolSchool[1][3] + distSchoolMandatory[3][2]; + float d2 = distHomeSchool[3] + distSchoolSchool[3][1] - distSchoolMandatory[1][2]; + return Math.min( d1, d2 ) - distHomeMandatory[2]; + } + + private float getAbsoluteDeviationDistanceInboundChild13Chauffeur2() { + float d1 = distMandatorySchool[2][1] + distSchoolSchool[1][3] + distSchoolHome[3]; + float d2 = distMandatorySchool[2][3] + distSchoolSchool[3][1] + distSchoolHome[1]; + return Math.min( d1, d2 ) - distHomeMandatory[2]; + } + + private float getAbsoluteDeviationDistanceOutboundChild23Chauffeur1() { + float d1 = distHomeSchool[2] + distSchoolSchool[2][3] + distSchoolMandatory[3][1]; + float d2 = distHomeSchool[3] + distSchoolSchool[3][2] - distSchoolMandatory[2][1]; + return Math.min( d1, d2 ) - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceInboundChild23Chauffeur1() { + float d1 = distMandatorySchool[1][2] + distSchoolSchool[2][3] + distSchoolHome[3]; + float d2 = distMandatorySchool[1][3] + distSchoolSchool[3][2] + distSchoolHome[2]; + return Math.min( d1, d2 ) - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceOutboundChild23Chauffeur2() { + float d1 = distHomeSchool[2] + distSchoolSchool[2][3] + distSchoolMandatory[3][2]; + float d2 = distHomeSchool[3] + distSchoolSchool[3][2] - distSchoolMandatory[2][2]; + return Math.min( d1, d2 ) - distHomeMandatory[2]; + } + + private float getAbsoluteDeviationDistanceInboundChild23Chauffeur2() { + float d1 = distMandatorySchool[2][2] + distSchoolSchool[2][3] + distSchoolHome[3]; + float d2 = distMandatorySchool[2][3] + distSchoolSchool[3][2] + distSchoolHome[2]; + return Math.min( d1, d2 ) - distHomeMandatory[2]; + } + + private float getAbsoluteDeviationDistanceOutboundChild123Chauffeur1() { + float d1 = distHomeSchool[1] + distSchoolSchool[1][2] + distSchoolSchool[2][3] + distSchoolMandatory[3][1]; + float d2 = distHomeSchool[1] + distSchoolSchool[1][3] + distSchoolSchool[3][2] + distSchoolMandatory[2][1]; + float d3 = distHomeSchool[2] + distSchoolSchool[2][1] + distSchoolSchool[1][3] + distSchoolMandatory[3][1]; + float d4 = distHomeSchool[2] + distSchoolSchool[2][3] + distSchoolSchool[3][1] + distSchoolMandatory[1][1]; + float d5 = distHomeSchool[3] + distSchoolSchool[3][1] + distSchoolSchool[1][2] + distSchoolMandatory[2][1]; + float d6 = distHomeSchool[3] + distSchoolSchool[3][2] + distSchoolSchool[2][1] + distSchoolMandatory[1][1]; + float d = Math.min( d1, d2 ); + d = Math.min( d, d3 ); + d = Math.min( d, d4 ); + d = Math.min( d, d5 ); + d = Math.min( d, d6 ); + return d - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceInboundChild123Chauffeur1() { + float d1 = distMandatorySchool[1][1] + distSchoolSchool[1][2] + distSchoolSchool[2][3] + distSchoolHome[3]; + float d2 = distMandatorySchool[1][1] + distSchoolSchool[1][3] + distSchoolSchool[3][2] + distSchoolHome[2]; + float d3 = distMandatorySchool[1][2] + distSchoolSchool[2][1] + distSchoolSchool[1][3] + distSchoolHome[3]; + float d4 = distMandatorySchool[1][2] + distSchoolSchool[2][3] + distSchoolSchool[3][1] + distSchoolHome[1]; + float d5 = distMandatorySchool[1][3] + distSchoolSchool[3][1] + distSchoolSchool[1][2] + distSchoolHome[2]; + float d6 = distMandatorySchool[1][3] + distSchoolSchool[3][2] + distSchoolSchool[2][1] + distSchoolHome[1]; + float d = Math.min( d1, d2 ); + d = Math.min( d, d3 ); + d = Math.min( d, d4 ); + d = Math.min( d, d5 ); + d = Math.min( d, d6 ); + return d - distHomeMandatory[1]; + } + + private float getAbsoluteDeviationDistanceOutboundChild123Chauffeur2() { + float d1 = distHomeSchool[1] + distSchoolSchool[1][2] + distSchoolSchool[2][3] + distSchoolMandatory[3][2]; + float d2 = distHomeSchool[1] + distSchoolSchool[1][3] + distSchoolSchool[3][2] + distSchoolMandatory[2][2]; + float d3 = distHomeSchool[2] + distSchoolSchool[2][1] + distSchoolSchool[1][3] + distSchoolMandatory[3][2]; + float d4 = distHomeSchool[2] + distSchoolSchool[2][3] + distSchoolSchool[3][1] + distSchoolMandatory[1][2]; + float d5 = distHomeSchool[3] + distSchoolSchool[3][1] + distSchoolSchool[1][2] + distSchoolMandatory[2][2]; + float d6 = distHomeSchool[3] + distSchoolSchool[3][2] + distSchoolSchool[2][1] + distSchoolMandatory[1][2]; + float d = Math.min( d1, d2 ); + d = Math.min( d, d3 ); + d = Math.min( d, d4 ); + d = Math.min( d, d5 ); + d = Math.min( d, d6 ); + return d - distHomeMandatory[2]; + } + + private float getAbsoluteDeviationDistanceInboundChild123Chauffeur2() { + float d1 = distMandatorySchool[2][1] + distSchoolSchool[1][2] + distSchoolSchool[2][3] + distSchoolHome[3]; + float d2 = distMandatorySchool[2][1] + distSchoolSchool[1][3] + distSchoolSchool[3][2] + distSchoolHome[2]; + float d3 = distMandatorySchool[2][2] + distSchoolSchool[2][1] + distSchoolSchool[1][3] + distSchoolHome[3]; + float d4 = distMandatorySchool[2][2] + distSchoolSchool[2][3] + distSchoolSchool[3][1] + distSchoolHome[1]; + float d5 = distMandatorySchool[2][3] + distSchoolSchool[3][1] + distSchoolSchool[1][2] + distSchoolHome[2]; + float d6 = distMandatorySchool[2][3] + distSchoolSchool[3][2] + distSchoolSchool[2][1] + distSchoolHome[1]; + float d = Math.min( d1, d2 ); + d = Math.min( d, d3 ); + d = Math.min( d, d4 ); + d = Math.min( d, d5 ); + d = Math.min( d, d6 ); + return d - distHomeMandatory[2]; + } + + + /** + * This method should only be called for relevant alternatives - those with multiple bundles for a single chauffeur. + */ + private int getAvailabilityForMultipleBundlesOutbound( int alt ) { + + // set availability to 0 if unavailable, or 1 if available + int availabilityForMultipleBundles = 1; + + List[] altChaufBundles = SchoolEscortingBundle.constructAltBundles( alt, altBundleIncidence ); + + //check the number of bundles + int chaufIndex = 0; + if ( altChaufBundles[1].size() > 1 ) //more than one bundle for the first chauffeur + chaufIndex = 1; + else if ( altChaufBundles[2].size() > 1 ) //more than one bundle for the second chauffeur + chaufIndex = 2; + else { + logger.fatal( "UEC method getAvailabilityForMultipleBundlesOutbound( alt=" + alt + " ) was called, but neither chauf has multiple escort bundles." ); + logger.fatal("Size of altChaufBundles[1] = "+altChaufBundles[1].size()); + logger.fatal("Size of altChaufBundles[2] = "+altChaufBundles[2].size()); + throw new RuntimeException( ); + } + + + // set the bundle depart intervals for all bundles and arrive back home intervals for pure escort only + for ( SchoolEscortingBundle bundleObj : altChaufBundles[chaufIndex] ) { + + int[] sortData = new int[ SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1 ]; + Arrays.fill( sortData, 999999999 ); + int[] children = bundleObj.getChildIds(); + for ( int j=0; j < children.length; j++ ) + sortData[children[j]] = escorteeDepartForSchool[children[j]]; + + int[] childrenOrder = IndexSort.indexSort( sortData ); + + int departHomeInterval = escorteeDepartForSchool[ childrenOrder[0] ]; + bundleObj.setDepartHome( departHomeInterval ); + + if ( bundleObj.getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + float roundTripMinutes = getRoundTripMinutesFromHomeThruAllSchoolsToHome( childrenOrder, children.length, DROP_OFF_DURATION ); + float arriveBackHomeMinute = convertIntervalToMinutes( departHomeInterval ) + roundTripMinutes; + int arriveHomeInterval = convertMinutesToInterval( arriveBackHomeMinute ); + bundleObj.setArriveHome( arriveHomeInterval ); + } + + } + + + int[] chaufBundlesOrder = getChaufBundlesOrderOutbound( altChaufBundles[chaufIndex] ); + + for( int j=1; j < chaufBundlesOrder.length; j++ ) { + SchoolEscortingBundle bundleSubsequent = altChaufBundles[chaufIndex].get( chaufBundlesOrder[j] ); + SchoolEscortingBundle bundlePrevious = altChaufBundles[chaufIndex].get( chaufBundlesOrder[j-1] ); + if ( bundleSubsequent.getDepartHome() <= bundlePrevious.getArriveHome() ) { + availabilityForMultipleBundles = 0; + break; + } + } + + return availabilityForMultipleBundles; + + } + + float convertIntervalToMinutes(int interval){ + + float minutes = interval * ModelStructure.TOD_INTERVAL_IN_MINUTES; + return minutes; + } + + int convertMinutesToInterval(float minutes){ + + int interval = (int) (minutes/ModelStructure.TOD_INTERVAL_IN_MINUTES); + interval = Math.min(interval,ModelStructure.MAX_TOD_INTERVAL); + return interval; + + } + + + /** + * This method should only be called for relevant alternatives - those with multiple bundles for a single chauffeur. + */ + private int getAvailabilityForMultipleBundlesInbound( int alt ) { + + // set availability to 0 if unavailable, or 1 if available + int availabilityForMultipleBundles = 1; + + List[] altChaufBundles = SchoolEscortingBundle.constructAltBundles( alt, altBundleIncidence ); + + int chaufIndex = 0; + if ( altChaufBundles[1].size() > 1 ) + chaufIndex = 1; + else if ( altChaufBundles[2].size() > 1 ) + chaufIndex = 2; + else { + logger.error( "UEC method getAvailabilityForMultipleBundlesInbound( alt=" + alt + " ) was called, but neither chauf has multiple escort bundles." ); + throw new RuntimeException( ); + } + + + // set the bundle arrive intervals for all bundles and depart from home intervals for pure escort only + for ( SchoolEscortingBundle bundleObj : altChaufBundles[chaufIndex] ) { + + int[] sortData = new int[ SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1 ]; + Arrays.fill( sortData, 999999999 ); + int[] children = bundleObj.getChildIds(); + for ( int j=0; j < children.length; j++ ) + sortData[children[j]] = escorteeDepartFromSchool[children[j]]; + + int[] childrenOrder = IndexSort.indexSort( sortData ); + + int departFromFirstSchoolInterval = escorteeDepartFromSchool[childrenOrder[0]]; + + float firstSchoolToHomeMinutes = getMinutesFromFirstSchoolToHome( childrenOrder, children.length, PICK_UP_DURATION ); + float arriveHomeMinutes = convertIntervalToMinutes( departFromFirstSchoolInterval ) + firstSchoolToHomeMinutes; + int arriveHomeInterval = convertMinutesToInterval( arriveHomeMinutes ); + bundleObj.setArriveHome( arriveHomeInterval ); + + if ( bundleObj.getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + float homeToFirstSchoolMinutes = getMazToMazTimeInMinutes( hhObj.getHhMgra(), escorteeSchoolLoc[childrenOrder[0]] ); + float departFromHomeMinutes = convertIntervalToMinutes( departFromFirstSchoolInterval ) - homeToFirstSchoolMinutes; + int departHomeInterval = convertMinutesToInterval( departFromHomeMinutes ); + bundleObj.setDepartHome( departHomeInterval ); + } + + } + + + int[] chaufBundlesOrder = getChaufBundlesOrderInbound( altChaufBundles[chaufIndex] ); + + for( int j=1; j < chaufBundlesOrder.length; j++ ) { + SchoolEscortingBundle bundleSubsequent = altChaufBundles[chaufIndex].get( chaufBundlesOrder[j] ); + SchoolEscortingBundle bundlePrevious = altChaufBundles[chaufIndex].get( chaufBundlesOrder[j-1] ); + if ( bundleSubsequent.getDepartHome() <= bundlePrevious.getArriveHome() ) { + availabilityForMultipleBundles = 0; + break; + } + } + + return availabilityForMultipleBundles; + + } + + private int getAvailabilityForInboundChauf1WithOutboundBundles( int alt ) { + return getAvailabilityForChaufWithPreviousDirectionBundles( 1, SchoolEscortingModel.DIR_INBOUND, alt ); + } + + private int getAvailabilityForInboundChauf2WithOutboundBundles( int alt ) { + return getAvailabilityForChaufWithPreviousDirectionBundles( 2, SchoolEscortingModel.DIR_INBOUND, alt ); + } + + private int getAvailabilityForOutboundChauf1WithInboundBundles( int alt ) { + return getAvailabilityForChaufWithPreviousDirectionBundles( 1, SchoolEscortingModel.DIR_OUTBOUND, alt ); + } + + private int getAvailabilityForOutboundChauf2WithInboundBundles( int alt ) { + return getAvailabilityForChaufWithPreviousDirectionBundles( 2, SchoolEscortingModel.DIR_OUTBOUND, alt ); + } + + /** + * This method should only be called for for relevant alternatives - those with multiple bundles for a single chauffeur. + */ + private int getAvailabilityForChaufWithPreviousDirectionBundles( int chaufid, int dir, int alt ) { + + // set availability to 0 if unavailable, or 1 if available + int availability = 1; + + List[] altChaufBundles = SchoolEscortingBundle.constructAltBundles( alt, altBundleIncidence ); + + // set the bundle depart and arrive intervals for all bundles for the alternative + for ( SchoolEscortingBundle bundleObj : altChaufBundles[chaufid] ) { + + // order the children by earliest pickup time and set arriveHome + int[] sortData = new int[ SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1 ]; + Arrays.fill( sortData, 999999999 ); + int[] children = bundleObj.getChildIds(); + for ( int j=0; j < children.length; j++ ) { + sortData[children[j]] = escorteeDepartFromSchool[children[j]]; + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) + sortData[children[j]] = escorteeDepartForSchool[children[j]]; + else + sortData[children[j]] = escorteeDepartFromSchool[children[j]]; + } + + int[] childrenOrder = IndexSort.indexSort( sortData ); + + int chaufPnum = chauffeurPnums[chaufid]; + + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) { + + // set OB depart to earliest child's depart from home or either pure escort or ride sharing + int departHomeInterval = escorteeDepartForSchool[ childrenOrder[0] ]; + bundleObj.setDepartHome( departHomeInterval ); + + if ( bundleObj.getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + + float roundTripMinutes = getRoundTripMinutesFromHomeThruAllSchoolsToHome( childrenOrder, children.length, DROP_OFF_DURATION ); + float arriveBackHomeMinute = convertIntervalToMinutes( departHomeInterval ) + roundTripMinutes; + int arriveHomeInterval = convertMinutesToInterval( arriveBackHomeMinute ); + bundleObj.setArriveHome( arriveHomeInterval ); + + // neither end of the alternative window can overlap the reserved window + if ( ( departHomeInterval >= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] && departHomeInterval <= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][1] ) || + ( arriveHomeInterval >= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] && arriveHomeInterval <= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][1] ) ) + availability = 0; + // if the start of the alternative window is before the start of the reserved window, the end of the alternative window must also be before the start of the reserved window. + else if ( departHomeInterval < chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] && arriveHomeInterval >= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] ) + availability = 0; + // the start of the alternative window cannot be after the start of the reserved window + else if ( departHomeInterval >= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] ) + availability = 0; + } + else { + + if ( chauffeurDap[chaufid] != 1 ) { + availability = 0; + } + else { + + float numMinutes = getTimeInMinutesFromHomeThruAllSchoolsToWork( chauffeurMandatoryLoc[chaufid], childrenOrder, children.length, DROP_OFF_DURATION ); + float arriveWorkMinute = convertIntervalToMinutes( departHomeInterval ) + numMinutes; + int arriveWorkInterval = convertMinutesToInterval( arriveWorkMinute ); + + if ( ( departHomeInterval >= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][0] && departHomeInterval <= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][1] ) || + ( arriveWorkInterval >= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][0] && arriveWorkInterval <= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][1] ) ) + availability = 0; + } + } + + } + else { + + if ( bundleObj.getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + + int departFromFirstSchoolInterval = escorteeDepartFromSchool[childrenOrder[0]]; + + float homeToFirstSchoolMinutes = getMazToMazTimeInMinutes( hhObj.getHhMgra(), escorteeSchoolLoc[childrenOrder[0]] ); + float departFromHomeMinutes = convertIntervalToMinutes( departFromFirstSchoolInterval ) - homeToFirstSchoolMinutes; + int departHomeInterval = convertMinutesToInterval( departFromHomeMinutes ); + + float firstSchoolToHomeMinutes = getMinutesFromFirstSchoolToHome( childrenOrder, children.length, PICK_UP_DURATION ); + float arriveHomeMinutes = convertIntervalToMinutes( departFromFirstSchoolInterval ) + firstSchoolToHomeMinutes; + int arriveHomeInterval = convertMinutesToInterval( arriveHomeMinutes ); + + // neither end of the alternative window can overlap the reserved window + if ( ( departHomeInterval >= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] && departHomeInterval <= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][1] ) || + ( arriveHomeInterval >= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] && arriveHomeInterval <= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][1] ) ) + availability = 0; + // the start of the alternative window cannot be before the end of the reserved window + else if ( departHomeInterval <= chaufExtents[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][1] ) + availability = 0; + } + else { + + if ( chauffeurDap[chaufid] != 1 ) { + availability = 0; + } + else { + + int departFromFirstSchoolInterval = escorteeDepartFromSchool[childrenOrder[0]]; + + float workToFirstSchoolMinutes = getMazToMazTimeInMinutes( chauffeurMandatoryLoc[chaufid], escorteeSchoolLoc[childrenOrder[0]] ); + float departWorkMinute = convertIntervalToMinutes( departFromFirstSchoolInterval ) - workToFirstSchoolMinutes; + int departWorkInterval = convertMinutesToInterval( departWorkMinute ); + + float firstSchoolToHomeMinutes = getMinutesFromFirstSchoolToHome( childrenOrder, children.length, PICK_UP_DURATION ); + float arriveHomeMinutes = convertIntervalToMinutes( departFromFirstSchoolInterval ) + firstSchoolToHomeMinutes; + int arriveHomeInterval = convertMinutesToInterval( arriveHomeMinutes ); + + if ( ( departWorkInterval >= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][0] && departWorkInterval <= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][1] ) || + ( arriveHomeInterval >= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][0] && arriveHomeInterval <= chaufExtents[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][1] ) ) + availability = 0; + } + } + + } + + } + + + return availability; + + } + + + /** + * This method creates and returns the chosen bundles given the attributes of the chauffeur and escortees on the bundle and the type of bundle selected (pure escort vs rideshare) + * and the direction for the bundle (outbound versus return). + * + * @param alt The chosen alternative. + * @param chaufIndex The chauffeur to get the bundle for. + * @param dir Outbound or inbound. + * @return A fully coded bundle for the chauffeur given the chosen alternative. + */ + public SchoolEscortingBundle[] getChosenBundles( int alt, int chaufIndex, int dir ) { + + //an arraylist of school escorting bundles, dimensioned by each chauffeur (2) + List[] altChaufBundles = SchoolEscortingBundle.constructAltBundles( alt, altBundleIncidence ); + + // set the bundle depart intervals for all bundles and arrive back home intervals for pure escort only + for ( SchoolEscortingBundle bundleObj : altChaufBundles[chaufIndex] ) { + + //if the bundle direction is outbound, sort the escortees by departure period, else sort by arrival period + int[] sortData = new int[ SchoolEscortingModel.NUM_ESCORTEES_PER_HH+1 ]; + Arrays.fill( sortData, 999999999 ); + int[] altBundleChildIds = bundleObj.getChildIds(); + for ( int j=0; j < altBundleChildIds.length; j++ ) { + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) + sortData[altBundleChildIds[j]] = escorteeDepartForSchool[altBundleChildIds[j]]; + else + sortData[altBundleChildIds[j]] = escorteeDepartFromSchool[altBundleChildIds[j]]; + } + int[] altBundleChildrenOrder = IndexSort.indexSort( sortData ); + + //set the school locations and person numbers for each escortee in the order of escortees set above + int[] altBundleChildSchools = new int[altBundleChildIds.length]; + int[] altBundleChildPnums = new int[altBundleChildIds.length]; + for ( int j=0; j < altBundleChildIds.length; j++ ) { + int k = altBundleChildrenOrder[j]; + altBundleChildSchools[j] = escorteeSchoolLoc[k]; + altBundleChildPnums[j] = escorteePnums[k]; + } + + //set other elements of the bundle for this choice\household + bundleObj.setDir( dir ); + bundleObj.setChaufPnum( chauffeurPnums[chaufIndex] ); + bundleObj.setChaufPid( chauffeurPids[chaufIndex] ); + bundleObj.setChaufPersType( chauffeurPersonType[chaufIndex] ); + bundleObj.setChildPnums( altBundleChildPnums ); + bundleObj.setSchoolMazs( altBundleChildSchools ); + bundleObj.setWorkOrSchoolMaz( chauffeurMandatoryLoc[chaufIndex] ); + + + //if the bundle is outbound + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) { + + //get an array of distances to each child's school starting from home. + float[] altBundleSchoolDistances = getDistancesToSchools( mgraDataManager.getTaz( hhObj.getHhMgra() ), altBundleChildrenOrder, altBundleChildIds.length ); + bundleObj.setSchoolDists( altBundleSchoolDistances ); + + // set OB depart to earliest child's depart from home for either pure escort or ride sharing + int departHomeInterval = escorteeDepartForSchool[ altBundleChildrenOrder[0] ]; + bundleObj.setDepartHome( departHomeInterval ); + + //if the bundle is pure escort, then the total trip time in minutes is from home through all passengers back to home and the arrival time back at home is the departure + //period plus the time and some time for stops. Otherwise the time arriving to work is the time period departing home + travel time through all escortees plus dwell. + if ( bundleObj.getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + + float roundTripMinutes = getRoundTripMinutesFromHomeThruAllSchoolsToHome( altBundleChildrenOrder, altBundleChildIds.length, DROP_OFF_DURATION ); + float arriveBackHomeMinute = convertIntervalToMinutes( departHomeInterval ) + roundTripMinutes; + int arriveHomeInterval = convertMinutesToInterval( arriveBackHomeMinute ); + bundleObj.setArriveHome( arriveHomeInterval ); + } + else { + float numMinutes = getTimeInMinutesFromHomeThruAllSchoolsToWork( chauffeurMandatoryLoc[chaufIndex], altBundleChildrenOrder, altBundleChildIds.length, DROP_OFF_DURATION ); + float arriveWorkMinute = convertIntervalToMinutes( departHomeInterval ) + numMinutes; + int arriveWorkInterval = convertMinutesToInterval( arriveWorkMinute ); + bundleObj.setArriveWork( arriveWorkInterval ); + } + + } + else { + + //on the return direction, the departure time from the first school is the time for the first child being escorted. + int departFromFirstSchoolInterval = escorteeDepartFromSchool[altBundleChildrenOrder[0]]; + + // if the bundle is a pure escort, set the departure time period from home to the time that the first child departs from school minus the time required to get to school. + if ( bundleObj.getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + float homeToFirstSchoolMinutes = getMazToMazTimeInMinutes( hhObj.getHhMgra(), escorteeSchoolLoc[altBundleChildrenOrder[0]] ); + float departFromHomeMinutes = convertIntervalToMinutes( departFromFirstSchoolInterval ) - homeToFirstSchoolMinutes; + int departHomeInterval = convertMinutesToInterval( departFromHomeMinutes ); + bundleObj.setDepartHome( departHomeInterval ); + + float[] altBundleSchoolDistances = getDistancesToSchools( mgraDataManager.getTaz( hhObj.getHhMgra() ), altBundleChildrenOrder, altBundleChildIds.length ); + bundleObj.setSchoolDists( altBundleSchoolDistances ); + } + else { //else if the bundle is rideshare, the time departing work is the time the first child leave school minus the time required to get to school from work. + float workToFirstSchoolMinutes = getMazToMazTimeInMinutes( chauffeurMandatoryLoc[chaufIndex], escorteeSchoolLoc[altBundleChildrenOrder[0]] ); + float departWorkMinute = convertIntervalToMinutes( departFromFirstSchoolInterval ) - workToFirstSchoolMinutes; + int departWorkInterval = convertMinutesToInterval( departWorkMinute ); + bundleObj.setDepartWork( departWorkInterval ); + + float[] altBundleSchoolDistances = getDistancesToSchools( mgraDataManager.getTaz( chauffeurMandatoryLoc[chaufIndex] ), altBundleChildrenOrder, altBundleChildIds.length ); + bundleObj.setSchoolDists( altBundleSchoolDistances ); + } + + //on the return direction, the arrival time back home is the time from the first child's departure time plus the time required to get home plus dwell time for each escortee. + float firstSchoolToHomeMinutes = getMinutesFromFirstSchoolToHome( altBundleChildrenOrder, altBundleChildIds.length, PICK_UP_DURATION ); + float arriveHomeMinutes = convertIntervalToMinutes( departFromFirstSchoolInterval ) + firstSchoolToHomeMinutes; + int arriveHomeInterval = convertMinutesToInterval( arriveHomeMinutes ); + bundleObj.setArriveHome( arriveHomeInterval ); + + bundleObj.setDepartPrimaryInterval( departFromFirstSchoolInterval ); + } + + } + + + int[] chaufBundlesOrder = null; + if ( altChaufBundles[chaufIndex].size() > 1 ) { + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) + chaufBundlesOrder = getChaufBundlesOrderOutbound( altChaufBundles[chaufIndex] ); + else + chaufBundlesOrder = getChaufBundlesOrderInbound( altChaufBundles[chaufIndex] ); + } + else { + chaufBundlesOrder = new int[]{ 0 }; + } + + SchoolEscortingBundle[] result = new SchoolEscortingBundle[chaufBundlesOrder.length]; + for( int j=0; j < chaufBundlesOrder.length; j++ ) + result[j] = altChaufBundles[chaufIndex].get( chaufBundlesOrder[j] ); + + + return result; + + } + + + /** + * Get an array of distances to each child's school. + * + * @param origTaz The originTaz is the origin of the first child's trip (home for outbound direction, primary destination for return direction) + * @param childrenOrder The order of each escortee, can be by departure time + * @param numChildren Number of children + * @return A float array of distances to each child's school. + */ + private float[] getDistancesToSchools( int origTaz, int[] childrenOrder, int numChildren ) { + + float[] distances = new float[numChildren]; + + for ( int j=0; j < numChildren; j++ ) { + int k = childrenOrder[j]; + int schoolTaz = mgraDataManager.getTaz( escorteeSchoolLoc[k] ); + distances[j] = (float) distanceArray[origTaz][schoolTaz]; + origTaz = schoolTaz; + } + + return distances; + + } + + + private float getMinutesFromFirstSchoolToHome( int[] childrenOrder, int numChildren, float minDuration ) { + + int homeTaz = mgraDataManager.getTaz( hhObj.getHhMgra() ); + int firstSchool = escorteeSchoolLoc[ childrenOrder[0] ]; + int firstSchoolTaz = mgraDataManager.getTaz( firstSchool ); + int originTaz = firstSchoolTaz; + + // distance is the cumulative distance from the school where the child is picked up to home, through other schools . + float distance = 0; + float duration = 0; + + for ( int j=1; j < numChildren; j++ ) { + int k = childrenOrder[j]; + int schoolTaz = mgraDataManager.getTaz( escorteeSchoolLoc[k] ); + distance += (float) distanceArray[originTaz][ schoolTaz ]; + originTaz = schoolTaz; + + duration += minDuration; + } + + distance += (float) distanceArray[originTaz][ homeTaz ]; + + float timeInMinutes = distance * MINUTES_PER_MILE + duration; + + return timeInMinutes; + + } + + + private float getMazToMazTimeInMinutes( int fromMaz, int toMaz ) { + + int fromTaz = mgraDataManager.getTaz( fromMaz ); + int toTaz = mgraDataManager.getTaz( toMaz ); + + float timeInMinutes = MINUTES_PER_MILE * (float) distanceArray[fromTaz][ toTaz]; + return timeInMinutes; + + } + + + private float getRoundTripMinutesFromHomeThruAllSchoolsToHome( int[] childrenOrder, int numChildren, float minDuration ) { + + int originTaz = mgraDataManager.getTaz( hhObj.getHhMgra() ); + + // cumulative distance and duration + float distance = 0; + float duration = 0; + + for ( int j=0; j < numChildren; j++ ) { + int k = childrenOrder[j]; + int schoolTaz = mgraDataManager.getTaz( escorteeSchoolLoc[k] ); + distance += (float) distanceArray[originTaz][ schoolTaz]; + originTaz = schoolTaz ; + + duration += minDuration; + } + int destTaz = mgraDataManager.getTaz( hhObj.getHhMgra() ); + distance += (float) distanceArray[originTaz][ destTaz]; + + float timeInMinutes = MINUTES_PER_MILE * distance + duration; + return timeInMinutes; + + } + + + private float getTimeInMinutesFromHomeThruAllSchoolsToWork( int workMaz, int[] childrenOrder, int numChildren, float minDuration ) { + + int homeTaz = mgraDataManager.getTaz( hhObj.getHhMgra() ); + int workTaz = mgraDataManager.getTaz( workMaz ); + + int originTaz = homeTaz; + + float distance = 0; + float duration = 0; + + for ( int j=0; j < numChildren; j++ ) { + int k = childrenOrder[j]; + int schoolTaz = mgraDataManager.getTaz( escorteeSchoolLoc[k] ); + distance += distanceArray[originTaz][ schoolTaz ]; + originTaz = schoolTaz; + duration += minDuration; + } + + distance += (float) distanceArray[originTaz][ workTaz ]; + + float timeInMinutes = MINUTES_PER_MILE * distance + duration; + return timeInMinutes; + + } + + + // Create an array to hold the list indices for the order in which escort activities should be performed. + // This method only gets called while checking availability for a chauffeur to have multiple bundles, so the + // list altChaufBundles has either 2 or 3 escort activities. + private int[] getChaufBundlesOrderOutbound( List altChaufBundles ) { + + int[] chaufBundlesOrder = null; + + // number of escort activities is 2. + if ( altChaufBundles.size() == 2 ) { + // [RS,PE]: if the first activity for the alternative is ride sharing, the second must be pure escort, and should be ordered before the ride sharing escort activity; + if ( altChaufBundles.get( 0 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) + chaufBundlesOrder = new int[]{ 1, 0 }; + // [PE,RS]: likewise if the second activity is ride sharing - the first must be pure escort, and must be ordered first + else if ( altChaufBundles.get( 1 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) + chaufBundlesOrder = new int[]{ 0, 1 }; + // [PE,PE]: otherwise, both activities are pure escort, and the depart times will determine the order + else if ( altChaufBundles.get( 1 ).getDepartHome() < altChaufBundles.get( 0 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 1, 0 }; + else + chaufBundlesOrder = new int[]{ 0, 1 }; + } + // number of escort activities is 3. + else { + // [RS,PE,PE]: if the first activity for the alternative is ride sharing, the second and third must also be pure escort, and should be ordered before the ride sharing escort activity; + if ( altChaufBundles.get( 0 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + if ( altChaufBundles.get( 2 ).getDepartHome() < altChaufBundles.get( 1 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 2, 1, 0 }; + else + chaufBundlesOrder = new int[]{ 1, 2, 0 }; + } + // [PE,RS,PE]: likewise if the second activity is ride sharing - the first and third must be pure escort, and must be ordered before ride sharing + else if ( altChaufBundles.get( 1 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + if ( altChaufBundles.get( 2 ).getDepartHome() < altChaufBundles.get( 0 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 2, 0, 1 }; + else + chaufBundlesOrder = new int[]{ 0, 2, 1 }; + } + // [PE,PE,RS]: likewise if the third activity is ride sharing - the first and second must be pure escort, and must be ordered before ride sharing + else if ( altChaufBundles.get( 2 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + if ( altChaufBundles.get( 1 ).getDepartHome() < altChaufBundles.get( 0 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 1, 0, 2 }; + else + chaufBundlesOrder = new int[]{ 0, 1, 2 }; + } + // [PE,PE,PE]: otherwise, all three activities are pure escort, and the depart times will determine the order + else { + int[] sortData = new int[]{ altChaufBundles.get( 0 ).getDepartHome(), altChaufBundles.get( 1 ).getDepartHome(), altChaufBundles.get( 2 ).getDepartHome() }; + chaufBundlesOrder = IndexSort.indexSort( sortData ); + } + } + + return chaufBundlesOrder; + + } + + + // Create an array to hold the list indices for the order in which escort activities should be performed. + // This method only gets called while checking availability for a chauffeur to have multiple bundles, so the + // list altChaufBundles has either 2 or 3 escort activities. + private int[] getChaufBundlesOrderInbound( List altChaufBundles ) { + + int[] chaufBundlesOrder = null; + + // number of escort activities is 2. + if ( altChaufBundles.size() == 2 ) { + // [RS,PE]: if the first activity for the alternative is ride sharing, the second must be pure escort, and should be ordered after the ride sharing escort activity; + if ( altChaufBundles.get( 0 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) + chaufBundlesOrder = new int[]{ 0, 1 }; + // [PE,RS]: likewise if the second activity is ride sharing - the first must be pure escort, and must be ordered second + else if ( altChaufBundles.get( 1 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) + chaufBundlesOrder = new int[]{ 1, 0 }; + // [PE,PE]: otherwise, both activities are pure escort, and the depart times will determine the order + else if ( altChaufBundles.get( 1 ).getDepartHome() < altChaufBundles.get( 0 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 1, 0 }; + else + chaufBundlesOrder = new int[]{ 0, 1 }; + } + // number of escort activities is 3. + else { + // [RS,PE,PE]: if the first activity for the alternative is ride sharing, the second and third must also be pure escort, and should be ordered after the ride sharing escort activity; + if ( altChaufBundles.get( 0 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + if ( altChaufBundles.get( 2 ).getDepartHome() < altChaufBundles.get( 1 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 0, 2, 1 }; + else + chaufBundlesOrder = new int[]{ 0, 1, 2 }; + } + // [PE,RS,PE]: likewise if the second activity is ride sharing - the first and third must be pure escort, and must be ordered after ride sharing + else if ( altChaufBundles.get( 1 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + if ( altChaufBundles.get( 2 ).getDepartHome() < altChaufBundles.get( 0 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 1, 2, 0 }; + else + chaufBundlesOrder = new int[]{ 1, 0, 2 }; + } + // [PE,PE,RS]: likewise if the third activity is ride sharing - the first and second must be pure escort, and must be ordered after ride sharing + else if ( altChaufBundles.get( 2 ).getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + if ( altChaufBundles.get( 1 ).getDepartHome() < altChaufBundles.get( 0 ).getDepartHome() ) + chaufBundlesOrder = new int[]{ 2, 1, 0 }; + else + chaufBundlesOrder = new int[]{ 2, 0, 1 }; + } + // [PE,PE,PE]: otherwise, all three activities are pure escort, and the depart times will determine the order + else { + int[] sortData = new int[]{ altChaufBundles.get( 0 ).getDepartHome(), altChaufBundles.get( 1 ).getDepartHome(), altChaufBundles.get( 2 ).getDepartHome() }; + chaufBundlesOrder = IndexSort.indexSort( sortData ); + } + } + + return chaufBundlesOrder; + + } + + + + + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingModel.java new file mode 100644 index 0000000..a79ed0b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolEscortingModel.java @@ -0,0 +1,2154 @@ +/* +* The school-escort model was designed by PB (Gupta, Vovsha, et al) +* as part of the Maricopa Association of Governments (MAG) +* Activity-based Travel Model Development project. +* +* This source code, which implements the school escort model, +* was written exclusively for and funded by MAG as part of the +* same project; therefore, per their contract, the +* source code belongs to MAG and can only be used with their +* permission. +* +* It is being adapted for the Southern Oregon ABM by PB & RSG +* with permission from MAG and all references to +* the school escort model as well as source code adapted from this +* original code should credit MAG's role in its development. +* +* The escort model and source code should not be transferred to or +* adapted for other agencies or used in other projects without +* expressed permission from MAG. +* +* The source code has been substantially revised to fit within the +* SANDAG\MTC\ODOT CT-RAMP model structure by RSG (2015). +*/ + +package org.sandag.abm.ctramp; +import java.util.ArrayList; +import java.util.Collections; +import java.util.Comparator; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Random; +import java.util.Set; +import java.util.TreeSet; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.calculator.IndexValues; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.IndexSort; +import com.pb.common.util.PropertyMap; + + +public class SchoolEscortingModel { + + public static final String ALT_TABLE_BUNDLE1_NAME = "bundle1"; + public static final String ALT_TABLE_BUNDLE2_NAME = "bundle2"; + public static final String ALT_TABLE_BUNDLE3_NAME = "bundle3"; + public static final String ALT_TABLE_CHAUF1_NAME = "chauf1"; + public static final String ALT_TABLE_CHAUF2_NAME = "chauf2"; + public static final String ALT_TABLE_CHAUF3_NAME = "chauf3"; + public static final String ALT_TABLE_NBUNDLES_NAME = "nbundles"; + public static final String ALT_TABLE_NBUNDLES_RS1_NAME = "nrs1"; + public static final String ALT_TABLE_NBUNDLES_ES1_NAME = "npe1"; + public static final String ALT_TABLE_NBUNDLES_RS2_NAME = "nrs2"; + public static final String ALT_TABLE_NBUNDLES_ES2_NAME = "npe2"; + public static final String ALT_TABLE_BUNDLE_INCIDENCE_FIRST_COLUMN_NAME = "b1_rs1_1"; + + + public static final int NUM_ESCORTEES_PER_HH = 3; + public static final int NUM_CHAUFFEURS_PER_HH = 2; + public static final int NUM_ESCORT_TYPES = 2; + public static final int NUM_BUNDLES = 3; + + + public static final int ESCORT_ELIGIBLE = 1; + + public static final int CHAUFFEUR_1 = 1; + public static final int CHAUFFEUR_2 = 2; + + public static final int DIR_OUTBOUND = 1; + public static final int DIR_INBOUND = 2; + + public static final int RIDE_SHARING_CHAUFFEUR_1 = 1; + public static final int PURE_ESCORTING_CHAUFFEUR_1 = 2; + public static final int RIDE_SHARING_CHAUFFEUR_2 = 3; + public static final int PURE_ESCORTING_CHAUFFEUR_2 = 4; + + + + // chauffeur priority lookup values determined by 100*PersonTypesOld(1-8) + 10*gender(1-2) + 1*age > 25 + private static final int PT_WEIGHT = 100; + private static final int G_WEIGHT = 10; + private static final int A_WEIGHT = 1; + + public static final int RESULT_CHILD_DIRECTION_FIELD = 0; + public static final int RESULT_CHILD_CHOSEN_ALT_FIELD = 1; + public static final int RESULT_CHILD_HHID_FIELD = 2; + public static final int RESULT_CHILD_PNUM_FIELD = 3; + public static final int RESULT_CHILD_PID_FIELD = 4; + public static final int RESULT_CHILD_PERSON_TYPE_FIELD = 5; + public static final int RESULT_CHILD_AGE_FIELD = 6; + public static final int RESULT_CHILD_CDAP_FIELD = 7; + public static final int RESULT_CHILD_SCHOOL_AT_HOME_FIELD = 8; + public static final int RESULT_CHILD_SCHOOL_LOC_FIELD = 9; + public static final int RESULT_CHILD_ESCORT_ELIGIBLE_FIELD = 10; + public static final int RESULT_CHILD_DEPART_FROM_HOME_FIELD = 11; + public static final int RESULT_CHILD_DEPART_TO_HOME_FIELD = 12; + public static final int RESULT_CHILD_DIST_TO_SCHOOL_FIELD = 13; + public static final int RESULT_CHILD_DIST_FROM_SCHOOL_FIELD = 14; + public static final int RESULT_CHILD_ADULT1_DEPART_FROM_HOME_FIELD = 15; + public static final int RESULT_CHILD_ADULT1_DEPART_TO_HOME_FIELD = 16; + public static final int RESULT_CHILD_ADULT2_DEPART_FROM_HOME_FIELD = 17; + public static final int RESULT_CHILD_ADULT2_DEPART_TO_HOME_FIELD = 18; + public static final int RESULT_CHILD_ESCORT_TYPE_FIELD = 19; + public static final int RESULT_CHILD_BUNDLE_ID_FIELD = 20; + public static final int RESULT_CHILD_CHILD_ID_FIELD = 21; + public static final int RESULT_CHILD_CHAUFFEUR_ID_FIELD = 22; + public static final int RESULT_CHILD_CHAUFFEUR_PNUM_FIELD = 23; + public static final int RESULT_CHILD_CHAUFFEUR_PID_FIELD = 24; + public static final int RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD = 25; + public static final int RESULT_CHILD_CHAUFFEUR_DEPART_HOME_FIELD = 26; + public static final int RESULT_CHILD_CHAUFFEUR_DEPART_WORK_FIELD = 27; + public static final int RESULT_CHILD_RANDOM_NUM_FIELD = 28; + public static final int NUM_RESULTS_BY_CHILD_FIELDS = 29; + + + public static final int RESULT_CHAUF_BUNDLE_ID_FIELD = 0; + public static final int RESULT_CHAUF_DIRECTION_FIELD = 1; + public static final int RESULT_CHAUF_CHOSEN_ALT_FIELD = 2; + public static final int RESULT_CHAUF_HHID_FIELD = 3; + public static final int RESULT_CHAUF_PNUM_FIELD = 4; + public static final int RESULT_CHAUF_PID_FIELD = 5; + public static final int RESULT_CHAUF_PERSON_TYPE_FIELD = 6; + public static final int RESULT_CHAUF_AGE_FIELD = 7; + public static final int RESULT_CHAUF_CDAP_FIELD = 8; + public static final int RESULT_CHAUF_ESCORT_ELIGIBLE_FIELD = 9; + public static final int RESULT_CHAUF_DEPART_HOME_FIELD = 10; + public static final int RESULT_CHAUF_ID_FIELD = 11; + public static final int RESULT_CHAUF_ESCORT_TYPE_FIELD = 12; + public static final int RESULT_CHAUF_CHILD1_PNUM_FIELD = 13; + public static final int RESULT_CHAUF_CHILD1_PERSON_TYPE_FIELD = 14; + public static final int RESULT_CHAUF_CHILD1_DEPART_HOME_FIELD = 15; + public static final int RESULT_CHAUF_CHILD2_PNUM_FIELD = 16; + public static final int RESULT_CHAUF_CHILD2_PERSON_TYPE_FIELD = 17; + public static final int RESULT_CHAUF_CHILD2_DEPART_HOME_FIELD = 18; + public static final int RESULT_CHAUF_CHILD3_PNUM_FIELD = 19; + public static final int RESULT_CHAUF_CHILD3_PERSON_TYPE_FIELD = 20; + public static final int RESULT_CHAUF_CHILD3_DEPART_HOME_FIELD = 21; + public static final int NUM_RESULTS_BY_CHAUF_FIELDS = 22; + + public static final int DRIVE_ALONE_MODE = 1; + public static final int SHARED_RIDE_2_MODE = 2; + public static final int SHARED_RIDE_3_MODE = 3; + + private Map chauffeurPriorityOutboundMap; + private Map chauffeurPriorityInboundMap; + + + private TableDataSet altTable; + private String[] altTableNames; + private int[] altTableBundle1; + private int[] altTableBundle2; + private int[] altTableBundle3; + private int[] altTableChauf1; + private int[] altTableChauf2; + private int[] altTableChauf3; + private int[] altTableNumBundles; + private int[] altTableNumRideSharing1Bundles; + private int[] altTableNumPureEscort1Bundles; + private int[] altTableNumRideSharing2Bundles; + private int[] altTableNumPureEscort2Bundles; + + private float defaultTourVOT = (float)7.5; //default VOT for pure escort tours generated by this model. + private float defaultTripVOT = (float)15.0; //default VOT for pure escort trips generated by this model. + + private int[][] altBundleIncidence; + + private int[] previousChoiceChauffeurs; + + private SchoolEscortingDmu decisionMaker; + private transient Logger logger = Logger.getLogger(SchoolEscortingModel.class); + + private static final String UEC_PATH_KEY = "uec.path"; + private static final String OUTBOUND_UEC_FILENAME_KEY = "school.escort.uec.filename"; + private static final String OUTBOUND_UEC_MODEL_SHEET_KEY = "school.escort.outbound.model.sheet"; + private static final String OUTBOUND_UEC_DATA_SHEET_KEY = "school.escort.data.sheet"; + private static final String OUTBOUND_CHOICE_MODEL_DESCRIPTION = "School Escorting - Outbound unconditional Choice"; + + private static final String INBOUND_CONDITIONAL_UEC_FILENAME_KEY = "school.escort.uec.filename"; + private static final String INBOUND_CONDITIONAL_UEC_MODEL_SHEET_KEY = "school.escort.inbound.conditonal.model.sheet"; + private static final String INBOUND_CONDITIONAL_UEC_DATA_SHEET_KEY = "school.escort.data.sheet"; + private static final String INBOUND_CONDITIONAL_CHOICE_MODEL_DESCRIPTION = "School Escorting - inbound Conditional Choice"; + + private static final String OUTBOUND_CONDITIONAL_UEC_FILENAME_KEY = "school.escort.uec.filename"; + private static final String OUTBOUND_CONDITIONAL_UEC_MODEL_SHEET_KEY = "school.escort.outbound.conditonal.model.sheet"; + private static final String OUTBOUND_CONDITIONAL_UEC_DATA_SHEET_KEY = "school.escort.data.sheet"; + private static final String OUTBOUND_CONDITIONAL_CHOICE_MODEL_DESCRIPTION = "School Escorting - Outbound Conditional Choice"; + + private static final String PROPERTIES_MODEL_OFFSET = "school.escort.RNG.offset"; + + private ChoiceModelApplication outboundModel; + private ChoiceModelApplication inboundConditionalModel; + private ChoiceModelApplication outboundConditionalModel; + + private MgraDataManager mgraDataManager; + private double[][] distanceArray; + + private IndexValues indexValues; + + private long randomOffset = 110001; + private MersenneTwister random; + + + public SchoolEscortingModel( HashMap propertyMap, MgraDataManager mgraDataManager, AutoTazSkimsCalculator tazDistanceCalculator ) { + + this.mgraDataManager = mgraDataManager; + + random = new MersenneTwister(); + randomOffset = PropertyMap.getLongValueFromPropertyMap(propertyMap,PROPERTIES_MODEL_OFFSET); + + //to do: set distance and time matrix + + createChauffeurPriorityOutboundMap(); + createChauffeurPriorityInboundMap(); + + double[][][] storedFromTazToAllTazsDistanceSkims = tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(); + distanceArray = storedFromTazToAllTazsDistanceSkims[ModelStructure.AM_SKIM_PERIOD_INDEX]; + decisionMaker = new SchoolEscortingDmu( mgraDataManager, distanceArray ); + + + // Create the choice model applications + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + + //1. outbound model + String outboundUecFile = uecPath + propertyMap.get(OUTBOUND_UEC_FILENAME_KEY); + int outboundDataPage = Util.getIntegerValueFromPropertyMap(propertyMap, OUTBOUND_UEC_DATA_SHEET_KEY); + int outboundModelPage = Util.getIntegerValueFromPropertyMap(propertyMap, OUTBOUND_UEC_MODEL_SHEET_KEY); + + // create the outbound choice model object + outboundModel = new ChoiceModelApplication(outboundUecFile, outboundModelPage, outboundDataPage, propertyMap, + (VariableTable) decisionMaker); + + //2. inbound conditional model + String inboundConditionalUecFile = uecPath + propertyMap.get(INBOUND_CONDITIONAL_UEC_FILENAME_KEY); + int inboundConditionalDataPage = Util.getIntegerValueFromPropertyMap(propertyMap, INBOUND_CONDITIONAL_UEC_DATA_SHEET_KEY); + int inboundConditionalModelPage = Util.getIntegerValueFromPropertyMap(propertyMap, INBOUND_CONDITIONAL_UEC_MODEL_SHEET_KEY); + + // create the inbound conditional choice model object + inboundConditionalModel = new ChoiceModelApplication(inboundConditionalUecFile, inboundConditionalModelPage, + inboundConditionalDataPage, propertyMap, + (VariableTable) decisionMaker); + + //3. outbound conditional model + String outboundConditionalUecFile = uecPath + propertyMap.get(OUTBOUND_CONDITIONAL_UEC_FILENAME_KEY); + int outboundConditionalDataPage = Util.getIntegerValueFromPropertyMap(propertyMap, OUTBOUND_CONDITIONAL_UEC_DATA_SHEET_KEY); + int outboundConditionalModelPage = Util.getIntegerValueFromPropertyMap(propertyMap, OUTBOUND_CONDITIONAL_UEC_MODEL_SHEET_KEY); + + // create the outbound conditional choice model object + outboundConditionalModel = new ChoiceModelApplication(outboundConditionalUecFile, outboundConditionalModelPage, + outboundConditionalDataPage, propertyMap, + (VariableTable) decisionMaker); + + indexValues = new IndexValues(); + + // get the 0-index columns from the alternatives table, and save in 1-base indexed arrays for lookup by alternative number (1,...,numAlts). + UtilityExpressionCalculator outboundUEC = outboundModel.getUEC(); + altTable = outboundUEC.getAlternativeData(); + altTableNames = outboundUEC.getAlternativeNames(); + + int[] temp = altTable.getColumnAsInt( ALT_TABLE_BUNDLE1_NAME ); + altTableBundle1 = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableBundle1[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_BUNDLE2_NAME ); + altTableBundle2 = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableBundle2[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_BUNDLE3_NAME ); + altTableBundle3 = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableBundle3[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_CHAUF1_NAME ); + altTableChauf1 = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableChauf1[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_CHAUF2_NAME ); + altTableChauf2 = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableChauf2[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_CHAUF3_NAME ); + altTableChauf3 = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableChauf3[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_NBUNDLES_NAME ); + altTableNumBundles = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableNumBundles[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_NBUNDLES_RS1_NAME ); + altTableNumRideSharing1Bundles = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableNumRideSharing1Bundles[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_NBUNDLES_ES1_NAME ); + altTableNumPureEscort1Bundles = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableNumPureEscort1Bundles[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_NBUNDLES_RS2_NAME ); + altTableNumRideSharing2Bundles = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableNumRideSharing2Bundles[i+1] = temp[i]; + + temp = altTable.getColumnAsInt( ALT_TABLE_NBUNDLES_ES2_NAME ); + altTableNumPureEscort2Bundles = new int[temp.length+1]; + for ( int i=0; i < temp.length; i++ ) + altTableNumPureEscort2Bundles[i+1] = temp[i]; + + int index = altTable.getColumnPosition( ALT_TABLE_BUNDLE_INCIDENCE_FIRST_COLUMN_NAME ); + int numColumns = NUM_BUNDLES * NUM_CHAUFFEURS_PER_HH * NUM_ESCORT_TYPES * NUM_ESCORTEES_PER_HH; + altBundleIncidence = new int[temp.length+1][ numColumns + 1 ]; + for ( int i=0; i < numColumns; i++ ) { + temp = altTable.getColumnAsInt( index+i ); + for ( int j=0; j < temp.length; j++ ) + altBundleIncidence[j+1][i+1] = temp[j]; + } + + decisionMaker.setAltTableBundleIncidence( altBundleIncidence ); + + previousChoiceChauffeurs = new int[NUM_CHAUFFEURS_PER_HH+1]; + + } + + + + /** + * Solve the school escort model for an array of households. The method sets DMU objects, calls the outbound choice model, the + * inbound conditional choice model, and another outbound conditional choice model. The method returns an ArrayList of results with + * 3 member lists: + * 0: results for escortees + * 1: results for chauffeurs + * 2: + * @param logger + * @param hhs + * @throws Exception + */ + public void applyModel( Household household ) throws Exception { + + List childResultList = new ArrayList(); + List chaufResultList = new ArrayList(); + + // apply model only if at least 1 child goes to school + // output: + // child - each direction, escortType(0=none, 1=ride sharing, 2=pure escort), pnum of chauffeur, bundle id, preferred departure time + // chauffeur - each direction, each bundle, pnums of children, preferred departure times + // household - bundles + + //TODO: apply schedule synchronization step after choice according to rules + + + int bundleListId = 0; + List escortBundleList = new ArrayList(); + List obPidList = new ArrayList(); + List obPeList = new ArrayList(); + List obRsList = new ArrayList(); + List ibPidList = new ArrayList(); + List ibPeList = new ArrayList(); + List ibRsList = new ArrayList(); + + try { + //there has to be at least one child with a school tour and one active adult + if ( (household.getNumChildrenWithSchoolTours() > 0) && (household.getNumberActiveAdults() > 0)) { + + boolean debug = false; + if ( household.getDebugChoiceModels() ) { + household.logEntireHouseholdObject("Escort Model trace for Household "+household.getHhId(), logger); + debug = true; + } + + long seed = household.getSeed() + randomOffset; + random.setSeed(seed); + + previousChoiceChauffeurs[1] = 0; + previousChoiceChauffeurs[2] = 0; + + setDmuAttributesForChildren( household, SchoolEscortingModel.DIR_OUTBOUND ); + setDmuAttributesForAdultsOutbound( household, null ); + int[][][] ob0BundleResults = applyOutboundChoiceModel( logger, household, random, debug ); + + + int[][][] chaufExtentsReservedForIb = getEscortBundlesExtent( ob0BundleResults[1], SchoolEscortingModel.DIR_OUTBOUND, household.getSize() ); + setDmuAttributesForChildren( household, SchoolEscortingModel.DIR_INBOUND ); + setDmuAttributesForAdultsInbound( household, chaufExtentsReservedForIb ); + + //note: first dimension = escortees versus chauffeurs. Second dimension = size of household or size * bundles. Third dimension = results + int[][][] ibBundleResults = applyInboundConditionalChoiceModel( logger, household, random, debug ); + + try { + bundleListId = createInboundEscortBundleObjects( ibBundleResults[1], bundleListId, escortBundleList, ibPidList, ibPeList, ibRsList ); + } + catch (Exception e) { + logger.error ( "exception caught saving inbound school escort bundle objects for hhid = " + household.getHhId() + ".", e ); + throw new RuntimeException(e); + } + + + int[][][] chaufExtentsReservedForOb = getEscortBundlesExtent( ibBundleResults[1], SchoolEscortingModel.DIR_INBOUND, household.getHhSize() ); + setDmuAttributesForChildren( household, SchoolEscortingModel.DIR_OUTBOUND ); + setDmuAttributesForAdultsOutbound( household, chaufExtentsReservedForOb ); + //note: first dimension = escortees versus chauffeurs. Second dimension = size of household or size * bundles. Third dimension = results + int[][][] obBundleResults = applyOutboundConditionalChoiceModel( logger, household, debug ); + + try { + bundleListId = createOutboundEscortBundleObjects( obBundleResults[1], bundleListId, escortBundleList, obPidList, obPeList, obRsList ); + } + catch (Exception e) { + logger.error ( "exception caught saving outbound school escort bundle objects for hhid = " + household.getHhId() + ".", e ); + throw new RuntimeException(e); + } + + for ( int j=1; j < ibBundleResults[0].length; j++ ) { + if ( ( ibBundleResults[0][j][RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD] == 4 || ibBundleResults[0][j][RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD] == 5 ) && ibBundleResults[0][j][RESULT_CHILD_ESCORT_TYPE_FIELD] == ModelStructure.RIDE_SHARING_TYPE ) + logger.info( "inbound child has ridesharing with non-working chauffeur, j=" + j ); + else if ( ( obBundleResults[0][j][RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD] == 4 || obBundleResults[0][j][RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD] == 5 ) && obBundleResults[0][j][RESULT_CHILD_ESCORT_TYPE_FIELD] == ModelStructure.RIDE_SHARING_TYPE ) + logger.info( "outbound child has ridesharing with non-working chauffeur, j=" + j ); + else if ( ( ibBundleResults[1][j][RESULT_CHAUF_PERSON_TYPE_FIELD] == 4 || ibBundleResults[1][j][RESULT_CHAUF_PERSON_TYPE_FIELD] == 5 ) && ibBundleResults[1][j][RESULT_CHAUF_ESCORT_TYPE_FIELD] == ModelStructure.RIDE_SHARING_TYPE ) + logger.info( "inbound non-working chauffeur has ridesharing, j=" + j ); + else if ( ( obBundleResults[1][j][RESULT_CHAUF_PERSON_TYPE_FIELD] == 4 || obBundleResults[1][j][RESULT_CHAUF_PERSON_TYPE_FIELD] == 5 ) && obBundleResults[1][j][RESULT_CHAUF_ESCORT_TYPE_FIELD] == ModelStructure.RIDE_SHARING_TYPE ) + logger.info( "outbound non-working chauffeur has ridesharing, j=" + j ); + } + + childResultList.add( obBundleResults[0] ); //outbound results for escortees + childResultList.add( ibBundleResults[0] ); //inbound results for escortees + chaufResultList.add( obBundleResults[1] ); //outbound results for chauffeurs + chaufResultList.add( ibBundleResults[1] ); //inbound results for chauffeurs + + + } + createTours(household, escortBundleList); + recodeSchoolTours(household); + + } + catch ( Exception e ) { + logger.error( "exception caught applying escort choice model for hh id:" + household.getHhId(), e ); + household.logEntireHouseholdObject("Escort model trace for problem household", logger); + int bundleNumber=0; + for(SchoolEscortingBundle bundle : escortBundleList){ + logger.error("School Escort Bundle "+bundleNumber); + bundle.logBundle(logger); + ++bundleNumber; + } + throw new RuntimeException(e); + } + + if(household.getDebugChoiceModels()){ + logger.info("Logging escort model results for household: "+household.getHhId()); + household.logEntireHouseholdObject("Escort model logging", logger); + } + + } + + + + private int[][][] getEscortBundlesExtent( int[][] bundleResults, int dir, int numPersons ) { + + Set processedChauffSet = new TreeSet(); + + int[][][] chaufExtent = new int[NUM_ESCORT_TYPES+1][numPersons+1][2]; + + for ( int j=1; j < bundleResults.length; j++ ) { + + int chaufid = bundleResults[j][SchoolEscortingModel.RESULT_CHAUF_ID_FIELD]; + if ( chaufid > 0 && !processedChauffSet.contains( chaufid ) ) { + + int chaufPnum = bundleResults[j][SchoolEscortingModel.RESULT_CHAUF_PNUM_FIELD]; + SchoolEscortingBundle[] escortBundles = decisionMaker.getChosenBundles( bundleResults[j][RESULT_CHAUF_CHOSEN_ALT_FIELD], chaufid, dir ); + + if ( escortBundles[0].getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + chaufExtent[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][0] = escortBundles[0].getDepartHome(); + chaufExtent[ModelStructure.RIDE_SHARING_TYPE][chaufPnum][1] = escortBundles[0].getArriveWork(); + } + else if ( escortBundles[0].getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + chaufExtent[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][0] = escortBundles[0].getDepartHome(); + + int lastBundleIndex = 0; + for ( int i=0; i < escortBundles.length; i++ ) + if ( escortBundles[i].getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) + lastBundleIndex = i; + chaufExtent[ModelStructure.PURE_ESCORTING_TYPE][chaufPnum][1] = escortBundles[lastBundleIndex].getArriveHome(); + } + + processedChauffSet.add( chaufid ); + + } + + } + + return chaufExtent; + + } + + + + /** + * Create outbound escort bundle objects and return the bundle list id incremented by the number of new bundles created. The method also adds the bundles to the escortBundleList and + * increments bundleListId by the number of outbound escort bundles. + * + * @param obBundleResults An integer array of results for escortees dimensioned by: household size + 1, escort results fields. + * @param bundleListId The starting bundle ID; will be incremented for each additional bundle, first for rideshare bundles, then escort bundles. + * @param escortBundleList A List of SchoolEscortingBundle objects that will be added to by this method. + * @param obPidList A List of chauffeur IDs that will be added to by this method, one for each outbound bundle + * @param obPeList A List of the outbound pure escort bundle IDs, one for each outbound pure escort bundle + * @param obRsList A List of the outbound rideshare bundle IDs, one for each outbound rideshare bundle + * @return The updated number of chosen bundles (last ID set in the ID lists) + */ + private int createOutboundEscortBundleObjects( int[][] obBundleResults, int bundleListId, List escortBundleList, List obPidList, List obPeList, List obRsList ) { + + int[] obRsIds = null; + int[] obPeIds = null; + + Set processedChauffSet = new TreeSet(); + + for ( int j=1; j < obBundleResults.length; j++ ) { + + int chaufid = obBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_ID_FIELD]; + if ( chaufid > 0 && !processedChauffSet.contains( chaufid ) ) { + + int chaufPid = obBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_PID_FIELD]; + int chaufPnum = obBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_PNUM_FIELD]; + int chaufPtype = obBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_PERSON_TYPE_FIELD]; + + SchoolEscortingBundle[] obEscortBundles = decisionMaker.getChosenBundles( obBundleResults[j][RESULT_CHAUF_CHOSEN_ALT_FIELD], chaufid, SchoolEscortingModel.DIR_OUTBOUND ); + + int numRs = 0; + int numPe = 0; + for ( int k=0; k < obEscortBundles.length; k++ ) { + if ( obEscortBundles[k].getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) + numRs++; + else if ( obEscortBundles[k].getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) + numPe++; + } + + obRsIds = new int[numRs]; + obPeIds = new int[numPe]; + + int n = 0; + for ( int k=0; k < obEscortBundles.length; k++ ) { + if ( obEscortBundles[k].getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + obEscortBundles[k].setId(bundleListId); + obEscortBundles[k].setChaufPnum( chaufPnum ); + obEscortBundles[k].setChaufPersType( chaufPtype ); + obEscortBundles[k].setChaufPid( chaufPid ); + escortBundleList.add( obEscortBundles[k] ); + obRsIds[n++] = bundleListId++; + } + } + n = 0; + for ( int k=0; k < obEscortBundles.length; k++ ) { + if ( obEscortBundles[k].getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + obEscortBundles[k].setId(bundleListId); + obEscortBundles[k].setChaufPnum( chaufPnum ); + obEscortBundles[k].setChaufPersType( chaufPtype ); + obEscortBundles[k].setChaufPid( chaufPid ); + escortBundleList.add( obEscortBundles[k] ); + obPeIds[n++] = bundleListId++; + } + } + + obPidList.add( chaufPid ); + obPeList.add( obPeIds ); + obRsList.add( obRsIds ); + + processedChauffSet.add( chaufid ); + + } + + } + + return bundleListId; + + } + + + /** + * Create inbound escort bundle objects and return the bundle list id incremented by the number of new bundles created. The method also adds the bundles to the escortBundleList and + * increments bundleListId by the number of inbound escort bundles. + * + * @param ibBundleResults An integer array of results for escortees dimensioned by: household size + 1, escort results fields. + * @param bundleListId The starting bundle ID; will be incremented for each additional bundle, first for rideshare bundles, then escort bundles. + * @param escortBundleList A List of SchoolEscortingBundle objects that will be added to by this method. + * @param ibPidList A List of chauffeur IDs that will be added to by this method, one for each inbound bundle + * @param ibPeList A List of the inbound pure escort bundle IDs, one for each inbound pure escort bundle + * @param ibRsList A List of the inbound rideshare bundle IDs, one for each inbound rideshare bundle + * @return The updated number of chosen bundles (last ID in the ID lists) + */ + private int createInboundEscortBundleObjects( int[][] ibBundleResults, int bundleListId, List escortBundleList, List ibPidList, List ibPeList, List ibRsList ) { + + int[] ibRsIds = null; + int[] ibPeIds = null; + + Set processedChauffSet = new TreeSet(); + + //for each person in the household + for ( int j=1; j < ibBundleResults.length; j++ ) { + + //the id of the chauffeur for this escortee + int chaufid = ibBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_ID_FIELD]; + + // If this household member is escorted and we haven't created a bundle for the chauffeur yet + if ( chaufid > 0 && !processedChauffSet.contains( chaufid ) ) { + + int chaufPid = ibBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_PID_FIELD]; + int chaufPnum = ibBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_PNUM_FIELD]; + int chaufPtype = ibBundleResults[j][SchoolEscortingModel.RESULT_CHAUF_PERSON_TYPE_FIELD]; + + //get the chosen bundles for this chauffeur in the inbound direction + SchoolEscortingBundle[] ibEscortBundles = decisionMaker.getChosenBundles( ibBundleResults[j][RESULT_CHAUF_CHOSEN_ALT_FIELD], chaufid, SchoolEscortingModel.DIR_INBOUND ); + + int numRs = 0; //number rideshare bundles + int numPe = 0; //number pure escort bundles + for ( int k=0; k < ibEscortBundles.length; k++ ) { + if ( ibEscortBundles[k].getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) + numRs++; + else if ( ibEscortBundles[k].getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) + numPe++; + } + + ibRsIds = new int[numRs]; //id of each inbound rideshare bundle + ibPeIds = new int[numPe]; //id of each inbound pure escort bundle + + //for each inbound bundle for this chauffeur, set the bundle chauffeur attributes + int n = 0; + for ( int k=0; k < ibEscortBundles.length; k++ ) { + if ( ibEscortBundles[k].getEscortType() == ModelStructure.RIDE_SHARING_TYPE ) { + ibEscortBundles[k].setId(bundleListId); + ibEscortBundles[k].setChaufPnum( chaufPnum ); + ibEscortBundles[k].setChaufPersType( chaufPtype ); + ibEscortBundles[k].setChaufPid( chaufPid ); + escortBundleList.add( ibEscortBundles[k] ); + ibRsIds[n++] = bundleListId++; + } + } + n = 0; + for ( int k=0; k < ibEscortBundles.length; k++ ) { + if ( ibEscortBundles[k].getEscortType() == ModelStructure.PURE_ESCORTING_TYPE ) { + ibEscortBundles[k].setId(bundleListId); + ibEscortBundles[k].setChaufPnum( chaufPnum ); + ibEscortBundles[k].setChaufPersType( chaufPtype ); + ibEscortBundles[k].setChaufPid( chaufPid ); + escortBundleList.add( ibEscortBundles[k] ); + ibPeIds[n++] = bundleListId++; + } + } + + ibPidList.add( chaufPid ); + ibPeList.add( ibPeIds ); + ibRsList.add( ibRsIds ); + + processedChauffSet.add( chaufid ); + + } + + } + + return bundleListId; + + } + + + /** + * Apply the outbound choice model for the household. Returns a three-dimensional integer array where: + * dimension 1: sized 2, 0 = results for escortees in household, 1 = results for chauffeurs + * dimension 2: if d1 = 0, sized by household size + 1, if d1 = 1, sized by household size * max bundles (3) + 1 + * dimension 3: if d1 = 0, size by number of result fields for escortees, if d1 = 1, sized by number of result fields for chauffeurs. + * Ever hear of an object? + * @param logger A logger to write messages and debug statements to. + * @param hh The household to solve the outbound model for. + * @param debug If true calculations will be logged to the logger. + * @return A ragged 3d integer array containing results for the outbound choice model for both escortees and chauffeurs. + * @throws Exception Will be thrown if no alternative is chosen. + */ + private int[][][] applyOutboundChoiceModel( Logger logger, Household hh, Random randObject, boolean debug ) throws Exception { + + + double rn = randObject.nextDouble(); + outboundModel.computeUtilities(decisionMaker, indexValues); + //double[] utilities = outboundModel. + int chosenObAlt = outboundModel.getChoiceResult(rn); + if ( chosenObAlt < 0 || debug ) { + + logger.info("Logging Escort Outbound Model Results for household "+hh.getHhId()); + + //int[] altvaluesToLog = new int[]{ 1, 7, 40, 70, 105, 138, 161, 188 }; + int[] altvaluesToLog = new int[50]; + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+1; + outboundModel.logUECResultsSpecificAlts( logger, "Escort model outbound UEC", altvaluesToLog ); + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+51; + outboundModel.logUECResultsSpecificAlts( logger, "Escort model outbound UEC", altvaluesToLog ); + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+101; + outboundModel.logUECResultsSpecificAlts( logger, "Escort model outbound UEC", altvaluesToLog ); + altvaluesToLog = new int[altTableNames.length - 150]; + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+151; + outboundModel.logUECResultsSpecificAlts( logger, "Escort model outbound UEC", altvaluesToLog ); + if ( chosenObAlt < 0 ) { + logger.error( hh.toString() ); + throw new Exception( "chosenObAlt = " + chosenObAlt + " for hhid=" + hh.getHhId() ); + } + + //outboundModel.logInfo("outbound unconditional model", "HHID "+ hh.getHhId(), logger); + + if(debug) + logger.info("Chose outbound unconditional alternative "+ chosenObAlt); + } + + // get field valuess from alternatives table associated with chosen alternative + int chosenObBundle1 = altTableBundle1[chosenObAlt]; + int chosenObBundle2 = altTableBundle2[chosenObAlt]; + int chosenObBundle3 = altTableBundle3[chosenObAlt]; + int chosenObChauf1 = altTableChauf1[chosenObAlt]; + int chosenObChauf2 = altTableChauf2[chosenObAlt]; + int chosenObChauf3 = altTableChauf3[chosenObAlt]; + + + // set the dmu attributes associated with the chosen alternative needed by the Inbound Conditional Choice model + decisionMaker.setOutboundEscortType1( chosenObChauf1 == RIDE_SHARING_CHAUFFEUR_1 || chosenObChauf1 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenObChauf1 == PURE_ESCORTING_CHAUFFEUR_1 || chosenObChauf1 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0 ); + decisionMaker.setOutboundEscortType2( chosenObChauf2 == RIDE_SHARING_CHAUFFEUR_1 || chosenObChauf2 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenObChauf2 == PURE_ESCORTING_CHAUFFEUR_1 || chosenObChauf2 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0 ); + decisionMaker.setOutboundEscortType3( chosenObChauf3 == RIDE_SHARING_CHAUFFEUR_1 || chosenObChauf3 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenObChauf3 == PURE_ESCORTING_CHAUFFEUR_1 || chosenObChauf3 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0 ); + decisionMaker.setOutboundChauffeur1( chosenObChauf1 ); + decisionMaker.setOutboundChauffeur2( chosenObChauf2 ); + decisionMaker.setOutboundChauffeur3( chosenObChauf3 ); + + int[][][] results = new int[2][][]; + results[0] = getResultsByChildArray( hh, decisionMaker, DIR_OUTBOUND, chosenObAlt, (int)(rn*1000000000), chosenObBundle1, chosenObBundle2, chosenObBundle3, chosenObChauf1, chosenObChauf2, chosenObChauf3 ); + results[1] = getResultsByChauffeurArray( hh, decisionMaker, DIR_OUTBOUND, chosenObAlt, chosenObBundle1, chosenObBundle2, chosenObBundle3, chosenObChauf1, chosenObChauf2, chosenObChauf3 ); + + return results; + + } + + + /** + * Apply the inbound conditional choice model for the household. Returns a three-dimensional integer array where: + * dimension 1: sized 2, 0 = results for escortees in household, 1 = results for chauffeurs + * dimension 2: if d1 = 0, sized by household size + 1, if d1 = 1, sized by household size * max bundles (3) + 1 + * dimension 3: if d1 = 0, size by number of result fields for escortees, if d1 = 1, sized by number of result fields for chauffeurs. + * Ever hear of an object? + * @param logger A logger to write messages and debug statements to. + * @param hh The household to solve the inbound conditional model for. + * @param debug If true calculations will be logged to the logger. + * @return A ragged 3d integer array containing results for the inbound conditional choice model for both escortees and chauffeurs. + * @throws Exception Will be thrown if no alternative is chosen. + */ + private int[][][] applyInboundConditionalChoiceModel( Logger logger, Household hh, Random randObject, boolean debug ) throws Exception { + + double rn = randObject.nextDouble(); + inboundConditionalModel.computeUtilities(decisionMaker, indexValues); + int chosenIbAlt = inboundConditionalModel.getChoiceResult(rn); + if ( chosenIbAlt < 0 || debug ) { + + logger.info("Logging Escort Inbound Conditional Model Results for household "+hh.getHhId()); + + //int[] altvaluesToLog = new int[]{ 1, 7, 40, 70, 105, 138, 161, 188 }; + int[] altvaluesToLog = new int[50]; + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+1; + inboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model inbound conditional UEC", altvaluesToLog ); + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+51; + inboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model inbound conditional UEC", altvaluesToLog ); + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+101; + inboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model inbound conditional UEC", altvaluesToLog ); + altvaluesToLog = new int[altTableNames.length - 150]; + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+151; + inboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model inbound conditional UEC", altvaluesToLog ); + if ( chosenIbAlt < 0 ) { + logger.error( hh.toString() ); + throw new Exception( "chosenIbAlt = " + chosenIbAlt + " for hhid=" + hh.getHhId() ); + } + + //inboundConditionalModel.logInfo("inbound conditional model", "HHID "+ hh.getHhId(), logger); + + if(debug) + logger.info("Chose inbound conditional alternative "+ chosenIbAlt); + } + + hh.setInboundEscortChoice(chosenIbAlt); + + // get field values from alternatives table associated with chosen alternative + int chosenIbBundle1 = altTableBundle1[chosenIbAlt]; + int chosenIbBundle2 = altTableBundle2[chosenIbAlt]; + int chosenIbBundle3 = altTableBundle3[chosenIbAlt]; + int chosenIbChauf1 = altTableChauf1[chosenIbAlt]; + int chosenIbChauf2 = altTableChauf2[chosenIbAlt]; + int chosenIbChauf3 = altTableChauf3[chosenIbAlt]; + + if ( debug ) { + int[] escortees = decisionMaker.getEscorteePnums(); + String escorteeString = String.format( "[%s%s%s]", String.valueOf(escortees[1]), (escortees[2] > 0 ? "," + String.valueOf(escortees[2]) : ""), (escortees[3] > 0 ? "," + String.valueOf(escortees[3]) : "") ); + int[] chaufs = decisionMaker.getChauffeurPnums(); + String chaufString = String.format( "[%s%s]", String.valueOf(chaufs[1]), (chaufs[2] > 0 ? "," + String.valueOf(chaufs[2]) : "") ); + logger.info( "hhid=" + hh.getHhId() + ", escortees=" + escorteeString + ", chaufs=" + chaufString ); + logger.info( "chosenIbAlt=" + chosenIbAlt + ", chosenIbChauf1=" + chosenIbChauf1 + ", chosenIbChauf2=" + chosenIbChauf2 + ", chosenIbChauf3=" + chosenIbChauf3 ); + logger.info( "chosenIbBundle1=" + chosenIbBundle1 + ", chosenIbBundle2=" + chosenIbBundle2 + ", chosenIbBundle3=" + chosenIbBundle3 ); + } + + + // set the dmu attributes associated with the chosen alternative needed by the Outbound Conditional Choice model + decisionMaker.setInboundEscortType1( chosenIbChauf1 == RIDE_SHARING_CHAUFFEUR_1 || chosenIbChauf1 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenIbChauf1 == PURE_ESCORTING_CHAUFFEUR_1 || chosenIbChauf1 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0 ); + decisionMaker.setInboundEscortType2( chosenIbChauf2 == RIDE_SHARING_CHAUFFEUR_1 || chosenIbChauf2 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenIbChauf2 == PURE_ESCORTING_CHAUFFEUR_1 || chosenIbChauf2 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0 ); + decisionMaker.setInboundEscortType3( chosenIbChauf3 == RIDE_SHARING_CHAUFFEUR_1 || chosenIbChauf3 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenIbChauf3 == PURE_ESCORTING_CHAUFFEUR_1 || chosenIbChauf3 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0 ); + decisionMaker.setInboundChauffeur1( chosenIbChauf1 ); + decisionMaker.setInboundChauffeur2( chosenIbChauf2 ); + decisionMaker.setInboundChauffeur3( chosenIbChauf3 ); + + + int[][][] results = new int[2][][]; + results[0] = getResultsByChildArray( hh, decisionMaker, DIR_INBOUND, chosenIbAlt, (int)(rn*1000000000), chosenIbBundle1, chosenIbBundle2, chosenIbBundle3, chosenIbChauf1, chosenIbChauf2, chosenIbChauf3 ); + results[1] = getResultsByChauffeurArray( hh, decisionMaker, DIR_INBOUND, chosenIbAlt, chosenIbBundle1, chosenIbBundle2, chosenIbBundle3, chosenIbChauf1, chosenIbChauf2, chosenIbChauf3 ); + + return results; + + } + + + /** + * Apply the outbound conditional choice model for the household. Returns a three-dimensional integer array where: + * dimension 1: sized 2, 0 = results for escortees in household, 1 = results for chauffeurs + * dimension 2: if d1 = 0, sized by household size + 1, if d1 = 1, sized by household size * max bundles (3) + 1 + * dimension 3: if d1 = 0, size by number of result fields for escortees, if d1 = 1, sized by number of result fields for chauffeurs. + * Ever hear of an object? + * @param logger A logger to write messages and debug statements to. + * @param hh The household to solve the outbound conditional model for. + * @param debug If true calculations will be logged to the logger. + * @return A ragged 3d integer array containing results for the outbound conditional choice model for both escortees and chauffeurs. + * @throws Exception Will be thrown if no alternative is chosen. + */ + private int[][][] applyOutboundConditionalChoiceModel( Logger logger, Household hh, boolean debug ) throws Exception { + + double rn = random.nextDouble(); + outboundConditionalModel.computeUtilities(decisionMaker, indexValues); + int chosenObAlt = outboundConditionalModel.getChoiceResult(rn); + if ( chosenObAlt < 0 || debug ) { + + logger.info("Logging Escort Outbound Conditional Model Results for household "+hh.getHhId()); + + //int[] altvaluesToLog = new int[]{ 1, 7, 40, 70, 105, 138, 161, 188 }; + int[] altvaluesToLog = new int[50]; + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+1; + outboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model outbound conditional UEC", altvaluesToLog ); + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+51; + outboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model outbound conditional UEC", altvaluesToLog ); + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+101; + outboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model outbound conditional UEC", altvaluesToLog ); + altvaluesToLog = new int[altTableNames.length - 150]; + for ( int i=0; i < altvaluesToLog.length; i++ ) + altvaluesToLog[i] = i+151; + outboundConditionalModel.logUECResultsSpecificAlts( logger, "Escort model outbound conditional UEC", altvaluesToLog ); + if ( chosenObAlt < 0 ) { + logger.error( hh.toString() ); + throw new Exception( "chosenObAlt = " + chosenObAlt + " for hhid=" + hh.getHhId() ); + } + + //outboundConditionalModel.logInfo("outbound conditional model", "HHID "+ hh.getHhId(), logger); + + if(debug) + logger.info("Chose outbound conditional alternative "+ chosenObAlt); + } + + hh.setOutboundEscortChoice(chosenObAlt); + + // get field valuess from alternatives table associated with chosen alternative + int chosenObBundle1 = altTableBundle1[chosenObAlt]; + int chosenObBundle2 = altTableBundle2[chosenObAlt]; + int chosenObBundle3 = altTableBundle3[chosenObAlt]; + int chosenObChauf1 = altTableChauf1[chosenObAlt]; + int chosenObChauf2 = altTableChauf2[chosenObAlt]; + int chosenObChauf3 = altTableChauf3[chosenObAlt]; + + if ( debug ) { + int[] escortees = decisionMaker.getEscorteePnums(); + String escorteeString = String.format( "[%s%s%s]", String.valueOf(escortees[1]), (escortees[2] > 0 ? "," + String.valueOf(escortees[2]) : ""), (escortees[3] > 0 ? "," + String.valueOf(escortees[3]) : "") ); + int[] chaufs = decisionMaker.getChauffeurPnums(); + String chaufString = String.format( "[%s%s]", String.valueOf(chaufs[1]), (chaufs[2] > 0 ? "," + String.valueOf(chaufs[2]) : "") ); + logger.info( "hhid=" + hh.getHhId() + ", escortees=" + escorteeString + ", chaufs=" + chaufString ); + logger.info( "chosenObAlt=" + chosenObAlt + ", chosenObChauf1=" + chosenObChauf1 + ", chosenObChauf2=" + chosenObChauf2 + ", chosenObChauf3=" + chosenObChauf3 ); + logger.info( "chosenObBundle1=" + chosenObBundle1 + ", chosenObBundle2=" + chosenObBundle2 + ", chosenObBundle3=" + chosenObBundle3 ); + } + + int[][][] results = new int[2][][]; + results[0] = getResultsByChildArray( hh, decisionMaker, DIR_OUTBOUND, chosenObAlt, (int)(rn*1000000000), chosenObBundle1, chosenObBundle2, chosenObBundle3, chosenObChauf1, chosenObChauf2, chosenObChauf3 ); + results[1] = getResultsByChauffeurArray( hh, decisionMaker, DIR_OUTBOUND, chosenObAlt, chosenObBundle1, chosenObBundle2, chosenObBundle3, chosenObChauf1, chosenObChauf2, chosenObChauf3 ); + + return results; + + } + + + private void setDmuAttributesForChildren( Household hh, int dir ) { + + List children = hh.getChildPersons(); + List cList = new ArrayList(); + for ( Person child : children ) { + if (child.getUsualSchoolLocation() > 0 && child.getNumSchoolTours() > 0 ) + cList.add( child ); + } + Person[] escortees = getOrderedSchoolChildrenForEscorting( cList, dir ); + + int[] schoolAtHome = new int[NUM_ESCORTEES_PER_HH+1]; + int[] schoolMazs = new int[NUM_ESCORTEES_PER_HH+1]; + int[] schoolDeparts = new int[NUM_ESCORTEES_PER_HH+1]; + int[] schoolReturns = new int[NUM_ESCORTEES_PER_HH+1]; + for ( int i=1; i < escortees.length; i++ ) { + if ( escortees[i] == null ) + continue; + ArrayList schoolTours = escortees[i].getListOfSchoolTours(); + if ( schoolTours != null ) { + Tour tour = schoolTours.get(0); + schoolAtHome[i] = 0; + schoolMazs[i] = tour.getTourDestMgra(); + schoolDeparts[i] = tour.getTourDepartPeriod(); + schoolReturns[i] = tour.getTourArrivePeriod(); + } + } + + decisionMaker.setEscorteeAttributes( cList.size(), escortees, schoolAtHome, schoolMazs, schoolDeparts, schoolReturns ); + + } + + + private void setDmuAttributesForAdultsInbound( Household hh, int[][][] chaufExtents ) { + + List activeAdults = hh.getActiveAdultPersons(); + + Person[] chauffers = getOrderedAdultsForChauffeuringInbound( activeAdults ); + + int[] mandatoryMazs = new int[chauffers.length]; + int[] mandatoryDeparts = new int[chauffers.length]; + int[] mandatoryReturns = new int[chauffers.length]; + for ( int i=1; i < chauffers.length; i++ ) { + if ( chauffers[i] == null ) + continue; + + ArrayList mandatoryTours = getMandatoryTours(chauffers[i]); + + if ( ! mandatoryTours.isEmpty() ) { + Tour tour2 = mandatoryTours.size() == 2 ? mandatoryTours.get(1) : mandatoryTours.get(0); + mandatoryMazs[i] = tour2.getTourDestMgra(); + mandatoryDeparts[i] = tour2.getTourDepartPeriod(); + mandatoryReturns[i] = tour2.getTourArrivePeriod(); + } + } + + decisionMaker.setChaufferAttributes( activeAdults.size(), chauffers, mandatoryMazs, mandatoryDeparts, mandatoryReturns, chaufExtents ); + decisionMaker.setDistanceTimeAttributes( hh, distanceArray ); + + // set the potential chauffeur pnums from the outbound unconditional choice for use with the inbound conditional choice + decisionMaker.setOutboundPotentialChauffeur1( previousChoiceChauffeurs[1] ); + decisionMaker.setOutboundPotentialChauffeur2( previousChoiceChauffeurs[2] ); + + // set the potential chauffeur pnum values in the inbound direction for eventual use in the outbound conditional choice + for ( int i=1; i < chauffers.length; i++ ) { + if ( chauffers[i] == null ) + previousChoiceChauffeurs[i] = 0; + else + previousChoiceChauffeurs[i] = chauffers[i].getPersonNum(); + } + + } + + + /** + * Get a list of mandatory tours for this person. + * + * @param p A person. + * @return An ArrayList of mandatory tours. Empty if no mandatory tours. + */ + ArrayList getMandatoryTours(Person p){ + + ArrayList mandatoryTours = new ArrayList(); + + if(p.getListOfWorkTours()!=null) + mandatoryTours.addAll(p.getListOfWorkTours()); + + if(p.getListOfSchoolTours()!=null) + mandatoryTours.addAll(p.getListOfSchoolTours()); + + return mandatoryTours; + + } + /** + * Set DMU attributes for adults in the outbound direction. + * + * @param hh + * @param chaufExtents + */ + private void setDmuAttributesForAdultsOutbound( Household hh, int[][][] chaufExtents ) { + + List activeAdults = hh.getActiveAdultPersons(); + + Person[] chauffers = getOrderedAdultsForChauffeuringOutbound( activeAdults ); + + int[] mandatoryMazs = new int[NUM_CHAUFFEURS_PER_HH+1]; + int[] mandatoryDeparts = new int[NUM_CHAUFFEURS_PER_HH+1]; + int[] mandatoryReturns = new int[NUM_CHAUFFEURS_PER_HH+1]; + + + for ( int i=1; i < chauffers.length; i++ ) { + if ( chauffers[i] == null ) + continue; + + ArrayList mandatoryTours = getMandatoryTours(chauffers[i]); + + if ( ! mandatoryTours.isEmpty() ) { + Tour tour1 = mandatoryTours.get(0); + Tour tour2 = mandatoryTours.size() == 2 ? mandatoryTours.get(1) : mandatoryTours.get(0); + mandatoryMazs[i] = tour1.getTourDestMgra(); + mandatoryDeparts[i] = tour1.getTourDepartPeriod(); + mandatoryReturns[i] = tour2.getTourArrivePeriod(); + } + + } + + decisionMaker.setChaufferAttributes( activeAdults.size(), chauffers, mandatoryMazs, mandatoryDeparts, mandatoryReturns, chaufExtents ); + decisionMaker.setDistanceTimeAttributes( hh, distanceArray ); + + // set the potential chauffeur pnums from the inbound conditional choice for use with the outbound conditional choice + decisionMaker.setInboundPotentialChauffeur1( previousChoiceChauffeurs[1] ); + decisionMaker.setInboundPotentialChauffeur2( previousChoiceChauffeurs[2] ); + + // set the potential chauffeur pnum values in the outbound direction for eventual use in the inbound conditional choice + for ( int i=1; i < chauffers.length; i++ ) { + if ( chauffers[i] == null ) + previousChoiceChauffeurs[i] = 0; + else + previousChoiceChauffeurs[i] = chauffers[i].getPersonNum(); + } + + } + + + /** + * Order children in list according to age, distance and time period, and return the result in an array. + * + * @param childList List of children to escort + * @param dir Direction of travel (outbound or return) + * @return + */ + private Person[] getOrderedSchoolChildrenForEscorting( List childList, int dir) { + + Household hh = childList.get( 0 ).getHouseholdObject(); + int homeTaz = mgraDataManager.getTaz( hh.getHhMgra() ); + + // sort the eligible children by age so that the 3 youngest are the final candidates + Collections.sort( childList, + new Comparator() { + @Override + public int compare( Person p1, Person p2 ) { + return p1.getAge() - p2.getAge(); + } + } + ); + + Person[] returnArray = new Person[NUM_ESCORTEES_PER_HH+1]; + + //if there is only one child to escort, its easy - just return him/her. + if ( childList.size() == 1 ) { + returnArray[1] = childList.get( 0 ); + } + //if there are two or three children sort them according to distance and departure time time + else if ( childList.size() == 2 ) { + + Person child0 = childList.get( 0 ); + ArrayList schoolTours = child0.getListOfSchoolTours(); + Tour tour0 = schoolTours.get(0); + int timeInterval0 = 0; + int schoolTaz = mgraDataManager.getTaz( tour0.getTourDestMgra()); + float dist0 = (float) distanceArray[homeTaz][ schoolTaz]; + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) { + timeInterval0 = tour0.getTourDepartPeriod(); + } + else { + timeInterval0 = tour0.getTourArrivePeriod(); + } + + Person child1 = childList.get( 1 ); + schoolTours = child1.getListOfSchoolTours(); + Tour tour1 = schoolTours.get(0); + int timeInterval1 = 0; + schoolTaz = mgraDataManager.getTaz( tour1.getTourDestMgra()); + float dist1 = (float) distanceArray[homeTaz][ schoolTaz]; + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) { + timeInterval1 = tour1.getTourDepartPeriod(); + } + else { + timeInterval1 = tour1.getTourArrivePeriod(); + } + + int[] sortData = new int[2]; + sortData[0] = timeInterval0*10000000 + (int)(dist0*1000); + sortData[1] = timeInterval1*10000000 + (int)(dist1*1000); + int[] sortIndices = IndexSort.indexSort( sortData ); + + returnArray[1] = childList.get( sortIndices[0] ); + returnArray[2] = childList.get( sortIndices[1] ); + + } + else if ( childList.size() >= 3 ) { + + Person child0 = childList.get( 0 ); + ArrayList schoolTours = child0.getListOfSchoolTours(); + Tour tour0 = schoolTours.get(0); + int timeInterval0 = 0; + int schoolTaz = mgraDataManager.getTaz( tour0.getTourDestMgra()); + float dist0 = (float) distanceArray[homeTaz][ schoolTaz]; + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) { + timeInterval0 = tour0.getTourDepartPeriod(); + } + else { + timeInterval0 = tour0.getTourArrivePeriod(); + } + + Person child1 = childList.get( 1 ); + schoolTours = child1.getListOfSchoolTours(); + Tour tour1 = schoolTours.get(0); + int timeInterval1 = 0; + schoolTaz = mgraDataManager.getTaz( tour1.getTourDestMgra()); + float dist1 = (float) distanceArray[homeTaz][ schoolTaz]; + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) { + timeInterval1 = tour1.getTourDepartPeriod(); + } + else { + timeInterval1 = tour1.getTourArrivePeriod(); + } + + Person child2 = childList.get( 2 ); + schoolTours = child2.getListOfSchoolTours(); + Tour tour2 = schoolTours.get(0); + int timeInterval2 = 0; + schoolTaz = mgraDataManager.getTaz( tour2.getTourDestMgra()); + float dist2 = (float) distanceArray[homeTaz][ schoolTaz]; + + if ( dir == SchoolEscortingModel.DIR_OUTBOUND ) { + timeInterval2 = tour2.getTourDepartPeriod(); + } + else { + timeInterval2 = tour2.getTourArrivePeriod(); + } + + int[] sortData = new int[3]; + sortData[0] = timeInterval0*10000000 + (int)(dist0*1000); + sortData[1] = timeInterval1*10000000 + (int)(dist1*1000); + sortData[2] = timeInterval2*10000000 + (int)(dist2*1000); + int[] sortIndices = IndexSort.indexSort( sortData ); + + returnArray[1] = childList.get( sortIndices[0] ); + returnArray[2] = childList.get( sortIndices[1] ); + returnArray[3] = childList.get( sortIndices[2] ); + + } + + return returnArray; + + } + + + private Person[] getOrderedAdultsForChauffeuringOutbound( List adultList ) { + + Collections.sort( adultList, + new Comparator() { + @Override + public int compare( Person p1, Person p2 ) { + int p1LookupValue = PT_WEIGHT*p1.getPersonTypeNumber() + G_WEIGHT*p1.getGender() + A_WEIGHT*(p1.getAge() > 25 ? 1 : 0); + int p2LookupValue = PT_WEIGHT*p2.getPersonTypeNumber() + G_WEIGHT*p2.getGender() + A_WEIGHT*(p2.getAge() > 25 ? 1 : 0); + if(!chauffeurPriorityOutboundMap.containsKey(p1LookupValue)){ + logger.fatal("Cannot find lookup value "+p1LookupValue+" in outbound chauffeur priority map"); + throw new RuntimeException(); + } + if(!chauffeurPriorityOutboundMap.containsKey(p2LookupValue)){ + logger.fatal("Cannot find lookup value "+p2LookupValue+" in outbound chauffeur priority map"); + throw new RuntimeException(); + } + int p1Score = chauffeurPriorityOutboundMap.get(p1LookupValue); + int p2Score = chauffeurPriorityOutboundMap.get(p2LookupValue); + return p1Score - p2Score; + } + } + ); + + Person[] returnArray = new Person[NUM_CHAUFFEURS_PER_HH+1]; + for ( int i=0; i < adultList.size() && i < NUM_CHAUFFEURS_PER_HH; i++ ) + returnArray[i+1] = adultList.get( i ); + + return returnArray; + + } + + + /** + * Orders the list of adults passed to the method by person type, gender, and age combination. + * + * @param adultList A list of potential chauffeurs + * @return An ordered array of the chauffeurs. + */ + private Person[] getOrderedAdultsForChauffeuringInbound( List adultList ) { + + Collections.sort( adultList, + new Comparator() { + @Override + public int compare( Person p1, Person p2 ) { + int p1LookupValue = PT_WEIGHT*p1.getPersonTypeNumber() + G_WEIGHT*p1.getGender() + A_WEIGHT*(p1.getAge() >= 25 ? 1 : 0); + int p2LookupValue = PT_WEIGHT*p2.getPersonTypeNumber() + G_WEIGHT*p2.getGender() + A_WEIGHT*(p2.getAge() >= 25 ? 1 : 0); + return chauffeurPriorityInboundMap.get(p1LookupValue) - chauffeurPriorityInboundMap.get(p2LookupValue); + } + } + ); + + Person[] returnArray = new Person[NUM_CHAUFFEURS_PER_HH+1]; + for ( int i=0; i < adultList.size() && i < NUM_CHAUFFEURS_PER_HH; i++ ) + returnArray[i+1] = adultList.get( i ); + + return returnArray; + + } + + /** + * Create the priority map for outbound chauffeurs, according to person type, gender, and age bin. + */ + private void createChauffeurPriorityOutboundMap() { + + chauffeurPriorityOutboundMap = new HashMap(); + + int lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 1 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 2 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 3 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 4 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 5 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 6 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 7 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 8 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 9 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 10 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 11 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 12 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 13 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 13 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 14 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 14 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 15 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 15 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityOutboundMap.put( lookupValue, 16 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityOutboundMap.put( lookupValue, 16 ); + + } + + + /** + * Create the priority map for inbound chauffeurs, according to person type, gender, and age bin. + */ + private void createChauffeurPriorityInboundMap() { + + chauffeurPriorityInboundMap = new HashMap(); + + int lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 1 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 1 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 2 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 2 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 3 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 3 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 4 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 5 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_PART_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 5 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 6 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_FULL_TIME_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 6 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 7 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 8 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_NON_WORKER_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 8 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 9 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_UNIVERSITY_STUDENT_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 9 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 10 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.FEMALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 10 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*0; + chauffeurPriorityInboundMap.put( lookupValue, 11 ); + + lookupValue = PT_WEIGHT*Person.PERSON_TYPE_RETIRED_INDEX + G_WEIGHT*Person.MALE_INDEX + A_WEIGHT*1; + chauffeurPriorityInboundMap.put( lookupValue, 11 ); + + } + + /** + * Gets the results for each child in the household. The method returns a two dimensional array where the first + * dimension is sized by persons in household + 1, and the second dimension is the total number of fields for child results. + * The first dimension is indexed into by person number and the second dimension is indexed into by result field number. + * Results include household and person attributes for the child being escorted and the chauffeur who is escorting them, + * as well as the attributes of the choice. + * + * @param hh + * @param decisionMaker + * @param direction + * @param chosenAlt Number of chosen alternative. + * @param intRandNum + * @param chosenBundle1 The bundle for child 1: 0 = not escorted. Max 3 bundles + * @param chosenBundle2 The bundle for child 2: 0 = not escorted. Max 3 bundles + * @param chosenBundle3 The bundle for child 3: 0 = not escorted. Max 3 bundles + * @param chosenChauf1 The chauffeur for child 1: 0 = not escorted; 1 = driver 1, rideshare; 2 = driver 1, pure escort; 3 = driver 2, rideshare; 4 = driver 2, pure escort + * @param chosenChauf2 The chauffeur for child 2: 0 = not escorted; 1 = driver 1, rideshare; 2 = driver 1, pure escort; 3 = driver 2, rideshare; 4 = driver 2, pure escort + * @param chosenChauf3 The chauffeur for child 3: 0 = not escorted; 1 = driver 1, rideshare; 2 = driver 1, pure escort; 3 = driver 2, rideshare; 4 = driver 2, pure escort + * @return An integer array of results for each person in the household. + */ + private int[][] getResultsByChildArray( Household hh, SchoolEscortingDmu decisionMaker, int direction, int chosenAlt, int intRandNum, int chosenBundle1, int chosenBundle2, int chosenBundle3, int chosenChauf1, int chosenChauf2, int chosenChauf3 ) { + + int[][] resultsByChild = new int[hh.getHhSize()+1][NUM_RESULTS_BY_CHILD_FIELDS]; + + + int[] adultPnums = decisionMaker.getChauffeurPnums(); + int[] childPnums = decisionMaker.getEscorteePnums(); + + + // set result attributes for all children in the Household + for ( int pnum=1; pnum <= hh.getHhSize(); pnum++ ) { + Person person = hh.getPerson( pnum ); + resultsByChild[pnum][RESULT_CHILD_HHID_FIELD] = hh.getHhId(); + resultsByChild[pnum][RESULT_CHILD_PNUM_FIELD] = pnum; + resultsByChild[pnum][RESULT_CHILD_PID_FIELD] = person.getPersonId(); + resultsByChild[pnum][RESULT_CHILD_PERSON_TYPE_FIELD] = person.getPersonTypeNumber(); + resultsByChild[pnum][RESULT_CHILD_AGE_FIELD] = person.getAge(); + resultsByChild[pnum][RESULT_CHILD_CDAP_FIELD] = person.getCdapIndex(); + resultsByChild[pnum][RESULT_CHILD_SCHOOL_AT_HOME_FIELD] = 0; + resultsByChild[pnum][RESULT_CHILD_SCHOOL_LOC_FIELD] = person.getPersonSchoolLocationZone(); + } + + // set result attributes for children that are to be escorted + for ( Person child : hh.getChildPersons() ) { + int pnum = child.getPersonNum(); + resultsByChild[pnum][RESULT_CHILD_DIRECTION_FIELD] = direction; + resultsByChild[pnum][RESULT_CHILD_CHOSEN_ALT_FIELD] = chosenAlt; + resultsByChild[pnum][RESULT_CHILD_RANDOM_NUM_FIELD] = intRandNum; + } + + // for each escorted child + for ( int i=1; i < childPnums.length; i++ ) { + if ( childPnums[i] > 0 ) { + resultsByChild[childPnums[i]][RESULT_CHILD_ESCORT_ELIGIBLE_FIELD] = ESCORT_ELIGIBLE; + resultsByChild[childPnums[i]][RESULT_CHILD_DEPART_FROM_HOME_FIELD] = decisionMaker.getEscorteeDepartForSchool()[i]; + resultsByChild[childPnums[i]][RESULT_CHILD_DEPART_TO_HOME_FIELD] = decisionMaker.getEscorteeDepartFromSchool()[i]; + resultsByChild[childPnums[i]][RESULT_CHILD_DIST_TO_SCHOOL_FIELD] = decisionMaker.getEscorteeDistToSchool()[i]; + resultsByChild[childPnums[i]][RESULT_CHILD_DIST_FROM_SCHOOL_FIELD] = decisionMaker.getEscorteeDistFromSchool()[i]; + if ( adultPnums[1] > 0 ) { + resultsByChild[childPnums[i]][RESULT_CHILD_ADULT1_DEPART_FROM_HOME_FIELD] = decisionMaker.getChauffeurDepartForMandatory()[1]; + resultsByChild[childPnums[i]][RESULT_CHILD_ADULT1_DEPART_TO_HOME_FIELD] = decisionMaker.getChauffeurDepartFromMandatory()[1]; + } + if ( adultPnums[2] > 0 ) { + resultsByChild[childPnums[i]][RESULT_CHILD_ADULT2_DEPART_FROM_HOME_FIELD] = decisionMaker.getChauffeurDepartForMandatory()[2]; + resultsByChild[childPnums[i]][RESULT_CHILD_ADULT2_DEPART_TO_HOME_FIELD] = decisionMaker.getChauffeurDepartFromMandatory()[2]; + } + } + } + + // for each adult + for ( int i=1; i < adultPnums.length; i++ ) { + if ( adultPnums[i] > 0 ) { + resultsByChild[adultPnums[i]][RESULT_CHILD_DEPART_FROM_HOME_FIELD] = decisionMaker.getChauffeurDepartForMandatory()[i]; + resultsByChild[adultPnums[i]][RESULT_CHILD_DEPART_TO_HOME_FIELD] = decisionMaker.getChauffeurDepartFromMandatory()[i]; + } + } + + if ( chosenChauf1 > 0 ) { + int childid = 1; + int chaufid = chosenChauf1 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_1 ? CHAUFFEUR_1 : chosenChauf1 == RIDE_SHARING_CHAUFFEUR_2 || chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_2 ? CHAUFFEUR_2 : 0; + int escortType = chosenChauf1 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf1 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_1 || chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0; + resultsByChild[childPnums[childid]][RESULT_CHILD_ESCORT_TYPE_FIELD] = escortType; + resultsByChild[childPnums[childid]][RESULT_CHILD_BUNDLE_ID_FIELD] = chosenBundle1; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHILD_ID_FIELD] = childid; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_ID_FIELD] = chaufid; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PNUM_FIELD] = adultPnums[chaufid]; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PID_FIELD] = hh.getPerson( adultPnums[chaufid] ).getPersonId(); + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD] = hh.getPerson( adultPnums[chaufid] ).getPersonTypeNumber(); + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_DEPART_HOME_FIELD] = decisionMaker.getChauffeurDepartForMandatory()[chaufid]; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_DEPART_WORK_FIELD] = decisionMaker.getChauffeurDepartFromMandatory()[chaufid]; + } + + if ( chosenChauf2 > 0 ) { + int childid = 2; + int chaufid = chosenChauf2 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_1 ? CHAUFFEUR_1 : chosenChauf2 == RIDE_SHARING_CHAUFFEUR_2 || chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_2 ? CHAUFFEUR_2 : 0; + int escortType = chosenChauf2 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf2 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_1 || chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0; + resultsByChild[childPnums[childid]][RESULT_CHILD_ESCORT_TYPE_FIELD] = escortType; + resultsByChild[childPnums[childid]][RESULT_CHILD_BUNDLE_ID_FIELD] = chosenBundle2; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHILD_ID_FIELD] = childid; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_ID_FIELD] = chaufid; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PNUM_FIELD] = adultPnums[chaufid]; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PID_FIELD] = hh.getPerson( adultPnums[chaufid] ).getPersonId(); + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD] = hh.getPerson( adultPnums[chaufid] ).getPersonTypeNumber(); + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_DEPART_HOME_FIELD] = decisionMaker.getChauffeurDepartForMandatory()[chaufid]; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_DEPART_WORK_FIELD] = decisionMaker.getChauffeurDepartFromMandatory()[chaufid]; + } + + if ( chosenChauf3 > 0 ) { + int childid = 3; + int chaufid = chosenChauf3 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_1 ? CHAUFFEUR_1 : chosenChauf3 == RIDE_SHARING_CHAUFFEUR_2 || chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_2 ? CHAUFFEUR_2 : 0; + int escortType = chosenChauf3 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf3 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_1 || chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0; + resultsByChild[childPnums[childid]][RESULT_CHILD_ESCORT_TYPE_FIELD] = escortType; + resultsByChild[childPnums[childid]][RESULT_CHILD_BUNDLE_ID_FIELD] = chosenBundle3; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHILD_ID_FIELD] = childid; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_ID_FIELD] = chaufid; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PNUM_FIELD] = adultPnums[chaufid]; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PID_FIELD] = hh.getPerson( adultPnums[chaufid] ).getPersonId(); + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_PERSON_TYPE_FIELD] = hh.getPerson( adultPnums[chaufid] ).getPersonTypeNumber(); + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_DEPART_HOME_FIELD] = decisionMaker.getChauffeurDepartForMandatory()[chaufid]; + resultsByChild[childPnums[childid]][RESULT_CHILD_CHAUFFEUR_DEPART_WORK_FIELD] = decisionMaker.getChauffeurDepartFromMandatory()[chaufid]; + } + + return resultsByChild; + + } + + + /** + * Get the results for each chauffeur in the household and escort bundles undertaken. The method returns a two dimensional integer array + * where the first dimension is sized by household size * total possible bundles (3) + 1, and the second dimension is sized by number of + * results fields for chauffeurs. + * + * @param hh + * @param decisionMaker + * @param direction + * @param chosenAlt + * @param chosenBundle1 The bundle for child 1: 0 = not escorted. Max 3 bundles + * @param chosenBundle2 The bundle for child 2: 0 = not escorted. Max 3 bundles + * @param chosenBundle3 The bundle for child 3: 0 = not escorted. Max 3 bundles + * @param chosenChauf1 The chauffeur for child 1: 0 = not escorted; 1 = driver 1, rideshare; 2 = driver 1, pure escort; 3 = driver 2, rideshare; 4 = driver 2, pure escort + * @param chosenChauf2 The chauffeur for child 2: 0 = not escorted; 1 = driver 1, rideshare; 2 = driver 1, pure escort; 3 = driver 2, rideshare; 4 = driver 2, pure escort + * @param chosenChauf3 The chauffeur for child 3: 0 = not escorted; 1 = driver 1, rideshare; 2 = driver 1, pure escort; 3 = driver 2, rideshare; 4 = driver 2, pure escort + * @return + */ + private int[][] getResultsByChauffeurArray( Household hh, SchoolEscortingDmu decisionMaker, int direction, int chosenAlt, int chosenBundle1, int chosenBundle2, int chosenBundle3, int chosenChauf1, int chosenChauf2, int chosenChauf3 ) { + + int[][] resultsByChauffeurBundle = new int[hh.getHhSize()*NUM_BUNDLES+1][NUM_RESULTS_BY_CHAUF_FIELDS]; + + + int[] adultPnums = decisionMaker.getChauffeurPnums(); + int[] childPnums = decisionMaker.getEscorteePnums(); + + + // set result attributes for chauffeurs + for ( int pnum=1; pnum <= hh.getHhSize(); pnum++ ) { + Person person = hh.getPerson( pnum ); + for ( int i=1; i <= NUM_BUNDLES; i++ ) { + int rowIndex = (pnum-1)*NUM_BUNDLES+i; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_BUNDLE_ID_FIELD] = i; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_HHID_FIELD] = hh.getHhId(); + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_PNUM_FIELD] = pnum; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_PID_FIELD] = person.getPersonId(); + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_PERSON_TYPE_FIELD] = person.getPersonTypeNumber(); + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_AGE_FIELD] = person.getAge(); + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CDAP_FIELD] = person.getCdapIndex(); + } + } + + for ( Person adult : hh.getAdultPersons() ) { + int pnum = adult.getPersonNum(); + for ( int i=1; i <= NUM_BUNDLES; i++ ) { + int rowIndex = (pnum-1)*NUM_BUNDLES+i; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_DIRECTION_FIELD] = direction; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHOSEN_ALT_FIELD] = chosenAlt; + } + } + + for ( int i=1; i < adultPnums.length; i++ ) { + if ( adultPnums[i] > 0 ) { + for ( int j=1; j <= NUM_BUNDLES; j++ ) { + int rowIndex = (adultPnums[i]-1)*NUM_BUNDLES+j; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_ESCORT_ELIGIBLE_FIELD] = ESCORT_ELIGIBLE; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_DEPART_HOME_FIELD] = direction == DIR_OUTBOUND ? decisionMaker.getChauffeurDepartForMandatory()[i] : decisionMaker.getChauffeurDepartFromMandatory()[i]; + } + } + } + + + if ( chosenChauf1 > 0 ) { + int childid = 1; + int chaufid = chosenChauf1 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_1 ? CHAUFFEUR_1 : chosenChauf1 == RIDE_SHARING_CHAUFFEUR_2 || chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_2 ? CHAUFFEUR_2 : 0; + int escortType = chosenChauf1 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf1 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_1 || chosenChauf1 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0; + int bundle = chosenBundle1; + int rowIndex = (adultPnums[chaufid]-1)*NUM_BUNDLES + bundle; + + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_ID_FIELD] = chaufid; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_ESCORT_TYPE_FIELD] = escortType; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD1_PNUM_FIELD] = childPnums[childid]; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD1_PERSON_TYPE_FIELD] = hh.getPerson( childPnums[childid] ).getPersonTypeNumber(); + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD1_DEPART_HOME_FIELD] = direction == DIR_OUTBOUND ? decisionMaker.getEscorteeDepartForSchool()[childid] : decisionMaker.getEscorteeDepartFromSchool()[childid]; + } + + if ( chosenChauf2 > 0 ) { + int childid = 2; + int chaufid = chosenChauf2 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_1 ? CHAUFFEUR_1 : chosenChauf2 == RIDE_SHARING_CHAUFFEUR_2 || chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_2 ? CHAUFFEUR_2 : 0; + int escortType = chosenChauf2 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf2 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_1 || chosenChauf2 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0; + int bundle = chosenBundle2; + int rowIndex = (adultPnums[chaufid]-1)*NUM_BUNDLES + bundle; + + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_ID_FIELD] = chaufid; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_ESCORT_TYPE_FIELD] = escortType; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD2_PNUM_FIELD] = childPnums[childid]; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD2_PERSON_TYPE_FIELD] = hh.getPerson( childPnums[childid] ).getPersonTypeNumber(); + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD2_DEPART_HOME_FIELD] = direction == DIR_OUTBOUND ? decisionMaker.getEscorteeDepartForSchool()[childid] : decisionMaker.getEscorteeDepartFromSchool()[childid]; + } + + if ( chosenChauf3 > 0 ) { + int childid = 3; + int chaufid = chosenChauf3 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_1 ? CHAUFFEUR_1 : chosenChauf3 == RIDE_SHARING_CHAUFFEUR_2 || chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_2 ? CHAUFFEUR_2 : 0; + int escortType = chosenChauf3 == RIDE_SHARING_CHAUFFEUR_1 || chosenChauf3 == RIDE_SHARING_CHAUFFEUR_2 ? ModelStructure.RIDE_SHARING_TYPE : chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_1 || chosenChauf3 == PURE_ESCORTING_CHAUFFEUR_2 ? ModelStructure.PURE_ESCORTING_TYPE : 0; + int bundle = chosenBundle3; + int rowIndex = (adultPnums[chaufid]-1)*NUM_BUNDLES + bundle; + + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_ID_FIELD] = chaufid; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_ESCORT_TYPE_FIELD] = escortType; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD3_PNUM_FIELD] = childPnums[childid]; + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD3_PERSON_TYPE_FIELD] = hh.getPerson( childPnums[childid] ).getPersonTypeNumber(); + resultsByChauffeurBundle[rowIndex][RESULT_CHAUF_CHILD3_DEPART_HOME_FIELD] = direction == DIR_OUTBOUND ? decisionMaker.getEscorteeDepartForSchool()[childid] : decisionMaker.getEscorteeDepartFromSchool()[childid]; + } + + return resultsByChauffeurBundle; + + } + + /** + * Modify and/or create tours based on the results of the school escort model. + * + * @param household + * @param escortBundleList An array of escort bundles. + */ + public void createTours(Household household, List escortBundleList){ + + + //for each bundle + for(SchoolEscortingBundle escortBundle : escortBundleList){ + + //get chauffeur + int chauffeurPnum = escortBundle.getChaufPnum(); + if(chauffeurPnum==0) + continue; + Person chauffeur = household.getPerson(chauffeurPnum); + + //get the list of ordered children in the bundle + int[] childPnums = escortBundle.getChildPnums(); + int[] schoolMAZs = escortBundle.getSchoolMazs(); + + Tour chauffeurTour = null; + int escortType = escortBundle.getEscortType(); + int numStops = 0; + //************************************************************************************************************** + // + // Pure escort tour : Need to create the chauffeur tour + // Also, number of stops(trips) is equal to children + // + //************************************************************************************************************** + if(escortType==ModelStructure.PURE_ESCORTING_TYPE){ + + ArrayList existingTours = chauffeur.getListOfIndividualNonMandatoryTours(); + int id=0; + if(existingTours!=null) + id=existingTours.size(); + else + existingTours = new ArrayList(); + + //generate a non-mandatory escort tour + chauffeurTour = new Tour(id++, household, chauffeur, "Escort", + ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY, ModelStructure.ESCORT_PRIMARY_PURPOSE_INDEX); + + chauffeurTour.setTourOrigMgra(household.getHhMgra()); + chauffeurTour.setTourPurpose("Escort"); + + if(escortBundle.getDir() == DIR_OUTBOUND){ + //the destination of the outbound tour is the school MAZ of the last child to drop off + int destMAZ = schoolMAZs[schoolMAZs.length-1]; + chauffeurTour.setTourDestMgra(destMAZ); + }else{ + //the destination of the inbound tour is the school MAZ of the first child to pick up + int destMAZ = schoolMAZs[0]; + chauffeurTour.setTourDestMgra(destMAZ); + } + + int departPeriod = escortBundle.getDepartHome(); + int arrivePeriod = escortBundle.getArriveHome(); + chauffeurTour.setTourDepartPeriod(departPeriod); + chauffeurTour.setTourArrivePeriod(arrivePeriod); + chauffeur.scheduleWindow(departPeriod, arrivePeriod); + chauffeurTour.setValueOfTime(defaultTourVOT); + existingTours.add(chauffeurTour); + numStops = escortBundle.getChildPnums().length; + + } + //************************************************************************************************************** + // + // Ridesharing tour: Need to find chauffeur tour in existing mandatory tour array + // Also, number of stops is equal to children + 1 + // + //************************************************************************************************************** + if(escortType==ModelStructure.RIDE_SHARING_TYPE){ + + // ******************************************************************************************** + // Change the mandatory tour of the chauffeur + // ******************************************************************************************** + ArrayList chauffeurMandatoryTours = getMandatoryTours(chauffeur); + if(chauffeurMandatoryTours.isEmpty()){ + logger.fatal("Error: trying to get mandatory tours for person "+chauffeurPnum+" in household "+household.getHhId()+" for ride-sharing bundle"); + household.logEntireHouseholdObject("Escort model debug", logger); + throw new RuntimeException(); + } + + //number of stops is number of children needing to be dropped off plus one for the primary destination/tour origin + numStops = childPnums.length+1; + + //get tour and find existing tour mode (if already set by this method) + if(escortBundle.getDir()==DIR_OUTBOUND) + chauffeurTour = chauffeurMandatoryTours.get(0); + else{ + chauffeurTour = chauffeurMandatoryTours.get(chauffeurMandatoryTours.size() - 1 ); + } + } // end if rideshare type + + //set tour mode to max of existing tour mode and mode for occupancy + int occupancy = childPnums.length + 1; + + //check for stops in the opposite direction, in order to set the occupancy to the max for the tour + int occupancyInOppositeDirection = 0; + if(escortBundle.getDir()==DIR_OUTBOUND){ + Stop[] stops = chauffeurTour.getInboundStops(); + if(stops!=null) + occupancyInOppositeDirection = stops.length; + }else{ + Stop[] stops = chauffeurTour.getOutboundStops(); + if(stops!=null) + occupancyInOppositeDirection = stops.length; + } + + if(Math.max(occupancy,occupancyInOppositeDirection)==2) + chauffeurTour.setTourModeChoice(SHARED_RIDE_2_MODE); + else + chauffeurTour.setTourModeChoice(SHARED_RIDE_3_MODE); + + + //create stops for each child on the chauffeurs tour if ride-share type, or children - 1 if pure escort + if(escortBundle.getDir()==DIR_OUTBOUND){ + + chauffeurTour.setEscortTypeOutbound(escortType); + chauffeurTour.setDriverPnumOutbound(chauffeurPnum); + + //if this is a pure rideshare tour, and there's only one child, create one stop for the outbound direction and move on. + if(escortType==ModelStructure.PURE_ESCORTING_TYPE && numStops == 1){ + Stop stop = chauffeurTour.createStop( "Home", "Escort", false, false); + stop.setOrig(household.getHhMgra()); + stop.setDest(chauffeurTour.getTourDestMgra()); + stop.setStopPeriod(chauffeurTour.getTourDepartPeriod()); + stop.setMode(SHARED_RIDE_2_MODE); + stop.setValueOfTime(defaultTripVOT); + stop.setEscorteePnumDest(childPnums[0]); + stop.setEscortStopTypeDest(ModelStructure.ESCORT_STOP_TYPE_DROPOFF); + }//more than one stop on the outbound direction on pure escort or its a rideshare tour + else{ + //insert stops on tour for each child to be escorted + String[] stopOrigPurposes = new String[numStops]; + String[] stopDestPurposes = new String[numStops]; + int[] stopPurposeIndices = new int[numStops]; + stopOrigPurposes[0] = "Home"; + + for(int i = 0; i < numStops-1; ++i){ + if (i > 0) + stopOrigPurposes[i] = stopDestPurposes[i - 1]; + stopPurposeIndices[i] = ModelStructure.ESCORT_STOP_PURPOSE_INDEX; + stopDestPurposes[i] = ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME; + + } + stopOrigPurposes[numStops-1] = stopDestPurposes[numStops - 2]; + stopDestPurposes[numStops-1] = chauffeurTour.getTourPrimaryPurpose(); + chauffeurTour.createOutboundStops(stopOrigPurposes, stopDestPurposes, stopPurposeIndices); + + Stop[] stops = chauffeurTour.getOutboundStops(); + int origMAZ = household.getHhMgra(); + int escorteePnumOrig=0; + byte escortStopTypeOrig=0; + for (int i = 0; i < stops.length; ++i) { + Stop stop = stops[i]; + + //mode to stop is the occupancy - number of stops so far + int mode = 0; + if(occupancy==1) + mode = DRIVE_ALONE_MODE; + else if(occupancy==2) + mode = SHARED_RIDE_2_MODE; + else + mode = SHARED_RIDE_3_MODE; + stop.setMode(mode); + stop.setValueOfTime(defaultTripVOT); + + //decrement the occupancy + occupancy--; + + //set other information for the stop (really the trip to the school) + stop.setEscorteePnumOrig(escorteePnumOrig); + stop.setEscortStopTypeOrig(escortStopTypeOrig); + stop.setOrig(origMAZ); + stop.setStopPeriod(chauffeurTour.getTourDepartPeriod()); + + if(i 0) + stopOrigPurposes[i] = stopDestPurposes[i - 1]; + stopPurposeIndices[i] = ModelStructure.ESCORT_STOP_PURPOSE_INDEX; + stopDestPurposes[i] = ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME; + + } + stopOrigPurposes[numStops-1] = stopDestPurposes[numStops - 2]; + stopDestPurposes[numStops-1] = "HOME"; + chauffeurTour.createInboundStops(stopOrigPurposes, stopDestPurposes, stopPurposeIndices); + + Stop[] stops = chauffeurTour.getInboundStops(); + int origMAZ = chauffeurTour.getTourDestMgra(); + + + + //if it is a pure escort tour, the origin of the first inbound stop is escort + int escorteePnumOrig=0; + byte escortStopTypeOrig=0; + if(escortType==ModelStructure.PURE_ESCORTING_TYPE){ + escorteePnumOrig = childPnums[0]; + escortStopTypeOrig = ModelStructure.ESCORT_STOP_TYPE_PICKUP; + occupancy = 2; //driver + child + }else{ + occupancy=1; //driver + } + for (int i = 0; i < stops.length; ++i) { + Stop stop = stops[i]; + int mode = 0; + if(occupancy==1) + mode = DRIVE_ALONE_MODE; + else if(occupancy==2) + mode = SHARED_RIDE_2_MODE; + else + mode = SHARED_RIDE_3_MODE; + stop.setMode(mode); + stop.setValueOfTime(defaultTripVOT); + + //increment the occupancy + occupancy++; + + //set the person being escorted + stop.setEscorteePnumOrig(escorteePnumOrig); + stop.setEscortStopTypeOrig(escortStopTypeOrig); + stop.setStopPeriod(chauffeurTour.getTourArrivePeriod()); + escortStopTypeOrig = ModelStructure.ESCORT_STOP_TYPE_PICKUP; //origin stop type of next stop to this stop type + stop.setOrig(origMAZ); + + + int childIndex = i; + if(escortType==ModelStructure.PURE_ESCORTING_TYPE) + ++childIndex; + + if(i adults = household.getActiveAdultPersons(); + List children = household.getChildPersons(); + + if(adults == null || children == null) + return; + + //cycle thru adults in household + for(Person adult : adults){ + ArrayList mandatoryTours = getMandatoryTours(adult); + ArrayList nonMandatoryTours = adult.getListOfIndividualNonMandatoryTours(); + + ArrayList chauffeurTours = new ArrayList(); + + //add mandatory tours to the potential list of chauffeur tours + if(mandatoryTours!=null) + if(mandatoryTours.size()>0) + chauffeurTours.addAll(mandatoryTours); + + //add non-mandatory tours to the potential list of chauffeur tours + if(nonMandatoryTours!=null) + if(nonMandatoryTours.size()>0) + chauffeurTours.addAll(nonMandatoryTours); + + //if there are no possible chauffeur tours, we're done. + if(chauffeurTours.size()==0){ + return; + } + + //cycle thru mandatory tours for each adult + for(Tour chauffeurTour : chauffeurTours){ + + if(chauffeurTour.getEscortTypeOutbound()==ModelStructure.RIDE_SHARING_TYPE||chauffeurTour.getEscortTypeOutbound()==ModelStructure.PURE_ESCORTING_TYPE){ + + //cycle thru children in household + for(Person child : children){ + + if(child.getListOfSchoolTours() !=null) + recodeSchoolTour(household, child.getPersonNum(), chauffeurTour, DIR_OUTBOUND); + } + } + if(chauffeurTour.getEscortTypeInbound()==ModelStructure.RIDE_SHARING_TYPE||chauffeurTour.getEscortTypeInbound()==ModelStructure.PURE_ESCORTING_TYPE){ + + //cycle thru children in household + for(Person child : children){ + + if(child.getListOfSchoolTours() !=null) + recodeSchoolTour(household, child.getPersonNum(), chauffeurTour, DIR_INBOUND); + } + } + + } + } + } + + /** + * Recode the child's school tour to be consistent with the chauffeurTour for the given direction. If the + * child does not have any school tours, the method will simply return. If there is a school tour, and the + * chauffeur is escorting the child, then the child's stop sequence, tour and trip modes, and other + * relevant data is made consistent with the chauffeur's tour. + * + * @param household Household object for the given child pnum. + * @param childPnum The person number of the child. + * @param chauffeurTour The chauffeurTour to use for checking\coding. + * @param direction Outbound or inbound direction. + */ + public void recodeSchoolTour(Household household, int childPnum, Tour chauffeurTour, int direction){ + + //get child's school tour + Person child = household.getPerson(childPnum); + ArrayList schoolTours = child.getListOfSchoolTours(); + + // no school tours for this child + if(schoolTours.isEmpty()){ + return; + } + Tour schoolTour = schoolTours.get(0); + schoolTour.setTourModeChoice(SHARED_RIDE_2_MODE); + + if(direction==DIR_OUTBOUND){ + Stop[] chauffeurStops = chauffeurTour.getOutboundStops(); + + int driverPnum = chauffeurTour.getDriverPnumOutbound(); + + //loop through chauffeur tour stops + for(int i = 0; i < chauffeurStops.length; ++i){ + Stop chauffeurStop = chauffeurStops[i]; + + int occupancy=0; + if(chauffeurTour.getTourPurpose().equals("Escort")) + occupancy = chauffeurStops.length+1; //occupancy of last trip is equal to number of stops + 1 for first child picked up + else + occupancy = chauffeurStops.length; + + if(chauffeurStop.getEscorteePnumDest()==childPnum){ + + int existingTourMode = schoolTour.getTourModeChoice(); + schoolTour.setTourModeChoice(Math.max(existingTourMode,chauffeurTour.getTourModeChoice())); + schoolTour.setDriverPnumOutbound(driverPnum); + schoolTour.setEscortTypeOutbound(chauffeurTour.getEscortTypeOutbound()); + + //child is first stop; no intermediate stops on this child's school tour in the outbound direction + if(i==0){ + Stop stop = schoolTour.createStop( "Home", "School", false, false); + stop.setOrig(household.getHhMgra()); + stop.setDest(schoolTour.getTourDestMgra()); + stop.setStopPeriod(schoolTour.getTourDepartPeriod()); + if(occupancy==2) + stop.setMode(SHARED_RIDE_2_MODE); + else + stop.setMode(SHARED_RIDE_3_MODE); + stop.setValueOfTime(defaultTripVOT); + stop.setEscorteePnumDest(childPnum); + stop.setEscortStopTypeDest(ModelStructure.ESCORT_STOP_TYPE_DROPOFF); + break; + } + + //child is second or third stop; create outbound stops array with one or two previous stops. + if(i>0){ + //insert stops on tour for each child to be escorted + String[] stopOrigPurposes = new String[i + 1]; + String[] stopDestPurposes = new String[i + 1]; + int[] stopPurposeIndices = new int[i + 1]; + stopOrigPurposes[0] = "Home"; + + for(int j = 0; j < i; ++j){ + if (j > 0) + stopOrigPurposes[j] = stopDestPurposes[j - 1]; + stopPurposeIndices[j] = ModelStructure.ESCORT_STOP_PURPOSE_INDEX; + stopDestPurposes[j] = ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME; + } + stopOrigPurposes[i] = stopDestPurposes[i - 1]; + stopDestPurposes[i] = schoolTour.getTourPrimaryPurpose(); + schoolTour.createOutboundStops(stopOrigPurposes, stopDestPurposes, stopPurposeIndices); + + Stop[] stops = schoolTour.getOutboundStops(); + int origMAZ = household.getHhMgra(); + int escorteePnumOrig=0; + byte escortStopTypeOrig=0; + for (int j = 0; j < stops.length; ++j) { + Stop stop = stops[j]; + stop.setOrig(origMAZ); + stop.setDest(chauffeurStops[j].getDest()); + origMAZ = stop.getDest(); + stop.setStopPeriod(schoolTour.getTourDepartPeriod()); + if(occupancy==2) + stop.setMode(SHARED_RIDE_2_MODE); + else + stop.setMode(SHARED_RIDE_3_MODE); + stop.setValueOfTime(defaultTripVOT); + stop.setEscorteePnumOrig(escorteePnumOrig); + stop.setEscortStopTypeOrig(escortStopTypeOrig); + stop.setEscorteePnumDest(chauffeurStops[j].getEscorteePnumDest()); + stop.setEscortStopTypeDest(ModelStructure.ESCORT_STOP_TYPE_DROPOFF); + escorteePnumOrig = chauffeurStops[j].getEscorteePnumDest(); + escortStopTypeOrig = ModelStructure.ESCORT_STOP_TYPE_DROPOFF; + } + break; + } + + } //end if found child in chauffeur stop array + --occupancy; + + } //end cycling through stops in outbound direction + + + } //end if in outbound direction + + // things are more complicated in the inbound direction. in this case, the child who is the last to be + // picked up has the simple tour. + if(direction==DIR_INBOUND){ + Stop[] chauffeurStops = chauffeurTour.getInboundStops(); + + int driverPnum = chauffeurTour.getDriverPnumInbound(); + + //loop through chauffeur tour stops from last to first + for(int i = chauffeurStops.length - 1; i >=0; --i){ + Stop chauffeurStop = chauffeurStops[i]; + if(chauffeurStop.getEscorteePnumOrig()==childPnum){ + + int existingTourMode = schoolTour.getTourModeChoice(); + schoolTour.setTourModeChoice(Math.max(existingTourMode,chauffeurTour.getTourModeChoice())); + schoolTour.setDriverPnumInbound(driverPnum); + schoolTour.setEscortTypeInbound(chauffeurTour.getEscortTypeInbound()); + + //child is last stop; no intermediate stops on this child's school tour in the inbound direction + if(i==chauffeurStops.length-1){ + Stop stop = schoolTour.createStop( "School", "Home", true, false); + stop.setOrig(schoolTour.getTourDestMgra()); + stop.setDest(household.getHhMgra()); + stop.setStopPeriod(schoolTour.getTourArrivePeriod()); + int occupancy=0; + if(chauffeurTour.getTourPurpose().equals("Escort")) + occupancy = chauffeurStops.length+1; //occupancy of last trip is equal to number of stops + 1 for first child picked up + else + occupancy = chauffeurStops.length; + if(occupancy==2) + stop.setMode(SHARED_RIDE_2_MODE); + else + stop.setMode(SHARED_RIDE_3_MODE); + stop.setValueOfTime(defaultTripVOT); + stop.setEscorteePnumOrig(childPnum); + stop.setEscortStopTypeOrig(ModelStructure.ESCORT_STOP_TYPE_PICKUP); + break; + } + + //child is not last stop; create inbound stops array with one or two subsequent stops. + if(i 0) + stopOrigPurposes[j] = stopDestPurposes[j - 1]; + stopPurposeIndices[j] = ModelStructure.ESCORT_STOP_PURPOSE_INDEX; + stopDestPurposes[j] = ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME; + } + stopOrigPurposes[numberOfOtherChildrenToPickup] = stopDestPurposes[numberOfOtherChildrenToPickup - 1]; + stopDestPurposes[numberOfOtherChildrenToPickup] = "Home"; + schoolTour.createInboundStops(stopOrigPurposes, stopDestPurposes, stopPurposeIndices); + + Stop[] stops = schoolTour.getInboundStops(); + int origMAZ = chauffeurTour.getTourDestMgra(); + int escorteePnumOrig=0; + byte escortStopTypeOrig=0; + for (int j = 0; j < stops.length; ++j) { + Stop stop = stops[j]; + stop.setOrig(origMAZ); + stop.setDest(chauffeurStops[j].getDest()); + origMAZ = stop.getDest(); + stop.setStopPeriod(schoolTour.getTourDepartPeriod()); + stop.setMode(chauffeurStops[j].getMode()); + stop.setValueOfTime(defaultTripVOT); + stop.setEscorteePnumOrig(escorteePnumOrig); + stop.setEscortStopTypeOrig(escortStopTypeOrig); + stop.setEscorteePnumDest(chauffeurStops[j].getEscorteePnumDest()); + stop.setEscortStopTypeDest(ModelStructure.ESCORT_STOP_TYPE_PICKUP); + escorteePnumOrig = chauffeurStops[j].getEscorteePnumDest(); + escortStopTypeOrig = ModelStructure.ESCORT_STOP_TYPE_PICKUP; + } + break; + } + + } //end if found child in chauffeur stop array + } //end cycling through stops in inbound direction + + } //end if inbound direction + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolLocationChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolLocationChoiceModel.java new file mode 100644 index 0000000..deb2c80 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolLocationChoiceModel.java @@ -0,0 +1,603 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class SchoolLocationChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(SchoolLocationChoiceModel.class); + private transient Logger dcManLogger = Logger.getLogger("tourDcMan"); + + // this constant used as a dimension for saving distance and logsums for + // alternatives in samples + private static final int MAXIMUM_SOA_ALTS_FOR_ANY_MODEL = 200; + + private static final int DC_DATA_SHEET = 0; + + private MgraDataManager mgraManager; + private DestChoiceSize dcSizeObj; + + private DestChoiceTwoStageModelDMU dcTwoStageDmuObject; + + private DestChoiceTwoStageModel dcTwoStageModelObject; + private TourModeChoiceModel mcModel; + + private String[] segmentNameList; + private HashMap segmentNameIndexMap; + + private int[] dcModelIndices; + + // A ChoiceModelApplication object and modeAltsAvailable[] is needed for + // each purpose + private ChoiceModelApplication[] locationChoiceModels; + private ChoiceModelApplication locationChoiceModel; + + private boolean[] dcModelAltsAvailable; + private int[] dcModelAltsSample; + private int[] dcModelSampleValues; + + private int[] uecSheetIndices; + + int origMgra; + + private int modelIndex; + private int shadowPricingIteration; + + private double[] sampleAlternativeDistances; + private double[] sampleAlternativeLogsums; + + private double[] mgraDistanceArray; + + private BuildAccessibilities aggAcc; + + private int soaSampleSize; + + private long soaRunTime; + + public SchoolLocationChoiceModel(int index, HashMap propertyMap, + DestChoiceSize dcSizeObj, BuildAccessibilities aggAcc, String dcUecFileName, + String soaUecFile, int soaSampleSize, String modeChoiceUecFile, + CtrampDmuFactoryIf dmuFactory, TourModeChoiceModel mcModel, + double[][][] schoolSizeProbs, double[][][] schoolTazDistProbs) + { + + this.aggAcc = aggAcc; + this.dcSizeObj = dcSizeObj; + this.mcModel = mcModel; + this.soaSampleSize = soaSampleSize; + + modelIndex = index; + + mgraManager = MgraDataManager.getInstance(); + + dcTwoStageDmuObject = dmuFactory.getDestChoiceSoaTwoStageDMU(); + dcTwoStageDmuObject.setAggAcc(this.aggAcc); + + dcTwoStageModelObject = new DestChoiceTwoStageModel(propertyMap, soaSampleSize); + dcTwoStageModelObject.setTazDistProbs(schoolTazDistProbs); + dcTwoStageModelObject.setMgraSizeProbs(schoolSizeProbs); + + shadowPricingIteration = 0; + + sampleAlternativeDistances = new double[MAXIMUM_SOA_ALTS_FOR_ANY_MODEL]; + sampleAlternativeLogsums = new double[MAXIMUM_SOA_ALTS_FOR_ANY_MODEL]; + + } + + public void setupSchoolSegments() + { + aggAcc.createSchoolSegmentNameIndices(); + uecSheetIndices = aggAcc.getSchoolDcUecSheets(); + segmentNameList = aggAcc.getSchoolSegmentNameList(); + } + + public void setupDestChoiceModelArrays(HashMap propertyMap, + String dcUecFileName, String soaUecFile, int soaSampleSize) + { + + segmentNameIndexMap = dcSizeObj.getSegmentNameIndexMap(); + + // create a lookup array to map purpose index to model index + dcModelIndices = new int[uecSheetIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int dcModelIndex = 0; + int dcSegmentIndex = 0; + for (int uecIndex : uecSheetIndices) + { + // if the uec sheet for the model segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, dcModelIndex); + dcModelIndices[dcSegmentIndex] = dcModelIndex++; + } else + { + dcModelIndices[dcSegmentIndex] = modelIndexMap.get(uecIndex); + } + + dcSegmentIndex++; + } + // the value of dcModelIndex is the number of ChoiceModelApplication + // objects to create + // the modelIndexMap keys are the uec sheets to use in building + // ChoiceModelApplication objects + + locationChoiceModels = new ChoiceModelApplication[modelIndexMap.size()]; + + int i = 0; + for (int uecIndex : modelIndexMap.keySet()) + { + + int modelIndex = -1; + try + { + modelIndex = modelIndexMap.get(uecIndex); + locationChoiceModels[modelIndex] = new ChoiceModelApplication(dcUecFileName, + uecIndex, DC_DATA_SHEET, propertyMap, (VariableTable) dcTwoStageDmuObject); + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught setting up DC ChoiceModelApplication[%d] for modelIndex=%d of %d models", + i, modelIndex, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + + dcModelAltsAvailable = new boolean[soaSampleSize + 1]; + dcModelAltsSample = new int[soaSampleSize + 1]; + dcModelSampleValues = new int[soaSampleSize]; + + mgraDistanceArray = new double[mgraManager.getMaxMgra() + 1]; + + } + + public void applySchoolLocationChoice(Household hh) + { + + if (hh.getDebugChoiceModels()) + { + String label = String.format("Pre school Location Choice HHId=%d Object", hh.getHhId()); + hh.logHouseholdObject(label, dcManLogger); + } + + // declare these variables here so their values can be logged if a + // RuntimeException occurs. + int i = -1; + + int homeMgra = hh.getHhMgra(); + Person[] persons = hh.getPersons(); + + int tourNum = 0; + for (i = 1; i < persons.length; i++) + { + + Person p = persons[i]; + + int segmentIndex = -1; + int segmentType = -1; + if (p.getPersonIsPreschoolChild() == 1 || p.getPersonIsStudentNonDriving() == 1 + || p.getPersonIsStudentDriving() == 1 || p.getPersonIsUniversityStudent() == 1) + { + + if (p.getPersonIsPreschoolChild() == 1) + { + segmentIndex = segmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.PRESCHOOL_SEGMENT_GROUP_INDEX]); + segmentType = BuildAccessibilities.PRESCHOOL_ALT_INDEX; + } else if (p.getPersonIsGradeSchool() == 1) + { + segmentIndex = aggAcc.getMgraGradeSchoolSegmentIndex(homeMgra); + segmentType = BuildAccessibilities.GRADE_SCHOOL_ALT_INDEX; + } else if (p.getPersonIsHighSchool() == 1) + { + segmentIndex = aggAcc.getMgraHighSchoolSegmentIndex(homeMgra); + segmentType = BuildAccessibilities.HIGH_SCHOOL_ALT_INDEX; + } else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() < 30) + { + segmentIndex = segmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_TYPICAL_SEGMENT_GROUP_INDEX]); + segmentType = BuildAccessibilities.UNIV_TYPICAL_ALT_INDEX; + } else if (p.getPersonIsUniversityStudent() == 1 && p.getAge() >= 30) + { + segmentIndex = segmentNameIndexMap + .get(BuildAccessibilities.SCHOOL_DC_SIZE_SEGMENT_NAME_LIST[BuildAccessibilities.UNIV_NONTYPICAL_SEGMENT_GROUP_INDEX]); + segmentType = BuildAccessibilities.UNIV_NONTYPICAL_ALT_INDEX; + } + + // if person type is a student but segment index is -1, the + // person is not enrolled + // assume home schooled + if (segmentIndex < 0) + { + p.setSchoolLocationSegmentIndex(ModelStructure.NOT_ENROLLED_SEGMENT_INDEX); + p.setSchoolLoc(ModelStructure.NOT_ENROLLED_SEGMENT_INDEX); + p.setSchoolLocDistance(0); + p.setSchoolLocLogsum(-999); + continue; + } else + { + // if the segment is in the skip shadow pricing set, and the + // iteration is > 0, dont' compute new choice + if (shadowPricingIteration == 0 + || !dcSizeObj.getSegmentIsInSkipSegmentSet(segmentIndex)) + p.setSchoolLocationSegmentIndex(segmentIndex); + } + + if (segmentType < 0) + { + segmentType = ModelStructure.NOT_ENROLLED_SEGMENT_INDEX; + } + } else // not a student person type + { + p.setSchoolLocationSegmentIndex(-1); + p.setSchoolLoc(0); + p.setSchoolLocDistance(0); + p.setSchoolLocLogsum(-999); + continue; + } + + // save person information in decision maker label, and log person + // object + if (hh.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", p + .getHouseholdObject().getHhId(), p.getPersonNum(), p.getPersonType()); + hh.logPersonObject(decisionMakerLabel, dcManLogger, p); + } + + // if the segment is in the skip shadow pricing set, and the + // iteration is > 0, dont' compute new choice + if (shadowPricingIteration > 0 && dcSizeObj.getSegmentIsInSkipSegmentSet(segmentIndex)) + continue; + + double[] results = null; + int modelIndex = 0; + try + { + + origMgra = homeMgra; + + // update the DC dmuObject for this person + dcTwoStageDmuObject.setHouseholdObject(hh); + dcTwoStageDmuObject.setPersonObject(p); + dcTwoStageDmuObject.setDmuIndexValues(hh.getHhId(), homeMgra, origMgra, 0); + + double[] homeMgraSizeArray = dcSizeObj.getDcSizeArray()[segmentIndex]; + mcModel.getAnmSkimCalculator().getAmPkSkimDistancesFromMgra(homeMgra, + mgraDistanceArray); + + // set size array for the tour segment and distance array from + // the home mgra to all destinaion mgras. + dcTwoStageDmuObject.setMgraSizeArray(homeMgraSizeArray); + dcTwoStageDmuObject.setMgraDistanceArray(mgraDistanceArray); + + modelIndex = dcModelIndices[segmentIndex]; + locationChoiceModel = locationChoiceModels[modelIndex]; + + // get the school location alternative chosen from the sample + results = selectLocationFromSampleOfAlternatives("school", segmentType, p, + segmentNameList[segmentIndex], segmentIndex, tourNum++, homeMgraSizeArray, + mgraDistanceArray); + + } catch (RuntimeException e) + { + logger.fatal(String + .format("Exception caught in dcModel selecting location for i=%d, hh.hhid=%d, person i=%d, in school location choice, modelIndex=%d, segmentType=%d, segmentIndex=%d, segmentName=%s", + i, hh.getHhId(), i, modelIndex, segmentType, segmentIndex, + segmentNameList[segmentIndex])); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + p.setSchoolLoc((int) results[0]); + p.setSchoolLocDistance((float) results[1]); + p.setSchoolLocLogsum((float) results[2]); + + } + + } + + /** + * + * @return an array with chosen mgra, distance to chosen mgra, and logsum to + * chosen mgra. + */ + private double[] selectLocationFromSampleOfAlternatives(String segmentType, + int segmentTypeIndex, Person person, String segmentName, int sizeSegmentIndex, + int tourNum, double[] homeMgraSizeArray, double[] homeMgraDistanceArray) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcManLogger; + + Household household = person.getHouseholdObject(); + + // get sample of locations and correction factors for sample using the + // alternate method + dcTwoStageModelObject.chooseSample(household.getHhTaz(), sizeSegmentIndex, + segmentTypeIndex, soaSampleSize, household.getHhRandom(), + household.getDebugChoiceModels()); + int[] finalSample = dcTwoStageModelObject.getUniqueSampleMgras(); + double[] sampleCorrectionFactors = dcTwoStageModelObject + .getUniqueSampleMgraCorrectionFactors(); + int numUniqueAlts = dcTwoStageModelObject.getNumberofUniqueMgrasInSample(); + + Arrays.fill(dcModelAltsAvailable, false); + Arrays.fill(dcModelAltsSample, 0); + Arrays.fill(dcModelSampleValues, 999999); + + // set sample of alternatives correction factors used in destination + // choice utility for the sampled alternatives. + dcTwoStageDmuObject.setDcSoaCorrections(sampleCorrectionFactors); + + // for the destination mgras in the sample, compute mc logsums and save + // in dmuObject. + // also save correction factor and set availability and sample value for + // the + // sample alternative to true. 1, respectively. + for (int i = 0; i < numUniqueAlts; i++) + { + + int destMgra = finalSample[i]; + dcModelSampleValues[i] = finalSample[i]; + + // set logsum value in DC dmuObject for the logsum index, sampled + // zone and subzone. + double logsum = getModeChoiceLogsum(household, person, destMgra, segmentTypeIndex); + dcTwoStageDmuObject.setMcLogsum(i, logsum); + + sampleAlternativeLogsums[i] = logsum; + sampleAlternativeDistances[i] = homeMgraDistanceArray[finalSample[i]]; + + // set availaibility and sample values for the purpose, dcAlt. + dcModelAltsAvailable[i + 1] = true; + dcModelAltsSample[i + 1] = 1; + + } + + dcTwoStageDmuObject.setSampleArray(dcModelSampleValues); + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format( + "Usual %s Location Choice Model for: Segment=%s", segmentType, segmentName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourNum=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tourNum); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Usual " + segmentType + " Location Choice Model for: Segment=" + + segmentName + ", Person Num: " + person.getPersonNum() + ", Person Type: " + + person.getPersonType() + ", TourNum=" + tourNum); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + locationChoiceModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + locationChoiceModel.computeUtilities(dcTwoStageDmuObject, + dcTwoStageDmuObject.getDmuIndexValues(), dcModelAltsAvailable, dcModelAltsSample); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (locationChoiceModel.getAvailabilityCount() > 0) + { + try + { + chosen = locationChoiceModel.getChoiceResult(rn); + } catch (Exception e) + { + } + } else + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, no available %s destination choice alternatives to choose from in choiceModelApplication.", + dcTwoStageDmuObject.getHouseholdObject().getHhId(), dcTwoStageDmuObject + .getPersonObject().getPersonNum(), segmentName)); + } + + if (household.getDebugChoiceModels() || chosen <= 0) + { + + double[] utilities = locationChoiceModel.getUtilities(); + double[] probabilities = locationChoiceModel.getProbabilities(); + boolean[] availabilities = locationChoiceModel.getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb Distance Logsum"); + modelLogger + .info("--------------------- -------------- -------------- -------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 1; j < finalSample.length; j++) + { + int alt = finalSample[j]; + cumProb += probabilities[j]; + String altString = String.format("j=%d, mgra=%d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j + 1], utilities[j], probabilities[j], cumProb)); + } + + modelLogger.info(" "); + if (chosen > 0) + { + String altString = String.format("j=%d, mgra=%d", chosen - 1, + finalSample[chosen - 1]); + modelLogger.info(String.format("Choice: %s with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + } else + { + String altString = String.format("No Chosen Alt, availability count = %d", + locationChoiceModel.getAvailabilityCount()); + modelLogger.info(altString); + } + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + locationChoiceModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + locationChoiceModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, + chosen); + + // write UEC calculation results to separate model specific log file + locationChoiceModel.logUECResults(modelLogger, loggingHeader); + + if (chosen < 0) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, no available %s destination choice alternatives to choose from in choiceModelApplication.", + dcTwoStageDmuObject.getHouseholdObject().getHhId(), + dcTwoStageDmuObject.getPersonObject().getPersonNum(), segmentName)); + System.exit(-1); + } + + } + + double[] returnArray = new double[3]; + + returnArray[0] = finalSample[chosen - 1]; + returnArray[1] = sampleAlternativeDistances[chosen - 1]; + returnArray[2] = sampleAlternativeLogsums[chosen - 1]; + + return returnArray; + + } + + private double getModeChoiceLogsum(Household household, Person person, int sampleDestMgra, + int segmentTypeIndex) + { + + int purposeIndex = 0; + String purpose = ""; + if (segmentTypeIndex < 0) + { + purposeIndex = ModelStructure.WORK_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.WORK_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.PRESCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.GRADE_SCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.HIGH_SCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.UNIV_TYPICAL_ALT_INDEX) + { + purposeIndex = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.UNIV_NONTYPICAL_ALT_INDEX) + { + purposeIndex = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME; + } + + // create a temporary tour to use to calculate mode choice logsum + Tour mcLogsumTour = new Tour(person, 0, purposeIndex); + mcLogsumTour.setTourPurpose(purpose); + mcLogsumTour.setTourOrigMgra(household.getHhMgra()); + mcLogsumTour.setTourDestMgra(sampleDestMgra); + mcLogsumTour.setTourDepartPeriod(Person.DEFAULT_MANDATORY_START_PERIOD); + mcLogsumTour.setTourArrivePeriod(Person.DEFAULT_MANDATORY_END_PERIOD); + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + + if (household.getDebugChoiceModels()) + { + dcManLogger.info(""); + dcManLogger.info(""); + choiceModelDescription = "location choice logsum for segmentTypeIndex=" + + segmentTypeIndex + ", temp tour PurposeIndex=" + purposeIndex; + decisionMakerLabel = "HHID: " + household.getHhId() + ", PersNum: " + + person.getPersonNum(); + household.logPersonObject(choiceModelDescription + ", " + decisionMakerLabel, + dcManLogger, person); + } + + double logsum = -1; + try + { + logsum = mcModel.getModeChoiceLogsum(household, person, mcLogsumTour, dcManLogger, + choiceModelDescription, decisionMakerLabel); + } catch (Exception e) + { + choiceModelDescription = "location choice logsum for segmentTypeIndex=" + + segmentTypeIndex + ", temp tour PurposeIndex=" + purposeIndex; + decisionMakerLabel = "HHID: " + household.getHhId() + ", PersNum: " + + person.getPersonNum(); + logger.fatal("exception caught calculating ModeChoiceLogsum for usual work/school location choice."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + e.printStackTrace(); + System.exit(-1); + } + + return logsum; + } + + public int getModelIndex() + { + return modelIndex; + } + + public void setDcSizeObject(DestChoiceSize dcSizeObj) + { + this.dcSizeObj = dcSizeObj; + } + + public long getSoaRunTime() + { + return soaRunTime; + } + + public void resetSoaRunTime() + { + soaRunTime = 0; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolLocationChoiceTaskJppf.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolLocationChoiceTaskJppf.java new file mode 100644 index 0000000..b162282 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SchoolLocationChoiceTaskJppf.java @@ -0,0 +1,238 @@ +package org.sandag.abm.ctramp; + +import java.net.UnknownHostException; +import java.util.Date; +import java.util.HashMap; +import org.jppf.node.protocol.AbstractTask; +import org.jppf.node.protocol.DataProvider; +import com.pb.common.calculator.MatrixDataServerIf; + +public class SchoolLocationChoiceTaskJppf + extends AbstractTask +{ + + private static String VERSION = "Task.1.0.3"; + + private transient HashMap propertyMap; + private transient MatrixDataServerIf ms; + private transient HouseholdDataManagerIf hhDataManager; + private transient ModelStructure modelStructure; + private transient String tourCategory; + private transient DestChoiceSize dcSizeObj; + private transient String dcUecFileName; + private transient String soaUecFileName; + private transient int soaSampleSize; + private transient CtrampDmuFactoryIf dmuFactory; + private transient String restartModelString; + + private int iteration; + private int startIndex; + private int endIndex; + private int taskIndex = -1; + + public SchoolLocationChoiceTaskJppf(int taskIndex, int startIndex, int endIndex, int iteration) + { + this.startIndex = startIndex; + this.endIndex = endIndex; + this.taskIndex = taskIndex; + this.iteration = iteration; + } + + public void run() + { + + String start = (new Date()).toString(); + long startTime = System.currentTimeMillis(); + + String threadName = null; + try + { + threadName = "[" + java.net.InetAddress.getLocalHost().getHostName() + "] " + + Thread.currentThread().getName(); + } catch (UnknownHostException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + // logger.info( String.format( + // "startTime=%d, task=%d run(), thread=%s, start=%d, end=%d.", + // startTime, + // taskIndex, threadName, startIndex, + // endIndex ) ); + + try + { + DataProvider dataProvider = getDataProvider(); + + this.propertyMap = (HashMap) dataProvider.getParameter("propertyMap"); + this.ms = (MatrixDataServerIf) dataProvider.getParameter("ms"); + this.hhDataManager = (HouseholdDataManagerIf) dataProvider.getParameter("hhDataManager"); + this.modelStructure = (ModelStructure) dataProvider.getParameter("modelStructure"); + this.tourCategory = (String) dataProvider.getParameter("tourCategory"); + this.dcSizeObj = (DestChoiceSize) dataProvider.getParameter("dcSizeObj"); + this.dcUecFileName = (String) dataProvider.getParameter("dcUecFileName"); + this.soaUecFileName = (String) dataProvider.getParameter("soaUecFileName"); + this.soaSampleSize = (Integer) dataProvider.getParameter("soaSampleSize"); + this.dmuFactory = (CtrampDmuFactoryIf) dataProvider.getParameter("dmuFactory"); + this.restartModelString = (String) dataProvider.getParameter("restartModelString"); + + } catch (Exception e) + { + e.printStackTrace(); + } + + // HouseholdChoiceModelsManager hhModelManager = + // HouseholdChoiceModelsManager.getInstance( + // propertyMap, restartModelString, modelStructure, dmuFactory); + // hhModelManager.clearHhModels(); + // hhModelManager = null; + + // get the factory object used to create and recycle dcModel objects. + DestChoiceModelManager modelManager = DestChoiceModelManager.getInstance(); + + // one of tasks needs to initialize the manager object by passing + // attributes + // needed to create a destination choice model object. + modelManager.managerSetup(propertyMap, modelStructure, ms, dcUecFileName, soaUecFileName, + soaSampleSize, dmuFactory, restartModelString); + + // get a dcModel object from manager, which either creates one or + // returns one + // for re-use. + MandatoryDestChoiceModel dcModel = modelManager.getDcSchoolModelObject(taskIndex, + iteration, dcSizeObj); + + // logger.info( String.format( + // "%s, task=%d run(), thread=%s, start=%d, end=%d.", VERSION, + // taskIndex, + // threadName, startIndex, endIndex ) ); + System.out.println(String.format("%s: %s, task=%d run(), thread=%s, start=%d, end=%d.", + new Date(), VERSION, taskIndex, threadName, startIndex, endIndex)); + + long setup1 = (System.currentTimeMillis() - startTime) / 1000; + + Household[] householdArray = hhDataManager.getHhArray(startIndex, endIndex); + + long setup2 = (System.currentTimeMillis() - startTime) / 1000; + // logger.info( String.format( + // "task=%d processing households[%d:%d], thread=%s, setup1=%d, setup2=%d.", + // taskIndex, startIndex, endIndex, + // threadName, setup1, setup2 ) ); + System.out.println(String.format("%s: task=%d processing households[%d:%d], thread=%s.", + new Date(), taskIndex, startIndex, endIndex, threadName)); + + int i = -1; + try + { + + boolean runDebugHouseholdsOnly = Util.getBooleanValueFromPropertyMap(propertyMap, + HouseholdDataManager.DEBUG_HHS_ONLY_KEY); + + for (i = 0; i < householdArray.length; i++) + { + // for debugging only - process only household objects specified + // for debugging, if property key was set to true + if (runDebugHouseholdsOnly && !householdArray[i].getDebugChoiceModels()) continue; + + dcModel.applySchoolLocationChoice(householdArray[i]); + } + + hhDataManager.setHhArray(householdArray, startIndex); + + //check to make sure hh array got set in hhDataManager + boolean allHouseholdsAreSame = false; + while(!allHouseholdsAreSame) { + Household[] householdArrayRemote = hhDataManager.getHhArray(startIndex, endIndex); + for(int j = 0; j< householdArrayRemote.length;++j) { + + Household remoteHousehold = householdArrayRemote[j]; + Household localHousehold = householdArray[j]; + + allHouseholdsAreSame = checkIfSameSchoolLocationResults(remoteHousehold, localHousehold); + + if(!allHouseholdsAreSame) + break; + } + if(!allHouseholdsAreSame) { + System.out.println("Warning: found households in household manager (starting array index "+startIndex+") not updated with school location choice results; updating"); + hhDataManager.setHhArray(householdArray, startIndex); + + } + } + + + } catch (Exception e) + { + if (i >= 0 && i < householdArray.length) System.out + .println(String + .format("exception caught in taskIndex=%d applying dc model for i=%d, hhId=%d, startIndex=%d.", + taskIndex, i, householdArray[i].getHhId(), startIndex)); + else System.out.println(String.format( + "exception caught in taskIndex=%d applying dc model for i=%d, startIndex=%d.", + taskIndex, i, startIndex)); + System.out.println("Exception caught:"); + e.printStackTrace(); + System.out.println("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(e); + } + + long getHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup1; + long processHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup2 - getHhs; + // logger.info( String.format( + // "task=%d finished, thread=%s, getHhs=%d, processHhs=%d.", taskIndex, + // threadName, getHhs, processHhs ) ); + System.out.println(String.format("%s: task=%d finished, thread=%s.", new Date(), taskIndex, + threadName)); + + long total = (System.currentTimeMillis() - startTime) / 1000; + String resultString = String + .format("result for thread=%s, task=%d, startIndex=%d, endIndex=%d, startTime=%s, endTime=%s, setup1=%d, setup2=%d, getHhs=%d, run=%d, total=%d.", + threadName, taskIndex, startIndex, endIndex, start, new Date(), setup1, + setup2, getHhs, processHhs, total); + // logger.info( resultString ); + setResult(resultString); + + modelManager.returnDcSchoolModelObject(dcModel, taskIndex, startIndex, endIndex); + + } + + /** + * Returns true if school location results are the same, else returns false. + * + * @param thisHousehold + * @param thatHousehold + * @return true or false + */ + public boolean checkIfSameSchoolLocationResults(Household thisHousehold, Household thatHousehold) { + + Person[] thisPersons = thisHousehold.getPersons(); + Person[] thatPersons = thatHousehold.getPersons(); + + if(thisPersons.length!=thatPersons.length) + return false; + + for(int k=1;k +{ + + private static String VERSION = "Task.1.0.3"; + + private transient HashMap propertyMap; + private transient MatrixDataServerIf ms; + private transient HouseholdDataManagerIf hhDataManager; + private transient ModelStructure modelStructure; + private transient String tourCategory; + private transient DestChoiceSize dcSizeObj; + private transient String dcUecFileName; + private transient String soaUecFileName; + private transient int soaSampleSize; + private transient CtrampDmuFactoryIf dmuFactory; + private transient String restartModelString; + + private int iteration; + private int startIndex; + private int endIndex; + private int taskIndex = -1; + + public SchoolLocationChoiceTaskJppfNew(int taskIndex, int startIndex, int endIndex, + int iteration) + { + this.startIndex = startIndex; + this.endIndex = endIndex; + this.taskIndex = taskIndex; + this.iteration = iteration; + } + + public void run() + { + + String start = (new Date()).toString(); + long startTime = System.currentTimeMillis(); + + String threadName = null; + try + { + threadName = "[" + java.net.InetAddress.getLocalHost().getHostName() + "] " + + Thread.currentThread().getName(); + } catch (UnknownHostException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + // logger.info( String.format( + // "startTime=%d, task=%d run(), thread=%s, start=%d, end=%d.", + // startTime, + // taskIndex, threadName, startIndex, + // endIndex ) ); + + try + { + DataProvider dataProvider = getDataProvider(); + + this.propertyMap = (HashMap) dataProvider.getParameter("propertyMap"); + this.ms = (MatrixDataServerIf) dataProvider.getParameter("ms"); + this.hhDataManager = (HouseholdDataManagerIf) dataProvider.getParameter("hhDataManager"); + this.modelStructure = (ModelStructure) dataProvider.getParameter("modelStructure"); + this.tourCategory = (String) dataProvider.getParameter("tourCategory"); + this.dcSizeObj = (DestChoiceSize) dataProvider.getParameter("dcSizeObj"); + this.dcUecFileName = (String) dataProvider.getParameter("dcUecFileName"); + this.soaUecFileName = (String) dataProvider.getParameter("soaUecFileName"); + this.soaSampleSize = (Integer) dataProvider.getParameter("soaSampleSize"); + this.dmuFactory = (CtrampDmuFactoryIf) dataProvider.getParameter("dmuFactory"); + this.restartModelString = (String) dataProvider.getParameter("restartModelString"); + + } catch (Exception e) + { + e.printStackTrace(); + } + + // HouseholdChoiceModelsManager hhModelManager = + // HouseholdChoiceModelsManager.getInstance( + // propertyMap, restartModelString, modelStructure, dmuFactory); + // hhModelManager.clearHhModels(); + // hhModelManager = null; + + // get the factory object used to create and recycle dcModel objects. + DestChoiceModelManager modelManager = DestChoiceModelManager.getInstance(); + + // one of tasks needs to initialize the manager object by passing + // attributes + // needed to create a destination choice model object. + modelManager.managerSetup(propertyMap, modelStructure, ms, dcUecFileName, soaUecFileName, + soaSampleSize, dmuFactory, restartModelString); + + // get a dcModel object from manager, which either creates one or + // returns one + // for re-use. + SchoolLocationChoiceModel dcModel = modelManager.getSchoolLocModelObject(taskIndex, + iteration, dcSizeObj); + + // logger.info( String.format( + // "%s, task=%d run(), thread=%s, start=%d, end=%d.", VERSION, + // taskIndex, + // threadName, startIndex, endIndex ) ); + System.out.println(String.format("%s: %s, task=%d run(), thread=%s, start=%d, end=%d.", + new Date(), VERSION, taskIndex, threadName, startIndex, endIndex)); + + long setup1 = (System.currentTimeMillis() - startTime) / 1000; + + Household[] householdArray = hhDataManager.getHhArray(startIndex, endIndex); + + long setup2 = (System.currentTimeMillis() - startTime) / 1000; + // logger.info( String.format( + // "task=%d processing households[%d:%d], thread=%s, setup1=%d, setup2=%d.", + // taskIndex, startIndex, endIndex, + // threadName, setup1, setup2 ) ); + System.out.println(String.format("%s: task=%d processing households[%d:%d], thread=%s.", + new Date(), taskIndex, startIndex, endIndex, threadName)); + + int i = -1; + try + { + + boolean runDebugHouseholdsOnly = Util.getBooleanValueFromPropertyMap(propertyMap, + HouseholdDataManager.DEBUG_HHS_ONLY_KEY); + + for (i = 0; i < householdArray.length; i++) + { + // for debugging only - process only household objects specified + // for debugging, if property key was set to true + if (runDebugHouseholdsOnly && !householdArray[i].getDebugChoiceModels()) continue; + + dcModel.applySchoolLocationChoice(householdArray[i]); + } + + hhDataManager.setHhArray(householdArray, startIndex); + + //check to make sure hh array got set in hhDataManager + boolean allHouseholdsAreSame = false; + while(!allHouseholdsAreSame) { + Household[] householdArrayRemote = hhDataManager.getHhArray(startIndex, endIndex); + for(int j = 0; j< householdArrayRemote.length;++j) { + + Household remoteHousehold = householdArrayRemote[j]; + Household localHousehold = householdArray[j]; + + allHouseholdsAreSame = checkIfSameSchoolLocationResults(remoteHousehold, localHousehold); + + if(!allHouseholdsAreSame) + break; + } + if(!allHouseholdsAreSame) { + System.out.println("Warning: found households in household manager (starting array index "+startIndex+") not updated with school location choice results; updating"); + hhDataManager.setHhArray(householdArray, startIndex); + + } + } + + } catch (Exception e) + { + if (i >= 0 && i < householdArray.length) System.out + .println(String + .format("exception caught in taskIndex=%d applying dc model for i=%d, hhId=%d, startIndex=%d.", + taskIndex, i, householdArray[i].getHhId(), startIndex)); + else System.out.println(String.format( + "exception caught in taskIndex=%d applying dc model for i=%d, startIndex=%d.", + taskIndex, i, startIndex)); + System.out.println("Exception caught:"); + e.printStackTrace(); + System.out.println("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(e); + } + + long getHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup1; + long processHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup2 - getHhs; + // logger.info( String.format( + // "task=%d finished, thread=%s, getHhs=%d, processHhs=%d.", taskIndex, + // threadName, getHhs, processHhs ) ); + System.out.println(String.format("%s: task=%d finished, thread=%s.", new Date(), taskIndex, + threadName)); + + long total = (System.currentTimeMillis() - startTime) / 1000; + String resultString = String + .format("result for thread=%s, task=%d, startIndex=%d, endIndex=%d, startTime=%s, endTime=%s, setup1=%d, setup2=%d, getHhs=%d, run=%d, total=%d.", + threadName, taskIndex, startIndex, endIndex, start, new Date(), setup1, + setup2, getHhs, processHhs, total); + // logger.info( resultString ); + setResult(resultString); + + modelManager.returnSchoolLocModelObject(dcModel, taskIndex, startIndex, endIndex); + + clearClassAttributes(); + } + + /** + * Returns true if school location results are the same, else returns false. + * + * @param thisHousehold + * @param thatHousehold + * @return true or false + */ + public boolean checkIfSameSchoolLocationResults(Household thisHousehold, Household thatHousehold) { + + Person[] thisPersons = thisHousehold.getPersons(); + Person[] thatPersons = thatHousehold.getPersons(); + + if(thisPersons.length!=thatPersons.length) + return false; + + for(int k=1;k + * The type that the matrices are segmented against. + */ +public interface SegmentedSparseMatrix { + /** + * Get the value of the matrix for a specified segment and row/column ids. + * + * @param segment + * The segment. + * + * @param rowId + * The row id. + * + * @param columnId + * The column id. + * + * @return the matrix value at (rowId,columnId) for {@code segment}. + */ + double getValue(S segment, int rowId, int columnId); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SoaDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SoaDMU.java new file mode 100644 index 0000000..740cbb0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SoaDMU.java @@ -0,0 +1,10 @@ +package org.sandag.abm.ctramp; + +/** + * @author crf
+ * Started: Nov 15, 2008 3:25:49 PM + */ +public interface SoaDMU +{ + Household getHouseholdObject(); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SqliteService.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SqliteService.java new file mode 100644 index 0000000..73c7178 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SqliteService.java @@ -0,0 +1,118 @@ +package org.sandag.abm.ctramp; + +import java.sql.Connection; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; + +public class SqliteService +{ + + Connection c = null; + String databaseFile; + + public void connect(String fileName, String tableName) throws DAOException + { + + try + { + c = ConnectionHelper.getConnection(fileName); + Statement s = c.createStatement(); + + s.execute("CREATE TABLE IF NOT EXISTS " + tableName + " (" + " id INTEGER, " + + " numProcessed INTEGER, " + " totalToProcess INTEGER, " + + " startUp INTEGER, " + " runTime INTEGER, " + " shutDown INTEGER " + + ")"); + + s.execute("DELETE FROM " + tableName); + + } catch (SQLException e) + { + e.printStackTrace(); + throw new DAOException(e); + } + + } + + public void listRecords(String tableName) throws DAOException + { + + try + { + + Statement s = c.createStatement(); + + ResultSet rs = s + .executeQuery("SELECT id, numProcessed, totalToProcess, startUp, runTime, shutDown FROM " + + tableName + " ORDER BY id"); + while (rs.next()) + { + System.out.println(rs.getInt("id") + ", " + rs.getInt("numProcessed") + ", " + + rs.getInt("totalToProcess") + ", " + rs.getInt("startUp") + ", " + + rs.getInt("runTime") + ", " + rs.getInt("shutDown")); + } + + } catch (SQLException e) + { + e.printStackTrace(); + throw new DAOException(e); + } + + } + + public void insertRecord(String tableName, int id, int numProcessed, int totalToProcess, + int startUp, int runTime, int shutDown) throws DAOException + { + + try + { + + Statement s = c.createStatement(); + String query = String + .format("INSERT INTO %s (id, numProcessed, totalToProcess, startUp, runTime, shutDown) VALUES (%d, %d, %d, %d, %d, %d)", + tableName, id, numProcessed, totalToProcess, startUp, runTime, shutDown); + s.execute(query); + + } catch (SQLException e) + { + e.printStackTrace(); + throw new DAOException(e); + } + + } + + public void updateRecord(String tableName, int id, int numProcessed, int totalToProcess, + int startUp, int runTime, int shutDown) throws DAOException + { + + try + { + + Statement s = c.createStatement(); + String query = String + .format("UPDATE %s SET numProcessed=%d, totalToProcess=%d, startUp=%d, runTime=%d, shutDown=%d WHERE id=%d", + tableName, numProcessed, totalToProcess, startUp, runTime, shutDown, id); + s.execute(query); + + } catch (SQLException e) + { + e.printStackTrace(); + throw new DAOException(e); + } + + } + + public static void main(String[] args) + { + + SqliteService s = new SqliteService(); + s.connect("c:/jim/status.db", "uwsl"); + + s.insertRecord("uwsl", 0, 27, 1250, 99, 102, 10); + s.insertRecord("uwsl", 2, 29, 1250, 58, 101, 9); + s.insertRecord("uwsl", 1, 32, 1250, 77, 99, 8); + s.listRecords("uwsl"); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/Stop.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Stop.java new file mode 100644 index 0000000..882b5b8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Stop.java @@ -0,0 +1,304 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import org.apache.log4j.Logger; + +public class Stop + implements Serializable +{ + + static final byte STOP_TYPE_PICKUP = 1; + static final byte STOP_TYPE_DROPOFF = 2; + static final byte STOP_TYPE_OTHER = 3; + int id; + int orig; + int dest; + int park; + int mode; + byte micromobilityWalkMode; + byte micromobilityAccessMode; + byte micromobilityEgressMode; + float micromobilityWalkLogsum; + float micromobilityAccessLogsum; + float micromobilityEgressLogsum; + private float modeLogsum; + private float parkingCost; + + int stopPeriod; + int boardTap; + int alightTap; + boolean inbound; + int set = -1; + + private int escorteePnumOrig; + private byte escortStopTypeOrig; + private int escorteePnumDest; + private byte escortStopTypeDest; + + String origPurpose; + String destPurpose; + int stopPurposeIndex; + + Tour parentTour; + + private double valueOfTime; + + public Stop(Tour parentTour, String origPurpose, String destPurpose, int id, boolean inbound, + int stopPurposeIndex) + { + this.parentTour = parentTour; + this.origPurpose = origPurpose; + this.destPurpose = destPurpose; + this.stopPurposeIndex = stopPurposeIndex; + this.id = id; + this.inbound = inbound; + } + + public void setOrig(int orig) + { + this.orig = orig; + } + + public void setDest(int dest) + { + this.dest = dest; + } + + public void setPark(int park) + { + this.park = park; + } + + public void setMode(int mode) + { + this.mode = mode; + } + + public void setSet(int Skimset) + { + set = Skimset; + } + + public void setBoardTap(int tap) + { + boardTap = tap; + } + + public void setAlightTap(int tap) + { + alightTap = tap; + } + + public void setStopPeriod(int period) + { + stopPeriod = period; + } + + public int getOrig() + { + return orig; + } + + public int getDest() + { + return dest; + } + + public int getPark() + { + return park; + } + + public String getOrigPurpose() + { + return origPurpose; + } + + public String getDestPurpose() + { + return destPurpose; + } + + public void setOrigPurpose(String purpose) + { + origPurpose=purpose; + } + public void setDestPurpose(String purpose){ + destPurpose = purpose; + } + public int getStopPurposeIndex() + { + return stopPurposeIndex; + } + + public int getMode() + { + return mode; + } + public int getSet() + { + return set; + } + + public int getBoardTap() + { + return boardTap; + } + + public int getAlightTap() + { + return alightTap; + } + + public int getStopPeriod() + { + return stopPeriod; + } + + public Tour getTour() + { + return parentTour; + } + + public boolean isInboundStop() + { + return inbound; + } + + public int getStopId() + { + return id; + } + + public int getEscorteePnumOrig() { + return escorteePnumOrig; + } + + public void setEscorteePnumOrig(int escorteePnum) { + this.escorteePnumOrig = escorteePnum; + } + + public byte getEscortStopTypeOrig() { + return escortStopTypeOrig; + } + + public void setEscortStopTypeOrig(byte stopType) { + this.escortStopTypeOrig = stopType; + } + + public int getEscorteePnumDest() { + return escorteePnumDest; + } + + public void setEscorteePnumDest(int escorteePnum) { + this.escorteePnumDest = escorteePnum; + } + + public byte getEscortStopTypeDest() { + return escortStopTypeDest; + } + + public void setEscortStopTypeDest(byte stopType) { + this.escortStopTypeDest = stopType; + } + + public float getModeLogsum() { + return modeLogsum; + } + + public void setModeLogsum(float modeLogsum) { + this.modeLogsum = modeLogsum; + } + public double getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(double valueOfTime) { + this.valueOfTime = valueOfTime; + } + + public void setMicromobilityWalkMode(byte micromobilityWalkMode) { + this.micromobilityWalkMode=micromobilityWalkMode; + } + + public byte getMicromobilityWalkMode() { + return micromobilityWalkMode; + } + public float getMicromobilityWalkLogsum() { + return micromobilityWalkLogsum; + } + + public void setMicromobilityWalkLogsum(float micromobilityWalkLogsum) { + this.micromobilityWalkLogsum = micromobilityWalkLogsum; + } + + public byte getMicromobilityAccessMode() { + return micromobilityAccessMode; + } + + public void setMicromobilityAccessMode(byte micromobilityAccessMode) { + this.micromobilityAccessMode = micromobilityAccessMode; + } + + public byte getMicromobilityEgressMode() { + return micromobilityEgressMode; + } + + public void setMicromobilityEgressMode(byte micromobilityEgressMode) { + this.micromobilityEgressMode = micromobilityEgressMode; + } + + public float getMicromobilityAccessLogsum() { + return micromobilityAccessLogsum; + } + + public void setMicromobilityAccessLogsum(float micromobilityAccessLogsum) { + this.micromobilityAccessLogsum = micromobilityAccessLogsum; + } + + public float getMicromobilityEgressLogsum() { + return micromobilityEgressLogsum; + } + + public void setMicromobilityEgressLogsum(float micromobilityEgressLogsum) { + this.micromobilityEgressLogsum = micromobilityEgressLogsum; + } + + public float getParkingCost() { + return parkingCost; + } + + public void setParkingCost(float parkingCost) { + this.parkingCost = parkingCost; + } + + public void logStopObject(Logger logger, int totalChars) + { + + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "-"; + + Household.logHelper(logger, "stopId: ", id, totalChars); + Household.logHelper(logger, "origPurpose: ", origPurpose, totalChars); + Household.logHelper(logger, "destPurpose: ", destPurpose, totalChars); + Household.logHelper(logger, "orig: ", orig, totalChars); + Household.logHelper(logger, "dest: ", dest, totalChars); + Household.logHelper(logger, "mode: ", mode, totalChars); + Household.logHelper(logger, "value of time: ", ((float)valueOfTime), totalChars); + Household.logHelper(logger, "boardTap: ", boardTap, totalChars); + Household.logHelper(logger, "alightTap: ", alightTap, totalChars); + Household.logHelper(logger, "TapSet: ", set, totalChars); + Household.logHelper(logger, "direction: ", inbound ? "inbound" : "outbound", totalChars); + Household.logHelper( logger, "stopPeriod: ", stopPeriod, totalChars ); + Household.logHelper( logger, "orig escort stop type: ",escortStopTypeOrig, totalChars); + Household.logHelper( logger, "orig escortee pnum: ",escorteePnumOrig, totalChars); + Household.logHelper( logger, "dest escort stop type: ",escortStopTypeDest, totalChars); + Household.logHelper( logger, "dest escortee pnum: ",escorteePnumDest, totalChars); + logger.info(separater); + logger.info(""); + logger.info(""); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDCSoaDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDCSoaDMU.java new file mode 100644 index 0000000..ab675da --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDCSoaDMU.java @@ -0,0 +1,167 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import com.pb.common.calculator.VariableTable; + +/** + * @author crf
+ * Started: Nov 14, 2008 3:32:58 PM + */ +public class StopDCSoaDMU + implements Serializable, VariableTable +{ + + protected HashMap methodIndexMap; + + protected int tourModeIndex; + protected int[] walkTransitAvailableAtMgra; + protected double origDestDistance; + protected double[] distancesFromOrigMgra; + protected double[] distancesToDestMgra; + protected double[] logSizeTerms; + protected ModelStructure modelStructure; + + public StopDCSoaDMU(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + } + + /** + * set the array of distance values from the origin MGRA of the stop to all + * MGRAs. + * + * @param distances + */ + public void setDistancesFromOrigMgra(double[] distances) + { + distancesFromOrigMgra = distances; + } + + /** + * set the array of distance values from all MGRAs to the final destination + * MGRA of the stop. + * + * @param distances + */ + public void setDistancesToDestMgra(double[] distances) + { + distancesToDestMgra = distances; + } + + /** + * set the OD distance value from the stop origin MGRA to the final + * destination MGRA of the stop. + * + * @param distances + */ + public void setOrigDestDistance(double distance) + { + origDestDistance = distance; + } + + /** + * set the tour mode index value for the tour of the stop being located + * + * @param tour + */ + public void setTourModeIndex(int index) + { + tourModeIndex = index; + } + + /** + * set the array of attributes for all MGRAs that says their is walk transit + * access for the indexed mgra + * + * @param tour + */ + public void setWalkTransitAvailable(int[] avail) + { + walkTransitAvailableAtMgra = avail; + } + + /** + * set the array of logged size terms for all MGRAs for the stop being + * located + * + * @param size + */ + public void setLnSlcSizeAlt(double[] size) + { + logSizeTerms = size; + } + + public double getOrigToMgraDistanceAlt(int alt) + { + return distancesFromOrigMgra[alt]; + } + + public double getMgraToDestDistanceAlt(int alt) + { + return distancesToDestMgra[alt]; + } + + public double getOdDistance() + { + return origDestDistance; + } + + public int getTourModeIsWalk() + { + boolean tourModeIsWalk = modelStructure.getTourModeIsWalk(tourModeIndex); + return tourModeIsWalk ? 1 : 0; + } + + public int getTourModeIsBike() + { + boolean tourModeIsBike = modelStructure.getTourModeIsBike(tourModeIndex); + return tourModeIsBike ? 1 : 0; + } + + public int getTourModeIsWalkTransit() + { + return (modelStructure.getTourModeIsWalkTransit(tourModeIndex) ? 1 : 0); + } + + public int getWalkTransitAvailableAlt(int alt) + { + return walkTransitAvailableAtMgra[alt]; + } + + public double getLnSlcSizeAlt(int alt) + { + return logSizeTerms[alt]; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDepartArrivePeriodModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDepartArrivePeriodModel.java new file mode 100644 index 0000000..3c1e437 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDepartArrivePeriodModel.java @@ -0,0 +1,144 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class will be used for determining the number of stops on individual + * mandatory, individual non-mandatory and joint tours. + * + * @author Christi Willison + * @version Nov 4, 2008 + *

+ * Created by IntelliJ IDEA. + */ +public class StopDepartArrivePeriodModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(StopDepartArrivePeriodModel.class); + + private static final String PROPERTIES_STOP_TOD_LOOKUP_FILE = "stop.depart.arrive.proportions"; + + // define names used in lookup file + private static final String TOUR_PURPOSE_INDEX_COLUMN_HEADING = "tourpurp"; + private static final String HALF_TOUR_DIRECTION_COLUMN_HEADING = "isInbound"; + private static final String TOUR_TOD_PERIOD_HEADING = "interval"; + private static final String TRIP_NUMBER_COLUMN_HEADING = "trip"; + private static final String INTERVAL_1_PROPORTION_COLUMN_HEADING = "p1"; + + private static final int NUM_DIRECTIONS = 2; + private static final int NUM_TRIPS = 4; + + private double[][][][][] proportions; + + private ModelStructure modelStructure; + + /** + * Constructor + * + * @param propertyMap + * - properties HashMap + * @param modelStructure + * - model definitions helper class + */ + public StopDepartArrivePeriodModel(HashMap propertyMap, + ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + setupModels(propertyMap); + } + + private void setupModels(HashMap propertyMap) + { + + logger.info(String.format("setting up stop depart/arrive choice model.")); + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String propsFile = uecPath + propertyMap.get(PROPERTIES_STOP_TOD_LOOKUP_FILE); + + // read the stop purpose lookup table data and populate the maps used to + // assign stop purposes + readLookupProportions(propsFile); + + } + + private void readLookupProportions(String propsLookupFilename) + { + + // read the stop purpose proportions into a TableDataSet + TableDataSet propsLookupTable = null; + String fileName = ""; + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + propsLookupTable = reader.readFile(new File(propsLookupFilename)); + } catch (Exception e) + { + logger.error(String.format( + "Exception occurred reading stop purpose lookup proportions file: %s.", + fileName), e); + throw new RuntimeException(); + } + + // allocate an array for storing proportions arrays. + int lastInterval = modelStructure + .getTimePeriodIndexForTime(ModelStructure.LAST_TOD_INTERVAL_HOUR); + proportions = new double[ModelStructure.NUM_PRIMARY_PURPOSES + 1][NUM_DIRECTIONS][lastInterval + 1][NUM_TRIPS + 1][lastInterval + 1]; + + // fields in lookup file are: + // tourpurp isInbound interval trip p1-p40 (alternative interval + // proportions) + + // populate the outProportionsMaps and inProportionsMaps arrays of maps + // from data in the TableDataSet. + // when stops are generated, they can lookup the proportions for stop + // depart or arrive interval determined + // by tour purpose, outbound/inbound direction and interval of previous + // trip. From these proportions, + // a stop tod interval can be drawn. + + // loop over rows in the TableDataSet + for (int i = 0; i < propsLookupTable.getRowCount(); i++) + { + + // get the tour primary purpose index (1-10) + int tourPrimaryPurposeIndex = (int) propsLookupTable.getValueAt(i + 1, + TOUR_PURPOSE_INDEX_COLUMN_HEADING); + + // get the half tour direction (0 for outbound or 1 for inbound) + int direction = (int) propsLookupTable.getValueAt(i + 1, + HALF_TOUR_DIRECTION_COLUMN_HEADING); + + // get the tod interval (1-40) + int todInterval = (int) propsLookupTable.getValueAt(i + 1, TOUR_TOD_PERIOD_HEADING); + + // get the trip number (1-4) + int tripNumber = (int) propsLookupTable.getValueAt(i + 1, TRIP_NUMBER_COLUMN_HEADING); + + // get the index of the first alternative TOD interval proportion. + int firstPropColumn = propsLookupTable + .getColumnPosition(INTERVAL_1_PROPORTION_COLUMN_HEADING); + + // starting at this column, read the proportions for all TOD + // interval proportions. + // Create the array of proportions for this table record. + for (int j = 1; j <= lastInterval; j++) + proportions[tourPrimaryPurposeIndex][direction][todInterval][tripNumber][j] = propsLookupTable + .getValueAt(i + 1, firstPropColumn + j - 1); + + } + + } + + public double[] getStopTodIntervalProportions(int tourPrimaryPurposeIndex, int direction, + int prevTripTodInterval, int tripNumber) + { + return proportions[tourPrimaryPurposeIndex][direction][prevTripTodInterval][tripNumber]; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDestChoiceSize.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDestChoiceSize.java new file mode 100644 index 0000000..a09ac84 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopDestChoiceSize.java @@ -0,0 +1,214 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Map; +import java.util.Set; +import org.apache.log4j.Logger; +import com.pb.common.datafile.CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * @author crf
+ * Started: Nov 15, 2008 4:17:57 PM + */ +public class StopDestChoiceSize + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(StopDestChoiceSize.class); + + public static final String PROPERTIES_STOP_DC_SIZE_INPUT = "StopDestinationChoice.SizeCoefficients.InputFile"; + + private final Map>> sizeMap; // map + // of + // purpose,purpose + // segment, + // and + // zone/subzone + // to + // size + private final TazDataIf tazDataManager; + private final ModelStructure modelStructure; + private Map>> sizeCoefficients; + + public StopDestChoiceSize(HashMap propertyMap, TazDataIf tazDataManager, + ModelStructure modelStructure) + { + this.tazDataManager = tazDataManager; + this.modelStructure = modelStructure; + sizeMap = new HashMap>>(); + + String projectDirectory = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String coeffsFileName = propertyMap.get(PROPERTIES_STOP_DC_SIZE_INPUT); + coeffsFileName = projectDirectory + coeffsFileName; + + loadSizeData(coeffsFileName); + } + + public double getDcSize(String purpose, String purposeSegment, int zone, int subzone) + { + return sizeMap.get(purpose).get(purposeSegment).get(getZoneSubzoneMapping(zone, subzone)); + } + + private int getZoneSubzoneMapping(int zone, int subzone) + { + return zone * 10 + subzone; + } + + private void loadSizeData(String coeffsFileName) + { + loadSizeCoefficientTableInformation(readSizeCoefficientTable(coeffsFileName)); + determineSizeCoefficients(); + } + + private TableDataSet readSizeCoefficientTable(String coeffsFileName) + { + try + { + CSVFileReader reader = new CSVFileReader(); + return reader.readFile(new File(coeffsFileName)); + } catch (Exception e) + { + logger.fatal(String.format( + "Exception occurred reading DC Stop Size coefficients data file = %s.", + coeffsFileName), e); + throw new RuntimeException(); + } + } + + private Set getValidPurposes() + { + Set validPurposes = new HashSet(); + validPurposes.add(modelStructure.WORK_PURPOSE_NAME.toLowerCase()); + validPurposes.add(modelStructure.ESCORT_PURPOSE_NAME.toLowerCase()); + validPurposes.add(modelStructure.SHOPPING_PURPOSE_NAME.toLowerCase()); + validPurposes.add(modelStructure.EAT_OUT_PURPOSE_NAME.toLowerCase()); + validPurposes.add(modelStructure.OTH_MAINT_PURPOSE_NAME.toLowerCase()); + validPurposes.add(modelStructure.SOCIAL_PURPOSE_NAME.toLowerCase()); + validPurposes.add(modelStructure.OTH_DISCR_PURPOSE_NAME.toLowerCase()); + return validPurposes; + } + + private Set getValidSegments(String purpose) + { + Set validSegments = new HashSet(); + validSegments.add(purpose); + if (purpose.equals(modelStructure.ESCORT_PURPOSE_NAME.toLowerCase())) + for (String segment : modelStructure.ESCORT_SEGMENT_NAMES) + validSegments.add(segment.toLowerCase()); + return validSegments; + } + + private void loadSizeCoefficientTableInformation(TableDataSet coefficients) + { + Set sizeTazColumns = new HashSet(); + String[] coefficientTableColumns = coefficients.getColumnLabels(); + String purposeColumn = modelStructure.getDcSizeCoeffPurposeFieldName(); + String segmentColumn = modelStructure.getDcSizeCoeffSegmentFieldName(); + boolean foundPurposeColumn = false; + boolean foundSegmentColumn = false; + boolean errors = false; + for (String label : coefficientTableColumns) + { + if (label.equals(purposeColumn)) + { + foundPurposeColumn = true; + continue; + } + if (label.equals(segmentColumn)) + { + foundSegmentColumn = true; + continue; + } + + if (!tazDataManager.isValidZoneTableField(label)) + { + logger.fatal("Stop size coefficient table column does not correspond to taz data column: " + + label); + errors = true; + } + sizeTazColumns.add(label); + } + if (!foundPurposeColumn) + { + logger.fatal("Purpose column (" + purposeColumn + + ") not found in stop size coefficient table"); + errors = true; + } + if (!foundSegmentColumn) + { + logger.fatal("Purpose segment column (" + segmentColumn + + ") not found in stop size coefficient table"); + errors = true; + } + + if (!errors) + { + sizeCoefficients = new HashMap>>(); + Set validPurposes = getValidPurposes(); + for (int i = 1; i <= coefficients.getRowCount(); i++) + { + String purpose = coefficients.getStringValueAt(i, purposeColumn).toLowerCase(); + String segment = coefficients.getStringValueAt(i, segmentColumn).toLowerCase(); + if (validPurposes.contains(purpose)) + { + if (!sizeCoefficients.containsKey(purpose)) + sizeCoefficients.put(purpose, new HashMap>()); + if (getValidSegments(purpose).contains(segment)) + { + Map coefficientMap = new HashMap(); + for (String column : sizeTazColumns) + coefficientMap.put(column, (double) coefficients.getValueAt(i, column)); + sizeCoefficients.get(purpose).put(segment, coefficientMap); + } else + { + logger.fatal("Invalid segment for purpose " + purpose + + " found in stop destination choice size coefficient table: " + + segment); + errors = true; + } + + } else + { + logger.fatal("Invalid purpose found in stop destination choice size coefficient table: " + + purpose); + errors = true; + } + } + } + + if (errors) + { + throw new RuntimeException( + "Errors in stop destination choice size coefficient file; see log file for details."); + } + } + + private void determineSizeCoefficients() + { + sizeMap.clear(); + for (String purpose : sizeCoefficients.keySet()) + { + sizeMap.put(purpose, new HashMap>()); + for (String segment : sizeCoefficients.get(purpose).keySet()) + { + Map zoneSizeMap = new HashMap(); + for (int i = 1; i <= tazDataManager.getNumberOfZones(); i++) + { + double size = 0.0d; + Map coefficients = sizeCoefficients.get(purpose).get(segment); + for (String column : sizeCoefficients.get(purpose).get(segment).keySet()) + size += tazDataManager.getZoneTableValue(i, column) + * coefficients.get(column); + double[] walkPercentages = tazDataManager.getZonalWalkPercentagesForTaz(i); + for (int j = 0; j < tazDataManager.getNumberOfSubZones(); j++) + zoneSizeMap.put(getZoneSubzoneMapping(i, j), size * walkPercentages[j]); + } + sizeMap.get(purpose).put(segment, zoneSizeMap); + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopFrequencyDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopFrequencyDMU.java new file mode 100644 index 0000000..51403ef --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopFrequencyDMU.java @@ -0,0 +1,428 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + * This class is used for ... + * + * @author Christi Willison + * @version Nov 4, 2008 + *

+ * Created by IntelliJ IDEA. + */ +public abstract class StopFrequencyDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(StopFrequencyDMU.class); + + protected HashMap methodIndexMap; + + public static final int[] NUM_OB_STOPS_FOR_ALT = {-99999999, 0, 0, 0, 0, + 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3 }; + public static final int[] NUM_IB_STOPS_FOR_ALT = {-99999999, 0, 1, 2, 3, + 0, 1, 2, 3, 0, 1, 2, 3, 0, 1, 2, 3 }; + + public String STOP_PURPOSE_FILE_WORK_NAME = "Work"; + public String STOP_PURPOSE_FILE_UNIVERSITY_NAME = "University"; + public String STOP_PURPOSE_FILE_SCHOOL_NAME = "School"; + public String STOP_PURPOSE_FILE_ESCORT_NAME = "Escort"; + public String STOP_PURPOSE_FILE_SHOPPING_NAME = "Shopping"; + public String STOP_PURPOSE_FILE_MAINT_NAME = "Maint"; + public String STOP_PURPOSE_FILE_EAT_OUT_NAME = "EatOut"; + public String STOP_PURPOSE_FILE_VISIT_NAME = "Visit"; + public String STOP_PURPOSE_FILE_DISCR_NAME = "Discr"; + public String STOP_PURPOSE_FILE_WORK_BASED_NAME = "WorkBased"; + + protected IndexValues dmuIndex; + protected Household household; + protected Person person; + protected Tour tour; + + protected ModelStructure modelStructure; + + private double shoppingAccessibility; + private double maintenanceAccessibility; + private double discretionaryAccessibility; + + public StopFrequencyDMU(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + dmuIndex = new IndexValues(); + } + + public abstract HashMap getTourPurposeChoiceModelIndexMap(); + + public abstract int[] getModelSheetValuesArray(); + + public void setDmuIndexValues(int hhid, int homeTaz, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhid); + dmuIndex.setZoneIndex(homeTaz); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (household.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug SF UEC"); + } + + } + + public void setHouseholdObject(Household household) + { + this.household = household; + } + + public void setPersonObject(Person person) + { + this.person = person; + } + + public void setTourObject(Tour tour) + { + this.tour = tour; + } + + public int getTourIsJoint() + { + return tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY) ? 1 + : 0; + } + + public void setShoppingAccessibility(double shoppingAccessibility) + { + this.shoppingAccessibility = shoppingAccessibility; + } + + public void setMaintenanceAccessibility(double maintenanceAccessibility) + { + this.maintenanceAccessibility = maintenanceAccessibility; + } + + public void setDiscretionaryAccessibility(double discretionaryAccessibility) + { + this.discretionaryAccessibility = discretionaryAccessibility; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the household income in dollars + */ + public int getIncomeInDollars() + { + return household.getIncomeInDollars(); + } + + /** + * @return the number of full time workers in the household + */ + public int getNumFtWorkers() + { + return household.getNumFtWorkers(); + } + + /** + * @return the number of part time workers in the household + */ + public int getNumPtWorkers() + { + return household.getNumPtWorkers(); + } + + /** + * @return the person type index for the person making the tour + */ + public int getPersonType() + { + return person.getPersonTypeNumber(); + } + + /** + * @return the number of persons in the household + */ + public int getHhSize() + { + return household.getHhSize(); + } + + /** + * @return the number of driving age students in the household + */ + public int getNumHhDrivingStudents() + { + return household.getNumDrivingStudents(); + } + + /** + * @return the number of non-driving age students in the household + */ + public int getNumHhNonDrivingStudents() + { + return household.getNumNonDrivingStudents(); + } + + /** + * @return the number of preschool age students in the household + */ + public int getNumHhPreschool() + { + return household.getNumPreschool(); + } + + /** + * @return the number of work tours made by this person + */ + public int getWorkTours() + { + return person.getNumWorkTours(); + } + + /** + * + * @return 1 if the outbound portion of the tour is escort, in which case stops are already determined, else 0 + */ + public int getOutboundIsEscort(){ + + return ((tour.getEscortTypeOutbound() == ModelStructure.RIDE_SHARING_TYPE) ||(tour.getEscortTypeOutbound() == ModelStructure.PURE_ESCORTING_TYPE)) + ? 1 : 0; + } + + /** + * + * @return 1 if the inbound portion of the tour is escort, in which case stops are already determined, else 0 + */ + public int getInboundIsEscort(){ + + return ((tour.getEscortTypeInbound() == ModelStructure.RIDE_SHARING_TYPE) ||(tour.getEscortTypeInbound() == ModelStructure.PURE_ESCORTING_TYPE)) + ? 1 : 0; + } + + /** + * @return the total number of tours made by this person + */ + public int getTotalTours() + { + return person.getNumTotalIndivTours(); + } + + /** + * @return the total number of tours made by this person + */ + public int getTotalHouseholdTours() + { + return household.getNumTotalIndivTours(); + } + + /** + * @return the distance from the home mgra to the work mgra for this person + */ + public double getWorkLocationDistance() + { + return person.getWorkLocationDistance(); + } + + /** + * @return the distance from the home mgra to the school mgra for this + * person + */ + public double getSchoolLocationDistance() + { + return person.getSchoolLocationDistance(); + } + + /** + * @return the age of this person + */ + public int getAge() + { + return person.getAge(); + } + + /** + * @return the number of school tours made by this person + */ + public int getSchoolTours() + { + return person.getNumSchoolTours(); + } + + /** + * @return the number of escort tours made by this person + */ + public int getEscortTours() + { + return person.getNumIndividualEscortTours(); + } + + /** + * @return the number of shopping tours made by this person + */ + public int getShoppingTours() + { + return person.getNumIndividualShoppingTours(); + } + + /** + * @return the number of maintenance tours made by this person + */ + public int getMaintenanceTours() + { + return person.getNumIndividualOthMaintTours(); + } + + /** + * @return the number of eating out tours made by this person + */ + public int getEatTours() + { + return person.getNumIndividualEatOutTours(); + } + + /** + * @return the number of visit tours made by this person + */ + public int getVisitTours() + { + return person.getNumIndividualSocialTours(); + } + + /** + * @return the number of discretionary tours made by this person + */ + public int getDiscretionaryTours() + { + return person.getNumIndividualOthDiscrTours(); + } + + /** + * @return the shopping accessibility for the household (alts 28-30) + */ + public double getShoppingAccessibility() + { + return shoppingAccessibility; + } + + /** + * @return the maintenance accessibility for the household (alts 31-33) + */ + public double getMaintenanceAccessibility() + { + return maintenanceAccessibility; + } + + /** + * @return the discretionary accessibility for the household (alts 40-42) + */ + public double getDiscretionaryAccessibility() + { + return discretionaryAccessibility; + } + + /** + * @return the number of inbound stops that correspond to the chosen stop + * frequency alternative + */ + public int getNumIbStopsAlt(int alt) + { + return NUM_IB_STOPS_FOR_ALT[alt]; + } + + /** + * @return the number of outbound stops that correspond to the chosen stop + * frequency alternative + */ + public int getNumObStopsAlt(int alt) + { + return NUM_OB_STOPS_FOR_ALT[alt]; + } + + /** + * get the tour duration, measured in hours + * + * @return duration of tour in hours - number of half-hour intervals - + * arrive period - depart period divided by 2. + */ + public float getTourDurationInHours() + { + return (tour.getTourArrivePeriod() - tour.getTourDepartPeriod()) / 2; + } + + public int getTourModeIsAuto() + { + return modelStructure.getTourModeIsSovOrHov(tour.getTourModeChoice()) ? 1 : 0; + } + + public int getTourModeIsTransit() + { + return modelStructure.getTourModeIsTransit(tour.getTourModeChoice()) ? 1 : 0; + } + + public int getTourModeIsNonMotorized() + { + return modelStructure.getTourModeIsNonMotorized(tour.getTourModeChoice()) ? 1 : 0; + } + + public int getTourModeIsSchoolBus() + { + return modelStructure.getTourModeIsSchoolBus(tour.getTourModeChoice()) ? 1 : 0; + } + + public int getTourDepartPeriod() + { + return tour.getTourDepartPeriod(); + } + + public int getTourArrivePeriod() + { + return tour.getTourArrivePeriod(); + } + + public int getTelecommuteFrequency() { + return person.getTelecommuteChoice(); + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopFrequencyModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopFrequencyModel.java new file mode 100644 index 0000000..a5778c5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopFrequencyModel.java @@ -0,0 +1,811 @@ +package org.sandag.abm.ctramp; + +import java.io.File; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Random; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; + +/** + * This class will be used for determining the number of stops on individual + * mandatory, individual non-mandatory and joint tours. + * + * @author Christi Willison + * @version Nov 4, 2008 + *

+ * Created by IntelliJ IDEA. + */ +public class StopFrequencyModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(StopFrequencyModel.class); + private transient Logger stopFreqLogger = Logger.getLogger("stopFreqLog"); + + private static final String PROPERTIES_UEC_STOP_FREQ = "stf.uec.file"; + private static final String PROPERTIES_STOP_PURPOSE_LOOKUP_FILE = "stf.purposeLookup.proportions"; + + private static String[] shopTypes = {"", + "shopSov0", "shopSov1", "shopSov2" }; + private static String[] maintTypes = {"", + "maintSov0", "maintSov1", "maintSov2" }; + private static String[] discrTypes = {"", + "discrSov0", "discrSov1", "discrSov2" }; + + private static final int UEC_DATA_PAGE = 0; + + // define names used in lookup file + private static final String TOUR_PRIMARY_PURPOSE_COLUMN_HEADING = "PrimPurp"; + private static final String HALF_TOUR_DIRECTION_COLUMN_HEADING = "Direction"; + private static final String TOUR_DEPARTURE_START_RANGE_COLUMN_HEADING = "DepartRangeStart"; + private static final String TOUR_DEPARTURE_END_RANGE_COLUMN_HEADING = "DepartRangeEnd"; + private static final String PERSON_TYPE_COLUMN_HEADING = "Ptype"; + + private static final String OUTBOUND_DIRECTION_NAME = "Outbound"; + private static final String INBOUND_DIRECTION_NAME = "Inbound"; + + private static final String FT_WORKER_PERSON_TYPE_NAME = "FT Worker"; + private static final String PT_WORKER_PERSON_TYPE_NAME = "PT Worker"; + private static final String UNIVERSITY_PERSON_TYPE_NAME = "University Student"; + private static final String NONWORKER_PERSON_TYPE_NAME = "Homemaker"; + private static final String RETIRED_PERSON_TYPE_NAME = "Retired"; + private static final String DRIVING_STUDENT_PERSON_TYPE_NAME = "Driving-age Child"; + private static final String NONDRIVING_STUDENT_PERSON_TYPE_NAME = "Pre-Driving Child"; + private static final String PRESCHOOL_PERSON_TYPE_NAME = "Preschool"; + private static final String ALL_PERSON_TYPE_NAME = "All"; + + private StopFrequencyDMU dmuObject; + private ChoiceModelApplication[] choiceModelApplication; + + HashMap tourPurposeModelIndexMap; + HashMap tourPrimaryPurposeIndexNameMap; + + private HashMap indexPurposeMap; + private HashMap[] outProportionsMaps; + private HashMap[] inProportionsMaps; + + private AccessibilitiesTable accTable; + private ModelStructure modelStructure; + private MgraDataManager mgraManager; + + /** + * Constructor that will be used to set up the ChoiceModelApplications for + * each type of tour + * + * @param projectDirectory + * - name of root level project directory + * @param resourceBundle + * - properties file with paths identified + * @param dmuObject + * - decision making unit for stop frequency + * @param tazDataManager + * - holds information about TAZs in the model. + */ + public StopFrequencyModel(HashMap propertyMap, CtrampDmuFactoryIf dmuFactory, + ModelStructure myModelStructure, AccessibilitiesTable myAccTable) + { + accTable = myAccTable; + modelStructure = myModelStructure; + setupModels(propertyMap, dmuFactory); + } + + private void setupModels(HashMap propertyMap, CtrampDmuFactoryIf dmuFactory) + { + + mgraManager = MgraDataManager.getInstance(propertyMap); + + logger.info(String.format("setting up stop frequency choice models.")); + + // String projectDirectory = propertyMap.get( + // CtrampApplication.PROPERTIES_PROJECT_DIRECTORY ); + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String stfUecFile = propertyMap.get(PROPERTIES_UEC_STOP_FREQ); + String uecFileName = uecPath + stfUecFile; + + dmuObject = dmuFactory.getStopFrequencyDMU(); + + tourPrimaryPurposeIndexNameMap = modelStructure.getIndexPrimaryPurposeNameMap(); + + tourPurposeModelIndexMap = dmuObject.getTourPurposeChoiceModelIndexMap(); + int[] modelSheetsArray = dmuObject.getModelSheetValuesArray(); + + // one choice model for each model sheet specified + choiceModelApplication = new ChoiceModelApplication[modelSheetsArray.length]; + for (int i = 0; i < modelSheetsArray.length; i++) + choiceModelApplication[i] = new ChoiceModelApplication(uecFileName, + modelSheetsArray[i], UEC_DATA_PAGE, propertyMap, (VariableTable) dmuObject); + + String purposeLookupFileName = uecPath + + propertyMap.get(PROPERTIES_STOP_PURPOSE_LOOKUP_FILE); + + // read the stop purpose lookup table data and populate the maps used to + // assign stop purposes + readPurposeLookupProportionsTable(purposeLookupFileName); + + } + + public void applyModel(Household household) + { + + int totalStops = 0; + int totalTours = 0; + + Logger modelLogger = stopFreqLogger; + if (household.getDebugChoiceModels()) + household.logHouseholdObject("Pre Stop Frequency Choice: HH=" + household.getHhId(), + stopFreqLogger); + + // get this household's person array + Person[] personArray = household.getPersons(); + + // set the household id, origin taz, hh taz, and debugFlag=false in the + // dmu + dmuObject.setHouseholdObject(household); + + // set the auto sufficiency dependent non-mandatory accessibility values + // for + // the household + int autoSufficiency = household.getAutoSufficiency(); + dmuObject.setShoppingAccessibility(accTable.getAggregateAccessibility( + shopTypes[autoSufficiency], household.getHhMgra())); + dmuObject.setMaintenanceAccessibility(accTable.getAggregateAccessibility( + maintTypes[autoSufficiency], household.getHhMgra())); + dmuObject.setDiscretionaryAccessibility(accTable.getAggregateAccessibility( + discrTypes[autoSufficiency], household.getHhMgra())); + + // process the joint tours for the household first + Tour[] jt = household.getJointTourArray(); + if (jt != null) + { + + List tourList = new ArrayList(); + for (Tour t : jt) + tourList.add(t); + + int tourCount = 0; + for (Tour tour : tourList) + { + + try + { + + //tour.clearStopModelResults(); + + int modelIndex = tourPurposeModelIndexMap + .get(tour.getTourPrimaryPurposeIndex()); + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + if (household.getDebugChoiceModels()) + { + choiceModelDescription = String + .format("Joint Tour Stop Frequency Choice Model:"); + decisionMakerLabel = String.format( + "HH=%d, TourType=%s, TourId=%d, TourPurpose=%s.", + household.getHhId(), tour.getTourCategory(), tour.getTourId(), + tour.getTourPurpose()); + choiceModelApplication[modelIndex].choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + modelLogger.info(" "); + loggingHeader = choiceModelDescription + " for " + decisionMakerLabel; + + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + } + + // set the tour object + dmuObject.setTourObject(tour); + + // set the tour orig/dest TAZs associated with the tour + // orig/dest MGRAs in the IndexValues object. + dmuObject.setDmuIndexValues(household.getHhId(), household.getHhTaz(), + mgraManager.getTaz(tour.getTourOrigMgra()), + mgraManager.getTaz(tour.getTourDestMgra())); + + // compute the utilities + float logsum = (float) choiceModelApplication[modelIndex].computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + tour.setStopFreqLogsum(logsum); + + // get the random number from the household + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, make choice. + int choice = -1; + if (choiceModelApplication[modelIndex].getAvailabilityCount() > 0) choice = choiceModelApplication[modelIndex] + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught applying joint tour stop frequency choice model for %s type tour: HHID=%d, tourCount=%d, randomCount=%f -- no avaialable stop frequency alternative to choose.", + tour.getTourCategory(), household.getHhId(), tourCount, + randomCount)); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = choiceModelApplication[modelIndex].getUtilities(); + double[] probabilities = choiceModelApplication[modelIndex] + .getProbabilities(); + String[] altNames = choiceModelApplication[modelIndex] + .getAlternativeNames(); + + // 0s-indexing + modelLogger.info(decisionMakerLabel); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("------------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < altNames.length; k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %15s", k + 1, altNames[k]); + modelLogger.info(String.format("%-20s%18.6e%18.6e%18.6e", altString, + utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %s", choice, altNames[choice - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + choiceModelApplication[modelIndex].logAlternativesInfo( + choiceModelDescription, decisionMakerLabel); + choiceModelApplication[modelIndex].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, choice); + + // write UEC calculation results to separate model + // specific log file + choiceModelApplication[modelIndex] + .logUECResults(modelLogger, loggingHeader); + } + + // save the chosen alternative and create and populate the + // arrays of inbound/outbound + // stops in the tour object + totalStops += setStopFreqChoice(tour, choice); + + totalTours++; + tourCount++; + + } catch (Exception e) + { + logger.error(String + .format("Exception caught processing joint tour stop frequency choice model for %s type tour: HHID=%d, tourCount=%d.", + tour.getTourCategory(), household.getHhId(), tourCount)); + throw new RuntimeException(e); + } + + } + + } + + // now loop through the person array (1-based), and process all tours + // for + // each person + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + + if (household.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", + household.getHhId(), person.getPersonNum(), person.getPersonType()); + household.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + // set the person + dmuObject.setPersonObject(person); + + List tourList = new ArrayList(); + + // apply stop frequency for all person tours + tourList.addAll(person.getListOfWorkTours()); + tourList.addAll(person.getListOfSchoolTours()); + tourList.addAll(person.getListOfIndividualNonMandatoryTours()); + tourList.addAll(person.getListOfAtWorkSubtours()); + + int tourCount = 0; + for (Tour tour : tourList) + { + + try + { + + //tour.clearStopModelResults(); + + int modelIndex = tourPurposeModelIndexMap + .get(tour.getTourPrimaryPurposeIndex()); + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + choiceModelDescription = String + .format("Individual Tour Stop Frequency Choice Model:"); + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, TourType=%s, TourId=%d, TourPurpose=%s, modelIndex=%d.", + household.getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourCategory(), + tour.getTourId(), tour.getTourPurpose(), modelIndex); + + choiceModelApplication[modelIndex].choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + loggingHeader = choiceModelDescription + " for " + decisionMakerLabel; + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + } + + // set the tour object + dmuObject.setTourObject(tour); + + // compute the utilities + dmuObject.setDmuIndexValues(household.getHhId(), household.getHhTaz(), + mgraManager.getTaz(tour.getTourOrigMgra()), + mgraManager.getTaz(tour.getTourDestMgra())); + + float logsum = (float) choiceModelApplication[modelIndex].computeUtilities(dmuObject, + dmuObject.getDmuIndexValues()); + tour.setStopFreqLogsum(logsum); + + // get the random number from the household + Random random = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = random.nextDouble(); + + // if the choice model has at least one available + // alternative, + // make choice. + int choice = -1; + if (choiceModelApplication[modelIndex].getAvailabilityCount() > 0) choice = choiceModelApplication[modelIndex] + .getChoiceResult(rn); + else + { + logger.error(String + .format("Exception caught applying Individual Tour stop frequency choice model for %s type tour: j=%d, HHID=%d, personNum=%d, tourCount=%d, randomCount=%f -- no avaialable stop frequency alternative to choose.", + tour.getTourCategory(), j, household.getHhId(), + person.getPersonNum(), tourCount, randomCount)); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = choiceModelApplication[modelIndex].getUtilities(); + double[] probabilities = choiceModelApplication[modelIndex] + .getProbabilities(); + String[] altNames = choiceModelApplication[modelIndex] + .getAlternativeNames(); // 0s-indexing + + modelLogger.info(decisionMakerLabel); + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("------------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < altNames.length; ++k) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %15s", k + 1, altNames[k]); + modelLogger.info(String.format("%-20s%18.6e%18.6e%18.6e", altString, + utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %s", choice, altNames[choice - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", + altString, rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug log file + choiceModelApplication[modelIndex].logAlternativesInfo( + choiceModelDescription, decisionMakerLabel); + choiceModelApplication[modelIndex].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, choice); + + // write UEC calculation results to separate model + // specific + // log file + choiceModelApplication[modelIndex] + .logUECResults(modelLogger, loggingHeader); + + } + + // choiceResultsFreq[choice][modelIndex]++; + + // save the chosen alternative and create and populate the + // arrays + // of inbound/outbound stops in the tour object + totalStops += setStopFreqChoice(tour, choice); + totalTours++; + + tourCount++; + + } catch (Exception e) + { + logger.error(String + .format("Exception caught processing Individual Tour stop frequency choice model for %s type tour: j=%d, HHID=%d, personNum=%d, tourCount=%d.", + tour.getTourCategory(), j, household.getHhId(), + person.getPersonNum(), tourCount)); + throw new RuntimeException(e); + } + + } + + } // j (person loop) + + household.setStfRandomCount(household.getHhRandomCount()); + + } + + private int setStopFreqChoice(Tour tour, int stopFreqChoice) + { + + tour.setStopFreqChoice(stopFreqChoice); + + // set argument values for method call to get stop purpose + Household hh = tour.getPersonObject().getHouseholdObject(); + int tourDepartPeriod = tour.getTourDepartPeriod(); + int tourArrivePeriod = tour.getTourArrivePeriod(); + + //log out tour details if invalid tour departure and arrival time periods are found + if(tourDepartPeriod==-1||tourArrivePeriod==-1) tour.logTourObject(logger, 100); + + int tourPrimaryPurposeIndex = tour.getTourPrimaryPurposeIndex(); + String tourPrimaryPurpose = tourPrimaryPurposeIndexNameMap.get(tourPrimaryPurposeIndex); + String personType = tour.getPersonObject().getPersonType(); + + int numObStops = dmuObject.getNumObStopsAlt(stopFreqChoice); + if ((numObStops > 0) && (tour.getEscortTypeOutbound()!=ModelStructure.RIDE_SHARING_TYPE) && (tour.getEscortTypeOutbound()!=ModelStructure.PURE_ESCORTING_TYPE)) + { + // get a stop purpose for each outbound stop generated, plus the + // stop at + // the primary destination + String[] obStopOrigPurposes = new String[numObStops + 1]; + String[] obStopDestPurposes = new String[numObStops + 1]; + int[] obStopPurposeIndices = new int[numObStops + 1]; + obStopOrigPurposes[0] = tour.getTourCategory().equalsIgnoreCase( + ModelStructure.AT_WORK_CATEGORY) ? "Work" : "Home"; + for (int i = 0; i < numObStops; i++) + { + if (i > 0) obStopOrigPurposes[i] = obStopDestPurposes[i - 1]; + obStopPurposeIndices[i] = getStopPurpose(hh, OUTBOUND_DIRECTION_NAME, + tourDepartPeriod, tourPrimaryPurpose, personType); + obStopDestPurposes[i] = indexPurposeMap.get(obStopPurposeIndices[i]); + } + obStopOrigPurposes[numObStops] = obStopDestPurposes[numObStops - 1]; + obStopDestPurposes[numObStops] = tourPrimaryPurpose; + // the last stop record is for the trip from stop to destination + + // pass in the array of stop purposes; length of array determines + // number + // of outbound stop objects created. + if (tour.getOutboundStops() != null) + { + Exception e = new RuntimeException(); + logger.error("outbound stops array for hhid=" + tour.getHhId() + ", person=" + + tour.getPersonObject().getPersonNum() + ", tour=" + tour.getTourId() + + ", purpose=" + tour.getTourPurpose(), e); + try + { + throw e; + } catch (Exception e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + tour.createOutboundStops(obStopOrigPurposes, obStopDestPurposes, obStopPurposeIndices); + } + + int numIbStops = dmuObject.getNumIbStopsAlt(stopFreqChoice); + if ((numIbStops > 0) && (tour.getEscortTypeInbound()!=ModelStructure.RIDE_SHARING_TYPE) && (tour.getEscortTypeInbound()!=ModelStructure.PURE_ESCORTING_TYPE)) + { + // get a stop purpose for each inbound stop generated + String[] ibStopOrigPurposes = new String[numIbStops + 1]; + String[] ibStopDestPurposes = new String[numIbStops + 1]; + int[] ibStopPurposeIndices = new int[numIbStops + 1]; + ibStopOrigPurposes[0] = tour.getTourPrimaryPurpose(); + for (int i = 0; i < numIbStops; i++) + { + if (i > 0) ibStopOrigPurposes[i] = ibStopDestPurposes[i - 1]; + ibStopPurposeIndices[i] = getStopPurpose(hh, INBOUND_DIRECTION_NAME, + tourArrivePeriod, tourPrimaryPurpose, personType); + ibStopDestPurposes[i] = indexPurposeMap.get(ibStopPurposeIndices[i]); + } + ibStopOrigPurposes[numIbStops] = ibStopDestPurposes[numIbStops - 1]; + ibStopDestPurposes[numIbStops] = tour.getTourCategory().equalsIgnoreCase( + ModelStructure.AT_WORK_CATEGORY) ? "Work" : "Home"; + // the last stop record is for the trip from stop to home or work + + // pass in the array of stop purposes; length of array determines + // number + // of inbound stop objects created. + if (tour.getInboundStops() != null) + { + Exception e = new RuntimeException(); + logger.error("inbound stops array for hhid=" + tour.getHhId() + ", person=" + + tour.getPersonObject().getPersonNum() + ", tour=" + tour.getTourId() + + ", purpose=" + tour.getTourPurpose(), e); + try + { + throw e; + } catch (Exception e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + } + + tour.createInboundStops(ibStopOrigPurposes, ibStopDestPurposes, ibStopPurposeIndices); + } + + return numObStops + numIbStops; + + } + + private void readPurposeLookupProportionsTable(String purposeLookupFilename) + { + + // read the stop purpose proportions into a TableDataSet + TableDataSet purposeLookupTable = null; + String fileName = ""; + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + purposeLookupTable = reader.readFile(new File(purposeLookupFilename)); + } catch (Exception e) + { + logger.error(String.format( + "Exception occurred reading stop purpose lookup proportions file: %s.", + fileName), e); + throw new RuntimeException(); + } + + // allocate a HashMap array for each direction, dimensioned to maximum + // departure hour, to map keys determined by combination of categories + // to + // proportions arrays. + int numDepartPeriods = modelStructure.getNumberOfTimePeriods(); + outProportionsMaps = new HashMap[numDepartPeriods + 1]; + inProportionsMaps = new HashMap[numDepartPeriods + 1]; + for (int i = 0; i <= numDepartPeriods; i++) + { + outProportionsMaps[i] = new HashMap(); + inProportionsMaps[i] = new HashMap(); + } + + // create a mapping between names used in lookup file and purpose names + // used + // in model + HashMap primaryPurposeMap = new HashMap(); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_WORK_NAME, + ModelStructure.WORK_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_UNIVERSITY_NAME, + ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_SCHOOL_NAME, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_ESCORT_NAME, + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_SHOPPING_NAME, + ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_EAT_OUT_NAME, + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_MAINT_NAME, + ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_VISIT_NAME, + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_DISCR_NAME, + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME); + primaryPurposeMap.put(dmuObject.STOP_PURPOSE_FILE_WORK_BASED_NAME, + ModelStructure.WORK_BASED_PRIMARY_PURPOSE_NAME); + + // create a mapping between stop purpose alternative indices selected + // from + // monte carlo process and stop purpose names used in model + // the indices are the order of the proportions columns in the table + indexPurposeMap = new HashMap(); + indexPurposeMap.put(1, "work related"); + indexPurposeMap.put(2, ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME); + indexPurposeMap.put(3, ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME); + indexPurposeMap.put(4, ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME); + indexPurposeMap.put(5, ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME); + indexPurposeMap.put(6, ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME); + indexPurposeMap.put(7, ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME); + indexPurposeMap.put(8, ModelStructure.VISITING_PRIMARY_PURPOSE_NAME); + indexPurposeMap.put(9, ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME); + + // create a mapping between names used in lookup file and person type + // names + // used in model + HashMap personTypeMap = new HashMap(); + personTypeMap.put(FT_WORKER_PERSON_TYPE_NAME, Person.PERSON_TYPE_FULL_TIME_WORKER_NAME); + personTypeMap.put(PT_WORKER_PERSON_TYPE_NAME, Person.PERSON_TYPE_PART_TIME_WORKER_NAME); + personTypeMap.put(UNIVERSITY_PERSON_TYPE_NAME, Person.PERSON_TYPE_UNIVERSITY_STUDENT_NAME); + personTypeMap.put(NONWORKER_PERSON_TYPE_NAME, Person.PERSON_TYPE_NON_WORKER_NAME); + personTypeMap.put(RETIRED_PERSON_TYPE_NAME, Person.PERSON_TYPE_RETIRED_NAME); + personTypeMap + .put(DRIVING_STUDENT_PERSON_TYPE_NAME, Person.PERSON_TYPE_STUDENT_DRIVING_NAME); + personTypeMap.put(NONDRIVING_STUDENT_PERSON_TYPE_NAME, + Person.PERSON_TYPE_STUDENT_NON_DRIVING_NAME); + personTypeMap.put(PRESCHOOL_PERSON_TYPE_NAME, Person.PERSON_TYPE_PRE_SCHOOL_CHILD_NAME); + personTypeMap.put(ALL_PERSON_TYPE_NAME, ALL_PERSON_TYPE_NAME); + + // fields in lookup file are: + // PrimPurp Direction DepartRangeStart DepartRangeEnd Ptype Work + // University + // School Escort Shop Maintenance Eating Out Visiting Discretionary + + // populate the outProportionsMaps and inProportionsMaps arrays of maps + // from + // data in the TableDataSet. + // when stops are generated, they can lookup the proportions for stop + // purpose + // selection from a map determined + // by tour purpose, person type, outbound/inbound direction and tour + // departure time. From these proportions, + // a stop purpose can be drawn. + + // loop over rows in the TableDataSet + for (int i = 0; i < purposeLookupTable.getRowCount(); i++) + { + + // get the tour primary purpose + String tourPrimPurp = primaryPurposeMap.get(purposeLookupTable.getStringValueAt(i + 1, + TOUR_PRIMARY_PURPOSE_COLUMN_HEADING)); + + // get the half tour direction + String direction = purposeLookupTable.getStringValueAt(i + 1, + HALF_TOUR_DIRECTION_COLUMN_HEADING); + + // get the beginning of the range of departure hours + int departPeriodRangeStart = (int) purposeLookupTable.getValueAt(i + 1, + TOUR_DEPARTURE_START_RANGE_COLUMN_HEADING); + + // get the end of the range of departure hours + int arriveperiodRangeEnd = (int) purposeLookupTable.getValueAt(i + 1, + TOUR_DEPARTURE_END_RANGE_COLUMN_HEADING); + + int startRange = modelStructure.getTimePeriodIndexForTime(departPeriodRangeStart); + int endRange = modelStructure.getTimePeriodIndexForTime(arriveperiodRangeEnd); + + // get the person type + String personType = personTypeMap.get(purposeLookupTable.getStringValueAt(i + 1, + PERSON_TYPE_COLUMN_HEADING)); + + // columns following person type are proportions by stop purpose. + // Get the + // index of the first stop purpose proportion. + int firstPropColumn = purposeLookupTable.getColumnPosition(PERSON_TYPE_COLUMN_HEADING) + 1; + + // starting at this column, read the proportions for all stop + // purposes. + // Create the array of proportions for this table record. + double[] props = new double[indexPurposeMap.size()]; + for (int j = 0; j < props.length; j++) + { + props[j] = purposeLookupTable.getValueAt(i + 1, firstPropColumn + j); + } + + // get a HashMap for the direction and each hour in the start/end + // range, + // and store the proportions in that map for the key. + // the key to use for any of these HashMaps is created consisting of + // "TourPrimPurp_PersonType" + // if the person type for the record is "All", a key is defined for + // each + // person type, and the proportions stored for each key. + if (personType.equalsIgnoreCase(ALL_PERSON_TYPE_NAME)) + { + for (String ptype : personTypeMap.values()) + { + String key = tourPrimPurp + "_" + ptype; + if (direction.equalsIgnoreCase(OUTBOUND_DIRECTION_NAME)) + { + for (int k = startRange; k <= endRange; k++) + { + outProportionsMaps[k].put(key, props); + } + } else if (direction.equalsIgnoreCase(INBOUND_DIRECTION_NAME)) + { + for (int k = startRange; k <= endRange; k++) + inProportionsMaps[k].put(key, props); + } + } + } else + { + String key = tourPrimPurp + "_" + personType; + if (direction.equalsIgnoreCase(OUTBOUND_DIRECTION_NAME)) + { + for (int k = startRange; k <= endRange; k++) + outProportionsMaps[k].put(key, props); + } else if (direction.equalsIgnoreCase(INBOUND_DIRECTION_NAME)) + { + for (int k = startRange; k <= endRange; k++) + inProportionsMaps[k].put(key, props); + } + } + + } + + } + + private int getStopPurpose(Household household, String halfTourDirection, int tourDepartPeriod, + String tourPrimaryPurpose, String personType) + { + + double[] props = null; + String key = tourPrimaryPurpose + "_" + personType; + + try + { + if (halfTourDirection.equalsIgnoreCase(OUTBOUND_DIRECTION_NAME)) props = outProportionsMaps[tourDepartPeriod] + .get(key); + else if (halfTourDirection.equalsIgnoreCase(INBOUND_DIRECTION_NAME)) + props = inProportionsMaps[tourDepartPeriod].get(key); + + double rn = household.getHhRandom().nextDouble(); + int choice = ChoiceModelApplication.getMonteCarloSelection(props, rn); + + return (choice + 1); + + } catch (Exception e) + { + logger.error("exception caught trying to determine stop purpose."); + logger.error("key=" + key + ", tourPrimaryPurpose=" + tourPrimaryPurpose + + ", personType=" + personType + ", halfTourDirection=" + halfTourDirection + + ", tourDepartPeriod=" + tourDepartPeriod); + throw new RuntimeException(); + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopLocationDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopLocationDMU.java new file mode 100644 index 0000000..180f181 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/StopLocationDMU.java @@ -0,0 +1,411 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + * This class is used for ... + * + * @author Christi Willison + * @version Nov 4, 2008 + *

+ * Created by IntelliJ IDEA. + */ +public class StopLocationDMU + implements Serializable, VariableTable +{ + + protected HashMap methodIndexMap; + + protected IndexValues dmuIndex; + protected Household household; + protected Person person; + protected Tour tour; + protected Stop stop; + protected ModelStructure modelStructure; + + protected int numberInSample; + protected int tourModeIndex; + protected double origDestDistance; + + // these arrays are dimensioned to the total number of location choice + // alternatives (number of MGRAs) + protected int[] walkTransitAvailableAtMgra; + protected double[] distancesFromOrigMgra; + protected double[] distancesFromTourOrigMgra; + protected double[] distancesToDestMgra; + protected double[] distancesToTourDestMgra; + protected double[] logSizeTerms; + + protected double[] bikeLogsumsFromOrigMgra; + protected double[] bikeLogsumsToDestMgra; + + + + // these arrays are dimensioned to the maximum number of alternatives in the + // sample + protected double[] mcLogsums; + protected double[] slcSoaCorrections; + protected int[] sampleArray; + + public StopLocationDMU(ModelStructure modelStructure) + { + dmuIndex = new IndexValues(); + + this.modelStructure = modelStructure; + } + + public void setDmuIndexValues(int hhid, int homeTaz, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhid); + dmuIndex.setZoneIndex(homeTaz); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (household.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug SL UEC"); + } + + } + + public void setStopObject(Stop myStop) + { + stop = myStop; + tour = stop.getTour(); + person = tour.getPersonObject(); + household = person.getHouseholdObject(); + } + + /** + * set the value for the number of unique alternatives in the sample. + * sampleArray can be indexed as i=1; i <= numberInSample. + * sampleArray.length - 1 is the maximum number of locations in the sample. + * + * @param num + * - number of unique alternatives in the sample. + */ + public void setNumberInSample(int num) + { + numberInSample = num; + } + + /** + * set the array of sample MGRA values from which the stop location MGRA + * will be selected. + * + * @param sample + * - the sample array of MGRA location choice alternatives. - use + * numberInSample as upperbound of relevant choices in sample + */ + public void setSampleOfAlternatives(int[] sample) + { + sampleArray = sample; + } + + public void setSlcSoaCorrections(double[] corrections) + { + slcSoaCorrections = corrections; + } + + public void setMcLogsums(double[] logsums) + { + mcLogsums = logsums; + } + + public void setLogSize(double[] size) + { + logSizeTerms = size; + } + + /** + * set the array of distance values from the origin MGRA of the stop to all + * MGRAs. + * + * @param distances + */ + public void setDistancesFromOrigMgra(double[] distances) + { + distancesFromOrigMgra = distances; + } + + /** + * set the array of distance values from the tour origin MGRA to all MGRAs. + * + * @param distances + */ + public void setDistancesFromTourOrigMgra(double[] distances) + { + distancesFromTourOrigMgra = distances; + } + + /** + * set the array of distance values from all MGRAs to the final destination + * MGRA of the stop. + * + * @param distances + */ + public void setDistancesToDestMgra(double[] distances) + { + distancesToDestMgra = distances; + } + + /** + * set the array of distance values from all MGRAs to the tour destination + * MGRA. + * + * @param distances + */ + public void setDistancesToTourDestMgra(double[] distances) + { + distancesToTourDestMgra = distances; + } + + /** + * @param bikeLogsumsFromOrigMgra the bikeLogsumsFromOrigMgra to set + */ + public void setBikeLogsumsFromOrigMgra(double[] bikeLogsumsFromOrigMgra) { + this.bikeLogsumsFromOrigMgra = bikeLogsumsFromOrigMgra; + } + + /** + * @param bikeLogsumsToDestMgra the bikeLogsumsToDestMgra to set + */ + public void setBikeLogsumsToDestMgra(double[] bikeLogsumsToDestMgra) { + this.bikeLogsumsToDestMgra = bikeLogsumsToDestMgra; + } + + /** + * set the OD distance value from the stop origin MGRA to the final + * destination MGRA of the stop. + * + * @param distances + */ + public void setOrigDestDistance(double distance) + { + origDestDistance = distance; + } + + /** + * set the tour mode index value for the tour of the stop being located + * + * @param tour + */ + public void setTourModeIndex(int index) + { + tourModeIndex = index; + } + + /** + * set the array of attributes for all MGRAs that says their is walk transit + * access for the indexed mgra + * + * @param tour + */ + public void setWalkTransitAvailable(int[] avail) + { + walkTransitAvailableAtMgra = avail; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getSampleMgraAlt(int alt) + { + return sampleArray[alt]; + } + + public double getSlcSoaCorrectionsAlt(int alt) + { + return slcSoaCorrections[alt]; + } + + public double getMcLogsumAlt(int alt) + { + return mcLogsums[alt]; + } + + /** + * get the logged size term from the full set of size terms for all mgra + * associated with the sample alternative + * + * @param alt + * - element number for the sample array + * @return logged size term for mgra associated with the sample element + */ + public double getLnSlcSizeSampleAlt(int alt) + { + int mgra = sampleArray[alt]; + return logSizeTerms[mgra]; + } + + /** + * get the logged size term ffrom the full set of size terms for all mgra + * alternatives + * + * @param mgra + * - mgra location alternive + * @return logged size term for mgra + */ + public double getLnSlcSizeAlt(int mgra) + { + return logSizeTerms[mgra]; + } + + protected int getTourIsJoint() + { + return tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY) ? 1 + : 0; + } + + public int getTourMode() + { + return tour.getTourModeChoice(); + } + + public int getTourPurpose() + { + return tour.getTourPrimaryPurposeIndex(); + } + + public int getFemale() + { + return person.getPersonIsFemale(); + } + + public int getIncomeInDollars() + { + return household.getIncomeInDollars(); + } + + public int getAge() + { + return person.getAge(); + } + + public int getStopPurpose() + { + return stop.getStopPurposeIndex(); + } + + public int getStopNumber() + { + return (stop.getStopId() + 1); + } + + public int getInboundStop() + { + return stop.isInboundStop() ? 1 : 0; + } + + public int getStopsOnHalfTour() + { + return stop.isInboundStop() ? tour.getInboundStops().length + : tour.getOutboundStops().length; + } + + public double getOrigToMgraDistanceAlt(int alt) + { + // int dummy=0; + // double dist = Math.abs(distancesFromOrigMgra[alt] - + // distancesToDestMgra[alt]); + // double maxSegDist = Math.max(distancesFromOrigMgra[alt], + // distancesToDestMgra[alt]); + // if ( dist > 0 && dist < 1 && origDestDistance > 40 ) + // dummy = 1; + + return distancesFromOrigMgra[alt]; + } + + public double getTourOrigToMgraDistanceAlt(int alt) + { + return distancesFromTourOrigMgra[alt]; + } + + public double getMgraToDestDistanceAlt(int alt) + { + return distancesToDestMgra[alt]; + } + + public double getMgraToTourDestDistanceAlt(int alt) + { + return distancesToTourDestMgra[alt]; + } + + public double getOrigToMgraBikeLogsumAlt(int alt) + { + return bikeLogsumsFromOrigMgra[alt]; + } + + public double getMgraToDestBikeLogsumAlt(int alt) + { + return bikeLogsumsToDestMgra[alt]; + } + + + + public double getOdDistance() + { + return origDestDistance; + } + + public int getTourModeIsWalk() + { + boolean tourModeIsWalk = modelStructure.getTourModeIsWalk(tourModeIndex); + return tourModeIsWalk ? 1 : 0; + } + + public int getTourModeIsBike() + { + boolean tourModeIsBike = modelStructure.getTourModeIsBike(tourModeIndex); + return tourModeIsBike ? 1 : 0; + } + + public int getTourModeIsWalkTransit() + { + return (modelStructure.getTourModeIsWalkTransit(tourModeIndex) ? 1 : 0); + } + + public int getWalkTransitAvailableAlt(int alt) + { + return walkTransitAvailableAtMgra[alt]; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SubtourDepartureAndDurationTime.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SubtourDepartureAndDurationTime.java new file mode 100644 index 0000000..736fd49 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SubtourDepartureAndDurationTime.java @@ -0,0 +1,956 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; + +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import org.sandag.abm.accessibilities.NonTransitUtilities; +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.ResourceUtil; + +/** + * Created by IntelliJ IDEA. User: Jim Date: Jul 11, 2008 Time: 9:25:30 AM To + * change this template use File | Settings | File Templates. + */ +public class SubtourDepartureAndDurationTime + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(SubtourDepartureAndDurationTime.class); + private transient Logger todLogger = Logger.getLogger("todLogger"); + private transient Logger tourMCNonManLogger = Logger.getLogger("tourMcNonMan"); + + private static final String TOD_UEC_FILE_TARGET = "departTime.uec.file"; + private static final String TOD_UEC_DATA_TARGET = "departTime.data.page"; + private static final String TOD_UEC_AT_WORK_MODEL_TARGET = "departTime.atwork.page"; + + private static String[] tourPurposeNames; + + private int[] todModelIndices; + private HashMap purposeNameIndexMap; + + private static final String[] DC_MODEL_SHEET_KEYS = { + TOD_UEC_AT_WORK_MODEL_TARGET, TOD_UEC_AT_WORK_MODEL_TARGET, + TOD_UEC_AT_WORK_MODEL_TARGET }; + + private int[] tourDepartureTimeChoiceSample; + + // DMU for the UEC + private TourDepartureTimeAndDurationDMU todDmuObject; + private TourModeChoiceDMU mcDmuObject; + + // model structure to compare the .properties time of day with the UECs + private ModelStructure modelStructure; + + private TazDataManager tazs; + private MgraDataManager mgraManager; + + // private double[][] dcSizeArray; + + private ChoiceModelApplication[] todModels; + private TourModeChoiceModel mcModel; + + private int[] altStarts; + private int[] altEnds; + + private boolean[] needToComputeLogsum; + private double[] modeChoiceLogsums; + + private short[] tempWindow; + + // create an array to count the subtours propcessed within work tours + // there are at most 2 work tours per person + private int[] subtourNumForWorkTours = new int[2]; + + private int noAltChoice = 1; + + private long mcTime; + + public SubtourDepartureAndDurationTime(HashMap propertyMap, + ModelStructure modelStructure, CtrampDmuFactoryIf dmuFactory, + TourModeChoiceModel mcModel) + { + + // set the model structure + this.modelStructure = modelStructure; + this.mcModel = mcModel; + + logger.info(String.format("setting up %s time-of-day choice model.", + ModelStructure.AT_WORK_CATEGORY)); + + setupTodChoiceModels(propertyMap, dmuFactory); + } + + private void setupTodChoiceModels(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + + tazs = TazDataManager.getInstance(); + mgraManager = MgraDataManager.getInstance(); + + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + + String todUecFileName = propertyMap.get(TOD_UEC_FILE_TARGET); + todUecFileName = uecFileDirectory + todUecFileName; + + todDmuObject = dmuFactory.getTourDepartureTimeAndDurationDMU(); + + mcDmuObject = dmuFactory.getModeChoiceDMU(); + + int numLogsumIndices = modelStructure.getSkimPeriodCombinationIndices().length; + needToComputeLogsum = new boolean[numLogsumIndices]; + modeChoiceLogsums = new double[numLogsumIndices]; + + tourPurposeNames = new String[3]; + tourPurposeNames[0] = modelStructure.AT_WORK_BUSINESS_PURPOSE_NAME; + tourPurposeNames[1] = modelStructure.AT_WORK_EAT_PURPOSE_NAME; + tourPurposeNames[2] = modelStructure.AT_WORK_MAINT_PURPOSE_NAME; + + // create the array of tod model indices + int[] uecSheetIndices = new int[tourPurposeNames.length]; + + purposeNameIndexMap = new HashMap(tourPurposeNames.length); + + int i = 0; + for (String purposeName : tourPurposeNames) + { + int uecIndex = Util.getIntegerValueFromPropertyMap(propertyMap, DC_MODEL_SHEET_KEYS[i]); + purposeNameIndexMap.put(purposeName, i); + uecSheetIndices[i] = uecIndex; + i++; + } + + // create a lookup array to map purpose index to model index + todModelIndices = new int[uecSheetIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int todModelIndex = 0; + int todSegmentIndex = 0; + for (int uecIndex : uecSheetIndices) + { + // if the uec sheet for the model segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, todModelIndex); + todModelIndices[todSegmentIndex] = todModelIndex++; + } else + { + todModelIndices[todSegmentIndex] = modelIndexMap.get(uecIndex); + } + + todSegmentIndex++; + } + + todModels = new ChoiceModelApplication[modelIndexMap.size()]; + int todModelDataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, + TOD_UEC_DATA_TARGET); + + for (int uecIndex : modelIndexMap.keySet()) + { + int modelIndex = modelIndexMap.get(uecIndex); + try + { + todModels[modelIndex] = new ChoiceModelApplication(todUecFileName, uecIndex, + todModelDataSheet, propertyMap, (VariableTable) todDmuObject); + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught setting up At-work Subtour TOD ChoiceModelApplication[%d] for model index=%d of %d models", + i, i, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + + // get the alternatives table from the work tod UEC. + TableDataSet altsTable = todModels[0].getUEC().getAlternativeData(); + + altStarts = altsTable.getColumnAsInt(CtrampApplication.START_FIELD_NAME); + altEnds = altsTable.getColumnAsInt(CtrampApplication.END_FIELD_NAME); + todDmuObject.setTodAlts(altStarts, altEnds); + + int numDepartureTimeChoiceAlternatives = todModels[0].getNumberOfAlternatives(); + tourDepartureTimeChoiceSample = new int[numDepartureTimeChoiceAlternatives + 1]; + Arrays.fill(tourDepartureTimeChoiceSample, 1); + + tempWindow = new short[modelStructure.getNumberOfTimePeriods() + 1]; + + } + + public void applyModel(Household hh, boolean runModeChoice) + { + + mcTime = 0; + + Logger modelLogger = todLogger; + + // get the peron objects for this household + Person[] persons = hh.getPersons(); + for (int p = 1; p < persons.length; p++) + { + + Person person = persons[p]; + + // get the work tours for the person + ArrayList subtourList = person.getListOfAtWorkSubtours(); + + // if no work subtours for person, nothing to do. + if (subtourList.size() == 0) continue; + + ArrayList workTourList = person.getListOfWorkTours(); + int numWorkTours = workTourList.size(); + + // save a copy of this person's original time windows + short[] personWindow = person.getTimeWindows(); + for (int w = 0; w < personWindow.length; w++) + tempWindow[w] = personWindow[w]; + + for (int i = 0; i < subtourNumForWorkTours.length; i++) + subtourNumForWorkTours[i] = 0; + + int m = -1; + int tourPurpNum = 1; + int noWindowCountFirstTemp = 0; + int noWindowCountLastTemp = 0; + int noLaterAlternativeCountTemp = 0; + for (Tour t : subtourList) + { + + Tour workTour = null; + int workTourIndex = 0; + + try + { + + workTourIndex = t.getWorkTourIndexFromSubtourId(t.getTourId()); + subtourNumForWorkTours[workTourIndex]++; + workTour = workTourList.get(workTourIndex); + + // if the first subtour for a work tour, make window of work + // tour available, and other windows not available + if (subtourNumForWorkTours[workTourIndex] == 1) + { + person.resetTimeWindow(workTour.getTourDepartPeriod(), + workTour.getTourArrivePeriod()); + person.scheduleWindow(0, workTour.getTourDepartPeriod() - 1); + person.scheduleWindow(workTour.getTourArrivePeriod() + 1, + modelStructure.getNumberOfTimePeriods()); + } else if (subtourNumForWorkTours[workTourIndex] > 2) + { + logger.error("too many subtours for a work tour. workTourIndex=" + + workTourIndex + ", subtourNumForWorkTours[workTourIndex]" + + subtourNumForWorkTours[workTourIndex]); + logger.error("hhid=" + hh.getHhId() + ", persNum=" + person.getPersonNum()); + throw new RuntimeException(); + } + + // get the choice model for the tour purpose + String tourPurposeName = t.getSubTourPurpose(); + + int tourPurposeIndex = purposeNameIndexMap.get(tourPurposeName); + m = todModelIndices[tourPurposeIndex]; + + // write debug header + String separator = ""; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (hh.getDebugChoiceModels()) + { + + choiceModelDescription = String.format( + "AtWork Subtour Departure Time Choice Model for: Purpose=%s", + tourPurposeName); + decisionMakerLabel = String + .format("HH=%d, PersonNum=%d, PersonType=%s, tourId=%d, num=%d of %d %s tours", + hh.getHhId(), person.getPersonNum(), + person.getPersonType(), t.getTourId(), tourPurpNum, + subtourList.size(), tourPurposeName); + todModels[m].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + String loggerString = "AtWork Subtour Departure Time Choice Model: Debug Statement for Household ID: " + + hh.getHhId() + + ", Person Num: " + + person.getPersonNum() + + ", Person Type: " + + person.getPersonType() + + ", Tour Id: " + + t.getTourId() + + ", num " + + tourPurpNum + + " of " + + subtourList.size() + " " + tourPurposeName + " tours."; + for (int k = 0; k < loggerString.length(); k++) + separator += "+"; + modelLogger.info(loggerString); + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + loggingHeader = String.format("%s for %s", choiceModelDescription, + decisionMakerLabel); + + } + + // set the dmu object + todDmuObject.setHousehold(hh); + todDmuObject.setPerson(person); + todDmuObject.setTour(t); + + int otherTourEndHour = -1; + + // check for multiple tours for this person, by purpose + // set the first or second switch if multiple tours for + // person, by purpose + if (subtourList.size() == 1) + { + // not a multiple tour pattern + todDmuObject.setFirstTour(0); + todDmuObject.setSubsequentTour(0); + todDmuObject.setTourNumber(1); + todDmuObject.setEndOfPreviousScheduledTour(0); + } else if (subtourList.size() > 1) + { + // Two-plus tour multiple tour pattern + if (tourPurpNum == 1) + { + // first of 2+ tours + todDmuObject.setFirstTour(1); + todDmuObject.setSubsequentTour(0); + todDmuObject.setTourNumber(tourPurpNum); + todDmuObject.setEndOfPreviousScheduledTour(0); + } else + { + // 2nd or greater tours + todDmuObject.setFirstTour(0); + todDmuObject.setSubsequentTour(1); + todDmuObject.setTourNumber(tourPurpNum); + // the ArrayList is 0-based, and we want the + // previous tour, so subtract 2 from tourPurpNum to + // get the right index + otherTourEndHour = subtourList.get(tourPurpNum - 2) + .getTourArrivePeriod(); + todDmuObject.setEndOfPreviousScheduledTour(otherTourEndHour); + } + } + + // set the choice availability and sample + boolean[] departureTimeChoiceAvailability = person.getAvailableTimeWindows( + altStarts, altEnds); + Arrays.fill(tourDepartureTimeChoiceSample, 1); + + if (departureTimeChoiceAvailability.length != tourDepartureTimeChoiceSample.length) + { + logger.error(String + .format("error in at-work subtour departure time choice model for hhId=%d, personNum=%d, tour purpose index=%d, tour ArrayList index=%d.", + hh.getHhId(), person.getPersonNum(), tourPurposeIndex, + tourPurpNum - 1)); + logger.error(String + .format("length of the availability array determined by the number of alternatives set in the person scheduler=%d", + departureTimeChoiceAvailability.length)); + logger.error(String + .format("does not equal the length of the sample array determined by the number of alternatives in the at-work subtour UEC=%d.", + tourDepartureTimeChoiceSample.length)); + throw new RuntimeException(); + } + + // if no time window is available for the tour, make the + // first and last alternatives available + // for that alternative, and keep track of the number of + // times this condition occurs. + int alternativeAvailable = -1; + for (int a = 0; a < departureTimeChoiceAvailability.length; a++) + { + if (departureTimeChoiceAvailability[a]) + { + alternativeAvailable = a; + break; + } + } + + int chosen = -1; + int chosenStartPeriod = -1; + int chosenEndPeriod = -1; + + // alternate making the first and last periods chosen if no + // alternatives are available + if (alternativeAvailable < 0) + { + + if (noAltChoice == 1) + { + if (subtourList.size() > 1 && tourPurpNum > 1) + { + chosenStartPeriod = otherTourEndHour; + chosenEndPeriod = otherTourEndHour; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to previous sub-tour arrive period=" + + chosenStartPeriod + "."); + } else + { + chosenStartPeriod = workTour.getTourDepartPeriod(); + chosenEndPeriod = workTour.getTourDepartPeriod(); + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled and no previous sub-tour, depart AND arrive set to work tour depart period=" + + chosenStartPeriod + "."); + } + noWindowCountFirstTemp++; + noAltChoice = departureTimeChoiceAvailability.length - 1; + } else + { + if (subtourList.size() > 1 && tourPurpNum > 1) + { + chosenStartPeriod = otherTourEndHour; + chosenEndPeriod = otherTourEndHour; + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled, depart AND arrive set to previous sub-tour arrive period=" + + chosenStartPeriod + "."); + } else + { + chosenStartPeriod = workTour.getTourArrivePeriod(); + chosenEndPeriod = workTour.getTourArrivePeriod(); + if (hh.getDebugChoiceModels()) + modelLogger + .info("All alternatives already scheduled and no previous sub-tour, depart AND arrive set to work tour arrive period=" + + chosenStartPeriod + "."); + } + noWindowCountLastTemp++; + noAltChoice = 1; + } + + // schedule the chosen alternative + person.scheduleWindow(chosenStartPeriod, chosenEndPeriod); + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + + if (runModeChoice) + { + + long check = System.nanoTime(); + + if (hh.getDebugChoiceModels()) + hh.logHouseholdObject( + "Pre At-work Subtour Tour Mode Choice Household " + + hh.getHhId() + ", Tour " + tourPurpNum + " of " + + subtourList.size(), tourMCNonManLogger); + + // set the mode choice attributes needed by + // @variables in the UEC spreadsheets + setModeChoiceDmuAttributes(hh, person, t, chosenStartPeriod, + chosenEndPeriod); + + // use the mcModel object already setup for + // computing logsums and get + // the mode choice, where the selected + // worklocation and subzone an departure time and + // duration are set + // for this work tour. + int chosenMode = mcModel.getModeChoice(mcDmuObject, + t.getTourPrimaryPurpose()); + t.setTourModeChoice(chosenMode); + + mcTime += (System.nanoTime() - check); + + } + + } else + { + + // calculate and store the mode choice logsum for the + // usual work location for this worker at the various + // departure time and duration alternativees + setTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(t, + departureTimeChoiceAvailability); + + if (hh.getDebugChoiceModels()) + { + hh.logTourObject(loggingHeader, modelLogger, person, t); + } + + todDmuObject.setOriginZone(mgraManager.getTaz(t.getTourOrigMgra())); + todDmuObject.setDestinationZone(mgraManager.getTaz(t.getTourDestMgra())); + + float logsum = (float) todModels[m].computeUtilities(todDmuObject, todDmuObject.getIndexValues(), + departureTimeChoiceAvailability, tourDepartureTimeChoiceSample); + t.setTimeOfDayLogsum(logsum); + + Random hhRandom = hh.getHhRandom(); + int randomCount = hh.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available + // alternative, make choice. + if (todModels[m].getAvailabilityCount() > 0) + { + chosen = todModels[m].getChoiceResult(rn); + + // debug output + if (hh.getDebugChoiceModels()) + { + + double[] utilities = todModels[m].getUtilities(); + double[] probabilities = todModels[m].getProbabilities(); + boolean[] availabilities = todModels[m].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + + personTypeString + ", Tour Id: " + t.getTourId() + + ", Tour num: " + tourPurpNum + " of " + + subtourList.size() + " " + tourPurposeName + " tours."); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("-------------------- ------------ -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < todModels[m].getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d out=%-3d, in=%-3d", + k + 1, altStarts[k], altEnds[k]); + modelLogger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", + altString, availabilities[k + 1], utilities[k], + probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d out=%-3d, in=%-3d", chosen, + altStarts[chosen - 1], altEnds[chosen - 1]); + modelLogger.info(String.format( + "Choice: %s, with rn=%.8f, randomCount=%d", altString, rn, + randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to debug + // log file + todModels[m].logAlternativesInfo(choiceModelDescription, + decisionMakerLabel); + todModels[m].logSelectionInfo(choiceModelDescription, + decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate + // model specific log file + loggingHeader = String.format("%s for %s", choiceModelDescription, + decisionMakerLabel); + todModels[m].logUECResults(modelLogger, loggingHeader); + + } + + } else + { + + // since there were no alternatives with valid + // utility, assuming previous + // tour of this type scheduled up to the last + // period, so no periods left + // for this tour. + + // TODO: do a formal check for this so we can still + // flag other reasons why there's + // no valid utility for any alternative + chosen = departureTimeChoiceAvailability.length - 1; + noLaterAlternativeCountTemp++; + + } + + // schedule the chosen alternative + chosenStartPeriod = altStarts[chosen - 1]; + chosenEndPeriod = altEnds[chosen - 1]; + person.scheduleWindow(chosenStartPeriod, chosenEndPeriod); + t.setTourDepartPeriod(chosenStartPeriod); + t.setTourArrivePeriod(chosenEndPeriod); + + if (runModeChoice) + { + + if (hh.getDebugChoiceModels()) + hh.logHouseholdObject( + "Pre At-work Subtour Tour Mode Choice Household " + + hh.getHhId() + ", Tour " + tourPurpNum + " of " + + subtourList.size(), tourMCNonManLogger); + + // set the mode choice attributes needed by + // @variables in the UEC spreadsheets + setModeChoiceDmuAttributes(hh, person, t, chosenStartPeriod, + chosenEndPeriod); + + // use the mcModel object already setup for + // computing logsums and get + // the mode choice, where the selected + // worklocation and subzone an departure time and + // duration are set + // for this work tour. + int chosenMode = mcModel.getModeChoice(mcDmuObject, + t.getTourPrimaryPurpose()); + t.setTourModeChoice(chosenMode); + + } + + } + + } catch (Exception e) + { + String errorMessage = String + .format("Exception caught for HHID=%d, personNum=%d, At-work Subtour Departure time choice, tour ArrayList index=%d.", + hh.getHhId(), person.getPersonNum(), tourPurpNum - 1); + String decisionMakerLabel = String + .format("Final At-work Subtour Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + hh.getHhId(), person.getPersonNum(), person.getPersonType()); + hh.logPersonObject(decisionMakerLabel, modelLogger, person); + todModels[m].logUECResults(modelLogger, errorMessage); + + logger.error(errorMessage, e); + throw new RuntimeException(); + } + + tourPurpNum++; + + } + + for (int w = 0; w < person.getTimeWindows().length; w++) + person.getTimeWindows()[w] = tempWindow[w]; + + if (hh.getDebugChoiceModels()) + { + String decisionMakerLabel = String + .format("Final At-work Subtour Departure Time Person Object: HH=%d, PersonNum=%d, PersonType=%s", + hh.getHhId(), person.getPersonNum(), person.getPersonType()); + hh.logPersonObject(decisionMakerLabel, modelLogger, person); + } + + } + + hh.setAwtodRandomCount(hh.getHhRandomCount()); + + } + + private void setModeChoiceDmuAttributes(Household household, Person person, Tour t, + int startPeriod, int endPeriod) + { + + t.setTourDepartPeriod(startPeriod); + t.setTourArrivePeriod(endPeriod); + + int workTourIndex = t.getWorkTourIndexFromSubtourId(t.getTourId()); + Tour workTour = person.getListOfWorkTours().get(workTourIndex); + + // update the MC dmuObjects for this person + mcDmuObject.setHouseholdObject(household); + mcDmuObject.setPersonObject(person); + mcDmuObject.setTourObject(t); + mcDmuObject.setWorkTourObject(workTour); + mcDmuObject.setDmuIndexValues(household.getHhId(), household.getHhMgra(), + t.getTourOrigMgra(), t.getTourDestMgra(), household.getDebugChoiceModels()); + + + mcDmuObject.setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(t + .getTourOrigMgra()))); + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager.getTaz(t + .getTourDestMgra()))); + + mcDmuObject.setOriginMgra(t.getTourOrigMgra()); + mcDmuObject.setDestMgra(t.getTourDestMgra()); + + } + + private void setTourModeChoiceLogsumsForDepartureTimeAndDurationAlternatives(Tour tour, + boolean[] altAvailable) + { + + Person person = tour.getPersonObject(); + Household household = person.getHouseholdObject(); + + Arrays.fill(needToComputeLogsum, true); + Arrays.fill(modeChoiceLogsums, -999); + + Logger modelLogger = todLogger; + String choiceModelDescription = String.format( + "At-work Subtour Mode Choice Logsum calculation for %s Departure Time Choice", + tour.getTourPurpose()); + String decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d", household.getHhId(), person + .getPersonNum(), person.getPersonType(), tour.getTourId(), person + .getListOfWorkTours().size()); + String loggingHeader = String + .format("%s %s", choiceModelDescription, decisionMakerLabel); + + for (int a = 1; a <= altStarts.length; a++) + { + + // if the depart/arrive alternative is unavailable, no need to check + // to see if a logsum has been calculated + if (!altAvailable[a]) continue; + + int startPeriod = altStarts[a - 1]; + int endPeriod = altEnds[a - 1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + if (needToComputeLogsum[index]) + { + + String periodString = modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(startPeriod)) + + " to " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(endPeriod)); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, startPeriod, endPeriod); + + if (household.getDebugChoiceModels()) + household.logTourObject(loggingHeader + ", " + periodString, modelLogger, + person, mcDmuObject.getTourObject()); + + try + { + modeChoiceLogsums[index] = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel + ", " + + periodString); + } catch (Exception e) + { + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + periodString + " work tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + throw new RuntimeException(e); + } + needToComputeLogsum[index] = false; + } + + } + + todDmuObject.setModeChoiceLogsums(modeChoiceLogsums); + + mcDmuObject.getTourObject().setTourDepartPeriod(0); + mcDmuObject.getTourObject().setTourArrivePeriod(0); + } + + public long getModeChoiceTime() + { + return mcTime; + } + + public static void main(String[] args) + { + + // set values for these arguments so an object instance can be created + // and setup run to test integrity of UEC files before running full + // model. + HashMap propertyMap; + + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + ResourceBundle rb = ResourceBundle.getBundle(args[0]); + propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + } + + String matrixServerAddress = (String) propertyMap.get("RunModel.MatrixServerAddress"); + String matrixServerPort = (String) propertyMap.get("RunModel.MatrixServerPort"); + + MatrixDataServerIf ms = new MatrixDataServerRmi(matrixServerAddress, + Integer.parseInt(matrixServerPort), MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + + /* + */ + ModelStructure modelStructure = new SandagModelStructure(); + SandagCtrampDmuFactory dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + TazDataManager tazManager = TazDataManager.getInstance(propertyMap); + + BuildAccessibilities aggAcc = BuildAccessibilities.getInstance(); + if (!aggAcc.getAccessibilitiesAreBuilt()) + { + aggAcc.setupBuildAccessibilities(propertyMap, false); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateConstants(); + // aggAcc.buildAccessibilityComponents(propertyMap); + + boolean readAccessibilities = Util.getBooleanValueFromPropertyMap(propertyMap, + CtrampApplication.READ_ACCESSIBILITIES); + if (readAccessibilities) + { + + // output data + String projectDirectory = propertyMap + .get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file"); + + aggAcc.readAccessibilityTableFromFile(accFileName); + + } else + { + + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + } + + } + + double[][] expConstants = aggAcc.getExpConstants(); + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + + double[][][] sovExpUtilities = null; + double[][][] hovExpUtilities = null; + double[][][] nMotorExpUtilities = null; + double[][][] maasExpUtilities = null; + NonTransitUtilities ntUtilities = new NonTransitUtilities(propertyMap, sovExpUtilities, + hovExpUtilities, nMotorExpUtilities, maasExpUtilities); + + MandatoryAccessibilitiesCalculator mandAcc = new MandatoryAccessibilitiesCalculator( + propertyMap, ntUtilities, expConstants, logsumHelper.getBestTransitPathCalculator()); + + TourModeChoiceModel awmcModel = new TourModeChoiceModel(propertyMap, modelStructure, + ModelStructure.AT_WORK_CATEGORY, dmuFactory, logsumHelper); + + SubtourDestChoiceModel testObject = new SubtourDestChoiceModel(propertyMap, modelStructure, + aggAcc, dmuFactory, awmcModel); + System.out.println("SubtourDestChoiceModel object creation passed."); + + SubtourDepartureAndDurationTime testObject2 = new SubtourDepartureAndDurationTime( + propertyMap, modelStructure, dmuFactory, awmcModel); + System.out.println("SubtourDepartureAndDurationTime object creation passed."); + + // String hhHandlerAddress = (String) + // propertyMap.get("RunModel.HouseholdServerAddress"); + // int hhServerPort = Integer.parseInt((String) + // propertyMap.get("RunModel.HouseholdServerPort")); + // + // HouseholdDataManagerIf householdDataManager = new + // HouseholdDataManagerRmi(hhHandlerAddress, hhServerPort, + // SandagHouseholdDataManager.HH_DATA_SERVER_NAME); + // + // + // householdDataManager.setPropertyFileValues(propertyMap); + // + // // have the household data manager read the synthetic population + // // files and apply its tables to objects mapping method. + // boolean restartHhServer = false; + // try + // { + // // possible values for the following can be none, ao, cdap, imtf, + // // imtod, awf, awl, awtod, jtf, jtl, jtod, inmtf, inmtl, inmtod, + // // stf, stl + // String restartModel = (String) + // propertyMap.get("RunModel.RestartWithHhServer"); + // if (restartModel.equalsIgnoreCase("none")) restartHhServer = true; + // else if (restartModel.equalsIgnoreCase("uwsl") + // || restartModel.equalsIgnoreCase("ao") + // || restartModel.equalsIgnoreCase("fp") + // || restartModel.equalsIgnoreCase("cdap") + // || restartModel.equalsIgnoreCase("imtf") + // || restartModel.equalsIgnoreCase("imtod") + // || restartModel.equalsIgnoreCase("awf") + // || restartModel.equalsIgnoreCase("awl") + // || restartModel.equalsIgnoreCase("awtod") + // || restartModel.equalsIgnoreCase("jtf") + // || restartModel.equalsIgnoreCase("jtl") + // || restartModel.equalsIgnoreCase("jtod") + // || restartModel.equalsIgnoreCase("inmtf") + // || restartModel.equalsIgnoreCase("inmtl") + // || restartModel.equalsIgnoreCase("inmtod") + // || restartModel.equalsIgnoreCase("stf") + // || restartModel.equalsIgnoreCase("stl")) restartHhServer = false; + // } catch (MissingResourceException e) + // { + // restartHhServer = true; + // } + // + // if (restartHhServer) + // { + // + // householdDataManager.setDebugHhIdsFromHashmap(); + // + // String inputHouseholdFileName = (String) + // propertyMap.get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + // String inputPersonFileName = (String) + // propertyMap.get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + // householdDataManager.setHouseholdSampleRate( 1.0f, 0 ); + // householdDataManager.setupHouseholdDataManager(modelStructure, null, + // inputHouseholdFileName, inputPersonFileName); + // + // } else + // { + // + // householdDataManager.setHouseholdSampleRate( 1.0f, 0 ); + // householdDataManager.setDebugHhIdsFromHashmap(); + // householdDataManager.setTraceHouseholdSet(); + // + // } + + // int id = householdDataManager.getArrayIndex( 1033380 ); + // int id = householdDataManager.getArrayIndex( 1033331 ); + // int id = householdDataManager.getArrayIndex( 423804 ); + // Household[] hh = householdDataManager.getHhArray( id, id ); + // testObject.applyModel( hh[0] ); + // testObject2.applyModel( hh[0], true ); + + /** + * used this block of code to test for typos and implemented dmu + * methiods in the TOD choice UECs + * + * String uecFileDirectory = propertyMap.get( + * CtrampApplication.PROPERTIES_UEC_PATH ); String todUecFileName = + * propertyMap.get( TOD_UEC_FILE_TARGET ); todUecFileName = + * uecFileDirectory + todUecFileName; + * + * ModelStructure modelStructure = new SandagModelStructure(); + * SandagCtrampDmuFactory dmuFactory = new + * SandagCtrampDmuFactory(modelStructure); + * TourDepartureTimeAndDurationDMU todDmuObject = + * dmuFactory.getTourDepartureTimeAndDurationDMU(); + * + * File uecFile = new File(todUecFileName); UtilityExpressionCalculator + * uec = new UtilityExpressionCalculator(uecFile, 10, 0, propertyMap, + * (VariableTable) todDmuObject); + * System.out.println("Subtour departure and duration UEC passed"); + */ + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/SubtourDestChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SubtourDestChoiceModel.java new file mode 100644 index 0000000..1d44542 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/SubtourDestChoiceModel.java @@ -0,0 +1,1185 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.Random; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; + +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.accessibilities.MandatoryAccessibilitiesCalculator; +import org.sandag.abm.accessibilities.NonTransitUtilities; +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagHouseholdDataManager; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.VariableTable; +import com.pb.common.matrix.MatrixType; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.util.IndexSort; +import com.pb.common.util.ResourceUtil; + +public class SubtourDestChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(SubtourDestChoiceModel.class); + private transient Logger dcNonManLogger = Logger.getLogger("tourDcNonMan"); + private transient Logger todMcLogger = Logger.getLogger("todMcLogsum"); + + // TODO eventually remove this target + private static final String PROPERTIES_DC_UEC_FILE = "nmdc.uec.file"; + private static final String PROPERTIES_DC_UEC_FILE2 = "nmdc.uec.file2"; + private static final String PROPERTIES_DC_SOA_UEC_FILE = "nmdc.soa.uec.file"; + + private static final String USE_NEW_SOA_METHOD_PROPERTY_KEY = "nmdc.use.new.soa"; + + private static final String PROPERTIES_DC_SOA_NON_MAND_SAMPLE_SIZE_KEY = "nmdc.soa.SampleSize"; + + private static final String PROPERTIES_DC_DATA_SHEET = "nmdc.data.page"; + + private static final String PROPERTIES_DC_AT_WORK_MODEL_SHEET = "nmdc.atwork.model.page"; + + private static final String PROPERTIES_DC_SOA_AT_WORK_MODEL_SHEET = "nmdc.soa.atwork.model.page"; + + // size term array indices for purposes are 0-based + public static final int PROPERTIES_AT_WORK_BUSINESS_SIZE_SHEET = 11; + public static final int PROPERTIES_AT_WORK_EAT_OUT_SIZE_SHEET = 10; + public static final int PROPERTIES_AT_WORK_OTHER_SIZE_SHEET = 9; + + private static String[] tourPurposeNames; + private static int[] tourPurposeIndices; + + // all three subtour purposes use the same DC sheet + private static final String[] DC_MODEL_SHEET_KEYS = { + PROPERTIES_DC_AT_WORK_MODEL_SHEET, PROPERTIES_DC_AT_WORK_MODEL_SHEET, + PROPERTIES_DC_AT_WORK_MODEL_SHEET }; + + // all three subtour purposes use the same SOA sheet + private static final String[] DC_SOA_MODEL_SHEET_KEYS = { + PROPERTIES_DC_SOA_AT_WORK_MODEL_SHEET, PROPERTIES_DC_SOA_AT_WORK_MODEL_SHEET, + PROPERTIES_DC_SOA_AT_WORK_MODEL_SHEET }; + + // all three subtour purposes use the same SOA sheet + private final int[] sizeSheetKeys = { + PROPERTIES_AT_WORK_BUSINESS_SIZE_SHEET, PROPERTIES_AT_WORK_EAT_OUT_SIZE_SHEET, + PROPERTIES_AT_WORK_OTHER_SIZE_SHEET }; + + // set default depart periods that represents each model period + private static final int EA = 1; + private static final int AM = 8; + private static final int MD = 16; + private static final int PM = 26; + private static final int EV = 36; + + private static final int[][][] PERIOD_COMBINATIONS = { + { {AM, AM}, {MD, MD}, {PM, PM}}, { {AM, AM}, {MD, MD}, {PM, PM}}, + { {AM, AM}, {MD, MD}, {PM, PM}} }; + + private static final double[][] PERIOD_COMBINATION_COEFFICIENTS = { + {-3.1453, -0.1029, -2.9056}, {-3.1453, -0.1029, -2.9056}, {-3.1453, -0.1029, -2.9056}}; + + private String tourCategory; + private ModelStructure modelStructure; + + private int[] dcModelIndices; + private HashMap purposeNameIndexMap; + + private HashMap subtourSegmentNameIndexMap; + + private double[][] dcSizeArray; + + private TourModeChoiceDMU mcDmuObject; + private DestChoiceDMU dcDmuObject; + private DestChoiceTwoStageModelDMU dcDistSoaDmuObject; + private DcSoaDMU dcSoaDmuObject; + + private boolean[] needToComputeLogsum; + private double[] modeChoiceLogsums; + + private TourModeChoiceModel mcModel; + private DestinationSampleOfAlternativesModel dcSoaModel; + private ChoiceModelApplication[] dcModel; + private ChoiceModelApplication[] dcModel2; + + private boolean[] dcModel2AltsAvailable; + private int[] dcModel2AltsSample; + private int[] dcModel2SampleValues; + + private BuildAccessibilities aggAcc; + + private TazDataManager tazs; + private MgraDataManager mgraManager; + + private double[] mgraDistanceArray; + + private DestChoiceTwoStageModel dcSoaTwoStageObject; + + private boolean useNewSoaMethod; + + private int soaSampleSize; + + private long soaRunTime; + + public SubtourDestChoiceModel(HashMap propertyMap, + ModelStructure myModelStructure, BuildAccessibilities myAggAcc, + CtrampDmuFactoryIf dmuFactory, TourModeChoiceModel myMcModel) + { + + tourCategory = ModelStructure.AT_WORK_CATEGORY; + modelStructure = myModelStructure; + mcModel = myMcModel; + aggAcc = myAggAcc; + + tourPurposeIndices = new int[3]; + tourPurposeIndices[0] = modelStructure.AT_WORK_PURPOSE_INDEX_BUSINESS; + tourPurposeIndices[1] = modelStructure.AT_WORK_PURPOSE_INDEX_EAT; + tourPurposeIndices[2] = modelStructure.AT_WORK_PURPOSE_INDEX_MAINT; + + tourPurposeNames = new String[3]; + tourPurposeNames[0] = modelStructure.AT_WORK_BUSINESS_PURPOSE_NAME; + tourPurposeNames[1] = modelStructure.AT_WORK_EAT_PURPOSE_NAME; + tourPurposeNames[2] = modelStructure.AT_WORK_MAINT_PURPOSE_NAME; + + logger.info(String.format("creating %s subtour dest choice mode instance", tourCategory)); + + mgraManager = MgraDataManager.getInstance(); + tazs = TazDataManager.getInstance(); + + soaSampleSize = Util.getIntegerValueFromPropertyMap(propertyMap, + PROPERTIES_DC_SOA_NON_MAND_SAMPLE_SIZE_KEY); + + useNewSoaMethod = Util.getBooleanValueFromPropertyMap(propertyMap, + USE_NEW_SOA_METHOD_PROPERTY_KEY); + + if (useNewSoaMethod) + dcSoaTwoStageObject = new DestChoiceTwoStageModel(propertyMap, soaSampleSize); + + // create an array of ChoiceModelApplication objects for each choice + // purpose + setupDestChoiceModelArrays(propertyMap, dmuFactory); + + } + + private void setupDestChoiceModelArrays(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + + String dcUecFileName = propertyMap.get(PROPERTIES_DC_UEC_FILE); + dcUecFileName = uecFileDirectory + dcUecFileName; + + String dcUecFileName2 = propertyMap.get(PROPERTIES_DC_UEC_FILE2); + dcUecFileName2 = uecFileDirectory + dcUecFileName2; + + String soaUecFileName = propertyMap.get(PROPERTIES_DC_SOA_UEC_FILE); + soaUecFileName = uecFileDirectory + soaUecFileName; + + int dcModelDataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, + PROPERTIES_DC_DATA_SHEET); + int soaSampleSize = Util.getIntegerValueFromPropertyMap(propertyMap, + PROPERTIES_DC_SOA_NON_MAND_SAMPLE_SIZE_KEY); + + dcDmuObject = dmuFactory.getDestChoiceDMU(); + dcDmuObject.setAggAcc(aggAcc); + dcDmuObject.setAccTable(aggAcc.getAccessibilitiesTableObject()); + + if (useNewSoaMethod) + { + dcDistSoaDmuObject = dmuFactory.getDestChoiceSoaTwoStageDMU(); + dcDistSoaDmuObject.setAggAcc(aggAcc); + dcDistSoaDmuObject.setAccTable(aggAcc.getAccessibilitiesTableObject()); + } + + dcSoaDmuObject = dmuFactory.getDcSoaDMU(); + dcSoaDmuObject.setAggAcc(aggAcc); + + mcDmuObject = dmuFactory.getModeChoiceDMU(); + + int numLogsumIndices = modelStructure.getSkimPeriodCombinationIndices().length; + needToComputeLogsum = new boolean[numLogsumIndices]; + modeChoiceLogsums = new double[numLogsumIndices]; + + // create the arrays of dc model and soa model indices + int[] uecSheetIndices = new int[tourPurposeNames.length]; + int[] soaUecSheetIndices = new int[tourPurposeNames.length]; + + purposeNameIndexMap = new HashMap(tourPurposeNames.length); + + int i = 0; + for (String purposeName : tourPurposeNames) + { + int uecIndex = Util.getIntegerValueFromPropertyMap(propertyMap, DC_MODEL_SHEET_KEYS[i]); + int soaUecIndex = Util.getIntegerValueFromPropertyMap(propertyMap, + DC_SOA_MODEL_SHEET_KEYS[i]); + purposeNameIndexMap.put(purposeName, i); + uecSheetIndices[i] = uecIndex; + soaUecSheetIndices[i] = soaUecIndex; + i++; + } + + // create a lookup array to map purpose index to model index + dcModelIndices = new int[uecSheetIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int dcModelIndex = 0; + int dcSegmentIndex = 0; + for (int uecIndex : uecSheetIndices) + { + // if the uec sheet for the model segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, dcModelIndex); + dcModelIndices[dcSegmentIndex] = dcModelIndex++; + } else + { + dcModelIndices[dcSegmentIndex] = modelIndexMap.get(uecIndex); + } + + dcSegmentIndex++; + } + + // the size term array in aggAcc gives mgra*purpose - need an array of + // all mgras for one purpose + double[][] aggAccDcSizeArray = aggAcc.getSizeTerms(); + subtourSegmentNameIndexMap = new HashMap(); + for (int k = 0; k < tourPurposeIndices.length; k++) + { + subtourSegmentNameIndexMap.put(tourPurposeNames[k], k); + } + + dcSizeArray = new double[tourPurposeNames.length][aggAccDcSizeArray.length]; + for (i = 0; i < aggAccDcSizeArray.length; i++) + { + for (int m : subtourSegmentNameIndexMap.values()) + { + int s = sizeSheetKeys[m]; + dcSizeArray[m][i] = aggAccDcSizeArray[i][s]; + } + } + + // create a sample of alternatives choice model object for use in + // selecting a sample + // of all possible destination choice alternatives. + dcSoaModel = new DestinationSampleOfAlternativesModel(soaUecFileName, soaSampleSize, + propertyMap, mgraManager, dcSizeArray, dcSoaDmuObject, soaUecSheetIndices); + + dcModel = new ChoiceModelApplication[modelIndexMap.size()]; + + if (useNewSoaMethod) + { + dcModel2 = new ChoiceModelApplication[modelIndexMap.size()]; + dcModel2AltsAvailable = new boolean[soaSampleSize + 1]; + dcModel2AltsSample = new int[soaSampleSize + 1]; + dcModel2SampleValues = new int[soaSampleSize]; + } + + i = 0; + for (int uecIndex : modelIndexMap.keySet()) + { + + try + { + dcModel[i] = new ChoiceModelApplication(dcUecFileName, uecIndex, dcModelDataSheet, + propertyMap, (VariableTable) dcDmuObject); + + if (useNewSoaMethod) + { + dcModel2[i] = new ChoiceModelApplication(dcUecFileName2, uecIndex, + dcModelDataSheet, propertyMap, (VariableTable) dcDistSoaDmuObject); + } + + i++; + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught setting up ATWork DC ChoiceModelApplication[%d] for model index=%d of %d models", + i, i, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + + mgraDistanceArray = new double[mgraManager.getMaxMgra() + 1]; + + } + + public void applyModel(Household hh) + { + + soaRunTime = 0; + + if (useNewSoaMethod) dcSoaTwoStageObject.resetSoaRunTime(); + else dcSoaModel.resetSoaRunTime(); + + // declare these variables here so their values can be logged if a + // RuntimeException occurs. + int i = -1; + + Logger modelLogger = dcNonManLogger; + if (hh.getDebugChoiceModels()) + hh.logHouseholdObject("Pre Subtour Location Choice Household " + hh.getHhId() + + " Object", modelLogger); + + Person[] persons = hh.getPersons(); + + for (i = 1; i < persons.length; i++) + { + + Person p = persons[i]; + + // get the at-work subtours for this person and choose a destination + // for each. + ArrayList tourList = p.getListOfAtWorkSubtours(); + + int currentTourNum = 0; + for (Tour tour : tourList) + { + + Tour workTour = null; + int workTourIndex = 0; + workTourIndex = tour.getWorkTourIndexFromSubtourId(tour.getTourId()); + workTour = p.getListOfWorkTours().get(workTourIndex); + + int chosen = -1; + try + { + + int homeMgra = hh.getHhMgra(); + int homeTaz = hh.getHhTaz(); + int origMgra = workTour.getTourDestMgra(); + tour.setTourOrigMgra(origMgra); + + // update the MC dmuObject for this person + mcDmuObject.setHouseholdObject(hh); + mcDmuObject.setPersonObject(p); + mcDmuObject.setTourObject(tour); + mcDmuObject.setDmuIndexValues(hh.getHhId(), homeMgra, origMgra, 0, + hh.getDebugChoiceModels()); + mcDmuObject.setOriginMgra(origMgra); + + // update the DC dmuObject for this person + dcDmuObject.setHouseholdObject(hh); + dcDmuObject.setPersonObject(p); + dcDmuObject.setTourObject(tour); + dcDmuObject.setDmuIndexValues(hh.getHhId(), homeMgra, origMgra, 0); + + if (useNewSoaMethod) + { + dcDistSoaDmuObject.setHouseholdObject(hh); + dcDistSoaDmuObject.setPersonObject(p); + dcDistSoaDmuObject.setTourObject(tour); + dcDistSoaDmuObject.setDmuIndexValues(hh.getHhId(), homeTaz, origMgra, 0); + } + + // for At-work Subtour DC, just count remaining At-work + // Subtour tours + int toursLeftCount = tourList.size() - currentTourNum; + dcDmuObject.setToursLeftCount(toursLeftCount); + if (useNewSoaMethod) dcDistSoaDmuObject.setToursLeftCount(toursLeftCount); + + // get the tour location alternative chosen from the sample + if (useNewSoaMethod) + { + chosen = selectLocationFromTwoStageSampleOfAlternatives(tour, mcDmuObject); + soaRunTime += dcSoaTwoStageObject.getSoaRunTime(); + } else + { + chosen = selectLocationFromSampleOfAlternatives(tour, dcDmuObject, + dcSoaDmuObject, mcDmuObject); + soaRunTime += dcSoaModel.getSoaRunTime(); + } + + } catch (RuntimeException e) + { + logger.fatal(String + .format("exception caught selecting %s tour destination choice for hh.hhid=%d, personNum=%d, tourId=%d, purposeName=%s", + tourCategory, hh.getHhId(), p.getPersonNum(), tour.getTourId(), + tour.getSubTourPurpose())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + // set chosen values in tour object + tour.setTourDestMgra(chosen); + + currentTourNum++; + } + + } + + hh.setAwlRandomCount(hh.getHhRandomCount()); + + } + + /** + * + * @return chosen mgra. + */ + private int selectLocationFromSampleOfAlternatives(Tour tour, DestChoiceDMU dcDmuObject, + DcSoaDMU dcSoaDmuObject, TourModeChoiceDMU mcDmuObject) + { + + Logger modelLogger = dcNonManLogger; + + // get the Household object for the person making this subtour + Person person = tour.getPersonObject(); + + // get the Household object for the person making this subtour + Household household = person.getHouseholdObject(); + + // get the tour purpose name + String tourPurposeName = tour.getSubTourPurpose(); + int tourPurposeIndex = purposeNameIndexMap.get(tourPurposeName); + + dcSoaDmuObject.setDestChoiceSize(dcSizeArray[tourPurposeIndex]); + + // the originMgra in the tour object is already set to the work tour + // dest mgra + // double[] workMgraDistanceArray = + // mandAcc.calculateDistancesForAllMgras( tour.getTourOrigMgra() ); + mcModel.getAnmSkimCalculator().getOpSkimDistancesFromMgra(tour.getTourOrigMgra(), + mgraDistanceArray); + dcSoaDmuObject.setDestDistance(mgraDistanceArray); + + dcDmuObject.setDestChoiceSize(dcSizeArray[tourPurposeIndex]); + dcDmuObject.setDestChoiceDistance(mgraDistanceArray); + + // compute the sample of alternatives set for the person + dcSoaModel.computeDestinationSampleOfAlternatives(dcSoaDmuObject, tour, person, + tourPurposeName, tourPurposeIndex, tour.getTourOrigMgra()); + + // get sample of locations and correction factors for sample + int[] finalSample = dcSoaModel.getSampleOfAlternatives(); + float[] sampleCorrectionFactors = dcSoaModel.getSampleOfAlternativesCorrections(); + + int m = dcModelIndices[tourPurposeIndex]; + int numAlts = dcModel[m].getNumberOfAlternatives(); + + // set the destAltsAvailable array to true for all destination choice + // alternatives for each purpose + boolean[] destAltsAvailable = new boolean[numAlts + 1]; + for (int k = 0; k <= numAlts; k++) + destAltsAvailable[k] = false; + + // set the destAltsSample array to 1 for all destination choice + // alternatives + // for each purpose + int[] destAltsSample = new int[numAlts + 1]; + for (int k = 0; k <= numAlts; k++) + destAltsSample[k] = 0; + + int[] sampleValues = new int[finalSample.length]; + + // for the destinations and sub-zones in the sample, compute mc logsums + // and + // save in DC dmuObject. + // also save correction factor and set availability and sample value for + // the + // sample alternative to true. 1, respectively. + for (int i = 1; i < finalSample.length; i++) + { + + int destMgra = finalSample[i]; + sampleValues[i] = finalSample[i]; + + // set logsum value in DC dmuObject for the logsum index, sampled + // zone and subzone. + double logsum = calculateSimpleTODChoiceLogsum(person, tour, destMgra, i); + dcDmuObject.setMcLogsum(destMgra, logsum); + + // set sample of alternatives correction factor used in destination + // choice utility for the sampled alternative. + dcDmuObject.setDcSoaCorrections(destMgra, sampleCorrectionFactors[i]); + + // set availaibility and sample values for the purpose, dcAlt. + destAltsAvailable[finalSample[i]] = true; + destAltsSample[finalSample[i]] = 1; + + } + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format( + "At-work Subtour Location Choice Model for: tour purpose=%s", tourPurposeName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourId()); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("At-work Subtour Location Choice Model for tour purpose=" + + tourPurposeName + ", Person Num: " + person.getPersonNum() + + ", Person Type: " + person.getPersonType() + ", TourId=" + tour.getTourId()); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + dcModel[m].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + float logsum = (float) dcModel[m].computeUtilities(dcDmuObject, dcDmuObject.getDmuIndexValues(), + destAltsAvailable, destAltsSample); + + tour.setTourDestinationLogsum(logsum); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (dcModel[m].getAvailabilityCount() > 0) + { + try + { + chosen = dcModel[m].getChoiceResult(rn); + } catch (Exception e) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, in %s destination choice.", + dcDmuObject.getHouseholdObject().getHhId(), dcDmuObject + .getPersonObject().getPersonNum(), tour.getTourId(), + tourPurposeName)); + throw new RuntimeException(); + } + } + + // write choice model alternative info to log file + int selectedIndex = -1; + for (int j = 1; j < finalSample.length; j++) + { + if (finalSample[j] == chosen) + { + selectedIndex = j; + break; + } + } + + if (household.getDebugChoiceModels() || chosen <= 0) + { + + double[] utilities = dcModel[m].getUtilities(); + double[] probabilities = dcModel[m].getProbabilities(); + boolean[] availabilities = dcModel[m].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- -------------- -------------- -------------- --------------"); + + int[] sortedSampleValueIndices = IndexSort.indexSort(sampleValues); + + double cumProb = 0.0; + for (int j = 1; j < finalSample.length; j++) + { + int k = sortedSampleValueIndices[j]; + int alt = finalSample[k]; + + if (finalSample[k] == chosen) selectedIndex = j; + + cumProb += probabilities[alt - 1]; + String altString = String.format("j=%d, mgra=%d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[alt], utilities[alt - 1], probabilities[alt - 1], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("j=%d, mgra=%d", selectedIndex, chosen); + modelLogger.info(String.format("Choice: %s with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + dcModel[m].logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + dcModel[m].logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log file + dcModel[m].logUECResults(modelLogger, loggingHeader); + + if (chosen < 0) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, tourPurpose=%d, no available %s destination choice alternatives to choose from in ChoiceModelApplication.", + dcDmuObject.getHouseholdObject().getHhId(), dcDmuObject + .getPersonObject().getPersonNum(), tour.getTourId(), + tourPurposeName)); + throw new RuntimeException(); + } + + } + + return chosen; + + } + + /** + * + * @return chosen mgra. + */ + private int selectLocationFromTwoStageSampleOfAlternatives(Tour tour, + TourModeChoiceDMU mcDmuObject) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcNonManLogger; + + // get the Household object for the person making this non-mandatory + // tour + Person person = tour.getPersonObject(); + + // get the Household object for the person making this non-mandatory + // tour + Household household = person.getHouseholdObject(); + + // get the tour purpose name + String tourPurposeName = tour.getSubTourPurpose(); + int tourPurposeIndex = purposeNameIndexMap.get(tourPurposeName); + + // get sample of locations and correction factors for sample using the + // alternate method + // for non-mandatory tour destination choice, the sizeSegmentType INdex + // and sizeSegmentIndex are the same values. + dcSoaTwoStageObject.chooseSample(mgraManager.getTaz(tour.getTourOrigMgra()), + tourPurposeIndex, tourPurposeIndex, soaSampleSize, household.getHhRandom(), + household.getDebugChoiceModels()); + int[] finalSample = dcSoaTwoStageObject.getUniqueSampleMgras(); + double[] sampleCorrectionFactors = dcSoaTwoStageObject + .getUniqueSampleMgraCorrectionFactors(); + int numUniqueAlts = dcSoaTwoStageObject.getNumberofUniqueMgrasInSample(); + + int m = dcModelIndices[tourPurposeIndex]; + int numAlts = dcModel2[m].getNumberOfAlternatives(); + + Arrays.fill(dcModel2AltsAvailable, false); + Arrays.fill(dcModel2AltsSample, 0); + Arrays.fill(dcModel2SampleValues, 999999); + + mcModel.getAnmSkimCalculator().getOpSkimDistancesFromMgra(tour.getTourOrigMgra(), + mgraDistanceArray); + dcDistSoaDmuObject.setMgraDistanceArray(mgraDistanceArray); + + int sizeIndex = subtourSegmentNameIndexMap.get(tourPurposeName); + dcDistSoaDmuObject.setMgraSizeArray(dcSizeArray[sizeIndex]); + + // set sample of alternatives correction factors used in destination + // choice utility for the sampled alternatives. + dcDistSoaDmuObject.setDcSoaCorrections(sampleCorrectionFactors); + + // for the destination mgras in the sample, compute mc logsums and save + // in dmuObject. + // also save correction factor and set availability and sample value for + // the + // sample alternative to true. 1, respectively. + for (int i = 0; i < numUniqueAlts; i++) + { + + int destMgra = finalSample[i]; + dcModel2SampleValues[i] = finalSample[i]; + + // set logsum value in DC dmuObject for the logsum index, sampled + // zone and subzone. + double logsum = calculateSimpleTODChoiceLogsum(person, tour, destMgra, i); + dcDistSoaDmuObject.setMcLogsum(i, logsum); + + // set availaibility and sample values for the purpose, dcAlt. + dcModel2AltsAvailable[i + 1] = true; + dcModel2AltsSample[i + 1] = 1; + + } + + dcDistSoaDmuObject.setSampleArray(dcModel2SampleValues); + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format( + "Non-Mandatory Location Choice Model for: tour purpose=%s", tourPurposeName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourId()); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Non-Mandatory Location Choice Model for tour purpose=" + + tourPurposeName + ", Person Num: " + person.getPersonNum() + + ", Person Type: " + person.getPersonType() + ", TourId=" + tour.getTourId()); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + dcModel2[m].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + float modelLogsum = (float) dcModel2[m].computeUtilities(dcDistSoaDmuObject, dcDistSoaDmuObject.getDmuIndexValues(), + dcModel2AltsAvailable, dcModel2AltsSample); + tour.setTourDestinationLogsum(modelLogsum); + + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (dcModel2[m].getAvailabilityCount() > 0) + { + try + { + chosen = dcModel2[m].getChoiceResult(rn); + } catch (Exception e) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, in %s destination choice.", + dcDistSoaDmuObject.getHouseholdObject().getHhId(), + dcDistSoaDmuObject.getPersonObject().getPersonNum(), + tour.getTourId(), tourPurposeName)); + throw new RuntimeException(); + } + } + + if (household.getDebugChoiceModels() || chosen <= 0) + { + + double[] utilities = dcModel2[m].getUtilities(); + double[] probabilities = dcModel2[m].getProbabilities(); + boolean[] availabilities = dcModel2[m].getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- -------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 0; j < finalSample.length; j++) + { + int alt = finalSample[j]; + cumProb += probabilities[j]; + String altString = String.format("j=%d, mgra=%d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j + 1], utilities[j], probabilities[j], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("j=%d, mgra=%d", chosen - 1, finalSample[chosen - 1]); + modelLogger.info(String.format("Choice: %s with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + dcModel2[m].logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + dcModel2[m].logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, chosen); + + // write UEC calculation results to separate model specific log file + dcModel2[m].logUECResults(modelLogger, loggingHeader); + + if (chosen < 0) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, tourId=%d, tourPurpose=%d, no available %s destination choice alternatives to choose from in ChoiceModelApplication.", + dcDistSoaDmuObject.getHouseholdObject().getHhId(), + dcDistSoaDmuObject.getPersonObject().getPersonNum(), + tour.getTourId(), tourPurposeName)); + throw new RuntimeException(); + } + + } + + return chosen; + + } + + private void setModeChoiceDmuAttributes(Household household, Person person, Tour t, + int startPeriod, int endPeriod, int sampleDestMgra) + { + + t.setTourDestMgra(sampleDestMgra); + t.setTourDepartPeriod(startPeriod); + t.setTourArrivePeriod(endPeriod); + + int workTourIndex = t.getWorkTourIndexFromSubtourId(t.getTourId()); + Tour workTour = person.getListOfWorkTours().get(workTourIndex); + + // update the MC dmuObjects for this person + mcDmuObject.setHouseholdObject(household); + mcDmuObject.setPersonObject(person); + mcDmuObject.setTourObject(t); + mcDmuObject.setWorkTourObject(workTour); + mcDmuObject.setDmuIndexValues(household.getHhId(), household.getHhMgra(), + t.getTourOrigMgra(), sampleDestMgra, household.getDebugChoiceModels()); + + + mcDmuObject.setPTazTerminalTime(tazs.getOriginTazTerminalTime(mgraManager.getTaz(t + .getTourOrigMgra()))); + mcDmuObject.setATazTerminalTime(tazs.getDestinationTazTerminalTime(mgraManager + .getTaz(sampleDestMgra))); + + mcDmuObject.setOriginMgra(t.getTourOrigMgra()); + mcDmuObject.setDestMgra(t.getTourDestMgra()); + + } + + private double calculateSimpleTODChoiceLogsum(Person person, Tour tour, int sampleDestMgra, + int sampleNum) + { + + Household household = person.getHouseholdObject(); + + Arrays.fill(needToComputeLogsum, true); + Arrays.fill(modeChoiceLogsums, -999); + + Logger modelLogger = todMcLogger; + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + choiceModelDescription = String + .format("At-work Subtour Simplified TOD logsum calculations for %s Location Choice, Sample Number %d", + tour.getSubTourPurpose(), sampleNum); + decisionMakerLabel = String.format( + "HH=%d, PersonNum=%d, PersonType=%s, tourId=%d of %d non-mand tours", + household.getHhId(), person.getPersonNum(), person.getPersonType(), + tour.getTourId(), person.getListOfAtWorkSubtours().size()); + loggingHeader = String.format("%s %s", choiceModelDescription, decisionMakerLabel); + } + + int i = 0; + int tourPurposeIndex = purposeNameIndexMap.get(tour.getSubTourPurpose()); + double totalExpUtility = 0.0; + for (int[] combo : PERIOD_COMBINATIONS[tourPurposeIndex]) + { + int startPeriod = combo[0]; + int endPeriod = combo[1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + if (needToComputeLogsum[index]) + { + + String periodString = modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(startPeriod)) + + " to " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(endPeriod)); + + // set the mode choice attributes needed by @variables in the + // UEC spreadsheets + setModeChoiceDmuAttributes(household, person, tour, startPeriod, endPeriod, + sampleDestMgra); + + if (household.getDebugChoiceModels()) + household.logTourObject(loggingHeader + ", " + periodString, modelLogger, + person, mcDmuObject.getTourObject()); + + try + { + modeChoiceLogsums[index] = mcModel.getModeChoiceLogsum(mcDmuObject, tour, + modelLogger, choiceModelDescription, decisionMakerLabel + ", " + + periodString); + } catch (Exception e) + { + logger.fatal("exception caught applying mcModel.getModeChoiceLogsum() for " + + periodString + " " + tour.getTourPrimaryPurpose() + " tour."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + e.printStackTrace(); + System.exit(-1); + // throw new RuntimeException(e); + } + needToComputeLogsum[index] = false; + } + + double expUtil = Math.exp(modeChoiceLogsums[index] + + PERIOD_COMBINATION_COEFFICIENTS[tourPurposeIndex][i]); + totalExpUtility += expUtil; + + if (household.getDebugChoiceModels()) + modelLogger + .info("i = " + + i + + ", purpose = " + + tourPurposeIndex + + ", " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(startPeriod)) + + " to " + + modelStructure.getModelPeriodLabel(modelStructure + .getModelPeriodIndex(endPeriod)) + + " MCLS = " + + modeChoiceLogsums[index] + + ", ASC = " + + PERIOD_COMBINATION_COEFFICIENTS[tourPurposeIndex][i] + + ", (MCLS + ASC) = " + + (modeChoiceLogsums[index] + PERIOD_COMBINATION_COEFFICIENTS[tourPurposeIndex][i]) + + ", exp(MCLS + ASC) = " + expUtil + ", cumExpUtility = " + + totalExpUtility); + + i++; + } + + double logsum = Math.log(totalExpUtility); + + if (household.getDebugChoiceModels()) + modelLogger.info("final simplified TOD logsum = " + logsum); + + return logsum; + } + + public void setNonMandatorySoaProbs(double[][][] soaDistProbs, double[][][] soaSizeProbs) + { + if (useNewSoaMethod) + { + dcSoaTwoStageObject.setTazDistProbs(soaDistProbs); + dcSoaTwoStageObject.setMgraSizeProbs(soaSizeProbs); + } + } + + public long getSoaRunTime() + { + return soaRunTime; + } + + public void resetSoaRunTime() + { + soaRunTime = 0; + } + + public static void main(String[] args) + { + + // set values for these arguments so an object instance can be created + // and setup run to test integrity of UEC files before running full + // model. + HashMap propertyMap; + + if (args.length == 0) + { + System.out + .println("no properties file base name (without .properties extension) was specified as an argument."); + return; + } else + { + ResourceBundle rb = ResourceBundle.getBundle(args[0]); + propertyMap = ResourceUtil.changeResourceBundleIntoHashMap(rb); + } + + String matrixServerAddress = (String) propertyMap.get("RunModel.MatrixServerAddress"); + String matrixServerPort = (String) propertyMap.get("RunModel.MatrixServerPort"); + + MatrixDataServerIf ms = new MatrixDataServerRmi(matrixServerAddress, + Integer.parseInt(matrixServerPort), MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(ms); + + MgraDataManager mgraManager = MgraDataManager.getInstance(propertyMap); + TazDataManager tazManager = TazDataManager.getInstance(propertyMap); + + /* + * + */ + ModelStructure modelStructure = new SandagModelStructure(); + SandagCtrampDmuFactory dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + BuildAccessibilities aggAcc = BuildAccessibilities.getInstance(); + if (!aggAcc.getAccessibilitiesAreBuilt()) + { + aggAcc.setupBuildAccessibilities(propertyMap, false); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateConstants(); + // aggAcc.buildAccessibilityComponents(propertyMap); + + boolean readAccessibilities = Util.getBooleanValueFromPropertyMap(propertyMap, + CtrampApplication.READ_ACCESSIBILITIES); + if (readAccessibilities) + { + + // output data + String projectDirectory = propertyMap + .get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String accFileName = projectDirectory + + Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file"); + + aggAcc.readAccessibilityTableFromFile(accFileName); + + } else + { + + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + } + + } + + double[][] expConstants = aggAcc.getExpConstants(); + + McLogsumsCalculator logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + + double[][][] sovExpUtilities = null; + double[][][] hovExpUtilities = null; + double[][][] nMotorExpUtilities = null; + double[][][] maasExpUtilities = null; + NonTransitUtilities ntUtilities = new NonTransitUtilities(propertyMap, sovExpUtilities, + hovExpUtilities, nMotorExpUtilities, maasExpUtilities); + + MandatoryAccessibilitiesCalculator mandAcc = new MandatoryAccessibilitiesCalculator( + propertyMap, ntUtilities, expConstants, logsumHelper.getBestTransitPathCalculator()); + + String hhHandlerAddress = (String) propertyMap.get("RunModel.HouseholdServerAddress"); + int hhServerPort = Integer.parseInt((String) propertyMap + .get("RunModel.HouseholdServerPort")); + + HouseholdDataManagerIf householdDataManager = new HouseholdDataManagerRmi(hhHandlerAddress, + hhServerPort, SandagHouseholdDataManager.HH_DATA_SERVER_NAME); + + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population + // files and apply its tables to objects mapping method. + boolean restartHhServer = false; + try + { + // possible values for the following can be none, ao, cdap, imtf, + // imtod, awf, awl, awtod, jtf, jtl, jtod, inmtf, inmtl, inmtod, + // stf, stl + String restartModel = (String) propertyMap.get("RunModel.RestartWithHhServer"); + if (restartModel.equalsIgnoreCase("none")) restartHhServer = true; + else if (restartModel.equalsIgnoreCase("uwsl") || restartModel.equalsIgnoreCase("ao") + || restartModel.equalsIgnoreCase("fp") || restartModel.equalsIgnoreCase("cdap") + || restartModel.equalsIgnoreCase("imtf") + || restartModel.equalsIgnoreCase("imtod") + || restartModel.equalsIgnoreCase("awf") || restartModel.equalsIgnoreCase("awl") + || restartModel.equalsIgnoreCase("awtod") + || restartModel.equalsIgnoreCase("jtf") || restartModel.equalsIgnoreCase("jtl") + || restartModel.equalsIgnoreCase("jtod") + || restartModel.equalsIgnoreCase("inmtf") + || restartModel.equalsIgnoreCase("inmtl") + || restartModel.equalsIgnoreCase("inmtod") + || restartModel.equalsIgnoreCase("stf") || restartModel.equalsIgnoreCase("stl")) + restartHhServer = false; + } catch (MissingResourceException e) + { + restartHhServer = true; + } + + if (restartHhServer) + { + + householdDataManager.setDebugHhIdsFromHashmap(); + + String inputHouseholdFileName = (String) propertyMap + .get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = (String) propertyMap + .get(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(1.0f, 0); + householdDataManager.setupHouseholdDataManager(modelStructure, inputHouseholdFileName, + inputPersonFileName); + + } else + { + + householdDataManager.setHouseholdSampleRate(1.0f, 0); + householdDataManager.setDebugHhIdsFromHashmap(); + householdDataManager.setTraceHouseholdSet(); + + } + + // int id = householdDataManager.getArrayIndex( 1033380 ); + // int id = householdDataManager.getArrayIndex( 1033331 ); + int id = householdDataManager.getArrayIndex(423804); + Household[] hh = householdDataManager.getHhArray(id, id); + + TourModeChoiceModel awmcModel = new TourModeChoiceModel(propertyMap, modelStructure, + ModelStructure.AT_WORK_CATEGORY, dmuFactory, logsumHelper); + + SubtourDestChoiceModel testObject = new SubtourDestChoiceModel(propertyMap, modelStructure, + aggAcc, dmuFactory, awmcModel); + + testObject.applyModel(hh[0]); + + /** + * used this block of code to test for typos and implemented dmu methods + * in the TOD choice UECs + * + * String uecFileDirectory = propertyMap.get( + * CtrampApplication.PROPERTIES_UEC_PATH ); + * + * ModelStructure modelStructure = new SandagModelStructure(); + * SandagCtrampDmuFactory dmuFactory = new + * SandagCtrampDmuFactory(modelStructure); + * + * String dcUecFileName = propertyMap.get( PROPERTIES_DC_UEC_FILE ); + * DestChoiceDMU dcDmuObject = dmuFactory.getDestChoiceDMU(); File + * uecFile = new File(uecFileDirectory + dcUecFileName); + * UtilityExpressionCalculator uec = new + * UtilityExpressionCalculator(uecFile, 13, 0, propertyMap, + * (VariableTable) dcDmuObject); + * System.out.println("Subtour destination choice UEC passed"); + * + * String soaUecFileName = propertyMap.get( PROPERTIES_DC_SOA_UEC_FILE + * ); DcSoaDMU dcSoaDmuObject = dmuFactory.getDcSoaDMU(); uecFile = new + * File(uecFileDirectory + soaUecFileName); uec = new + * UtilityExpressionCalculator(uecFile, 7, 0, propertyMap, + * (VariableTable) dcSoaDmuObject); + * System.out.println("Subtour destination choice SOA UEC passed"); + */ + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TNCAndTaxiWaitTimeCalculator.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TNCAndTaxiWaitTimeCalculator.java new file mode 100644 index 0000000..3731e65 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TNCAndTaxiWaitTimeCalculator.java @@ -0,0 +1,264 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import umontreal.iro.lecuyer.probdist.LognormalDist; + + + +public class TNCAndTaxiWaitTimeCalculator implements Serializable{ + + private static Logger logger = Logger.getLogger(TNCAndTaxiWaitTimeCalculator.class); + + private float[] startPopEmpPerSqMi; + + private LognormalDist[] TNCSingleWaitTimeDistribution; + private LognormalDist[] TNCSharedWaitTimeDistribution; + private LognormalDist[] TaxiWaitTimeDistribution; + float[] meanTNCSingleWaitTime ; + float[] meanTNCSharedWaitTime ; + float[] meanTaxiWaitTime ; + + /** + * Constructor; doesn't do anything (call @createTimeDistributions method next) + */ + public TNCAndTaxiWaitTimeCalculator(){ + + } + + /** + * Reads the propertyMap and finds values for property arrays + * TNC.waitTime.mean, Taxi.waitTime.mean, + * TNC.waitTime.sd, and Taxi.waitTime.sd - containing arrays + * of wait time and standard deviations for TNCs and Taxis by area type, + * plus an array of end ranges for area type (pop+emp)/sq miles + * with an implied start value of 0. + * Creates and stores umontreal.iro.lecuyer.probdist.LognormalDist + * TNCWaitTimeDistribution[] and TaxiWaitTimeDistribution[] where + * each element of the distribution corresponds to the areatype range. + * @param propertyMap + */ + + public void createWaitTimeDistributions(HashMap propertyMap){ + + //read properties + meanTNCSingleWaitTime = Util.getFloatArrayFromPropertyMap(propertyMap, "TNC.single.waitTime.mean"); + float[] sdTNCSingleWaitTime = Util.getFloatArrayFromPropertyMap(propertyMap, "TNC.single.waitTime.sd"); + + meanTNCSharedWaitTime = Util.getFloatArrayFromPropertyMap(propertyMap, "TNC.shared.waitTime.mean"); + float[] sdTNCSharedWaitTime = Util.getFloatArrayFromPropertyMap(propertyMap, "TNC.shared.waitTime.sd"); + + meanTaxiWaitTime = Util.getFloatArrayFromPropertyMap(propertyMap, "Taxi.waitTime.mean"); + float[] sdTaxiWaitTime = Util.getFloatArrayFromPropertyMap(propertyMap, "Taxi.waitTime.sd"); + + startPopEmpPerSqMi = Util.getFloatArrayFromPropertyMap(propertyMap, "WaitTimeDistribution.EndPopEmpPerSqMi"); + + // create the distribution arrays + TNCSingleWaitTimeDistribution = new LognormalDist[startPopEmpPerSqMi.length]; + TNCSharedWaitTimeDistribution = new LognormalDist[startPopEmpPerSqMi.length]; + TaxiWaitTimeDistribution = new LognormalDist[startPopEmpPerSqMi.length]; + + //iterate through area types + for(int i = 0; i< startPopEmpPerSqMi.length;++i){ + + // calculate the location and scale parameters from the mean and standard deviations + double locationTNCSingleWaitTime = calculateLocation(meanTNCSingleWaitTime[i], sdTNCSingleWaitTime[i]); + double scaleTNCSingleWaitTime = calculateScale(meanTNCSingleWaitTime[i], sdTNCSingleWaitTime[i]); + + + double locationTNCSharedWaitTime = calculateLocation(meanTNCSharedWaitTime[i], sdTNCSharedWaitTime[i]); + double scaleTNCSharedWaitTime = calculateScale(meanTNCSharedWaitTime[i], sdTNCSharedWaitTime[i]); + + // create the TNC wait time distribution for this area type + TNCSingleWaitTimeDistribution[i] = new LognormalDist(locationTNCSingleWaitTime, scaleTNCSingleWaitTime); + TNCSharedWaitTimeDistribution[i] = new LognormalDist(locationTNCSharedWaitTime, scaleTNCSharedWaitTime); + + double locationTaxiWaitTime = calculateLocation(meanTaxiWaitTime[i], sdTaxiWaitTime[i]); + double scaleTaxiWaitTime = calculateScale(meanTaxiWaitTime[i], sdTaxiWaitTime[i]); + + TaxiWaitTimeDistribution[i] = new LognormalDist(locationTaxiWaitTime, scaleTaxiWaitTime); + + } + } + + /** + * Calculate the lognormal distribution location given + * the mean and standard deviation of the distribution + * according to the formula: + * + * location = ln(mean/sqrt(1 + variance/mean^2)) + * + * @param mean + * @param standardDeviation + * @return Location variable (u) + */ + public double calculateLocation(double mean, double standardDeviation){ + + double variance = standardDeviation * standardDeviation; + double meanSquared = mean * mean; + double denom = Math.sqrt(1.0 + (variance/meanSquared)); + double location = mean/denom; + if(location<=0){ + logger.error("Error: Trying to calculation location for mean "+mean + +" and standard deviation "+standardDeviation); + throw new RuntimeException(); + } + + return Math.log(location); + + } + + /** + * Calculate the lognormal distribution scale given + * the mean and standard deviation of the distribution + * according to the formula: + * + * scale = sqrt(ln(1 + variance/mean^2)); + * + * @param mean + * @param standardDeviation + * @return Scale variable (sigma) + */ + public double calculateScale(double mean, double standardDeviation){ + + double variance = standardDeviation * standardDeviation; + double meanSquared = mean * mean; + return Math.sqrt(Math.log(1 + variance/meanSquared)); + } + + /** + * Sample from the Single TNC wait time distribution and return the wait time. + * @param rnum A unit-distributed random number. + * @param popEmpPerSqMi The population plus employment divided by square miles + * @return The sampled TNC wait time. + */ + public double sampleFromSingleTNCWaitTimeDistribution(double rnum, double popEmpPerSqMi){ + + for(int i = 0; i < startPopEmpPerSqMi.length;++i){ + + if(popEmpPerSqMi zoneValues = new HashMap(); + + for (int i = 1; i <= zoneTable.getRowCount(); i++) + { + int zone = (int) zoneTable.getValueAt(i, zoneCol); + if (zoneValues.containsKey(zone)) + { + logger.fatal(String + .format("zone employment table read from %s has duplicate value for ZONE=%d in column %d at record number %d", + zoneDataFileName, zone, zoneCol, (i + 1))); + throw new RuntimeException(); + } else + { + zoneValues.put(zone, i); + numZones++; + if (zone > maxZone) maxZone = zone; + } + + } + + } catch (IOException e) + { + logger.error(String + .format("Exception occurred reading zonal employment data file: %s into TableDataSet object.", + zoneDataFileName)); + throw new RuntimeException(); + } + + NUM_ZONES = numZones; + + // store the row numbers for each zone so that zonal attributes can be + // retrieved later using given a zone number + indexToZone = new int[numZones + 1]; + zoneTableRow = new int[maxZone + 1]; + for (int i = 1; i <= zoneTable.getRowCount(); i++) + { + int zone = (int) zoneTable.getValueAt(i, zoneCol); + zoneTableRow[zone] = i; + indexToZone[i] = zone; + } + + return zoneTable; + + } + + private void readWalkPercentagesFile(String fileName) + { + + int taz; + float[] shrtArray = new float[NUM_ZONES + 1]; + float[] longArray = new float[NUM_ZONES + 1]; + zonalWalkPctArray = new float[3][NUM_ZONES + 1]; + Arrays.fill(zonalWalkPctArray[0], 1.0f); + Arrays.fill(zonalWalkPctArray[1], 0.0f); + Arrays.fill(zonalWalkPctArray[2], 0.0f); + + if (fileName != null) + { + + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet(" " + reader.getDelimSet()); + TableDataSet wa = reader.readFile(new File(fileName)); + + int tazPosition = wa.getColumnPosition(walkPctZoneFieldName); + if (tazPosition <= 0) + { + logger.fatal(String + .format("expected zone field name=%s was not a field in the walk access file: %s.", + WALK_PERCENTAGE_FILE_ZONE_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int shrtPosition = wa.getColumnPosition(walkPctShortFieldName); + if (shrtPosition <= 0) + { + logger.fatal(String + .format("expected short field name=%s was not a field in the walk access file: %s.", + WALK_PERCENTAGE_FILE_SHORT_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int longPosition = wa.getColumnPosition(walkPctLongFieldName); + if (longPosition <= 0) + { + logger.fatal(String + .format("expected long field name=%s was not a field in the walk access file: %s.", + WALK_PERCENTAGE_FILE_LONG_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + for (int j = 1; j <= wa.getRowCount(); j++) + { + taz = (int) wa.getValueAt(j, tazPosition); + shrtArray[taz] = wa.getValueAt(j, shrtPosition); + longArray[taz] = wa.getValueAt(j, longPosition); + zonalWalkPctArray[1][taz] = shrtArray[taz]; + zonalWalkPctArray[2][taz] = longArray[taz]; + zonalWalkPctArray[0][taz] = (float) (1.0 - (shrtArray[taz] + longArray[taz])); + } + + } catch (IOException e) + { + logger.fatal( + String.format("exception caught reading walk access file: %s", fileName), e); + } + + } else + { + + logger.fatal("no zonal walk access data file was named in properties file with target: 'WalkPercentages.file ='."); + throw new RuntimeException(); + + } + + } + + private void readZonalAccessibilitiesFile(String fileName) + { + + int taz; + pkAutoRetail = new float[NUM_ZONES + 1]; + pkAutoTotal = new float[NUM_ZONES + 1]; + opAutoRetail = new float[NUM_ZONES + 1]; + opAutoTotal = new float[NUM_ZONES + 1]; + pkTransitRetail = new float[NUM_ZONES + 1]; + pkTransitTotal = new float[NUM_ZONES + 1]; + opTransitRetail = new float[NUM_ZONES + 1]; + opTransitTotal = new float[NUM_ZONES + 1]; + nonMotorizedRetail = new float[NUM_ZONES + 1]; + nonMotorizedTotal = new float[NUM_ZONES + 1]; + + if (fileName != null) + { + + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + reader.setDelimSet(" " + reader.getDelimSet()); + TableDataSet acc = reader.readFile(new File(fileName)); + + int tazPosition = acc.getColumnPosition(ACCESSIBILITIES_FILE_ZONE_FIELD_NAME); + if (tazPosition <= 0) + { + logger.fatal(String + .format("expected zone field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_FILE_ZONE_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int pkAutoRetailPosition = acc + .getColumnPosition(ACCESSIBILITIES_PEAK_AUTO_RETAIL_FIELD_NAME); + if (pkAutoRetailPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_PEAK_AUTO_RETAIL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int pkAutoTotalPosition = acc + .getColumnPosition(ACCESSIBILITIES_PEAK_AUTO_TOTAL_FIELD_NAME); + if (pkAutoTotalPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_PEAK_AUTO_TOTAL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int pkTransitRetailPosition = acc + .getColumnPosition(ACCESSIBILITIES_PEAK_TRANSIT_RETAIL_FIELD_NAME); + if (pkTransitRetailPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_PEAK_TRANSIT_RETAIL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int pkTransitTotalPosition = acc + .getColumnPosition(ACCESSIBILITIES_PEAK_TRANSIT_TOTAL_FIELD_NAME); + if (pkTransitTotalPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_PEAK_TRANSIT_TOTAL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int opAutoRetailPosition = acc + .getColumnPosition(ACCESSIBILITIES_OFF_PEAK_AUTO_RETAIL_FIELD_NAME); + if (opAutoRetailPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_OFF_PEAK_AUTO_RETAIL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int opAutoTotalPosition = acc + .getColumnPosition(ACCESSIBILITIES_OFF_PEAK_AUTO_TOTAL_FIELD_NAME); + if (opAutoTotalPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_OFF_PEAK_AUTO_TOTAL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int opTransitRetailPosition = acc + .getColumnPosition(ACCESSIBILITIES_OFF_PEAK_TRANSIT_RETAIL_FIELD_NAME); + if (opTransitRetailPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_OFF_PEAK_TRANSIT_RETAIL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int opTransitTotalPosition = acc + .getColumnPosition(ACCESSIBILITIES_OFF_PEAK_TRANSIT_TOTAL_FIELD_NAME); + if (opTransitTotalPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_OFF_PEAK_TRANSIT_TOTAL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int nonMotorizedRetailPosition = acc + .getColumnPosition(ACCESSIBILITIES_NON_MOTORIZED_RETAIL_FIELD_NAME); + if (nonMotorizedRetailPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_NON_MOTORIZED_RETAIL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + int nonMotorizedTotalPosition = acc + .getColumnPosition(ACCESSIBILITIES_NON_MOTORIZED_TOTAL_FIELD_NAME); + if (nonMotorizedTotalPosition <= 0) + { + logger.fatal(String + .format("expected field name=%s was not a field in the zonal accessibilities file: %s.", + ACCESSIBILITIES_NON_MOTORIZED_TOTAL_FIELD_NAME, fileName)); + throw new RuntimeException(); + } + + for (int i = 1; i <= acc.getRowCount(); i++) + { + taz = (int) acc.getValueAt(i, tazPosition); + pkAutoRetail[taz] = acc.getValueAt(i, pkAutoRetailPosition); + pkAutoTotal[taz] = acc.getValueAt(i, pkAutoTotalPosition); + pkTransitRetail[taz] = acc.getValueAt(i, pkTransitRetailPosition); + pkTransitTotal[taz] = acc.getValueAt(i, pkTransitTotalPosition); + opAutoRetail[taz] = acc.getValueAt(i, opAutoRetailPosition); + opAutoTotal[taz] = acc.getValueAt(i, opAutoTotalPosition); + opTransitRetail[taz] = acc.getValueAt(i, opTransitRetailPosition); + opTransitTotal[taz] = acc.getValueAt(i, opTransitTotalPosition); + nonMotorizedRetail[taz] = acc.getValueAt(i, nonMotorizedRetailPosition); + nonMotorizedTotal[taz] = acc.getValueAt(i, nonMotorizedTotalPosition); + } + + } catch (IOException e) + { + logger.fatal(String.format("exception caught reading accessibilities file: %s", + fileName), e); + } + + } else + { + + logger.fatal("no zonal accessibilities data file was named in properties file with target: " + + fileName); + throw new RuntimeException(); + + } + + } + + /** + * @param alt + * is the DC alternaive number + * @return zone number for the DC alt. + */ + private int getZoneFromAlt(int alt) + { + int zone = (int) ((alt - 1) / NUM_SUBZONES) + 1; + if (zone < 1 || zone > NUM_ZONES) + { + logger.fatal(String.format( + "invalid value for zone index = %d, determined for alt = %d.", zone, alt)); + logger.fatal(String.format("NUM_ZONES = %d, NUM_SUBZONES = %d.", NUM_ZONES, + NUM_SUBZONES)); + throw new RuntimeException(); + } + return zone; + } + + /** + * @param alt + * is the DC alternaive number + * @return walk subzone index for the DC alt. + */ + private int getWalkSubzoneFromAlt(int alt) + { + int zone = getZoneFromAlt(alt); + int subzone = alt - (zone - 1) * NUM_SUBZONES - 1; + if (subzone < 0 || subzone >= NUM_SUBZONES) + { + logger.fatal(String + .format("invalid value for walk subzone index = %d, zone = %d, determined for alt = %d.", + subzone, zone, alt)); + logger.fatal(String.format("NUM_ZONES = %d, NUM_SUBZONES = %d.", NUM_ZONES, + NUM_SUBZONES)); + throw new RuntimeException(); + } + return subzone; + } + + public String testRemote() + { + return String.format("testRemote() method in %s called.", this.getClass() + .getCanonicalName()); + } + + public int[] getAltToZoneArray() + { + return altToZone; + } + + public int[] getAltToSubZoneArray() + { + return altToSubZone; + } + + public int[] getIndexToZoneArray() + { + return indexToZone; + } + + public int[] getZoneTableRowArray() + { + return zoneTableRow; + } + + /** + * + * @param field + * is the field name to be checked against the column names in + * the zone data table. + * @return true if field matches one of the zone data table column names, + * otherwise false. + */ + public boolean isValidZoneTableField(String field) + { + return zoneDataTable.getColumnPosition(field) >= 0; + } + + public String[] getZoneDataTableColumnLabels() + { + return zoneDataTable.getColumnLabels(); + } + + public int getNumberOfZones() + { + return NUM_ZONES; + } + + public int getNumberOfSubZones() + { + return NUM_SUBZONES; + } + + public String[] getSubZoneNames() + { + return subZoneNames; + } + + public double[] getZonalWalkPercentagesForTaz(int taz) + { + double[] percentages = new double[NUM_SUBZONES]; + for (int i = 0; i < NUM_SUBZONES; i++) + percentages[i] = zonalWalkPctArray[i][taz]; + return percentages; + } + + public float getZoneTableValue(int taz, String fieldName) + { + // get the table row number for the TAZ passed in + int rowIndex = zoneTableRow[taz]; + + // get the table value from the rowIndex and fieldname passed in + return zoneDataTable.getValueAt(rowIndex, fieldName); + } + + // get the table column from the fieldname passed in + public int[] getZoneTableIntColumn(String fieldName) + { + return zoneDataTable.getColumnAsInt(fieldName); + } + + // get the table column from the fieldname passed in + public float[] getZoneTableFloatColumn(String fieldName) + { + return zoneDataTable.getColumnAsFloat(fieldName); + } + + /** + * @param tableRowNumber + * is the zone table row number + * @return zone number for the table row. + */ + public int getTazNumber(int tableRowNumber) + { + return (int) zoneDataTable.getValueAt(tableRowNumber, tazDataZoneFieldName); + } + + /** + * @return area type array from the zone data table. + */ + public int[] getZonalAreaType() + { + int atFieldPosition = zoneDataTable.getColumnPosition(tazDataAtFieldName); + if (atFieldPosition < 0) + { + logger.error(String + .format("The area type field name = %s defined in %s is not found as a field name in the zone data table.", + tazDataAtFieldName, this.getClass().getName())); + throw new RuntimeException(); + } + return zoneDataTable.getColumnAsInt(atFieldPosition); + } + + /** + * @return district array from the zone data table. + */ + public int[] getZonalDistrict() + { + int districtFieldPosition = zoneDataTable.getColumnPosition(tazDataDistFieldName); + if (districtFieldPosition < 0) + { + logger.error(String + .format("The district field name = %s defined in %s is not found as a field name in the zone data table.", + tazDataDistFieldName, this.getClass().getName())); + throw new RuntimeException(); + } + return zoneDataTable.getColumnAsInt(districtFieldPosition); + } + + /** + * @return county array from the zone data table. + */ + public int[] getZonalCounty() + { + int countyFieldPosition = zoneDataTable.getColumnPosition(tazDataCountyFieldName); + if (countyFieldPosition < 0) + { + logger.error(String + .format("The county field name = %s defined in %s is not found as a field name in the zone data table.", + tazDataCountyFieldName, this.getClass().getName())); + throw new RuntimeException(); + } + return zoneDataTable.getColumnAsInt(countyFieldPosition); + } + + public int getZoneIsCbd(int taz) + { + return getZoneIsInAreaType(taz, areaTypes[cbdAreaTypesArrayIndex]); + } + + public int getZoneIsUrban(int taz) + { + return getZoneIsInAreaType(taz, areaTypes[urbanAreaTypesArrayIndex]); + } + + public int getZoneIsSuburban(int taz) + { + return getZoneIsInAreaType(taz, areaTypes[suburbanAreaTypesArrayIndex]); + } + + public int getZoneIsRural(int taz) + { + return getZoneIsInAreaType(taz, areaTypes[ruralAreaTypesArrayIndex]); + } + + private int getZoneIsInAreaType(int taz, int[] areaTypes) + { + int returnValue = 0; + int tazAreaType = (int) getZoneTableValue(taz, tazDataAtFieldName); + for (int atIndex : areaTypes) + { + if (tazAreaType == atIndex) + { + returnValue = 1; + break; + } + } + return returnValue; + } + + /** + * @return parkTot array from the zone data table. + */ + public int[] getZonalParkTot() + { + int parkTotFieldPosition = zoneDataTable.getColumnPosition(parkTotFieldName); + if (parkTotFieldPosition < 0) + { + logger.error(String + .format("The parkTot field name = %s defined in %s is not found as a field name in the zone data table.", + parkTotFieldName, this.getClass().getName())); + throw new RuntimeException(); + } + return zoneDataTable.getColumnAsInt(parkTotFieldPosition); + } + + /** + * @return parkLong array from the zone data table. + */ + public int[] getZonalParkLong() + { + int parkLongFieldPosition = zoneDataTable.getColumnPosition(parkLongFieldName); + if (parkLongFieldPosition < 0) + { + logger.error(String + .format("The parkLong field name = %s defined in %s is not found as a field name in the zone data table.", + parkLongFieldName, this.getClass().getName())); + throw new RuntimeException(); + } + return zoneDataTable.getColumnAsInt(parkLongFieldPosition); + } + + /** + * @return propFree array from the zone data table. + */ + public float[] getZonalPropFree() + { + int propFreeFieldPosition = zoneDataTable.getColumnPosition(propFreeFieldName); + if (propFreeFieldPosition < 0) + { + logger.error(String + .format("The propFree field name = %s defined in %s is not found as a field name in the zone data table.", + propFreeFieldName, this.getClass().getName())); + throw new RuntimeException(); + } + return zoneDataTable.getColumnAsFloat(propFreeFieldPosition); + } + + /** + * @return parkRate array from the zone data table. + */ + public float[] getZonalParkRate() + { + int parkRateFieldPosition = zoneDataTable.getColumnPosition(parkRateFieldName); + if (parkRateFieldPosition < 0) + { + logger.error(String + .format("The parkRate field name = %s defined in %s is not found as a field name in the zone data table.", + parkRateFieldName, this.getClass().getName())); + throw new RuntimeException(); + } + return zoneDataTable.getColumnAsFloat(parkRateFieldPosition); + } + + public float[] getPkAutoRetailAccessibity() + { + return pkAutoRetail; + } + + public float[] getPkAutoTotalAccessibity() + { + return pkAutoTotal; + } + + public float[] getPkTransitRetailAccessibity() + { + return pkTransitRetail; + } + + public float[] getPkTransitTotalAccessibity() + { + return pkTransitTotal; + } + + public float[] getOpAutoRetailAccessibity() + { + return opAutoRetail; + } + + public float[] getOpAutoTotalAccessibity() + { + return opAutoTotal; + } + + public float[] getOpTransitRetailAccessibity() + { + return opTransitRetail; + } + + public float[] getOpTransitTotalAccessibity() + { + return opTransitTotal; + } + + public float[] getNonMotorizedRetailAccessibity() + { + return nonMotorizedRetail; + } + + public float[] getNonMotorizedTotalAccessibity() + { + return nonMotorizedTotal; + } + + public enum AreaType + { + CBD, URBAN, SUBURBAN, RURAL + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TazDataHandlerRmi.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TazDataHandlerRmi.java new file mode 100644 index 0000000..0e051c5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TazDataHandlerRmi.java @@ -0,0 +1,297 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; + +/** + * This class provides methods defined in the TazDataIf interface for accessing + * zonal data stored in its TazDataManager object. + * + * A CT-RAMP tour based model application could create an instance of a subclass + * of this class, where additional project specific varaible definitions and + * methods are defined and pass that instance to its model component objects. + * + * Alternatively, an application could use TazDataHandlerRmi as the base class + * instead and create a "remoteable" subclass. The TazDataHandlerRmi class + * implements the same interface, so the model component classes can be unaware + * of whether the taz data handler object accesses zonal data from its member + * object or remotely from a server. Those methods in the rmi class access zonal + * data from a TazDataManager object contained in a "taz data server" object + * which must exist in a separate JVM on the same machine or on another + * addressable machine over the network. + * + * The flexibility provided by this design is intended to allow the "local" + * instance to be declared and passed within a single JVM to model components + * for possibly greater performance (yet to be tested and proven) at production + * run time. The "rmi" instance however allows the model components to access + * zonal data from a "long-running process" (the server class may execute for + * weeks or months). This approach aids in model development as during + * development, model applications can be written to skip startup procedures for + * reading zonal data, and access them directly from the server that is already + * running. + * + * A similar approach is planned for managing objects such as Household objects + * and ModelResults objects so that model components, for example individual + * non-mandatory tour related models which occur well into the tour based model + * stream, can be run in a "hot-start" fasion, where the model component of + * interest is executed immediately where all the preliminary data and prior + * model results it requires are stored in long-running server objects. Testing + * and debugging of these model components can occur without the time required + * to run through all preliminary steps. + * + * + */ + +public class TazDataHandlerRmi + implements TazDataIf, Serializable +{ + + UtilRmi remote; + String connectString; + + public TazDataHandlerRmi(String hostname, int port, String className) + { + + connectString = String.format("//%s:%d/%s", hostname, port, className); + remote = new UtilRmi(connectString); + + } + + public String testRemote() + { + Object[] objArray = {}; + return (String) remote.method("testRemote", objArray); + } + + public int[] getAltToZoneArray() + { + Object[] objArray = {}; + return (int[]) remote.method("getAltToZoneArray", objArray); + } + + public int[] getAltToSubZoneArray() + { + Object[] objArray = {}; + return (int[]) remote.method("getAltToSubZoneArray", objArray); + } + + public int[] getIndexToZoneArray() + { + Object[] objArray = {}; + return (int[]) remote.method("getIndexToZoneArray", objArray); + } + + public int[] getZoneTableRowArray() + { + Object[] objArray = {}; + return (int[]) remote.method("getZoneTableRowArray", objArray); + } + + /** + * @param field + * is the field name to be checked against the column names in + * the zone data table. + * @return true if field matches one of the zone data table column names, + * otherwise false. + */ + public boolean isValidZoneTableField(String field) + { + Object[] objArray = {field}; + return (Boolean) remote.method("isValidZoneTableField", objArray); + } + + public String[] getZoneDataTableColumnLabels() + { + Object[] objArray = {}; + return (String[]) remote.method("getZoneDataTableColumnLabels", objArray); + } + + public int getNumberOfZones() + { + Object[] objArray = {}; + return (Integer) remote.method("getNumberOfZones", objArray); + } + + public int getNumberOfSubZones() + { + Object[] objArray = {}; + return (Integer) remote.method("getNumberOfSubZones", objArray); + } + + public String[] getSubZoneNames() + { + Object[] objArray = {}; + return (String[]) remote.method("getSubZoneNames", objArray); + } + + public double[] getZonalWalkPercentagesForTaz(int taz) + { + Object[] objArray = {taz}; + return (double[]) remote.method("getZonalWalkPercentagesForTaz", objArray); + } + + public float getZoneTableValue(int taz, String fieldName) + { + Object[] objArray = {taz, fieldName}; + return (Float) remote.method("getZoneTableValue", objArray); + } + + public int[] getZoneTableIntColumn(String fieldName) + { + Object[] objArray = {fieldName}; + return (int[]) remote.method("getZoneTableIntColumn", objArray); + } + + // get the table column from the fieldname passed in + public float[] getZoneTableFloatColumn(String fieldName) + { + Object[] objArray = {fieldName}; + return (float[]) remote.method("getZoneTableFloatColumn", objArray); + } + + /** + * @param tableRowNumber + * is the zone table row number + * @return zone number for the table row. + */ + public int getTazNumber(int tableRowNumber) + { + Object[] objArray = {tableRowNumber}; + return (Integer) remote.method("getTazNumber", objArray); + } + + /** + * @return area type from the zone data table for the zone. + */ + public int[] getZonalAreaType() + { + Object[] objArray = {}; + return (int[]) remote.method("getZonalAreaType", objArray); + } + + /** + * @return district from the zone data table for the zone. + */ + public int[] getZonalDistrict() + { + Object[] objArray = {}; + return (int[]) remote.method("getZonalDistrict", objArray); + } + + public int[] getZonalParkTot() + { + Object[] objArray = {}; + return (int[]) remote.method("getZonalParkTot", objArray); + } + + public int[] getZonalParkLong() + { + Object[] objArray = {}; + return (int[]) remote.method("getZonalParkLong", objArray); + } + + public float[] getZonalPropFree() + { + Object[] objArray = {}; + return (float[]) remote.method("getZonalPropFree", objArray); + } + + public float[] getZonalParkRate() + { + Object[] objArray = {}; + return (float[]) remote.method("getZonalParkRate", objArray); + } + + /** + * @return integer county value from the zone data table for the zone. + */ + public int[] getZonalCounty() + { + Object[] objArray = {}; + return (int[]) remote.method("getZonalCounty", objArray); + } + + public int getZoneIsCbd(int taz) + { + Object[] objArray = {taz}; + return (Integer) remote.method("getZoneIsCbd", objArray); + } + + public int getZoneIsUrban(int taz) + { + Object[] objArray = {taz}; + return (Integer) remote.method("getZoneIsUrban", objArray); + } + + public int getZoneIsSuburban(int taz) + { + Object[] objArray = {taz}; + return (Integer) remote.method("getZoneIsSuburban", objArray); + } + + public int getZoneIsRural(int taz) + { + Object[] objArray = {taz}; + return (Integer) remote.method("getZoneIsRural", objArray); + } + + public float[] getPkAutoRetailAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getPkAutoRetailAccessibity", objArray); + } + + public float[] getPkAutoTotalAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getPkAutoTotalAccessibity", objArray); + } + + public float[] getPkTransitRetailAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getPkTransitRetailAccessibity", objArray); + } + + public float[] getPkTransitTotalAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getPkTransitTotalAccessibity", objArray); + } + + public float[] getOpAutoRetailAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getOpAutoRetailAccessibity", objArray); + } + + public float[] getOpAutoTotalAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getOpAutoTotalAccessibity", objArray); + } + + public float[] getOpTransitRetailAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getOpTransitRetailAccessibity", objArray); + } + + public float[] getOpTransitTotalAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getOpTransitTotalAccessibity", objArray); + } + + public float[] getNonMotorizedRetailAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getNonMotorizedRetailAccessibity", objArray); + } + + public float[] getNonMotorizedTotalAccessibity() + { + Object[] objArray = {}; + return (float[]) remote.method("getNonMotorizedTotalAccessibity", objArray); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TazDataIf.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TazDataIf.java new file mode 100644 index 0000000..f43c846 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TazDataIf.java @@ -0,0 +1,152 @@ +package org.sandag.abm.ctramp; + +/** + * Created by IntelliJ IDEA. User: Jim Date: Jul 1, 2008 Time: 9:58:21 AM + * + * Interface for accessing zonal information used by CT-RAMP modules + */ +public interface TazDataIf +{ + + String testRemote(); + + int[] getAltToZoneArray(); + + int[] getAltToSubZoneArray(); + + int[] getIndexToZoneArray(); + + int[] getZoneTableRowArray(); + + int getZoneIsCbd(int taz); + + int getZoneIsUrban(int taz); + + int getZoneIsSuburban(int taz); + + int getZoneIsRural(int taz); + + float[] getPkAutoRetailAccessibity(); + + float[] getPkAutoTotalAccessibity(); + + float[] getPkTransitRetailAccessibity(); + + float[] getPkTransitTotalAccessibity(); + + float[] getOpAutoRetailAccessibity(); + + float[] getOpAutoTotalAccessibity(); + + float[] getOpTransitRetailAccessibity(); + + float[] getOpTransitTotalAccessibity(); + + float[] getNonMotorizedRetailAccessibity(); + + float[] getNonMotorizedTotalAccessibity(); + + /** + * + * @param field + * is the field name to be checked against the column names in + * the zone data table. + * @return true if field matches one of the zone data table column names, + * otherwise false. + */ + boolean isValidZoneTableField(String field); + + /** + * @return a String[] of the column labels in the zone data table + */ + String[] getZoneDataTableColumnLabels(); + + /** + * @return an int value for the number of zones, i.e. rows in the zone data + * table + */ + int getNumberOfZones(); + + /** + * @return an int value for the number of subZones, i.e. number of + * walkTransit accessible segments defined in model for zones. + * Typical value might be 3, "no walk access", "short walk access", + * "long walk access". + */ + int getNumberOfSubZones(); + + /** + * @return a String[] for the subZone names, e.g. "no walk access", + * "short walk access", "long walk access". + */ + String[] getSubZoneNames(); + + /** + * @param taz + * is the taz index for the zonalWalkPctArray which is + * dimensioned to ZONES+1, assuming taz index values range from 1 + * to NUM_ZONES. + * @return a double[], dimensioned to NUM_SIBZONES, with the subzone + * proportions for the TAZ passed in + */ + double[] getZonalWalkPercentagesForTaz(int taz); + + /** + * @param taz + * is the taz index for the zone data table which is dimensioned + * to ZONES+1, assuming taz index values range from 1 to + * NUM_ZONES. + * @param fieldName + * is the column label in the zone data table. + * @return a float value from the zone data table at the specified row index + * and column label. + */ + float getZoneTableValue(int taz, String fieldName); + + int[] getZoneTableIntColumn(String fieldName); + + float[] getZoneTableFloatColumn(String fieldName); + + /** + * @param tableRowNumber + * is the zone table row number + * @return zone number for the table row. + */ + int getTazNumber(int tableRowNumber); + + /** + * @return area type from the zone data table for the zone index. + */ + int[] getZonalAreaType(); + + /** + * @return district from the zone data table for the zone index. + */ + int[] getZonalDistrict(); + + /** + * @return integer county value from the zone data table for the zone index. + */ + int[] getZonalCounty(); + + /** + * @return the parking rate array + */ + float[] getZonalParkRate(); + + /** + * @return the proportion of free parking array + */ + float[] getZonalPropFree(); + + /** + * @return the number of long parking spots array + */ + int[] getZonalParkLong(); + + /** + * @return the number of parking spots array + */ + int[] getZonalParkTot(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TelecommuteDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TelecommuteDMU.java new file mode 100644 index 0000000..5a1aed8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TelecommuteDMU.java @@ -0,0 +1,172 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + * @author jef
+ * Started: Jun 2019 + */ +public class TelecommuteDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TelecommuteDMU.class); + + protected HashMap methodIndexMap; + + private Household hh; + private Person person; + private IndexValues dmuIndex; + + public TelecommuteDMU() + { + dmuIndex = new IndexValues(); + } + + /** need to set hh and home taz before using **/ + public void setPersonObject(Person person) + { + this.hh = person.getHouseholdObject(); + this.person = person; + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug Telecommute UEC"); + } + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /* dmu @ functions */ + + public int getIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + public int getNumberOfAdults() + { + Person[] persons = hh.getPersons(); + int adults=0; + for(int i=1;i=18) + ++adults; + } + return adults; + } + + public int getHasKids_0_5() + { + Person[] persons = hh.getPersons(); + int hasKids_0_5=0; + for(int i=1;i=0) && persons[i].getAge()<=5) { + hasKids_0_5=1; + break; + } + } + return hasKids_0_5; + } + + + public int getHasKids_6_12() + { + Person[] persons = hh.getPersons(); + int hasKids_6_12=0; + for(int i=1;i=6) && persons[i].getAge()<=12) { + hasKids_6_12=1; + break; + } + } + return hasKids_6_12; + } + + public int getFemale() + { + return person.getPersonIsFemale(); + } + + public int getPersonType() + { + return person.getPersonTypeNumber(); + } + + public int getNumberOfAutos() + { + return hh.getAutosOwned(); + + } + + public int getOccupation() + { + return person.getPersPecasOccup(); + } + + public int getPaysToPark() + { + + int freeParkingChoice = person.getFreeParkingAvailableResult(); + if((freeParkingChoice==ParkingProvisionModel.FP_MODEL_PAY_ALT)|| + (freeParkingChoice==ParkingProvisionModel.FP_MODEL_REIMB_ALT)) + + return 1; + return 0; + } + + public float getWorkDistance() { + + return person.getWorkLocationDistance(); + } + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TelecommuteModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TelecommuteModel.java new file mode 100644 index 0000000..5f47355 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TelecommuteModel.java @@ -0,0 +1,144 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class TelecommuteModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("tc"); + + private static final String TC_CONTROL_FILE_TARGET = "te.uec.file"; + private static final String TC_DATA_SHEET_TARGET = "te.data.page"; + private static final String TC_MODEL_SHEET_TARGET = "te.model.page"; + + public static final short TC_MODEL_NO_TC_CHOICE = -1; + public static final short TC_MODEL_NO_TELECOMMUTE = 0; + public static final short TC_MODEL_1_DAY_WEEK_CHOICE = 1; + public static final short TC_MODEL_2_3_DAYS_WEEK_CHOICE = 2; + public static final short TC_MODEL_4P_DAYS_WEEK_CHOICE = 3; + public static final short WORK_AT_HOME_CHOICE = 9; + + + private MgraDataManager mgraManager; + + private ChoiceModelApplication tcModel; + private TelecommuteDMU tcDmuObject; + + public TelecommuteModel(HashMap propertyMap, CtrampDmuFactoryIf dmuFactory) + { + mgraManager = MgraDataManager.getInstance(propertyMap); + setupTelecommuteChoiceModelApplication(propertyMap, dmuFactory); + } + + private void setupTelecommuteChoiceModelApplication(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + logger.info("Setting up telecommute choice model."); + + // locate the telecommute UEC + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String tcUecFile = uecFileDirectory + propertyMap.get(TC_CONTROL_FILE_TARGET); + + int dataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, TC_DATA_SHEET_TARGET); + int modelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, TC_MODEL_SHEET_TARGET); + + // create the telecommute model DMU object. + tcDmuObject = dmuFactory.getTelecommuteDMU(); + + // create the telecommute model object + tcModel = new ChoiceModelApplication(tcUecFile, modelSheet, dataSheet, propertyMap, + (VariableTable) tcDmuObject); + + } + + public void applyModel(Household hhObject) + { + + Random hhRandom = hhObject.getHhRandom(); + + // person array is 1-based + Person[] person = hhObject.getPersons(); + for (int i = 1; i < person.length; i++) + { + + int workLoc = person[i].getWorkLocation(); + if (workLoc == ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR) + { + + person[i].setTelecommuteChoice(WORK_AT_HOME_CHOICE); + + } else if (workLoc > 0 ) + { + + double randomNumber = hhRandom.nextDouble(); + short chosen = (short) ((short) getTelecommuteChoice(person[i], randomNumber) - (short)1); + person[i].setTelecommuteChoice(chosen ); + + + } else + { + + person[i].setTelecommuteChoice(TC_MODEL_NO_TC_CHOICE); + + } + } + + hhObject.setFpRandomCount(hhObject.getHhRandomCount()); + } + + private int getTelecommuteChoice(Person personObj, double randomNumber) + { + + // get the corresponding household object + Household hhObj = personObj.getHouseholdObject(); + tcDmuObject.setPersonObject(personObj); + + // set the zone and dest attributes to the person's work location + tcDmuObject.setDmuIndexValues(hhObj.getHhId(), personObj.getWorkLocation(), + hhObj.getHhTaz(), personObj.getWorkLocation()); + + // compute utilities and choose telecommute alternative. + float logsum = (float) tcModel.computeUtilities(tcDmuObject, tcDmuObject.getDmuIndexValues()); + personObj.setTelecommuteLogsum(logsum); + + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + if (tcModel.getAvailabilityCount() > 0) + { + chosenAlt = tcModel.getChoiceResult(randomNumber); + } else + { + String decisionMaker = String.format("HHID=%d, PERSID=%d", hhObj.getHhId(), + personObj.getPersonId()); + String errorMessage = String + .format("Exception caught for %s, no available telecommute alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.error(errorMessage); + + tcModel.logUECResults(logger, decisionMaker); + throw new RuntimeException(); + } + + // write choice model alternative info to log file + if (hhObj.getDebugChoiceModels()) + { + String decisionMaker = String.format("HHID=%d, PERSID=%d", hhObj.getHhId(), + personObj.getPersonId()); + tcModel.logAlternativesInfo("Telecommute Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d with rn %.8f", + "Telecommute Choice", decisionMaker, chosenAlt, randomNumber)); + tcModel.logUECResults(logger, decisionMaker); + } + + return chosenAlt; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TimeCoefficientDistributions.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TimeCoefficientDistributions.java new file mode 100644 index 0000000..b2fb242 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TimeCoefficientDistributions.java @@ -0,0 +1,284 @@ +package org.sandag.abm.ctramp; + +import java.io.BufferedWriter; +import java.nio.charset.Charset; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.ResourceBundle; +import java.util.Scanner; +import java.util.Set; + +import org.apache.log4j.Logger; + +import com.pb.common.math.MersenneTwister; +import com.pb.common.util.ResourceUtil; + +import umontreal.iro.lecuyer.probdist.LognormalDist; + +public class TimeCoefficientDistributions { + + private static Logger logger = Logger.getLogger(TimeCoefficientDistributions.class); + protected LognormalDist timeDistributionWork; + protected LognormalDist timeDistributionNonWork; + + + /** + * Constructor; doesn't do anything (call @createTimeDistributions method next) + */ + public TimeCoefficientDistributions(){ + + } + + /** + * Reads the propertyMap and finds values for properties + * timeDistributionMean.work, and + * timeDistributionStandardDistribution.work. + * Creates and stores umontreal.iro.lecuyer.probdist.LognormalDist + * workDistribution for work tours & trips. + * Reads the propertyMap and finds values for properties + * timeDistributionMean.nonwork, + * timeDistributionStandardDistribution.nonwork. + * Creates and stores a umontreal.iro.lecuyer.probdist.LognormalDist + * nonworkDistribution for non-work tours & trips. + * @param propertyMap + */ + + public void createTimeDistributions(HashMap propertyMap){ + + double meanWork = new Double(propertyMap.get("timeDistribution.mean.work" )); + double sdWork = new Double(propertyMap.get("timeDistribution.standardDeviation.work" )); + + double locationWork = calculateLocation(meanWork, sdWork); + double scaleWork = calculateScale(meanWork, sdWork); + + timeDistributionWork = new LognormalDist(locationWork, scaleWork); + + double meanNonWork = new Double(propertyMap.get("timeDistribution.mean.nonWork" )); + double sdNonWork = new Double(propertyMap.get("timeDistribution.standardDeviation.nonWork" )); + + double locationNonWork = calculateLocation(meanNonWork, sdNonWork); + double scaleNonWork = calculateScale(meanNonWork, sdNonWork); + + timeDistributionNonWork = new LognormalDist(locationNonWork, scaleNonWork); + + } + + /** + * Calculate the lognormal distribution location given + * the mean and standard deviation of the distribution + * according to the formula: + * + * location = ln(mean/sqrt(1 + variance/mean^2)) + * + * @param mean + * @param standardDeviation + * @return Location variable (u) + */ + public double calculateLocation(double mean, double standardDeviation){ + + double variance = standardDeviation * standardDeviation; + double meanSquared = mean * mean; + double denom = Math.sqrt(1.0 + (variance/meanSquared)); + double location = mean/denom; + if(location<=0){ + logger.error("Error: Trying to calculation location for mean "+mean + +" and standard deviation "+standardDeviation); + throw new RuntimeException(); + } + + return Math.log(location); + + } + + /** + * Calculate the lognormal distribution scale given + * the mean and standard deviation of the distribution + * according to the formula: + * + * scale = sqrt(ln(1 + variance/mean^2)); + * + * @param mean + * @param standardDeviation + * @return Scale variable (sigma) + */ + public double calculateScale(double mean, double standardDeviation){ + + double variance = standardDeviation * standardDeviation; + double meanSquared = mean * mean; + return Math.sqrt(Math.log(1 + variance/meanSquared)); + + + } + + /** + * Sample from the work distribution and return the factor to apply to work + * travel time coefficient. + * @param rnum A unit-distributed random number. + * @return The sampled time factor for work tours & trips. + */ + public double sampleFromWorkDistribution(double rnum){ + + return timeDistributionWork.inverseF(rnum); + } + + /** + * Sample from the non-work distribution and return the factor to apply + * to the non non-work travel time coefficient. + * + * @param rnum A unit-distributed random number. + * @return The sampled time factor for non-work tours and trips. + */ + public double sampleFromNonWorkDistribution(double rnum){ + + return timeDistributionNonWork.inverseF(rnum); + } + + /** + * Get the time distribution for work. + * + * @return The lognormal distribution for work. + */ + public LognormalDist getTimeDistributionWork() { + return timeDistributionWork; + } + + /** + * Get the time distribution for non-work. + * + * @return The lognormal distribution for non-work. + */ + public LognormalDist getTimeDistributionNonWork() { + return timeDistributionNonWork; + } + + + /** + * This method reads the input person file, samples from the lognormal + * time distributions for work and for non-work tours and trips, and + * appends the two fields for each person on the person file, over-writing the + * input person file with the results. If the fields already exist, nothing is + * done. The fields added to the person file are: + * + * timeFactorWork + * timeFactorNonWork + * + * @param propertyMap A property map with the following properties: + * Project.Directory: the path to directory to read the person file from. + * PopulationSynthesizer.InputToCTRAMP.PersonFile: the input person file + * timeDistribution.randomSeed: a random seed for sampling from the distributions for each person + */ + public void appendTimeDistributionsOnPersonFile(HashMap propertyMap){ + + logger.info("Appending time factors to person file"); + String directory = propertyMap.get("Project.Directory"); + String personFile = directory + propertyMap.get("PopulationSynthesizer.InputToCTRAMP.PersonFile"); + + long seed = new Long(propertyMap.get("timeDistribution.randomSeed")); + MersenneTwister random = new MersenneTwister(seed); + + Charset ENCODING = StandardCharsets.UTF_8; + + logger.info(""); + logger.info("Reading person file "+personFile); + Path path = Paths.get(personFile); + ArrayList personData = new ArrayList(5000000); + String header = null; + + + int persons = 0; + + + try (Scanner scanner = new Scanner(path, ENCODING.name())){ + + header = scanner.nextLine(); + + // does first row of person file contain field names for time factors? + if(header.contains("timeFactorWork")){ + + logger.info("File "+personFile+ " contains time factor fields already"); + scanner.close(); + return; + + }else{ + while (scanner.hasNextLine()){ + //add the row to the person data array list + personData.add(scanner.nextLine()); + ++persons; + + if(persons % 100000 == 0) + logger.info("Reading person file line "+persons); + } + } + scanner.close(); + }catch(Exception e){ + logger.fatal("Error while reading "+personFile); + throw new RuntimeException(); + } + + logger.info("Appending time factors to person file "+personFile); + header = header +",timeFactorWork,timeFactorNonWork"; + + try (BufferedWriter writer = Files.newBufferedWriter(path, ENCODING)){ + + //write the header with the additional fields + writer.write(header); + writer.newLine(); + + //write each person line, sampling from the work and non-work distributions for each and + //appending the results onto the initial data + for(int person = 0; person pMap; + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else + { + rb = ResourceBundle.getBundle(args[0]); + pMap = ResourceUtil.getResourceBundleAsHashMap(args[0]); + } + + TimeCoefficientDistributions timeDistributions = new TimeCoefficientDistributions(); + timeDistributions.createTimeDistributions(pMap); + timeDistributions.appendTimeDistributionsOnPersonFile(pMap); + + logger.info("All done!"); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TimeDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TimeDMU.java new file mode 100644 index 0000000..65f09c5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TimeDMU.java @@ -0,0 +1,105 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class TimeDMU + implements Serializable, VariableTable +{ + + IndexValues dmuIndex = null; + + // switches used in the Individual Mandatory Tour Frequency Model + int imtfWorkSwitch, imtfSchoolSwitch; + + public TimeDMU() + { + dmuIndex = new IndexValues(); + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz, boolean debugUec) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debugUec) + { + dmuIndex.setDebug(true); + // dmuIndex.setDebugLabel ( "Debug IMTF Time UEC" ); + dmuIndex.setDebugLabel("Debug AO Time UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + // /** + // * Used in the Individual Mandatory Tour Frequency model; set to true + // * when the model is applied for a worker (to get round trip time to work, + // * which uses peak skims) + // * @param workOn + // */ + // public void setImtfWorkSwitch(int workOn){ + // imtfWorkSwitch = workOn; + // } + // + // /** + // * Used in the Individual Mandatory Tour Frequency model; set to true + // * when the model is applied for a student (to get round trip time to + // school, + // * which uses peak skims in the o/d direction and off-peak skims in the + // d/o + // * direction) + // * @param schoolOn + // */ + // public void setImtfSchoolSwitch(int schoolOn){ + // imtfSchoolSwitch = schoolOn; + // } + // + // public int getImtfWorkSwitch(){ + // return this.imtfWorkSwitch; + // } + // + // public int getImtfSchoolSwitch(){ + // return this.imtfSchoolSwitch; + // } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public int getIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/Tour.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Tour.java new file mode 100644 index 0000000..0646c5c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/Tour.java @@ -0,0 +1,875 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.ArrayList; + +import org.apache.log4j.Logger; + +public class Tour + implements Serializable +{ + + private Person perObj; + private Household hhObj; + + private String tourCategory; + private String tourPurpose; + private String subtourPurpose; + + // use this array to hold personNum (i.e. index values for Household.persons + // array) for persons in tour. + // for individual tour types, this array is null. + // for joint tours, there will be an entry for each participating person. + private int[] personNumArray; + + // alternative number chosen by the joint tour composition model ( 1=adults, + // 2=children, 3=mixed ). + private int jointTourComposition; + + private int tourId; + private int tourOrigMgra; + private int tourDestMgra; + private int tourOrigWalkSubzone; + private int tourDestWalkSubzone; + private int tourDepartPeriod; + private int tourArrivePeriod; + private int tourMode; + private int subtourFreqChoice; + private int tourParkMgra; + + private float timeOfDayLogsum; + private float tourModeLogsum; + private float subtourFreqLogsum; + private float tourDestinationLogsum; + private float stopFreqLogsum; + + + private int tourPrimaryPurposeIndex; + + private float[] tourModalProbabilities; + private float[] tourModalUtilities; + + private int stopFreqChoice; + private Stop[] outboundStops; + private Stop[] inboundStops; + + private ArrayList outboundStopDestinationLogsums; + private ArrayList inboundStopDestinationLogsums; + + //Dimension N-path by 3 - 0=btap, 1=atap, 2=skim set , 3=utility + private double[][] bestWtwTapPairsOut; + + + private double[][] bestWtwTapPairsIn; + private double[][] bestWtdTapPairsOut; + private double[][] bestWtdTapPairsIn; + private double[][] bestDtwTapPairsOut; + private double[][] bestDtwTapPairsIn; + + private int choosenTransitPathIn; + + private int choosenTransitPathOut; + + private boolean useOwnedAV; + + private double valueOfTime; + + private int escortTypeOutbound; + private int escortTypeInbound; + private int driverPnumOutbound; + private int driverPnumInbound; + + // this constructor used for mandatory tour creation + public Tour(Person perObj, int tourId, int primaryIndex) + { + hhObj = perObj.getHouseholdObject(); + this.perObj = perObj; + this.tourId = tourId; + tourCategory = ModelStructure.MANDATORY_CATEGORY; + tourPrimaryPurposeIndex = primaryIndex; + + outboundStopDestinationLogsums = new ArrayList(); + inboundStopDestinationLogsums = new ArrayList(); + } + + // this constructor used for joint tour creation + public Tour(Household hhObj, String tourPurpose, String category, int primaryIndex) + { + this.hhObj = hhObj; + this.tourPurpose = tourPurpose; + tourCategory = category; + tourPrimaryPurposeIndex = primaryIndex; + outboundStopDestinationLogsums = new ArrayList(); + inboundStopDestinationLogsums = new ArrayList(); + } + + // this constructor used for individual non-mandatory or at-work subtour + // creation + public Tour(int id, Household hhObj, Person persObj, String tourPurpose, String category, + int primaryIndex) + { + this.hhObj = hhObj; + this.perObj = persObj; + tourId = id; + this.tourPurpose = tourPurpose; + tourCategory = category; + tourPrimaryPurposeIndex = primaryIndex; + outboundStopDestinationLogsums = new ArrayList(); + inboundStopDestinationLogsums = new ArrayList(); + } + + public Person getPersonObject() + { + return perObj; + } + + public void setPersonObject(Person p) + { + perObj = p; + } + + public void setPersonNumArray(int[] personNums) + { + personNumArray = personNums; + } + + public int[] getPersonNumArray() + { + return personNumArray; + } + + public boolean getPersonInJointTour(Person person) + { + boolean inTour = false; + for (int num : personNumArray) + { + if (person.getPersonNum() == num) + { + inTour = true; + break; + } + } + return inTour; + } + + public void setJointTourComposition(int compositionAlternative) + { + jointTourComposition = compositionAlternative; + } + + public int getJointTourComposition() + { + return jointTourComposition; + } + + public void setTourPurpose(String name) + { + tourPurpose = name; + } + + public void setSubTourPurpose(String name) + { + subtourPurpose = name; + } + + public String getSubTourPurpose() + { + return subtourPurpose; + } + + public String getTourCategory() + { + return tourCategory; + } + + public String getTourPurpose() + { + return tourPurpose; + } + + public String getTourPrimaryPurpose() + { + int index = tourPurpose.indexOf('_'); + if (index < 0) return tourPurpose; + else return tourPurpose.substring(0, index); + } + + // public int getTourPurposeIndex() { + // return tourPurposeIndex; + // } + + public int getTourPrimaryPurposeIndex() + { + return tourPrimaryPurposeIndex; + } + + public int getTourModeChoice() + { + return tourMode; + } + + public void setTourId(int id) + { + tourId = id; + } + + public void setTourOrigMgra(int origMgra) + { + tourOrigMgra = origMgra; + } + + public void setTourDestMgra(int destMgra) + { + tourDestMgra = destMgra; + } + + public void setTourOrigWalkSubzone(int subzone) + { + tourOrigWalkSubzone = subzone; + } + + public void setTourDestWalkSubzone(int subzone) + { + tourDestWalkSubzone = subzone; + } + + public void setTourDepartPeriod(int departPeriod) + { + tourDepartPeriod = departPeriod; + } + + public void setTourArrivePeriod(int arrivePeriod) + { + tourArrivePeriod = arrivePeriod; + } + + public void setTourModeChoice(int modeIndex) + { + tourMode = modeIndex; + } + + public void setTourParkMgra(int parkMgra) + { + tourParkMgra = parkMgra; + } + + // methods DMU will use to get info from household object + + public int getTourOrigMgra() + { + return tourOrigMgra; + } + + public int getTourDestMgra() + { + return tourDestMgra; + } + + public int getTourOrigWalkSubzone() + { + return tourOrigWalkSubzone; + } + + public int getTourDestWalkSubzone() + { + return tourDestWalkSubzone; + } + + public int getTourDepartPeriod() + { + return tourDepartPeriod; + } + + public int getTourArrivePeriod() + { + return tourArrivePeriod; + } + + public int getTourParkMgra() + { + return tourParkMgra; + } + + public int getHhId() + { + return hhObj.getHhId(); + } + + public int getHhMgra() + { + return hhObj.getHhMgra(); + } + + public int getTourId() + { + return tourId; + } + + public int getWorkTourIndexFromSubtourId(int subtourIndex) + { + // when subtour was created, it's purpose index was set to 10*work + // purpose + // index + at-work subtour index + return subtourIndex / 10; + } + + public int getSubtourIndexFromSubtourId(int subtourIndex) + { + // when subtour was created, it's purpose index was set to 10*work + // purpose + // index + at-work subtour index + int workTourIndex = subtourIndex / 10; + return subtourIndex - 10 * workTourIndex; + } + + public void setSubtourFreqChoice(int choice) + { + subtourFreqChoice = choice; + } + + public int getSubtourFreqChoice() + { + return subtourFreqChoice; + } + + public void setStopFreqChoice(int chosenAlt) + { + stopFreqChoice = chosenAlt; + } + + public int getStopFreqChoice() + { + return stopFreqChoice; + } + + public void createOutboundStops(String[] stopOrigPurposes, String[] stopDestPurposes, + int[] stopPurposeIndex) + { + outboundStops = new Stop[stopOrigPurposes.length]; + for (int i = 0; i < stopOrigPurposes.length; i++) + outboundStops[i] = new Stop(this, stopOrigPurposes[i], stopDestPurposes[i], i, false, + stopPurposeIndex[i]); + } + + public void createInboundStops(String[] stopOrigPurposes, String[] stopDestPurposes, + int[] stopPurposeIndex) + { + // needs outbound stops to be created first to get id numbering correct + + inboundStops = new Stop[stopOrigPurposes.length]; + for (int i = 0; i < stopOrigPurposes.length; i++) + inboundStops[i] = new Stop(this, stopOrigPurposes[i], stopDestPurposes[i], i, true, + stopPurposeIndex[i]); + } + + /** + * Create a Stop object to represent a half-tour where no stops were + * generated. The id for the stop is set to -1 so that trips for half-tours + * without stops can be distinguished in the output trip files from turs + * that have stops. Trips for these tours come from stop objects with ids in + * the range 0,...,3. + * + * @param origPurp + * is "home" or "work" (for at-work subtours) if outbound, or the + * primary tour purpose if inbound + * @param destPurp + * is "home" or "work" (for at-work subtours) if inbound, or the + * primary tour purpose if outbound + * @param inbound + * is true if the half-tour is inbound, or false if outbound. + * @return the created Stop object. + */ + public Stop createStop(String origPurp, String destPurp, + boolean inbound, boolean subtour) + { + Stop stop = null; + int id = -1; + if (inbound) + { + inboundStops = new Stop[1]; + inboundStops[0] = new Stop(this, origPurp, destPurp, id, inbound, 0); + stop = inboundStops[0]; + } else + { + outboundStops = new Stop[1]; + outboundStops[0] = new Stop(this, origPurp, destPurp, id, inbound, 0); + stop = outboundStops[0]; + } + return stop; + } + + public int getNumOutboundStops() + { + if (outboundStops == null) return 0; + else return outboundStops.length; + } + + public int getNumInboundStops() + { + if (inboundStops == null) return 0; + else return inboundStops.length; + } + + public Stop[] getOutboundStops() + { + return outboundStops; + } + + public Stop[] getInboundStops() + { + return inboundStops; + } + + public void clearStopModelResults() + { + stopFreqChoice = 0; + outboundStops = null; + inboundStops = null; + } + + public String getTourWindow(String purposeAbbreviation) + { + String returnString = String.format(" %5s: |", purposeAbbreviation); + short[] windows = perObj.getTimeWindows(); + for (int i = 1; i < windows.length; i++) + { + String tempString = String.format("%s", + i >= tourDepartPeriod && i <= tourArrivePeriod ? purposeAbbreviation : " "); + if (tempString.length() == 2 || tempString.length() == 3) + tempString = " " + tempString; + returnString += String.format("%4s|", tempString); + } + return returnString; + } + + public int getEscortTypeOutbound() { + return escortTypeOutbound; + } + public void setEscortTypeOutbound(int escortType) { + this.escortTypeOutbound = escortType; + } + public int getEscortTypeInbound() { + return escortTypeInbound; + } + public void setEscortTypeInbound(int escortType) { + this.escortTypeInbound = escortType; + } + public int getDriverPnumOutbound() { + return driverPnumOutbound; + } + public void setDriverPnumOutbound(int driverPnum) { + this.driverPnumOutbound = driverPnum; + } + public int getDriverPnumInbound() { + return driverPnumInbound; + } + public void setDriverPnumInbound(int driverPnum) { + this.driverPnumInbound = driverPnum; + } + public void logTourObject(Logger logger, int totalChars) + { + + String personNumArrayString = "-"; + if (personNumArray != null) + { + personNumArrayString = "[ "; + personNumArrayString += String.format("%d", personNumArray[0]); + for (int i = 1; i < personNumArray.length; i++) + personNumArrayString += String.format(", %d", personNumArray[i]); + personNumArrayString += " ]"; + } + + Household.logHelper(logger, "tourId: ", tourId, totalChars); + Household.logHelper(logger, "tourCategory: ", tourCategory, totalChars); + Household.logHelper(logger, "tourPurpose: ", tourPurpose, totalChars); + Household.logHelper(logger, "tourPurposeIndex: ", tourPrimaryPurposeIndex, totalChars); + Household.logHelper(logger, "personNumArray: ", personNumArrayString, totalChars); + Household.logHelper(logger, "jointTourComposition: ", jointTourComposition, totalChars); + Household.logHelper(logger, "tourOrigMgra: ", tourOrigMgra, totalChars); + Household.logHelper(logger, "tourDestMgra: ", tourDestMgra, totalChars); + Household.logHelper(logger, "tourOrigWalkSubzone: ", tourOrigWalkSubzone, totalChars); + Household.logHelper(logger, "tourDestWalkSubzone: ", tourDestWalkSubzone, totalChars); + Household.logHelper(logger, "tourDepartPeriod: ", tourDepartPeriod, totalChars); + Household.logHelper(logger, "tourArrivePeriod: ", tourArrivePeriod, totalChars); + Household.logHelper(logger, "tourMode: ", tourMode, totalChars); + Household.logHelper(logger, "escortTypeOutbound: ", escortTypeOutbound, totalChars); + Household.logHelper(logger, "driverPnumOutbound: ", driverPnumOutbound, totalChars); + Household.logHelper(logger, "escortTypeInbound: ", escortTypeInbound, totalChars); + Household.logHelper(logger, "driverPnumInbound: ", driverPnumInbound, totalChars); + Household.logHelper(logger, "stopFreqChoice: ", stopFreqChoice, totalChars); + + String tempString = String.format("outboundStops[%s]:", + outboundStops == null ? "" : String.valueOf(outboundStops.length)); + logger.info(tempString); + + tempString = String.format("inboundStops[%s]:", + inboundStops == null ? "" : String.valueOf(inboundStops.length)); + logger.info(tempString); + + if ( bestWtwTapPairsOut == null ) { + tempString = "bestWtwTapPairsOut: no tap pairs saved"; + } + else { + if ( bestWtwTapPairsOut[0] == null ) + tempString = "bestWtwTapPairsOut: " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString = "bestWtwTapPairsOut: " + 0 + "[" + bestWtwTapPairsOut[0][0] + "," + bestWtwTapPairsOut[0][1] + "," + bestWtwTapPairsOut[0][2] + "]"; + for (int i=1; i < bestWtwTapPairsOut.length; i++) + if ( bestWtwTapPairsOut[i] == null ) + tempString += ", " + i + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString += ", " + i + "[" + bestWtwTapPairsOut[i][0] + "," + bestWtwTapPairsOut[i][1] + "," + bestWtwTapPairsOut[0][2] + "]"; + + tempString += ", choosenTransitPathOut: " + choosenTransitPathOut; + } + logger.info(tempString); + + if ( bestWtwTapPairsIn == null ) { + tempString = "bestWtwTapPairsIn: no tap pairs saved"; + } + else { + if ( bestWtwTapPairsIn[0] == null ) + tempString = "bestWtwTapPairsIn: " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString = "bestWtwTapPairsIn: " + 0 + "[" + bestWtwTapPairsIn[0][0] + "," + bestWtwTapPairsIn[0][1] + "," + bestWtwTapPairsIn[0][2] + "]"; + for (int i=1; i < bestWtwTapPairsIn.length; i++) + if ( bestWtwTapPairsIn[i] == null ) + tempString += ", " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString += ", " + i + "[" + bestWtwTapPairsIn[i][0] + "," + bestWtwTapPairsIn[i][1] + "," + bestWtwTapPairsIn[0][2] + "]"; + + tempString += ", choosenTransitPathIn: " + choosenTransitPathIn; + } + logger.info(tempString); + + if ( bestWtdTapPairsOut == null ) { + tempString = "bestWtdTapPairsOut: no tap pairs saved"; + } + else { + if ( bestWtdTapPairsOut[0] == null ) + tempString = "bestWtdTapPairsOut: " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString = "bestWtdTapPairsOut: " + 0 + "[" + bestWtdTapPairsOut[0][0] + "," + bestWtdTapPairsOut[0][1] + "," + bestWtdTapPairsOut[0][2] + "]"; + for (int i=1; i < bestWtdTapPairsOut.length; i++) + if ( bestWtdTapPairsOut[i] == null ) + tempString += ", " + i + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString += ", " + i + "[" + bestWtdTapPairsOut[i][0] + "," + bestWtdTapPairsOut[i][1] + "," + bestWtdTapPairsOut[0][2] + "]"; + + tempString += ", choosenTransitPathOut: " + choosenTransitPathOut; + } + logger.info(tempString); + + if ( bestWtdTapPairsIn == null ) { + tempString = "bestWtdTapPairsIn: no tap pairs saved"; + } + else { + if ( bestWtdTapPairsIn[0] == null ) + tempString = "bestWtdTapPairsIn: " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString = "bestWtdTapPairsIn: " + 0 + "[" + bestWtdTapPairsIn[0][0] + "," + bestWtdTapPairsIn[0][1] + "," + bestWtdTapPairsIn[0][2] + "]"; + for (int i=1; i < bestWtdTapPairsIn.length; i++) + if ( bestWtdTapPairsIn[i] == null ) + tempString += ", " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString += ", " + i + "[" + bestWtdTapPairsIn[i][0] + "," + bestWtdTapPairsIn[i][1] + "," + bestWtdTapPairsIn[0][2] + "]"; + + tempString += ", choosenTransitPathIn: " + choosenTransitPathIn; + } + logger.info(tempString); + + if ( bestDtwTapPairsOut == null ) { + tempString = "bestDtwTapPairsOut: no tap pairs saved"; + } + else { + if ( bestDtwTapPairsOut[0] == null ) + tempString = "bestDtwTapPairsOut: " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString = "bestDtwTapPairsOut: " + 0 + "[" + bestDtwTapPairsOut[0][0] + "," + bestDtwTapPairsOut[0][1] + "," + bestDtwTapPairsOut[0][2] + "]"; + for (int i=1; i < bestDtwTapPairsOut.length; i++) + if ( bestDtwTapPairsOut[i] == null ) + tempString += ", " + i + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString += ", " + i + "[" + bestDtwTapPairsOut[i][0] + "," + bestDtwTapPairsOut[i][1] + "," + bestDtwTapPairsOut[0][2] + "]"; + + tempString += ", choosenTransitPathOut: " + choosenTransitPathOut; + } + logger.info(tempString); + + if ( bestDtwTapPairsIn == null ) { + tempString = "bestDtwTapPairsIn: no tap pairs saved"; + } + else { + if ( bestDtwTapPairsIn[0] == null ) + tempString = "bestDtwTapPairsIn: " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString = "bestDtwTapPairsIn: " + 0 + "[" + bestDtwTapPairsIn[0][0] + "," + bestDtwTapPairsIn[0][1] + "," + bestDtwTapPairsIn[0][2] + "]"; + for (int i=1; i < bestDtwTapPairsIn.length; i++) + if ( bestDtwTapPairsIn[i] == null ) + tempString += ", " + 0 + "[" + "none" + "," + "none" + "," + "none" + "]"; + else + tempString += ", " + i + "[" + bestDtwTapPairsIn[i][0] + "," + bestDtwTapPairsIn[i][1] + "," + bestDtwTapPairsIn[0][2] + "]"; + + tempString += ", choosenTransitPathIn: " + choosenTransitPathIn; + } + logger.info(tempString); + + } + + public void logEntireTourObject(Logger logger) + { + + int totalChars = 60; + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "-"; + + String personNumArrayString = "-"; + if (personNumArray != null) + { + personNumArrayString = "[ "; + personNumArrayString += String.format("%d", personNumArray[0]); + for (int i = 1; i < personNumArray.length; i++) + personNumArrayString += String.format(", %d", personNumArray[i]); + personNumArrayString += " ]"; + } + + Household.logHelper(logger, "tourId: ", tourId, totalChars); + Household.logHelper(logger, "tourCategory: ", tourCategory, totalChars); + Household.logHelper(logger, "tourPurpose: ", tourPurpose, totalChars); + Household.logHelper(logger, "tourPurposeIndex: ", tourPrimaryPurposeIndex, totalChars); + Household.logHelper(logger, "personNumArray: ", personNumArrayString, totalChars); + Household.logHelper(logger, "jointTourComposition: ", jointTourComposition, totalChars); + Household.logHelper(logger, "tourOrigMgra: ", tourOrigMgra, totalChars); + Household.logHelper(logger, "tourDestMgra: ", tourDestMgra, totalChars); + Household.logHelper(logger, "tourOrigWalkSubzone: ", tourOrigWalkSubzone, totalChars); + Household.logHelper(logger, "tourDestWalkSubzone: ", tourDestWalkSubzone, totalChars); + Household.logHelper(logger, "tourDepartPeriod: ", tourDepartPeriod, totalChars); + Household.logHelper(logger, "tourArrivePeriod: ", tourArrivePeriod, totalChars); + Household.logHelper(logger, "driverPnumOutbound: ", driverPnumOutbound, totalChars); + Household.logHelper(logger, "escortTypeInbound: ", escortTypeInbound, totalChars); + Household.logHelper(logger, "driverPnumInbound: ", driverPnumInbound, totalChars); + Household.logHelper(logger, "tourMode: ", tourMode, totalChars); + Household.logHelper(logger, "stopFreqChoice: ", stopFreqChoice, totalChars); + + if (outboundStops != null) + { + logger.info("Outbound Stops:"); + if (outboundStops.length > 0) + { + for (int i = 0; i < outboundStops.length; i++) + outboundStops[i].logStopObject(logger, totalChars); + } else + { + logger.info(" No outbound stops"); + } + } else + { + logger.info(" No outbound stops"); + } + + if (inboundStops != null) + { + logger.info("Inbound Stops:"); + if (inboundStops.length > 0) + { + for (int i = 0; i < inboundStops.length; i++) + inboundStops[i].logStopObject(logger, totalChars); + } else + { + logger.info(" No inbound stops"); + } + } else + { + logger.info(" No inbound stops"); + } + + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public void setTourModalUtilities(float[] utils) + { + tourModalUtilities = utils; + } + + public float[] getTourModalUtilities() + { + return tourModalUtilities; + } + + public void setTourModalProbabilities(float[] probs) + { + tourModalProbabilities = probs; + } + + public float[] getTourModalProbabilities() + { + return tourModalProbabilities; + } + + public void setBestWtwTapPairsOut(double[][] tapPairArray) + { + bestWtwTapPairsOut = tapPairArray; + } + + public void setBestWtwTapPairsIn(double[][] tapPairArray) + { + bestWtwTapPairsIn = tapPairArray; + } + + public void setBestWtdTapPairsOut(double[][] tapPairArray) + { + bestWtdTapPairsOut = tapPairArray; + } + + public void setBestWtdTapPairsIn(double[][] tapPairArray) + { + bestWtdTapPairsIn = tapPairArray; + } + + public void setBestDtwTapPairsOut(double[][] tapPairArray) + { + bestDtwTapPairsOut = tapPairArray; + } + + public void setBestDtwTapPairsIn(double[][] tapPairArray) + { + bestDtwTapPairsIn = tapPairArray; + } + + public void setChoosenTransitPathIn( int path ) + { + choosenTransitPathIn = path; + } + public void setChoosenTransitPathOut( int path ) + { + choosenTransitPathOut = path; + } + public double[][] getBestWtwTapPairsOut() + { + return bestWtwTapPairsOut; + } + + public double[][] getBestWtwTapPairsIn() + { + return bestWtwTapPairsIn; + } + + public double[][] getBestWtdTapPairsOut() + { + return bestWtdTapPairsOut; + } + + public double[][] getBestWtdTapPairsIn() + { + return bestWtdTapPairsIn; + } + + public double[][] getBestDtwTapPairsOut() + { + return bestDtwTapPairsOut; + } + + public double[][] getBestDtwTapPairsIn() + { + return bestDtwTapPairsIn; + } + + public double getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(double valueOfTime) { + this.valueOfTime = valueOfTime; + } + + public float getTimeOfDayLogsum() { + return timeOfDayLogsum; + } + + public void setTimeOfDayLogsum(float timeOfDayLogsum) { + this.timeOfDayLogsum = timeOfDayLogsum; + } + + public float getTourModeLogsum() { + return tourModeLogsum; + } + + public void setTourModeLogsum(float tourModeLogsum) { + this.tourModeLogsum = tourModeLogsum; + } + + public float getSubtourFreqLogsum() { + return subtourFreqLogsum; + } + + public void setSubtourFreqLogsum(float subtourFreqLogsum) { + this.subtourFreqLogsum = subtourFreqLogsum; + } + + public float getTourDestinationLogsum() { + return tourDestinationLogsum; + } + + public void setTourDestinationLogsum(float tourDestinationLogsum) { + this.tourDestinationLogsum = tourDestinationLogsum; + } + + public float getStopFreqLogsum() { + return stopFreqLogsum; + } + + public void setStopFreqLogsum(float stopFreqLogsum) { + this.stopFreqLogsum = stopFreqLogsum; + } + + public ArrayList getOutboundStopDestinationLogsums(){ + return outboundStopDestinationLogsums; + } + public ArrayList getInboundStopDestinationLogsums(){ + return inboundStopDestinationLogsums; + } + + public void addOutboundStopDestinationLogsum(float logsum){ + outboundStopDestinationLogsums.add(logsum); + } + + public void addInboundStopDestinationLogsum(float logsum){ + inboundStopDestinationLogsums.add(logsum); + } + + public boolean getUseOwnedAV() { + return useOwnedAV; + } + + public void setUseOwnedAV(boolean useOwnedAV) { + this.useOwnedAV = useOwnedAV; + } + + /** + * Iterate through persons on tour and return non-work time factor + * for oldest person. If the person array is null then return 1.0. + * + * @return Time factor for oldest person on joint tour. + */ + public double getJointTourTimeFactor() { + int[] personNumArray = getPersonNumArray(); + int oldestAge = -999; + Person oldestPerson = null; + for (int num : personNumArray){ + Person p = hhObj.getPerson(num); + if(p.getAge() > oldestAge){ + oldestPerson = p; + oldestAge = p.getAge(); + } + } + if(oldestPerson != null) + return oldestPerson.getTimeFactorNonWork(); + + return 1.0; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourDepartureTimeAndDurationDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourDepartureTimeAndDurationDMU.java new file mode 100644 index 0000000..6e55920 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourDepartureTimeAndDurationDMU.java @@ -0,0 +1,864 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class TourDepartureTimeAndDurationDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TourDepartureTimeAndDurationDMU.class); + + protected HashMap methodIndexMap; + + protected IndexValues dmuIndex; + + protected Person person; + protected Household household; + protected Tour tour; + + protected double destEmpDen; + protected int subsequentTourIsWork; + protected int subsequentTourIsSchool; + + protected double[] modeChoiceLogsums; + + private int[] altStarts; + private int[] altEnds; + + protected int originAreaType, destinationAreaType; + + protected int tourNumber; + + protected int firstTour; + protected int subsequentTour; + protected int endOfPreviousScheduledTour; + + protected ModelStructure modelStructure; + + public TourDepartureTimeAndDurationDMU(ModelStructure modelStructure) + { + this.modelStructure = modelStructure; + dmuIndex = new IndexValues(); + } + + public void setPerson(Person passedInPerson) + { + person = passedInPerson; + } + + public void setHousehold(Household passedInHousehold) + { + household = passedInHousehold; + + // set the origin and zone indices + dmuIndex.setZoneIndex(household.getHhMgra()); + dmuIndex.setHHIndex(household.getHhId()); + + // set the debug flag that can be used in the UEC + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (household.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug DepartTime UEC"); + } + + } + + public void setTour(Tour passedInTour) + { + tour = passedInTour; + } + + public void setOriginZone(int zone) + { + dmuIndex.setOriginZone(zone); + } + + public void setDestinationZone(int zone) + { + dmuIndex.setDestZone(zone); + } + + public void setOriginAreaType(int areaType) + { + originAreaType = areaType; + } + + public void setDestinationAreaType(int areaType) + { + destinationAreaType = areaType; + } + + public void setDestEmpDen(double arg) + { + destEmpDen = arg; + } + + public void setFirstTour(int trueOrFalse) + { + firstTour = trueOrFalse; + } + + public void setSubsequentTour(int trueOrFalse) + { + subsequentTour = trueOrFalse; + } + + public void setSubsequentTourIsWork(int trueOrFalse) + { + subsequentTourIsWork = trueOrFalse; + } + + public void setSubsequentTourIsSchool(int trueOrFalse) + { + subsequentTourIsSchool = trueOrFalse; + } + + /** + * Set the sequence number of this tour among all scheduled + * + * @param tourNum + */ + public void setTourNumber(int tourNum) + { + tourNumber = tourNum; + } + + public void setEndOfPreviousScheduledTour(int endHr) + { + endOfPreviousScheduledTour = endHr; + } + + public void setModeChoiceLogsums(double[] logsums) + { + modeChoiceLogsums = logsums; + } + + public void setTodAlts(int[] altStarts, int[] altEnds) + { + this.altStarts = altStarts; + this.altEnds = altEnds; + } + + public IndexValues getIndexValues() + { + return (dmuIndex); + } + + public Household getDmuHouseholdObject() + { + return household; + } + + public int getOriginZone() + { + return (dmuIndex.getOriginZone()); + } + + public int getDestinationZone() + { + return (dmuIndex.getDestZone()); + } + + public int getOriginAreaType() + { + return (originAreaType); + } + + public int getDestinationAreaType() + { + return (destinationAreaType); + } + + public int getPreDrivingAgeChild() + { + return (person.getPersonIsStudentNonDriving() == 1 || person.getPersonIsPreschoolChild() == 1) ? 1 + : 0; + } + + public int getPersonAge() + { + return person.getAge(); + } + + public int getPersonIsFemale() + { + return person.getGender() == 2 ? 1 : 0; + } + + public int getHouseholdSize() + { + return household.getHhSize(); + } + + public int getNumPreschoolChildrenInHh() + { + return household.getNumPreschool(); + } + + public int getNumChildrenUnder16InHh() + { + return household.getNumChildrenUnder16(); + } + + public int getNumNonWorkingAdultsInHh() + { + return household.getNumberOfNonWorkingAdults(); + } + + public int getFullTimeWorker() + { + return (this.person.getPersonTypeIsFullTimeWorker()); + } + + public int getPartTimeWorker() + { + return (this.person.getPersonTypeIsPartTimeWorker()); + } + + public int getUniversityStudent() + { + return (this.person.getPersonIsUniversityStudent()); + } + + public int getStudentDrivingAge() + { + return (this.person.getPersonIsStudentDriving()); + } + + public int getStudentNonDrivingAge() + { + return (this.person.getPersonIsStudentNonDriving()); + } + + public int getNonWorker() + { + return (this.person.getPersonIsNonWorkingAdultUnder65()); + } + + public int getRetired() + { + return (this.person.getPersonIsNonWorkingAdultOver65()); + } + + public int getAllAdultsFullTimeWorkers() + { + Person[] p = household.getPersons(); + boolean allAdultsAreFullTimeWorkers = true; + for (int i = 1; i < p.length; i++) + { + if (p[i].getPersonIsAdult() == 1 && p[i].getPersonIsFullTimeWorker() == 0) + { + allAdultsAreFullTimeWorkers = false; + break; + } + } + + if (allAdultsAreFullTimeWorkers) return 1; + else return 0; + } + + public int getSubtourPurposeIsEatOut() + { + if (tour.getSubTourPurpose().equalsIgnoreCase(modelStructure.AT_WORK_EAT_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getSubtourPurposeIsBusiness() + { + if (tour.getSubTourPurpose().equalsIgnoreCase(modelStructure.AT_WORK_BUSINESS_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getSubtourPurposeIsOther() + { + if (tour.getSubTourPurpose().equalsIgnoreCase(modelStructure.AT_WORK_MAINT_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getTourPurposeIsShopping() + { + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.SHOPPING_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getTourPurposeIsEatOut() + { + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.EAT_OUT_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getTourPurposeIsMaint() + { + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.OTH_MAINT_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getTourPurposeIsVisit() + { + if (tour.getTourPurpose().equalsIgnoreCase(modelStructure.SOCIAL_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getTourPurposeIsDiscr() + { + if (tour.getTourPurpose().equalsIgnoreCase(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getNumIndivShopTours() + { + int count = 0; + for (Tour t : person.getListOfIndividualNonMandatoryTours()) + if (t.getTourPurpose().equalsIgnoreCase(ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME)) + count++; + + return count; + } + + public int getNumIndivMaintTours() + { + int count = 0; + for (Tour t : person.getListOfIndividualNonMandatoryTours()) + if (t.getTourPurpose().equalsIgnoreCase(ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME)) + count++; + + return count; + } + + public int getNumIndivVisitTours() + { + int count = 0; + for (Tour t : person.getListOfIndividualNonMandatoryTours()) + if (t.getTourPurpose().equalsIgnoreCase(ModelStructure.VISITING_PRIMARY_PURPOSE_NAME)) + count++; + + return count; + } + + public int getNumIndivDiscrTours() + { + int count = 0; + for (Tour t : person.getListOfIndividualNonMandatoryTours()) + if (t.getTourPurpose().equalsIgnoreCase(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME)) + count++; + + return count; + } + + /* + * if ( tour.getTourCategory() == ModelStructure.AT_WORK_CATEGORY ) { return + * tour.getTourPurposeIndex(); } else { return 0; } } + */ + + public int getAdultsInTour() + { + + int count = 0; + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + Person[] persons = household.getPersons(); + + int[] personNums = tour.getPersonNumArray(); + for (int i = 0; i < personNums.length; i++) + { + int p = personNums[i]; + if (persons[p].getPersonIsAdult() == 1) count++; + } + } else if (tour.getTourCategory().equalsIgnoreCase( + ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY)) + { + if (person.getPersonIsAdult() == 1) count = 1; + } + + return count; + } + + public int getJointTourPartySize() + { + int count = 0; + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + count = tour.getPersonNumArray().length; + + return count; + } + + public int getKidsOnJointTour() + { + + int count = 0; + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + Person[] persons = household.getPersons(); + + int[] personNums = tour.getPersonNumArray(); + for (int i = 0; i < personNums.length; i++) + { + int p = personNums[i]; + if ((persons[p].getPersonIsPreschoolChild() + + persons[p].getPersonIsStudentNonDriving() + persons[p] + .getPersonIsStudentDriving()) > 0) count++; + } + } + + return count > 0 ? 1 : 0; + + } + + // return 1 if at least one preschool or pre-driving child is in joint tour, + // otherwise 0. + public int getPreschoolPredrivingInTour() + { + + int count = 0; + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + Person[] persons = household.getPersons(); + int[] personNums = tour.getPersonNumArray(); + for (int i = 0; i < personNums.length; i++) + { + int p = personNums[i]; + if (persons[p].getPersonIsPreschoolChild() == 1 + || persons[p].getPersonIsStudentNonDriving() == 1) return 1; + } + } else if (tour.getTourCategory().equalsIgnoreCase( + ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY)) + { + if (person.getPersonIsPreschoolChild() == 1 + || person.getPersonIsStudentNonDriving() == 1) count = 1; + } + + return count; + + } + + // return 1 if the person is preschool + public int getPreschool() + { + return person.getPersonIsPreschoolChild() == 1 ? 1 : 0; + + } + + // return 1 if at least one university student is in joint tour, otherwise + // 0. + public int getUnivInTour() + { + + int count = 0; + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + Person[] persons = household.getPersons(); + int[] personNums = tour.getPersonNumArray(); + for (int i = 0; i < personNums.length; i++) + { + int p = personNums[i]; + if (persons[p].getPersonIsUniversityStudent() == 1) return 1; + } + } else if (tour.getTourCategory().equalsIgnoreCase( + ModelStructure.INDIVIDUAL_NON_MANDATORY_CATEGORY)) + { + if (person.getPersonIsUniversityStudent() == 1) count = 1; + } + + return count; + + } + + // return 1 if all adults in joint tour are fulltime workers, 0 otherwise; + public int getAllWorkFull() + { + + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + int adultCount = 0; + int ftWorkerAdultCount = 0; + + Person[] persons = household.getPersons(); + int[] personNums = tour.getPersonNumArray(); + for (int i = 0; i < personNums.length; i++) + { + int p = personNums[i]; + if (persons[p].getPersonIsAdult() == 1) + { + adultCount++; + if (persons[p].getPersonIsFullTimeWorker() == 1) ftWorkerAdultCount++; + } + } + + if (adultCount > 0 && adultCount == ftWorkerAdultCount) return 1; + else return 0; + } + + return 0; + + } + + public int getPartyComp() + { + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + return tour.getJointTourComposition(); + } else + { + return 0; + } + } + + /** + * @return number of individual non-mandatory tours, including escort, for + * the person + */ + public int getPersonNonMandatoryTotalWithEscort() + { + return person.getListOfIndividualNonMandatoryTours().size(); + } + + /** + * @return number of individual non-mandatory tours, excluding escort, for + * the person + */ + public int getPersonNonMandatoryTotalNoEscort() + { + int count = 0; + for (Tour t : person.getListOfIndividualNonMandatoryTours()) + if (!t.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME)) count++; + return count; + } + + /** + * @return number of individual non-mandatory discretionary tours for the + * person + */ + public int getPersonDiscrToursTotal() + { + int count = 0; + for (Tour t : person.getListOfIndividualNonMandatoryTours()) + { + if (t.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME) + || t.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME) + || t.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME)) count++; + } + return count; + } + + /** + * @return number of individual non-mandatory tours, excluding escort, for + * the person + */ + public int getPersonEscortTotal() + { + int count = 0; + for (Tour t : person.getListOfIndividualNonMandatoryTours()) + if (t.getTourPurpose().startsWith("escort")) count++; + return count; + } + + public int getHhJointTotal() + { + Tour[] jt = household.getJointTourArray(); + if (jt == null) return 0; + else return jt.length; + } + + public int getPersonMandatoryTotal() + { + return person.getListOfWorkTours().size() + person.getListOfSchoolTours().size(); + } + + public int getPersonJointTotal() + { + Tour[] jtArray = household.getJointTourArray(); + if (jtArray == null) + { + return 0; + } else + { + int numJtParticipations = 0; + for (Tour jt : jtArray) + { + int[] personJtIndices = jt.getPersonNumArray(); + for (int pNum : personJtIndices) + { + if (pNum == person.getPersonNum()) + { + numJtParticipations++; + break; + } + } + } + return numJtParticipations; + } + } + + public int getPersonJointAndIndivDiscrToursTotal() + { + + int totDiscr = getPersonDiscrToursTotal(); + + Tour[] jtArray = household.getJointTourArray(); + if (jtArray == null) + { + return totDiscr; + } else + { + // count number of joint discretionary tours person participates in + int numJtParticipations = 0; + for (Tour jt : jtArray) + { + if (jt.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME) + || jt.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.VISITING_PRIMARY_PURPOSE_NAME) + || jt.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME)) + { + int[] personJtIndices = jt.getPersonNumArray(); + for (int pNum : personJtIndices) + { + if (pNum == person.getPersonNum()) + { + numJtParticipations++; + break; + } + } + } + } + return numJtParticipations + totDiscr; + } + } + + public int getFirstTour() + { + return firstTour; + } + + public int getSubsequentTour() + { + return subsequentTour; + } + + public int getWorkAndSchoolToursByWorker() + { + int returnValue = 0; + if (person.getPersonIsWorker() == 1) + { + if (person.getImtfChoice() == HouseholdIndividualMandatoryTourFrequencyModel.CHOICE_WORK_AND_SCHOOL) + returnValue = 1; + } + return returnValue; + } + + public int getWorkAndSchoolToursByStudent() + { + int returnValue = 0; + if (person.getPersonIsStudent() == 1) + { + if (person.getImtfChoice() == HouseholdIndividualMandatoryTourFrequencyModel.CHOICE_WORK_AND_SCHOOL) + returnValue = 1; + } + return returnValue; + } + + public double getModeChoiceLogsumAlt(int alt) + { + + int startPeriod = altStarts[alt - 1]; + int endPeriod = altEnds[alt - 1]; + + int index = modelStructure.getSkimPeriodCombinationIndex(startPeriod, endPeriod); + + return modeChoiceLogsums[index]; + + } + + public int getPrevTourEndsThisDeparturePeriodAlt(int alt) + { + + // get the departure period for the current alternative + int thisTourStartsPeriod = altStarts[alt - 1]; + + if (person.isPreviousArrival(thisTourStartsPeriod)) return 1; + else return 0; + + } + + public int getPrevTourBeginsThisArrivalPeriodAlt(int alt) + { + + // get the arrival period for the current alternative + int thisTourEndsPeriod = altStarts[alt - 1]; + + if (person.isPreviousDeparture(thisTourEndsPeriod)) return 1; + else return 0; + + } + + public int getAdjWindowBeforeThisPeriodAlt(int alt) + { + + int thisTourStartsPeriod = altStarts[alt - 1]; + + int numAdjacentPeriodsAvailable = 0; + for (int i = thisTourStartsPeriod - 1; i >= 0; i--) + { + if (person.isPeriodAvailable(i)) numAdjacentPeriodsAvailable++; + else break; + } + + return numAdjacentPeriodsAvailable; + + } + + public int getAdjWindowAfterThisPeriodAlt(int alt) + { + + int thisTourEndsPeriod = altEnds[alt - 1]; + + int numAdjacentPeriodsAvailable = 0; + for (int i = thisTourEndsPeriod + 1; i < modelStructure.getNumberOfTimePeriods(); i++) + { + if (person.isPeriodAvailable(i)) numAdjacentPeriodsAvailable++; + else break; + } + + return numAdjacentPeriodsAvailable; + + } + + public int getRemainingPeriodsAvailableAlt(int alt) + { + + int periodsAvail = person.getAvailableWindow(); + + int start = altStarts[alt - 1]; + int end = altEnds[alt - 1]; + + // determine the availabilty of each period after the alternative time + // window + // is hypothetically scheduled + // if start == end, the availability won't change, so no need to + // compute. + if (start != end) + { + + // the start and end periods will always be available after + // scheduling, so + // don't need to check them. + // the periods between start/end must be 0 or the alternative could + // not + // have been available, + // so count them all as unavailable after scheduling this window. + periodsAvail -= (end - start - 1); + + } + + return periodsAvail; + + } + + public float getRemainingInmToursToAvailablePeriodsRatioAlt(int alt) + { + int periodsAvail = getRemainingPeriodsAvailableAlt(alt); + if (periodsAvail > 0) + { + float ratio = (float) (person.getListOfIndividualNonMandatoryTours().size() - tourNumber) + / periodsAvail; + return ratio; + } else return -999; + } + + public int getMaximumAvailableTimeWindow() + { + return person.getMaximumContinuousAvailableWindow(); + } + + public int getMaxJointTimeWindow() + { + return household.getMaxJointTimeWindow(tour); + } + + /** + * get the number of tours left to be scheduled, including the current tour + * + * @return number of tours left to be scheduled, including the current tour + */ + public int getToursLeftToSchedule() + { + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + Tour[] jt = household.getJointTourArray(); + return jt.length - tourNumber + 1; + } else return person.getListOfIndividualNonMandatoryTours().size() - tourNumber + 1; + } + + public int getEndOfPreviousTour() + { + return endOfPreviousScheduledTour; + } + + public int getTourCategoryIsJoint() + { + return tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY) ? 1 + : 0; + } + + public float getOpSovTimeOd() + { + return 1; + } + + public float getOpSovTimeDo() + { + return 1; + } + + public int getDestMgraInCbd() + { + return 0; + } + + public int getOrigMgraInRural() + { + return 0; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourModeChoiceDMU.java new file mode 100644 index 0000000..7e83278 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourModeChoiceDMU.java @@ -0,0 +1,523 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class TourModeChoiceDMU implements Serializable, + VariableTable { + + protected transient Logger logger = Logger.getLogger(TourModeChoiceDMU.class); + + public static final int WTW = McLogsumsCalculator.WTW; + public static final int WTD = McLogsumsCalculator.WTD; + public static final int DTW = McLogsumsCalculator.DTW; + protected static final int NUM_ACC_EGR = McLogsumsCalculator.NUM_ACC_EGR; + + protected static final int OUT = McLogsumsCalculator.OUT; + protected static final int IN = McLogsumsCalculator.IN; + protected static final int NUM_DIR = McLogsumsCalculator.NUM_DIR; + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + protected float origTaxiWaitTime; + protected float destTaxiWaitTime; + protected float origSingleTNCWaitTime; + protected float destSingleTNCWaitTime; + protected float origSharedTNCWaitTime; + protected float destSharedTNCWaitTime; + + + protected Household hh; + protected Tour tour; + protected Tour workTour; + protected Person person; + + protected ModelStructure modelStructure; + + protected double origDuDen; + protected double origEmpDen; + protected double origTotInt; + protected double destDuDen; + protected double destEmpDen; + protected double destTotInt; + + protected double lsWgtAvgCostM; + protected double lsWgtAvgCostD; + protected double lsWgtAvgCostH; + protected double reimburseProportion; + protected int parkingArea; + + protected float pTazTerminalTime; + protected float aTazTerminalTime; + + protected double nmWalkTimeOut; + protected double nmWalkTimeIn; + protected double nmBikeTimeOut; + protected double nmBikeTimeIn; + + protected int originMgra; + protected int destMgra; + + protected double ivtCoeff; + protected double costCoeff; + + protected double[][] transitLogSum; + + + public TourModeChoiceDMU(ModelStructure modelStructure, Logger aLogger) { + this.modelStructure = modelStructure; + dmuIndex = new IndexValues(); + + //accEgr by in/outbound + transitLogSum = new double[NUM_ACC_EGR][NUM_DIR]; + + } + + public void setHouseholdObject(Household hhObject) { + hh = hhObject; + } + + + public Household getHouseholdObject() { + return hh; + } + + public void setPersonObject(Person personObject) { + person = personObject; + } + + public Person getPersonObject() { + return person; + } + + public void setWorkTourObject(Tour tourObject) { + workTour = tourObject; + } + + public void setTourObject(Tour tourObject) { + tour = tourObject; + } + + public Tour getTourObject() { + return tour; + } + + public int getParkingArea() { + return parkingArea; + } + + public void setParkingArea(int parkingArea) { + this.parkingArea = parkingArea; + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, + int destIndex, boolean debug) { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public int getPersonType() { + return person.getPersonTypeNumber(); + } + + public void setOrigDuDen(double arg) { + origDuDen = arg; + } + + public void setOrigEmpDen(double arg) { + origEmpDen = arg; + } + + public void setOrigTotInt(double arg) { + origTotInt = arg; + } + + public void setDestDuDen(double arg) { + destDuDen = arg; + } + + public void setDestEmpDen(double arg) { + destEmpDen = arg; + } + + public void setDestTotInt(double arg) { + destTotInt = arg; + } + + public void setReimburseProportion(double proportion) { + reimburseProportion = proportion; + } + + public void setLsWgtAvgCostM(double cost) { + lsWgtAvgCostM = cost; + } + + public void setLsWgtAvgCostD(double cost) { + lsWgtAvgCostD = cost; + } + + public void setLsWgtAvgCostH(double cost) { + lsWgtAvgCostH = cost; + } + + public void setPTazTerminalTime(float time) { + pTazTerminalTime = time; + } + + public void setATazTerminalTime(float time) { + aTazTerminalTime = time; + } + + public IndexValues getDmuIndexValues() { + return dmuIndex; + } + + public void setIndexDest(int d) { + dmuIndex.setDestZone(d); + } + + public void setTransitLogSum(int accEgr, boolean inbound, double value){ + transitLogSum[accEgr][inbound == true ? 1 : 0] = value; + } + + protected double getTransitLogSum(int accEgr,boolean inbound){ + return transitLogSum[accEgr][inbound == true ? 1 : 0]; + } + + public int getWorkTourModeIsSov() { + boolean tourModeIsSov = modelStructure.getTourModeIsSov(workTour + .getTourModeChoice()); + return tourModeIsSov ? 1 : 0; + } + + public int getWorkTourModeIsHov() { + boolean tourModeIsHov = modelStructure.getTourModeIsHov(workTour + .getTourModeChoice()); + return tourModeIsHov ? 1 : 0; + } + + public int getWorkTourModeIsBike() { + boolean tourModeIsBike = modelStructure.getTourModeIsBike(workTour + .getTourModeChoice()); + return tourModeIsBike ? 1 : 0; + } + + public int getTourCategoryJoint() { + if (tour.getTourCategory().equalsIgnoreCase( + ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + return 1; + else + return 0; + } + + public int getTourCategoryEscort() { + if (tour.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME)) + return 1; + else + return 0; + } + + public int getTourCategorySubtour() { + if (tour.getTourCategory().equalsIgnoreCase( + ModelStructure.AT_WORK_CATEGORY)) + return 1; + else + return 0; + } + + public int getNumberOfParticipantsInJointTour() { + int[] participants = tour.getPersonNumArray(); + int returnValue = 0; + if (participants != null) + returnValue = participants.length; + return returnValue; + } + + public int getHhSize() { + return hh.getHhSize(); + } + + public int getAutos() { + return hh.getAutosOwned(); + } + + public int getAge() { + return person.getAge(); + } + + public int getIncomeCategory() { + return hh.getIncomeCategory(); + } + + public int getIncomeInDollars() { + return hh.getIncomeInDollars(); + } + + + public void setNmWalkTimeOut(double nmWalkTime) { + nmWalkTimeOut = nmWalkTime; + } + + public double getNmWalkTimeOut() { + return nmWalkTimeOut; + } + + public void setNmWalkTimeIn(double nmWalkTime) { + nmWalkTimeIn = nmWalkTime; + } + + public double getNmWalkTimeIn() { + return nmWalkTimeIn; + } + + public void setNmBikeTimeOut(double nmBikeTime) { + nmBikeTimeOut = nmBikeTime; + } + + public double getNmBikeTimeOut() { + return nmBikeTimeOut; + } + + public void setNmBikeTimeIn(double nmBikeTime) { + nmBikeTimeIn = nmBikeTime; + } + + public double getNmBikeTimeIn() { + return nmBikeTimeIn; + } + + public double getWorkTimeFactor() { + return person.getTimeFactorWork(); + } + + public double getNonWorkTimeFactor(){ + return person.getTimeFactorNonWork(); + } + + /** + * Iterate through persons on tour and return non-work time factor + * for oldest person. If the person array is null then return 1.0. + * + * @return Time factor for oldest person on joint tour. + */ + public double getJointTourTimeFactor() { + int[] personNumArray = tour.getPersonNumArray(); + int oldestAge = -999; + Person oldestPerson = null; + for (int num : personNumArray){ + Person p = hh.getPerson(num); + if(p.getAge() > oldestAge){ + oldestPerson = p; + oldestAge = p.getAge(); + } + } + if(oldestPerson != null) + return oldestPerson.getTimeFactorNonWork(); + + return 1.0; + } + + + public int getFreeParkingEligibility() { + return person.getFreeParkingAvailableResult(); + } + + public double getReimburseProportion() { + return reimburseProportion; + } + + public double getMonthlyParkingCost() { + return lsWgtAvgCostM; + } + + public double getDailyParkingCost() { + return lsWgtAvgCostD; + } + + public double getHourlyParkingCost() { + return lsWgtAvgCostH; + } + + public double getPTazTerminalTime() { + return pTazTerminalTime; + } + + public double getATazTerminalTime() { + return aTazTerminalTime; + } + + public void setOriginMgra( int value ) { + originMgra = value; + } + + public void setDestMgra( int value ) { + destMgra = value; + } + + public int getOriginMgra() { + return originMgra; + } + + public int getDestMgra() { + return destMgra; + } + + /** + * 1 if household owns transponder, else 0 + * @return 1 if household owns transponder, else 0 + */ + public int getTransponderOwnership(){ + return hh.getTpChoice(); + } + + public double getIvtCoeff() { + return ivtCoeff; +} + +public void setIvtCoeff(double ivtCoeff) { + this.ivtCoeff = ivtCoeff; +} + +public double getCostCoeff() { + return costCoeff; +} + +public void setCostCoeff(double costCoeff) { + this.costCoeff = costCoeff; +} + + public int getIndexValue(String variableName) { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) { + throw new UnsupportedOperationException(); + } + public int getUseOwnedAV(){ + + if(tour==null) + return 0; + + return (tour.getUseOwnedAV() ? 1: 0); + } + + + + public float getOrigTaxiWaitTime() { + return origTaxiWaitTime; + } + + + + public void setOrigTaxiWaitTime(float origTaxiWaitTime) { + this.origTaxiWaitTime = origTaxiWaitTime; + } + + + + public float getDestTaxiWaitTime() { + return destTaxiWaitTime; + } + + + + public void setDestTaxiWaitTime(float destTaxiWaitTime) { + this.destTaxiWaitTime = destTaxiWaitTime; + } + + + + public float getOrigSingleTNCWaitTime() { + return origSingleTNCWaitTime; + } + + + + public void setOrigSingleTNCWaitTime(float origSingleTNCWaitTime) { + this.origSingleTNCWaitTime = origSingleTNCWaitTime; + } + + + + public float getDestSingleTNCWaitTime() { + return destSingleTNCWaitTime; + } + + + + public void setDestSingleTNCWaitTime(float destSingleTNCWaitTime) { + this.destSingleTNCWaitTime = destSingleTNCWaitTime; + } + + + + public float getOrigSharedTNCWaitTime() { + return origSharedTNCWaitTime; + } + + + + public void setOrigSharedTNCWaitTime(float origSharedTNCWaitTime) { + this.origSharedTNCWaitTime = origSharedTNCWaitTime; + } + + + + public float getDestSharedTNCWaitTime() { + return destSharedTNCWaitTime; + } + + + + public void setDestSharedTNCWaitTime(float destSharedTNCWaitTime) { + this.destSharedTNCWaitTime = destSharedTNCWaitTime; + } + + + +} + diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourModeChoiceModel.java new file mode 100644 index 0000000..48122f6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourModeChoiceModel.java @@ -0,0 +1,762 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; + + + + + + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.DriveTransitWalkSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitDriveSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitWalkSkimsCalculator; +import org.sandag.abm.modechoice.MgraDataManager; + +public class TourModeChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(TourModeChoiceModel.class); + private transient Logger tourMCManLogger = Logger.getLogger("tourMcMan"); + private transient Logger tourMCNonManLogger = Logger.getLogger("tourMcNonMan"); + + public static final String MANDATORY_MODEL_INDICATOR = ModelStructure.MANDATORY_CATEGORY; + public static final String NON_MANDATORY_MODEL_INDICATOR = "Non-Mandatory"; + public static final String AT_WORK_SUBTOUR_MODEL_INDICATOR = ModelStructure.AT_WORK_CATEGORY; + + public static final boolean DEBUG_BEST_PATHS = true; + + protected static final int OUT = McLogsumsCalculator.OUT; + protected static final int IN = McLogsumsCalculator.IN; + protected static final int NUM_DIR = McLogsumsCalculator.NUM_DIR; + + private static final int MC_DATA_SHEET = 0; + private static final String PROPERTIES_UEC_TOUR_MODE_CHOICE = "tourModeChoice.uec.file"; + private static final String PROPERTIES_UEC_MAINT_TOUR_MODE_SHEET = "tourModeChoice.maint.model.page"; + private static final String PROPERTIES_UEC_DISCR_TOUR_MODE_SHEET = "tourModeChoice.discr.model.page"; + private static final String PROPERTIES_UEC_AT_WORK_TOUR_MODE_SHEET = "tourModeChoice.atwork.model.page"; + + + private static final String PROPERTIES_TOUR_UTILITY_IVT_COEFFS = "tour.utility.ivt.coeffs"; + private static final String PROPERTIES_TOUR_UTILITY_INCOME_COEFFS = "tour.utility.income.coeffs"; + private static final String PROPERTIES_TOUR_UTILITY_INCOME_EXPONENTS = "tour.utility.income.exponents"; + + // A MyChoiceModelApplication object and modeAltsAvailable[] is needed for + // each purpose + private ChoiceModelApplication[] mcModel; + private TourModeChoiceDMU mcDmuObject; + private McLogsumsCalculator logsumHelper; + + private ModelStructure modelStructure; + + private String tourCategory; + private String[] tourPurposeList; + + private HashMap purposeModelIndexMap; + + private String[][] modeAltNames; + + private boolean saveUtilsProbsFlag = false; + + // following arrays used to store ivt coefficients, and income coefficients, income exponents to calculate cost coefficient, by tour purpose + double[] ivtCoeffs; + double[] incomeCoeffs; + double[] incomeExponents; + + private MgraDataManager mgraManager; + + //added for TNC and Taxi modes + TNCAndTaxiWaitTimeCalculator tncTaxiWaitTimeCalculator = null; + + public TourModeChoiceModel(HashMap propertyMap, ModelStructure myModelStructure, + String myTourCategory, CtrampDmuFactoryIf dmuFactory, McLogsumsCalculator myLogsumHelper) + { + + modelStructure = myModelStructure; + tourCategory = myTourCategory; + logsumHelper = myLogsumHelper; + // logsumHelper passed in, but if it were instantiated here, it woul be + // as follows + // logsumHelper = new McLogsumsAppender(); + // logsumHelper.setupSkimCalculators(propertyMap); + + mcDmuObject = dmuFactory.getModeChoiceDMU(); + setupModeChoiceModelApplicationArray(propertyMap, tourCategory); + + mgraManager = MgraDataManager.getInstance(); + + //get the coefficients for ivt and the coefficients to calculate the cost coefficient + ivtCoeffs = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TOUR_UTILITY_IVT_COEFFS); + incomeCoeffs = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TOUR_UTILITY_INCOME_COEFFS); + incomeExponents = Util.getDoubleArrayFromPropertyMap(propertyMap, PROPERTIES_TOUR_UTILITY_INCOME_EXPONENTS); + + tncTaxiWaitTimeCalculator = new TNCAndTaxiWaitTimeCalculator(); + tncTaxiWaitTimeCalculator.createWaitTimeDistributions(propertyMap); + + } + + public AutoAndNonMotorizedSkimsCalculator getAnmSkimCalculator() + { + return logsumHelper.getAnmSkimCalculator(); + } + + private void setupModeChoiceModelApplicationArray(HashMap propertyMap, + String tourCategory) + { + + logger.info(String.format("setting up %s tour mode choice model.", tourCategory)); + + // locate the individual mandatory tour mode choice model UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = propertyMap.get(PROPERTIES_UEC_TOUR_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + // default is to not save the tour mode choice utils and probs for each + // tour + String saveUtilsProbsString = propertyMap + .get(CtrampApplication.PROPERTIES_SAVE_TOUR_MODE_CHOICE_UTILS); + if (saveUtilsProbsString != null) + { + if (saveUtilsProbsString.equalsIgnoreCase("true")) saveUtilsProbsFlag = true; + } + + // get the number of purposes and declare the array dimension to be this + // size. + HashMap modelIndexMap = new HashMap(); + + // create a HashMap to map purposeName to model index + purposeModelIndexMap = new HashMap(); + + if (tourCategory.equalsIgnoreCase(MANDATORY_MODEL_INDICATOR)) + { + tourPurposeList = new String[3]; + tourPurposeList[0] = ModelStructure.WORK_PRIMARY_PURPOSE_NAME; + tourPurposeList[1] = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME; + tourPurposeList[2] = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + + int uecIndex = 1; + int mcModelIndex = 0; + for (String purposeName : tourPurposeList) + { + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, mcModelIndex); + purposeModelIndexMap.put(purposeName, mcModelIndex++); + } else + { + purposeModelIndexMap.put(purposeName, modelIndexMap.get(uecIndex)); + } + uecIndex++; + } + + } else if (tourCategory.equalsIgnoreCase(NON_MANDATORY_MODEL_INDICATOR)) + { + tourPurposeList = new String[6]; + tourPurposeList[0] = ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME; + tourPurposeList[1] = ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME; + tourPurposeList[2] = ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME; + tourPurposeList[3] = ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME; + tourPurposeList[4] = ModelStructure.VISITING_PRIMARY_PURPOSE_NAME; + tourPurposeList[5] = ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME; + + int maintSheet = Integer + .parseInt(propertyMap.get(PROPERTIES_UEC_MAINT_TOUR_MODE_SHEET)); + int discrSheet = Integer + .parseInt(propertyMap.get(PROPERTIES_UEC_DISCR_TOUR_MODE_SHEET)); + + int uecIndex = 1; + int mcModelIndex = 0; + int i = 0; + for (String purposeName : tourPurposeList) + { + + uecIndex = -1; + if (purposeName.equalsIgnoreCase(ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME) + || purposeName + .equalsIgnoreCase(ModelStructure.SHOPPING_PRIMARY_PURPOSE_NAME) + || purposeName + .equalsIgnoreCase(ModelStructure.OTH_MAINT_PRIMARY_PURPOSE_NAME)) uecIndex = maintSheet; + else if (purposeName.equalsIgnoreCase(ModelStructure.EAT_OUT_PRIMARY_PURPOSE_NAME) + || purposeName + .equalsIgnoreCase(ModelStructure.VISITING_PRIMARY_PURPOSE_NAME) + || purposeName + .equalsIgnoreCase(ModelStructure.OTH_DISCR_PRIMARY_PURPOSE_NAME)) + uecIndex = discrSheet; + + // if the uec sheet for the model segment is not in the map, add + // it, otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, mcModelIndex); + purposeModelIndexMap.put(purposeName, mcModelIndex++); + } else + { + purposeModelIndexMap.put(purposeName, modelIndexMap.get(uecIndex)); + } + i++; + } + + } else if (tourCategory.equalsIgnoreCase(AT_WORK_SUBTOUR_MODEL_INDICATOR)) + { + tourPurposeList = new String[1]; + tourPurposeList[0] = ModelStructure.WORK_BASED_PRIMARY_PURPOSE_NAME; + + int[] uecSheets = new int[1]; + uecSheets[0] = Integer + .parseInt(propertyMap.get(PROPERTIES_UEC_AT_WORK_TOUR_MODE_SHEET)); + + int mcModelIndex = 0; + int i = 0; + for (String purposeName : tourPurposeList) + { + int uecIndex = uecSheets[i]; + + // if the uec sheet for the model segment is not in the map, add + // it, otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, mcModelIndex); + purposeModelIndexMap.put(purposeName, mcModelIndex++); + } else + { + purposeModelIndexMap.put(purposeName, modelIndexMap.get(uecIndex)); + } + i++; + } + + } + + mcModel = new ChoiceModelApplication[modelIndexMap.size()]; + + // declare dimensions for the array of choice alternative availability + // by + // purpose + modeAltNames = new String[purposeModelIndexMap.size()][]; + + // for each unique model index, create the ChoiceModelApplication object + // and + // the availabilty array + int i = 0; + for (int m : modelIndexMap.keySet()) + { + mcModel[i] = new ChoiceModelApplication(mcUecFile, m, MC_DATA_SHEET, propertyMap, + (VariableTable) mcDmuObject); + modeAltNames[i] = mcModel[i].getAlternativeNames(); + i++; + } + + + } + + public double getModeChoiceLogsum(Household household, Person person, Tour tour, + Logger modelLogger, String choiceModelDescription, String decisionMakerLabel) + { + + // update the MC dmuObjects for this person + mcDmuObject.setHouseholdObject(household); + mcDmuObject.setPersonObject(person); + mcDmuObject.setTourObject(tour); + mcDmuObject.setDmuIndexValues(household.getHhId(), tour.getTourDestMgra(), + tour.getTourOrigMgra(), tour.getTourDestMgra(), household.getDebugChoiceModels()); + mcDmuObject.setOriginMgra(tour.getTourOrigMgra()); + mcDmuObject.setDestMgra(tour.getTourDestMgra()); + + float SingleTNCWaitTimeOrig = 0; + float SingleTNCWaitTimeDest = 0; + float SharedTNCWaitTimeOrig = 0; + float SharedTNCWaitTimeDest = 0; + float TaxiWaitTimeOrig = 0; + float TaxiWaitTimeDest = 0; + float popEmpDenOrig = (float) mgraManager.getPopEmpPerSqMi(tour.getTourOrigMgra()); + float popEmpDenDest = (float) mgraManager.getPopEmpPerSqMi(tour.getTourDestMgra()); + + if(household!=null){ + Random hhRandom = household.getHhRandom(); + double rnum = hhRandom.nextDouble(); + SingleTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SingleTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenDest); + SharedTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SharedTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenDest); + TaxiWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenOrig); + TaxiWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenDest); + }else{ + SingleTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanSingleTNCWaitTime( popEmpDenOrig); + SingleTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanSingleTNCWaitTime( popEmpDenDest); + SharedTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanSharedTNCWaitTime( popEmpDenOrig); + SharedTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanSharedTNCWaitTime( popEmpDenDest); + TaxiWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanTaxiWaitTime( popEmpDenOrig); + TaxiWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanTaxiWaitTime(popEmpDenDest); + } + + mcDmuObject.setOrigTaxiWaitTime(TaxiWaitTimeOrig); + mcDmuObject.setDestTaxiWaitTime(TaxiWaitTimeDest); + mcDmuObject.setOrigSingleTNCWaitTime(SingleTNCWaitTimeOrig); + mcDmuObject.setDestSingleTNCWaitTime(SingleTNCWaitTimeDest); + mcDmuObject.setOrigSharedTNCWaitTime(SharedTNCWaitTimeOrig); + mcDmuObject.setDestSharedTNCWaitTime(SharedTNCWaitTimeDest); + + return getModeChoiceLogsum(mcDmuObject, tour, modelLogger, choiceModelDescription, + decisionMakerLabel); + } + + public double getModeChoiceLogsum(TourModeChoiceDMU mcDmuObject, Tour tour, Logger modelLogger, + String choiceModelDescription, String decisionMakerLabel) + { + + int modelIndex = purposeModelIndexMap.get(tour.getTourPrimaryPurpose()); + + Household household = tour.getPersonObject().getHouseholdObject(); + double income = (double) household.getIncomeInDollars(); + double timeFactor = 1.0f; + if(tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + timeFactor = mcDmuObject.getJointTourTimeFactor(); + else if(tour.getTourPrimaryPurposeIndex()==ModelStructure.WORK_PRIMARY_PURPOSE_INDEX) + timeFactor = mcDmuObject.getWorkTimeFactor(); + else + timeFactor = mcDmuObject.getNonWorkTimeFactor(); + + double ivtCoeff = ivtCoeffs[modelIndex]; + double incomeCoeff = incomeCoeffs[modelIndex]; + double incomeExpon = incomeExponents[modelIndex]; + double costCoeff = calculateCostCoefficient(income, incomeCoeff,incomeExpon); + + mcDmuObject.setIvtCoeff(ivtCoeff*timeFactor); + mcDmuObject.setCostCoeff(costCoeff); + + float SingleTNCWaitTimeOrig = 0; + float SingleTNCWaitTimeDest = 0; + float SharedTNCWaitTimeOrig = 0; + float SharedTNCWaitTimeDest = 0; + float TaxiWaitTimeOrig = 0; + float TaxiWaitTimeDest = 0; + float popEmpDenOrig = (float) mgraManager.getPopEmpPerSqMi(tour.getTourOrigMgra()); + float popEmpDenDest = (float) mgraManager.getPopEmpPerSqMi(tour.getTourDestMgra()); + + if(household!=null){ + Random hhRandom = household.getHhRandom(); + double rnum = hhRandom.nextDouble(); + SingleTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SingleTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenDest); + SharedTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SharedTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenDest); + TaxiWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenOrig); + TaxiWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenDest); + }else{ + SingleTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanSingleTNCWaitTime( popEmpDenOrig); + SingleTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanSingleTNCWaitTime( popEmpDenDest); + SharedTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanSharedTNCWaitTime( popEmpDenOrig); + SharedTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanSharedTNCWaitTime( popEmpDenDest); + TaxiWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanTaxiWaitTime( popEmpDenOrig); + TaxiWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanTaxiWaitTime(popEmpDenDest); + } + + mcDmuObject.setOrigTaxiWaitTime(TaxiWaitTimeOrig); + mcDmuObject.setDestTaxiWaitTime(TaxiWaitTimeDest); + mcDmuObject.setOrigSingleTNCWaitTime(SingleTNCWaitTimeOrig); + mcDmuObject.setDestSingleTNCWaitTime(SingleTNCWaitTimeDest); + mcDmuObject.setOrigSharedTNCWaitTime(SharedTNCWaitTimeOrig); + mcDmuObject.setDestSharedTNCWaitTime(SharedTNCWaitTimeDest); + + // log headers to traceLogger + if (household.getDebugChoiceModels()) + { + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + } + + double logsum = logsumHelper.calculateTourMcLogsum(tour.getTourOrigMgra(), + tour.getTourDestMgra(), tour.getTourDepartPeriod(), tour.getTourArrivePeriod(), + mcModel[modelIndex], mcDmuObject); + + // write UEC calculation results to separate model specific log file + if (household.getDebugChoiceModels()) + { + String loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + mcModel[modelIndex].logUECResults(modelLogger, loggingHeader); + modelLogger.info(choiceModelDescription + " Logsum value: " + logsum); + modelLogger.info(""); + modelLogger.info(""); + } + + return logsum; + + } + + public int getModeChoice(TourModeChoiceDMU mcDmuObject, String purposeName) + { + + int modelIndex = purposeModelIndexMap.get(purposeName); + + Household household = mcDmuObject.getHouseholdObject(); + Tour tour = mcDmuObject.getTourObject(); + double income = (double) household.getIncomeInDollars(); + double ivtCoeff = ivtCoeffs[modelIndex]; + double incomeCoeff = incomeCoeffs[modelIndex]; + double incomeExpon = incomeExponents[modelIndex]; + double costCoeff = calculateCostCoefficient(income, incomeCoeff,incomeExpon); + double timeFactor = 1.0f; + if(tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + timeFactor = mcDmuObject.getJointTourTimeFactor(); + else if(tour.getTourPrimaryPurposeIndex()==ModelStructure.WORK_PRIMARY_PURPOSE_INDEX) + timeFactor = mcDmuObject.getWorkTimeFactor(); + else + timeFactor = mcDmuObject.getNonWorkTimeFactor(); + + mcDmuObject.setIvtCoeff(ivtCoeff * timeFactor); + mcDmuObject.setCostCoeff(costCoeff); + + float SingleTNCWaitTimeOrig = 0; + float SingleTNCWaitTimeDest = 0; + float SharedTNCWaitTimeOrig = 0; + float SharedTNCWaitTimeDest = 0; + float TaxiWaitTimeOrig = 0; + float TaxiWaitTimeDest = 0; + float popEmpDenOrig = (float) mgraManager.getPopEmpPerSqMi(tour.getTourOrigMgra()); + float popEmpDenDest = (float) mgraManager.getPopEmpPerSqMi(tour.getTourDestMgra()); + + if(household!=null){ + Random hhRandom = household.getHhRandom(); + double rnum = hhRandom.nextDouble(); + SingleTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SingleTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenDest); + SharedTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SharedTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenDest); + TaxiWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenOrig); + TaxiWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenDest); + }else{ + SingleTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanSingleTNCWaitTime( popEmpDenOrig); + SingleTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanSingleTNCWaitTime( popEmpDenDest); + SharedTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanSharedTNCWaitTime( popEmpDenOrig); + SharedTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanSharedTNCWaitTime( popEmpDenDest); + TaxiWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.getMeanTaxiWaitTime( popEmpDenOrig); + TaxiWaitTimeDest = (float) tncTaxiWaitTimeCalculator.getMeanTaxiWaitTime(popEmpDenDest); + } + + mcDmuObject.setOrigTaxiWaitTime(TaxiWaitTimeOrig); + mcDmuObject.setDestTaxiWaitTime(TaxiWaitTimeDest); + mcDmuObject.setOrigSingleTNCWaitTime(SingleTNCWaitTimeOrig); + mcDmuObject.setDestSingleTNCWaitTime(SingleTNCWaitTimeDest); + mcDmuObject.setOrigSharedTNCWaitTime(SharedTNCWaitTimeOrig); + mcDmuObject.setDestSharedTNCWaitTime(SharedTNCWaitTimeDest); + + Logger modelLogger = null; + if (tourCategory.equalsIgnoreCase(ModelStructure.MANDATORY_CATEGORY)) modelLogger = tourMCManLogger; + else modelLogger = tourMCNonManLogger; + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + String separator = ""; + + + if (household.getDebugChoiceModels()) + { + + if (tour.getTourCategory() + .equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + Person person = null; + Person[] persons = mcDmuObject.getHouseholdObject().getPersons(); + int[] personNums = tour.getPersonNumArray(); + for (int n = 0; n < personNums.length; n++) + { + int p = personNums[n]; + person = persons[p]; + + choiceModelDescription = String.format( + "%s Tour Mode Choice Model for: Purpose=%s, Home=%d, Dest=%d", + tourCategory, purposeName, household.getHhMgra(), + tour.getTourDestMgra()); + decisionMakerLabel = String + .format("HH=%d, person record %d of %d in joint tour, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), p, personNums.length, + person.getPersonNum(), person.getPersonType(), tour.getTourId()); + loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + + household.logTourObject(loggingHeader, modelLogger, person, tour); + } + } else + { + Person person = mcDmuObject.getPersonObject(); + + choiceModelDescription = String.format( + "%s Tour Mode Choice Model for: Purpose=%s, Orig=%d, Dest=%d", + tourCategory, purposeName, tour.getTourOrigMgra(), tour.getTourDestMgra()); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourId()); + loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + + household.logTourObject(loggingHeader, modelLogger, person, tour); + } + + } + + logsumHelper.setTourMcDmuAttributes(mcDmuObject, tour.getTourOrigMgra(), + tour.getTourDestMgra(), tour.getTourDepartPeriod(), tour.getTourArrivePeriod(), + (household.getDebugChoiceModels() && DEBUG_BEST_PATHS)); + + // mode choice UEC references highway skim matrices directly, so set + // index orig/dest to O/D TAZs. + IndexValues mcDmuIndex = mcDmuObject.getDmuIndexValues(); + mcDmuIndex.setOriginZone(mgraManager.getTaz(tour.getTourOrigMgra())); + mcDmuIndex.setDestZone(mgraManager.getTaz(tour.getTourDestMgra())); + mcDmuIndex.setZoneIndex(tour.getTourDestMgra()); + mcDmuObject.setOriginMgra(tour.getTourOrigMgra()); + mcDmuObject.setDestMgra(tour.getTourDestMgra()); + + float logsum = (float) mcModel[modelIndex].computeUtilities(mcDmuObject, mcDmuIndex); + tour.setTourModeLogsum(logsum); + + mcDmuIndex.setOriginZone(tour.getTourOrigMgra()); + mcDmuIndex.setDestZone(tour.getTourDestMgra()); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen; + if (mcModel[modelIndex].getAvailabilityCount() > 0) + { + + chosen = mcModel[modelIndex].getChoiceResult(rn); + + // best tap pairs were determined and saved in mcDmuObject while + // setting dmu skim attributes + // if chosen mode is a transit mode, save these tap pairs in the + // tour object; if not transit tour attributes remain null. + if (modelStructure.getTourModeIsTransit(chosen)) + { + tour.setBestWtwTapPairsOut(logsumHelper.getBestWtwTapsOut()); + tour.setBestWtwTapPairsIn(logsumHelper.getBestWtwTapsIn()); + tour.setBestWtdTapPairsOut(logsumHelper.getBestWtdTapsOut()); + tour.setBestWtdTapPairsIn(logsumHelper.getBestWtdTapsIn()); + tour.setBestDtwTapPairsOut(logsumHelper.getBestDtwTapsOut()); + tour.setBestDtwTapPairsIn(logsumHelper.getBestDtwTapsIn()); + } + + //value of time; lookup vot, votS2, or votS3 from the UEC depending on chosen mode + UtilityExpressionCalculator uec = mcModel[modelIndex].getUEC(); + + double vot = 0.0; + + if(modelStructure.getTourModeIsS2(chosen)){ + int votIndex = uec.lookupVariableIndex("votS2"); + vot = uec.getValueForIndex(votIndex); + }else if (modelStructure.getTourModeIsS3(chosen)){ + int votIndex = uec.lookupVariableIndex("votS3"); + vot = uec.getValueForIndex(votIndex); + }else{ + int votIndex = uec.lookupVariableIndex("vot"); + vot = uec.getValueForIndex(votIndex); + } + tour.setValueOfTime(vot); + + + } else + { + + if (tour.getTourCategory() + .equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + Person person = null; + Person[] persons = mcDmuObject.getHouseholdObject().getPersons(); + int[] personNums = tour.getPersonNumArray(); + for (int n = 0; n < personNums.length; n++) + { + int p = personNums[n]; + person = persons[p]; + + choiceModelDescription = String + .format("No alternatives available for %s Tour Mode Choice Model for: Purpose=%s, Home=%d, Dest=%d", + tourCategory, purposeName, household.getHhMgra(), + tour.getTourDestMgra()); + decisionMakerLabel = String + .format("HH=%d, person record %d of %d in joint tour, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), p, personNums.length, + person.getPersonNum(), person.getPersonType(), tour.getTourId()); + loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading( + choiceModelDescription, decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + + household.logTourObject(loggingHeader, modelLogger, person, tour); + } + } else + { + Person person = mcDmuObject.getPersonObject(); + + choiceModelDescription = String + .format("No alternatives available for %s Tour Mode Choice Model for: Purpose=%s, Orig=%d, Dest=%d", + tourCategory, purposeName, tour.getTourOrigMgra(), + tour.getTourDestMgra()); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourId=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tour.getTourId()); + loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + + mcModel[modelIndex].choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + modelLogger.info(" "); + for (int k = 0; k < loggingHeader.length(); k++) + separator += "+"; + modelLogger.info(loggingHeader); + modelLogger.info(separator); + + household.logTourObject(loggingHeader, modelLogger, person, tour); + } + + mcModel[modelIndex].logUECResults(modelLogger, loggingHeader); + modelLogger.info(""); + modelLogger.info(""); + + logger.error(String + .format("Exception caught for HHID=%d, no available %s tour mode alternatives to choose from in choiceModelApplication.", + household.getHhId(), tourCategory)); + throw new RuntimeException(); + } + + // debug output + if (household.getDebugChoiceModels()) + { + + double[] utilities = mcModel[modelIndex].getUtilities(); // 0s-indexing + double[] probabilities = mcModel[modelIndex].getProbabilities(); // 0s-indexing + boolean[] availabilities = mcModel[modelIndex].getAvailabilities(); // 1s-indexing + String[] altNames = mcModel[modelIndex].getAlternativeNames(); // 0s-indexing + + if (tour.getTourCategory() + .equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) + { + modelLogger.info("Joint Tour Id: " + tour.getTourId()); + } else + { + Person person = mcDmuObject.getPersonObject(); + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString + + ", Tour Id: " + tour.getTourId()); + } + modelLogger + .info("Alternative Utility Probability CumProb"); + modelLogger + .info("-------------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < mcModel[modelIndex].getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %s", k + 1, altNames[k]); + modelLogger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", altString, + availabilities[k + 1], utilities[k], probabilities[k], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("%-3d %s", chosen, altNames[chosen - 1]); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger.info(separator); + modelLogger.info(""); + modelLogger.info(""); + + // write choice model alternative info to log file + mcModel[modelIndex].logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + mcModel[modelIndex].logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, + chosen); + mcModel[modelIndex].logLogitCalculations(choiceModelDescription, decisionMakerLabel); + + // write UEC calculation results to separate model specific log file + mcModel[modelIndex].logUECResults(modelLogger, loggingHeader); + } + + if (saveUtilsProbsFlag) + { + + // get the utilities and probabilities arrays for the tour mode + // choice + // model for this tour and save them to the tour object + double[] dUtils = mcModel[modelIndex].getUtilities(); + double[] dProbs = mcModel[modelIndex].getProbabilities(); + + float[] utils = new float[dUtils.length]; + float[] probs = new float[dUtils.length]; + for (int k = 0; k < dUtils.length; k++) + { + utils[k] = (float) dUtils[k]; + probs[k] = (float) dProbs[k]; + } + + tour.setTourModalUtilities(utils); + tour.setTourModalProbabilities(probs); + + } + + return chosen; + + } + + public String[] getModeAltNames(int purposeIndex) + { + int modelIndex = purposeModelIndexMap.get(tourPurposeList[purposeIndex]); + return modeAltNames[modelIndex]; + } + + /** + * This method calculates a cost coefficient based on the following formula: + * + * costCoeff = incomeCoeff * 1/(max(income,1000)^incomeExponent) + * + * + * @param incomeCoeff + * @param incomeExponent + * @return A cost coefficent that should be multiplied by cost variables (cents) in tour mode choice + */ + public double calculateCostCoefficient(double income, double incomeCoeff, double incomeExponent){ + + return incomeCoeff * 1.0/(Math.pow(Math.max(income,1000.0),incomeExponent)); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourVehicleTypeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourVehicleTypeChoiceModel.java new file mode 100644 index 0000000..bd6ef9b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TourVehicleTypeChoiceModel.java @@ -0,0 +1,189 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; +import com.pb.common.calculator.VariableTable; +import com.pb.common.model.ModelException; + +import org.apache.log4j.Logger; + +public class TourVehicleTypeChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(TourVehicleTypeChoiceModel.class); + float probabilityBoostAutosLTDrivers = 0; + float probabilityBoostAutosGEDrivers = 0; + + + public TourVehicleTypeChoiceModel(HashMap rbMap) + { + + logger.info("setting up tour tNCVehicle type choice model."); + probabilityBoostAutosLTDrivers = Util.getFloatValueFromPropertyMap(rbMap,"Mobility.AV.ProbabilityBoost.AutosLTDrivers"); + probabilityBoostAutosGEDrivers = Util.getFloatValueFromPropertyMap(rbMap,"Mobility.AV.ProbabilityBoost.AutosGEDrivers"); + + + } + + /** + * Calculate the probability of the tour using the AV in the household. If AVs owned =0, returns 0, else + * returns a probability equal to the share of AVs in the household, boosted by the parameters in the properties file. + * The parameters are named Mobility.AV.ProbabilityBoost.AutosLTDrivers and Mobility.AV.ProbabilityBoost.AutosGEDrivers + * and are read in the object constructor. + * + * @param hhObj + * @return The probability of using one of the household AVs for the tour. + */ + public double calculateProbability(Household hhObj){ + + float numberOfAVs = (float) hhObj.getAutomatedVehicles(); + + if(numberOfAVs==0) + return 0; + + float numberOfCVs = (float) hhObj.getConventionalVehicles(); + float numberOfDrivers = (float) hhObj.getDrivers(); + float totalVehicles = numberOfAVs + numberOfCVs; + float probability = numberOfAVs/totalVehicles; + if(totalVehicles + * Started: Apr 14, 2009 11:09:58 AM + */ +public class TransponderChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TransponderChoiceDMU.class); + + protected HashMap methodIndexMap; + + private IndexValues dmuIndex; + + private Household hh; + + private double percentTazIncome100Kplus; + private double percentTazMultpleAutos; + private double expectedTravelTimeSavings; + private double transpDist; + private double pctDetour; + private double accessibility; + + public TransponderChoiceDMU() + { + dmuIndex = new IndexValues(); + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (hh.getDebugChoiceModels()) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug Free Parking UEC"); + } + } + + public void setHouseholdObject(Household hhObj) + { + hh = hhObj; + } + + public void setPctIncome100Kplus(double value) + { + percentTazIncome100Kplus = value; + } + + public void setPctTazMultpleAutos(double value) + { + percentTazMultpleAutos = value; + } + + public void setExpectedTravelTimeSavings(double value) + { + expectedTravelTimeSavings = value; + } + + public void setTransponderDistance(double value) + { + transpDist = value; + } + + public void setPctDetour(double value) + { + pctDetour = value; + } + + public void setAccessibility(double value) + { + accessibility = value; + } + + public double getPctIncome100Kplus() + { + return percentTazIncome100Kplus; + } + + public double getPctTazMultpleAutos() + { + return percentTazMultpleAutos; + } + + public double getExpectedTravelTimeSavings() + { + return expectedTravelTimeSavings; + } + + public double getTransponderDistance() + { + return transpDist; + } + + public double getPctDetour() + { + return pctDetour; + } + + public double getAccessibility() + { + return accessibility; + } + + public int getAutoOwnership() + { + return hh.getAutosOwned(); + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TransponderChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TransponderChoiceModel.java new file mode 100644 index 0000000..35eda9f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TransponderChoiceModel.java @@ -0,0 +1,131 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AccessibilitiesTable; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class TransponderChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("tp"); + + private static final String TP_CONTROL_FILE_TARGET = "tc.uec.file"; + private static final String TP_DATA_SHEET_TARGET = "tc.data.page"; + private static final String TP_MODEL_SHEET_TARGET = "tc.model.page"; + + public static final int TP_MODEL_NO_ALT = 1; + public static final int TP_MODEL_YES_ALT = 2; + + private ChoiceModelApplication tpModel; + private TransponderChoiceDMU tpDmuObject; + + private AccessibilitiesTable accTable; + + private double[] pctHighIncome; + private double[] pctMultipleAutos; + private double[] avgtts; + private double[] transpDist; + private double[] pctDetour; + + public TransponderChoiceModel(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory, AccessibilitiesTable accTable, double[] pctHighIncome, + double[] pctMultipleAutos, double[] avgtts, double[] transpDist, double[] pctDetour) + { + this.accTable = accTable; + this.pctHighIncome = pctHighIncome; + this.pctMultipleAutos = pctMultipleAutos; + this.avgtts = avgtts; + this.transpDist = transpDist; + this.pctDetour = pctDetour; + + setupTransponderChoiceModelApplication(propertyMap, dmuFactory); + } + + private void setupTransponderChoiceModelApplication(HashMap propertyMap, + CtrampDmuFactoryIf dmuFactory) + { + logger.info("setting up transponder choice model."); + + // locate the transponder choice UEC + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String tpUecFile = uecFileDirectory + propertyMap.get(TP_CONTROL_FILE_TARGET); + + int dataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, TP_DATA_SHEET_TARGET); + int modelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, TP_MODEL_SHEET_TARGET); + + // create the transponder choice model DMU object. + tpDmuObject = dmuFactory.getTransponderChoiceDMU(); + + // create the transponder choice model object + tpModel = new ChoiceModelApplication(tpUecFile, modelSheet, dataSheet, propertyMap, + (VariableTable) tpDmuObject); + + } + + public void applyModel(Household hhObject) + { + + int homeTaz = hhObject.getHhTaz(); + + tpDmuObject.setHouseholdObject(hhObject); + + // set the zone, orig and dest attributes + tpDmuObject.setDmuIndexValues(hhObject.getHhId(), hhObject.getHhTaz(), hhObject.getHhTaz(), + 0); + + tpDmuObject.setPctIncome100Kplus(pctHighIncome[homeTaz]); + tpDmuObject.setPctTazMultpleAutos(pctMultipleAutos[homeTaz]); + tpDmuObject.setExpectedTravelTimeSavings(avgtts[homeTaz]); + tpDmuObject.setTransponderDistance(transpDist[homeTaz]); + tpDmuObject.setPctDetour(pctDetour[homeTaz]); + + float accessibility = accTable.getAggregateAccessibility("transit", hhObject.getHhMgra()); + tpDmuObject.setAccessibility(accessibility); + + Random hhRandom = hhObject.getHhRandom(); + double randomNumber = hhRandom.nextDouble(); + + // compute utilities and choose transponder choice alternative. + float logsum = (float) tpModel.computeUtilities(tpDmuObject, tpDmuObject.getDmuIndexValues()); + + hhObject.setTransponderLogsum(logsum); + + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + if (tpModel.getAvailabilityCount() > 0) + { + chosenAlt = tpModel.getChoiceResult(randomNumber); + } else + { + String decisionMaker = String.format("HHID=%d", hhObject.getHhId()); + String errorMessage = String + .format("Exception caught for %s, no available transponder choice alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.error(errorMessage); + + tpModel.logUECResults(logger, decisionMaker); + throw new RuntimeException(); + } + + // write choice model alternative info to log file + if (hhObject.getDebugChoiceModels()) + { + String decisionMaker = String.format("HHID=%d", hhObject.getHhId()); + tpModel.logAlternativesInfo("Transponder Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d with rn %.8f", + "Transponder Choice", decisionMaker, chosenAlt, randomNumber)); + tpModel.logUECResults(logger, decisionMaker); + } + + hhObject.setTpChoice(chosenAlt - 1); + + hhObject.setTpRandomCount(hhObject.getHhRandomCount()); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/TripModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TripModeChoiceDMU.java new file mode 100644 index 0000000..b8ca3e7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/TripModeChoiceDMU.java @@ -0,0 +1,846 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class TripModeChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TripModeChoiceDMU.class); + + protected static final int WTW = McLogsumsCalculator.WTW; + protected static final int WTD = McLogsumsCalculator.WTD; + protected static final int DTW = McLogsumsCalculator.DTW; + protected static final int NUM_ACC_EGR = McLogsumsCalculator.NUM_ACC_EGR; + + protected static final int OUT = McLogsumsCalculator.OUT; + protected static final int IN = McLogsumsCalculator.IN; + protected static final int NUM_DIR = McLogsumsCalculator.NUM_DIR; + + protected HashMap methodIndexMap; + + protected Tour tour; + protected Person person; + protected Household hh; + protected IndexValues dmuIndex; + + protected double nmWalkTime; + protected double nmBikeTime; + + protected ModelStructure modelStructure; + + protected double origDuDen; + protected double origEmpDen; + protected double origTotInt; + protected double destDuDen; + protected double destEmpDen; + protected double destTotInt; + + protected int tripOrigIsTourDest; + protected int tripDestIsTourDest; + + protected int tripTime; + protected int firstTrip; + protected int lastTrip; + protected int outboundStops; + protected int inboundStops; + + protected int incomeInDollars; + protected int age; + protected int adults; + protected int autos; + protected int hhSize; + protected int personIsFemale; + + protected int departPeriod; + protected int arrivePeriod; + protected int tripPeriod; + + protected int escortTour; + protected int jointTour; + protected int partySize; + + protected int outboundHalfTourDirection; + protected float waitTimeTaxi; + protected float waitTimeSingleTNC; + protected float waitTimeSharedTNC; + + protected int tourModeIsDA; + protected int tourModeIsS2; + protected int tourModeIsS3; + protected int tourModeIsWalk; + protected int tourModeIsBike; + protected int tourModeIsWTran; + protected int tourModeIsPnr; + protected int tourModeIsKnr; + protected int tourModeIsSchBus; + + protected double reimburseAmount; + + protected float pTazTerminalTime; + protected float aTazTerminalTime; + + protected int[] mgraParkArea; + + protected double[] lsWgtAvgCostM; + protected double[] lsWgtAvgCostD; + protected double[] lsWgtAvgCostH; + + protected boolean segmentIsIk; + protected boolean autoModeRequiredForDriveTransit; + protected boolean walkModeAllowedForDriveTransit; + + protected double ivtCoeff; + protected double costCoeff; + + protected double[] transitLogSum; + + protected boolean inbound; + + protected int originMgra; + protected int destMgra; + + + public TripModeChoiceDMU(ModelStructure modelStructure, Logger aLogger) + { + this.modelStructure = modelStructure; + dmuIndex = new IndexValues(); + + transitLogSum = new double[McLogsumsCalculator.NUM_ACC_EGR]; + } + + + + public void setParkingCostInfo(int[] mgraParkArea, double[] lsWgtAvgCostM, + double[] lsWgtAvgCostD, double[] lsWgtAvgCostH) + { + this.mgraParkArea = mgraParkArea; + this.lsWgtAvgCostM = lsWgtAvgCostM; + this.lsWgtAvgCostD = lsWgtAvgCostD; + this.lsWgtAvgCostH = lsWgtAvgCostH; + } + + public void setHouseholdObject(Household hhObject) + { + hh = hhObject; + } + + public Household getHouseholdObject() + { + return hh; + } + + public void setPersonObject(Person personObject) + { + person = personObject; + } + + public Person getPersonObject() + { + return person; + } + + public void setTourObject(Tour tourObject) + { + tour = tourObject; + } + + public Tour getTourObject() + { + return tour; + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public float getTimeOutbound() + { + return tour.getTourDepartPeriod(); + } + + public float getTimeInbound() + { + return tour.getTourArrivePeriod(); + } + + public void setSegmentIsIk(boolean flag) + { + segmentIsIk = flag; + } + + public int getSegmentIsIk() + { + return segmentIsIk ? 1 : 0; + } + + public void setIncomeInDollars(int arg) + { + incomeInDollars = arg; + } + + public void setAutos(int arg) + { + autos = arg; + } + + public void setAdults(int arg) + { + adults = arg; + } + + public void setHhSize(int arg) + { + hhSize = arg; + } + + public void setAge(int arg) + { + age = arg; + } + + public void setPersonIsFemale(int arg) + { + personIsFemale = arg; + } + + public void setEscortTour(int arg) + { + escortTour = arg; + } + + public void setJointTour(int arg) + { + jointTour = arg; + } + + public void setPartySize(int arg) + { + partySize = arg; + } + + public void setOutboundHalfTourDirection(int arg) + { + outboundHalfTourDirection = arg; + } + + public void setDepartPeriod(int period) + { + departPeriod = period; + } + + public void setArrivePeriod(int period) + { + arrivePeriod = period; + } + + public void setTripPeriod(int period) + { + tripPeriod = period; + } + + public void setOutboundStops(int stops) + { + outboundStops = stops; + } + + public void setInboundStops(int stops) + { + inboundStops = stops; + } + + public void setFirstTrip(int trip) + { + firstTrip = trip; + } + + public void setLastTrip(int trip) + { + lastTrip = trip; + } + + public void setTourModeIsDA(int arg) + { + tourModeIsDA = arg; + } + + public void setTourModeIsS2(int arg) + { + tourModeIsS2 = arg; + } + + public void setTourModeIsS3(int arg) + { + tourModeIsS3 = arg; + } + + public void setTourModeIsWalk(int arg) + { + tourModeIsWalk = arg; + } + + public void setTourModeIsBike(int arg) + { + tourModeIsBike = arg; + } + + public void setTourModeIsWTran(int arg) + { + tourModeIsWTran = arg; + } + + public void setTourModeIsPnr(int arg) + { + tourModeIsPnr = arg; + } + + public void setTourModeIsKnr(int arg) + { + tourModeIsKnr = arg; + } + + public void setTourModeIsSchBus(int arg) + { + tourModeIsSchBus = arg; + } + + public void setOrigDuDen(double arg) + { + origDuDen = arg; + } + + public void setOrigEmpDen(double arg) + { + origEmpDen = arg; + } + + public void setOrigTotInt(double arg) + { + origTotInt = arg; + } + + public void setDestDuDen(double arg) + { + destDuDen = arg; + } + + public void setDestEmpDen(double arg) + { + destEmpDen = arg; + } + + public void setDestTotInt(double arg) + { + destTotInt = arg; + } + + public void setReimburseProportion(double prop) + { + reimburseAmount = prop; + } + + public void setPTazTerminalTime(float time) + { + pTazTerminalTime = time; + } + + public void setATazTerminalTime(float time) + { + aTazTerminalTime = time; + } + + public void setTripOrigIsTourDest(int value) + { + tripOrigIsTourDest = value; + } + + public void setTripDestIsTourDest(int value) + { + tripDestIsTourDest = value; + } + + public void setBikeLogsum(int origin, int dest, boolean inbound) { + //do nothing - this is a stub to allow SANDAG to work correctly + // see SandagTripModeChoiceModelDMU for actual implementation + } + + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public void setAutoModeRequiredForTripSegment(boolean flag) + { + autoModeRequiredForDriveTransit = flag; + } + + public void setWalkModeAllowedForTripSegment(boolean flag) + { + walkModeAllowedForDriveTransit = flag; + } + + public void setIndexDest(int d) + { + dmuIndex.setDestZone(d); + } + + public void setNonMotorizedWalkTime(double walkTime) + { + nmWalkTime = walkTime; + } + + public void setNonMotorizedBikeTime(double bikeTime) + { + nmBikeTime = bikeTime; + } + + public int getAutoModeAllowedForTripSegment() + { + return autoModeRequiredForDriveTransit ? 1 : 0; + } + + public int getWalkModeAllowedForTripSegment() + { + return walkModeAllowedForDriveTransit ? 1 : 0; + } + + public int getTourModeIsDA() + { + boolean tourModeIsDa = modelStructure.getTourModeIsSov(tour.getTourModeChoice()); + return tourModeIsDa ? 1 : 0; + } + + public int getTourModeIsS2() + { + boolean tourModeIsS2 = modelStructure.getTourModeIsS2(tour.getTourModeChoice()); + return tourModeIsS2 ? 1 : 0; + } + + public int getTourModeIsS3() + { + boolean tourModeIsS3 = modelStructure.getTourModeIsS3(tour.getTourModeChoice()); + return tourModeIsS3 ? 1 : 0; + } + + public int getTourModeIsSchBus() + { + boolean tourModeIsSchBus = modelStructure.getTourModeIsSchoolBus(tour.getTourModeChoice()); + return tourModeIsSchBus ? 1 : 0; + } + + public int getTourModeIsWalk() + { + boolean tourModeIsWalk = modelStructure.getTourModeIsWalk(tour.getTourModeChoice()); + return tourModeIsWalk ? 1 : 0; + } + + public int getTourModeIsBike() + { + boolean tourModeIsBike = modelStructure.getTourModeIsBike(tour.getTourModeChoice()); + return tourModeIsBike ? 1 : 0; + } + + public int getTourModeIsWTran() + { + boolean tourModeIsWTran = modelStructure.getTourModeIsWalkTransit(tour.getTourModeChoice()); + return tourModeIsWTran ? 1 : 0; + } + + public int getTourModeIsPnr() + { + boolean tourModeIsPnr = modelStructure.getTourModeIsPnr(tour.getTourModeChoice()); + return tourModeIsPnr ? 1 : 0; + } + + public int getTourModeIsKnr() + { + boolean tourModeIsKnr = modelStructure.getTourModeIsKnr(tour.getTourModeChoice()); + return tourModeIsKnr ? 1 : 0; + } + + public int getTourModeIsTncTransit() + { + boolean tourModeIsTncTransit = modelStructure.getTourModeIsTncTransit(tour.getTourModeChoice()); + return tourModeIsTncTransit ? 1 : 0; + } + + public int getTourModeIsMaas() + { + boolean tourModeIsMaas = modelStructure.getTourModeIsMaas(tour.getTourModeChoice()); + return tourModeIsMaas ? 1 : 0; + } + + public void setTransitLogSum(int accEgr, double value){ + transitLogSum[accEgr] = value; + } + + public double getTransitLogSum(int accEgr){ + return transitLogSum[accEgr]; + } + + + public double getODUDen() + { + return origDuDen; + } + + public double getOEmpDen() + { + return origEmpDen; + } + + public double getOTotInt() + { + return origTotInt; + } + + public double getDDUDen() + { + return destDuDen; + } + + public double getDEmpDen() + { + return destEmpDen; + } + + public double getDTotInt() + { + return destTotInt; + } + + public int getFirstTrip() + { + return firstTrip; + } + + public int getLastTrip() + { + return lastTrip; + } + + public int getTourCategoryJoint() + { + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.JOINT_NON_MANDATORY_CATEGORY)) return 1; + else return 0; + } + + public int getTourCategoryEscort() + { + if (tour.getTourPrimaryPurpose().equalsIgnoreCase( + ModelStructure.ESCORT_PRIMARY_PURPOSE_NAME)) return 1; + else return 0; + } + + public int getTourCategorySubtour() + { + if (tour.getTourCategory().equalsIgnoreCase(ModelStructure.AT_WORK_CATEGORY)) return 1; + else return 0; + } + + public int getNumberOfParticipantsInJointTour() + { + int[] participants = tour.getPersonNumArray(); + int returnValue = 0; + if (participants != null) returnValue = participants.length; + return returnValue; + } + + public int getHhSize() + { + return hh.getHhSize(); + } + + public int getAutos() + { + return hh.getAutosOwned(); } + + public int getAge() + { + return person.getAge(); + } + + public int getFemale() + { + return person.getPersonIsFemale(); + } + + public int getIncomeCategory() + { + return hh.getIncomeCategory(); + } + + public double getNm_walkTime() + { + return nmWalkTime; + } + + public double getNm_bikeTime() + { + return nmBikeTime; + } + + public double getReimburseAmount() + { + return reimburseAmount; + } + + public double getMonthlyParkingCostTourDest() + { + return lsWgtAvgCostM[tour.getTourDestMgra()]; + } + + public double getDailyParkingCostTourDest() + { + return lsWgtAvgCostD[tour.getTourDestMgra()]; + } + + public double getHourlyParkingCostTourDest() + { + return lsWgtAvgCostH[tour.getTourDestMgra()]; + } + + public double getHourlyParkingCostTripOrig() + { + return lsWgtAvgCostH[originMgra]; + } + + public double getHourlyParkingCostTripDest() + { + return lsWgtAvgCostH[destMgra]; + } + + public int getTripOrigIsTourDest() + { + return tripOrigIsTourDest; + } + + public int getTripDestIsTourDest() + { + return tripDestIsTourDest; + } + + public void setOriginMgra( int value ) { + originMgra = value; + } + + public void setDestMgra( int value ) { + destMgra = value; + } + + public int getFreeOnsite() + { + return person.getFreeParkingAvailableResult() == ParkingProvisionModel.FP_MODEL_FREE_ALT ? 1 + : 0; + } + + public int getPersonType() + { + return person.getPersonTypeNumber(); + } + + public double getWorkTimeFactor() { + return person.getTimeFactorWork(); + } + + public double getNonWorkTimeFactor(){ + return person.getTimeFactorNonWork(); + } + + /** + * Iterate through persons on tour and return non-work time factor + * for oldest person. If the person array is null then return 1.0. + * + * @return Time factor for oldest person on joint tour. + */ + public double getJointTourTimeFactor() { + int[] personNumArray = tour.getPersonNumArray(); + int oldestAge = -999; + Person oldestPerson = null; + for (int num : personNumArray){ + Person p = hh.getPerson(num); + if(p.getAge() > oldestAge){ + oldestPerson = p; + oldestAge = p.getAge(); + } + } + if(oldestPerson != null) + return oldestPerson.getTimeFactorNonWork(); + + return 1.0; + } + + public double getPTazTerminalTime() + { + return pTazTerminalTime; + } + + public double getATazTerminalTime() + { + return aTazTerminalTime; + } + + /** + * @return the originMgra + */ + public int getOriginMgra() { + return originMgra; + } + + /** + * @return the destMgra + */ + public int getDestMgra() { + return destMgra; + } + + public boolean isInbound() { + return inbound; + } + + public int getInbound() { + return inbound ? 1 : 0 ; + } + + + public void setInbound(boolean inbound) { + this.inbound = inbound; + } + + /** + * 1 if household owns transponder, else 0 + * @return 1 if household owns transponder, else 0 + */ + public int getTransponderOwnership(){ + return hh.getTpChoice(); + } + + + + + public double getIvtCoeff() { + return ivtCoeff; + } + + + + public void setIvtCoeff(double ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + + + public double getCostCoeff() { + return costCoeff; + } + + + + public void setCostCoeff(double costCoeff) { + this.costCoeff = costCoeff; + } + + public int getIncomeInDollars() + { + return hh.getIncomeInDollars(); + } + + public int getUseOwnedAV(){ + + if(tour==null) + return 0; + + return (tour.getUseOwnedAV() ? 1: 0); + } + + + + + public float getWaitTimeTaxi() { + return waitTimeTaxi; + } + + public void setWaitTimeTaxi(float waitTimeTaxi) { + this.waitTimeTaxi = waitTimeTaxi; + } + + public float getWaitTimeSingleTNC() { + return waitTimeSingleTNC; + } + + public void setWaitTimeSingleTNC(float waitTimeSingleTNC) { + this.waitTimeSingleTNC = waitTimeSingleTNC; + } + + public float getWaitTimeSharedTNC() { + return waitTimeSharedTNC; + } + + public void setWaitTimeSharedTNC(float waitTimeSharedTNC) { + this.waitTimeSharedTNC = waitTimeSharedTNC; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/UsualWorkSchoolLocationChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/UsualWorkSchoolLocationChoiceModel.java new file mode 100644 index 0000000..5b04c22 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/UsualWorkSchoolLocationChoiceModel.java @@ -0,0 +1,1003 @@ +package org.sandag.abm.ctramp; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.HashSet; +import java.util.List; +import java.util.MissingResourceException; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; +import org.jppf.client.JPPFClient; +import org.jppf.client.JPPFJob; +import org.jppf.node.protocol.DataProvider; +import org.jppf.node.protocol.JPPFTask; +import org.jppf.node.protocol.MemoryMapDataProvider; +import org.jppf.node.protocol.Task; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.util.ResourceUtil; + +public class UsualWorkSchoolLocationChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(UsualWorkSchoolLocationChoiceModel.class); + + private static final String USE_NEW_SOA_METHOD_PROPERTY_KEY = "uwsl.use.new.soa"; + + private static final String PROPERTIES_DC_SOA_WORK_SAMPLE_SIZE = "uwsl.work.soa.SampleSize"; + private static final String PROPERTIES_DC_SOA_SCHOOL_SAMPLE_SIZE = "uwsl.school.soa.SampleSize"; + private static final String PROPERTIES_UEC_USUAL_LOCATION = "uwsl.dc.uec.file"; + private static final String PROPERTIES_UEC_USUAL_LOCATION_NEW = "uwsl.dc2.uec.file"; + private static final String PROPERTIES_UEC_USUAL_LOCATION_SOA = "uwsl.soa.uec.file"; + + private static final String PROPERTIES_RESULTS_WORK_SCHOOL_LOCATION_CHOICE = "Results.UsualWorkAndSchoolLocationChoice"; + + private static final String PROPERTIES_WORK_SCHOOL_LOCATION_CHOICE_PACKET_SIZE = "distributed.task.packet.size"; + + private static final String WORK_SCHOOL_SEGMENTS_FILE_NAME = "workSchoolSegments.definitions"; + + private static final int[] WORK_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX = {1, 1, 1, + 1, 1, 1 }; + private static final int[] WORK_LOC_SEGMENT_TO_UEC_SHEET_INDEX = {2, 2, 2, + 2, 2, 2 }; + private static int PACKET_SIZE = 0; + + // TODO: see if we can eliminate the setup synchronization issues - + // otherwise the + // number of these small + // packets can be fine-tuned and set in properties file.. + + // The number of initialization packets are the number of "small" packets + // submited at the beginning of a + // distributed task to minimize synchronization issues that significantly + // slow + // down model object setup. + // It is assumed that after theses small packets have run, all the model + // objects + // will have been setup, + // and the task objects can process much bigger chuncks of households. + private static String PROPERTIES_NUM_INITIALIZATION_PACKETS = "number.initialization.packets"; + private static String PROPERTIES_INITIALIZATION_PACKET_SIZE = "initialization.packet.size"; + private static int NUM_INITIALIZATION_PACKETS = 0; + private static int INITIALIZATION_PACKET_SIZE = 0; + + private static final int NUM_WRITE_PACKETS = 1000; + + private String wsLocResultsFileName; + + private transient ResourceBundle resourceBundle; + + private MgraDataManager mgraManager; + private TazDataManager tdm; + + private int maxTaz; + + private MatrixDataServerIf ms; + private ModelStructure modelStructure; + private CtrampDmuFactoryIf dmuFactory; + + private String workLocUecFileName; + private String schoolLocUecFileName; + private String soaUecFileName; + private int soaWorkSampleSize; + private int soaSchoolSampleSize; + + private HashSet skipSegmentIndexSet; + + private BuildAccessibilities aggAcc; + private DestChoiceSize workerDcSizeObj; + private DestChoiceSize schoolDcSizeObj; + + private String restartModelString; + + private JPPFClient jppfClient = null; + + private boolean useNewSoaMethod; + + public UsualWorkSchoolLocationChoiceModel(ResourceBundle resourceBundle, + String restartModelString, JPPFClient jppfClient, ModelStructure modelStructure, + MatrixDataServerIf ms, CtrampDmuFactoryIf dmuFactory, BuildAccessibilities aggAcc) + { + + // set the local variables + this.resourceBundle = resourceBundle; + this.modelStructure = modelStructure; + this.dmuFactory = dmuFactory; + this.ms = ms; + this.jppfClient = jppfClient; + this.restartModelString = restartModelString; + this.aggAcc = aggAcc; + + try + { + PACKET_SIZE = Integer.parseInt(resourceBundle + .getString(PROPERTIES_WORK_SCHOOL_LOCATION_CHOICE_PACKET_SIZE)); + } catch (MissingResourceException e) + { + PACKET_SIZE = 0; + } + + try + { + NUM_INITIALIZATION_PACKETS = Integer.parseInt(resourceBundle + .getString(PROPERTIES_NUM_INITIALIZATION_PACKETS)); + } catch (MissingResourceException e) + { + NUM_INITIALIZATION_PACKETS = 0; + } + + try + { + INITIALIZATION_PACKET_SIZE = Integer.parseInt(resourceBundle + .getString(PROPERTIES_INITIALIZATION_PACKET_SIZE)); + } catch (MissingResourceException e) + { + INITIALIZATION_PACKET_SIZE = 0; + } + + try + { + wsLocResultsFileName = resourceBundle + .getString(PROPERTIES_RESULTS_WORK_SCHOOL_LOCATION_CHOICE); + } catch (MissingResourceException e) + { + wsLocResultsFileName = null; + } + + String uecPath = ResourceUtil.getProperty(resourceBundle, + CtrampApplication.PROPERTIES_UEC_PATH); + + // get the sample-of-alternatives sample size + soaWorkSampleSize = ResourceUtil.getIntegerProperty(resourceBundle, + PROPERTIES_DC_SOA_WORK_SAMPLE_SIZE); + soaSchoolSampleSize = ResourceUtil.getIntegerProperty(resourceBundle, + PROPERTIES_DC_SOA_SCHOOL_SAMPLE_SIZE); + + useNewSoaMethod = ResourceUtil.getBooleanProperty(resourceBundle, + USE_NEW_SOA_METHOD_PROPERTY_KEY); + + // locate the UECs for destination choice, sample of alts, and mode + // choice + String usualWorkLocationUecFileName; + String usualSchoolLocationUecFileName; + if (useNewSoaMethod) + { + usualWorkLocationUecFileName = ResourceUtil.getProperty(resourceBundle, + PROPERTIES_UEC_USUAL_LOCATION_NEW); + usualSchoolLocationUecFileName = ResourceUtil.getProperty(resourceBundle, + PROPERTIES_UEC_USUAL_LOCATION_NEW); + } else + { + usualWorkLocationUecFileName = ResourceUtil.getProperty(resourceBundle, + PROPERTIES_UEC_USUAL_LOCATION); + usualSchoolLocationUecFileName = ResourceUtil.getProperty(resourceBundle, + PROPERTIES_UEC_USUAL_LOCATION); + } + workLocUecFileName = uecPath + usualWorkLocationUecFileName; + schoolLocUecFileName = uecPath + usualSchoolLocationUecFileName; + + String usualLocationSoaUecFileName = ResourceUtil.getProperty(resourceBundle, + PROPERTIES_UEC_USUAL_LOCATION_SOA); + soaUecFileName = uecPath + usualLocationSoaUecFileName; + + mgraManager = MgraDataManager.getInstance(); + + } + + public void runWorkLocationChoiceModel(HouseholdDataManagerIf householdDataManager, + double[][] workerSizeTerms) + { + + HashMap propertyMap = ResourceUtil + .changeResourceBundleIntoHashMap(resourceBundle); + + // get the map of size term segment values to names + HashMap occupValueIndexMap = aggAcc.getWorkOccupValueIndexMap(); + + HashMap workSegmentIndexNameMap = aggAcc.getWorkSegmentIndexNameMap(); + HashMap workSegmentNameIndexMap = aggAcc.getWorkSegmentNameIndexMap(); + + int maxShadowPriceIterations = Integer.parseInt(propertyMap + .get(DestChoiceSize.PROPERTIES_WORK_DC_SHADOW_NITER)); + + // create an object for calculating destination choice attraction size + // terms + // and managing shadow price calculations. + workerDcSizeObj = new DestChoiceSize(propertyMap, workSegmentIndexNameMap, + workSegmentNameIndexMap, workerSizeTerms, maxShadowPriceIterations); + + int[][] originLocationsByHomeMgra = householdDataManager + .getWorkersByHomeMgra(occupValueIndexMap); + + // balance the size variables + workerDcSizeObj.balanceSizeVariables(originLocationsByHomeMgra); + + if (PACKET_SIZE == 0) PACKET_SIZE = householdDataManager.getNumHouseholds(); + + int currentIter = 0; + String fileName = propertyMap + .get(CtrampApplication.PROPERTIES_WORK_LOCATION_CHOICE_SHADOW_PRICE_INPUT_FILE); + if (fileName != null) + { + if (fileName.length() > 2) + { + String projectDirectory = ResourceUtil.getProperty(resourceBundle, + CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + workerDcSizeObj.restoreShadowPricingInfo(projectDirectory + fileName); + int underScoreIndex = fileName.lastIndexOf('_'); + int dotIndex = fileName.lastIndexOf('.'); + currentIter = Integer.parseInt(fileName.substring(underScoreIndex + 1, dotIndex)); + currentIter++; + } + } + + // String restartFlag = propertyMap.get( + // CtrampApplication.PROPERTIES_RESTART_WITH_HOUSEHOLD_SERVER ); + // if ( restartFlag == null ) + // restartFlag = "none"; + // if ( restartFlag.equalsIgnoreCase("none") ) + // currentIter = 0; + + long initTime = System.currentTimeMillis(); + + // shadow pricing iterations + for (int iter = 0; iter < workerDcSizeObj.getMaxShadowPriceIterations(); iter++) + { + + logger.info("Work location choice shadow pricing iteration "+iter); + int innerLoop=0; + + while(true) { + ++innerLoop; + try + { + JPPFJob job = new JPPFJob(); + job.setName("Work Location Choice Job"); + + ArrayList startEndTaskIndicesList = getTaskHouseholdRanges(householdDataManager + .getNumHouseholds()); + + DataProvider dataProvider = new MemoryMapDataProvider(); + dataProvider.setParameter("propertyMap", propertyMap); + dataProvider.setParameter("ms", ms); + dataProvider.setParameter("hhDataManager", householdDataManager); + dataProvider.setParameter("modelStructure", modelStructure); + dataProvider.setParameter("uecIndices", WORK_LOC_SEGMENT_TO_UEC_SHEET_INDEX); + dataProvider.setParameter("soaUecIndices", WORK_LOC_SOA_SEGMENT_TO_UEC_SHEET_INDEX); + dataProvider.setParameter("tourCategory", ModelStructure.MANDATORY_CATEGORY); + dataProvider.setParameter("dcSizeObj", workerDcSizeObj); + dataProvider.setParameter("dcUecFileName", workLocUecFileName); + dataProvider.setParameter("soaUecFileName", soaUecFileName); + dataProvider.setParameter("soaSampleSize", soaWorkSampleSize); + dataProvider.setParameter("dmuFactory", dmuFactory); + dataProvider.setParameter("restartModelString", restartModelString); + + job.setDataProvider(dataProvider); + + int startIndex = 0; + int endIndex = 0; + int taskIndex = 1; + WorkLocationChoiceTaskJppf myTask = null; + WorkLocationChoiceTaskJppfNew myTaskNew = null; + for (int[] startEndIndices : startEndTaskIndicesList) + { + startIndex = startEndIndices[0]; + endIndex = startEndIndices[1]; + + if (innerLoop == 1) { + resetWorkLocationResults(startIndex,endIndex,householdDataManager); + } + + //check if there's work to do (JEF) + if(workLocationResultsOK(startIndex, endIndex, householdDataManager)) + continue; + + if (useNewSoaMethod) + { + myTaskNew = new WorkLocationChoiceTaskJppfNew(taskIndex, startIndex, + endIndex, iter); + job.add(myTaskNew); + } else + { + myTask = new WorkLocationChoiceTaskJppf(taskIndex, startIndex, endIndex, + iter); + job.add(myTask); + } + taskIndex++; + } + //nothing to do, so break out of this loop (JEF) + if(job.getJobTasks().isEmpty()) { + logger.info("Work location choice tasks completed successfully after "+(innerLoop-1)+" loops"); + break; + }else { + logger.info("Work location choice tasks need to be executed in loop "+innerLoop); + } + logger.info("Usual work location choice model submitting tasks to jppf job"); + List> results = jppfClient.submitJob(job); + for (Task task : results) + { + //if (task.getException() != null) throw task.getException(); + //wu modefied for jppf 6.1.4 + if (task.getThrowable() != null) { + Throwable t = task.getThrowable(); + t.printStackTrace(); + } + try + { + String stringResult = (String) task.getResult(); + logger.info(stringResult); + System.out.println(stringResult); + } catch (Exception e) + { + logger.error("", e); + throw new RuntimeException(); + } + + } + + } catch (Exception e) + { + e.printStackTrace(); + } + } + + // sum the chosen destinations by purpose, dest zone and subzone for + // shadow pricing adjustment + int[][] finalModeledDestChoiceLocationsByDestMgra = householdDataManager + .getWorkToursByDestMgra(occupValueIndexMap); + + int[] numChosenDests = new int[workSegmentNameIndexMap.size()]; + + for (int i = 0; i < numChosenDests.length; i++) + { + for (int j = 1; j <= mgraManager.getMaxMgra(); j++) + numChosenDests[i] += finalModeledDestChoiceLocationsByDestMgra[i][j]; + } + + logger.info(String + .format("Usual work location choice tasks completed for shadow price iteration %d in %d seconds.", + iter, ((System.currentTimeMillis() - initTime) / 1000))); + logger.info(String.format("Chosen dests by segment:")); + double total = 0; + for (int i = 0; i < numChosenDests.length; i++) + { + String segmentString = workSegmentIndexNameMap.get(i); + logger.info(String.format("\t%-8d%-15s = %10d", i + 1, segmentString, + numChosenDests[i])); + total += numChosenDests[i]; + } + logger.info(String.format("\t%-8s%-15s = %10.0f", "total", "", total)); + + // apply the shadow price adjustments + workerDcSizeObj.reportMaxDiff(iter, finalModeledDestChoiceLocationsByDestMgra); + workerDcSizeObj.saveWorkMaxDiffValues(iter, finalModeledDestChoiceLocationsByDestMgra); + workerDcSizeObj.updateShadowPrices(finalModeledDestChoiceLocationsByDestMgra); + workerDcSizeObj.updateSizeVariables(); + workerDcSizeObj.updateShadowPricingInfo(currentIter, originLocationsByHomeMgra, + finalModeledDestChoiceLocationsByDestMgra, "work"); + + householdDataManager.setUwslRandomCount(currentIter); + + currentIter++; + + } // iter + + logger.info("Usual work location choices computed in " + + ((System.currentTimeMillis() - initTime) / 1000) + " seconds."); + + } + + public void runSchoolLocationChoiceModel(HouseholdDataManagerIf householdDataManager, + double[][] schoolSizeTerms, double[][] schoolFactors) + { + + HashMap propertyMap = ResourceUtil + .changeResourceBundleIntoHashMap(resourceBundle); + + // get the maps of segment names and indices for school location choice + // size + HashMap schoolSegmentIndexNameMap = aggAcc.getSchoolSegmentIndexNameMap(); + HashMap schoolSegmentNameIndexMap = aggAcc.getSchoolSegmentNameIndexMap(); + + int maxShadowPriceIterations = Integer.parseInt(propertyMap + .get(DestChoiceSize.PROPERTIES_SCHOOL_DC_SHADOW_NITER)); + + // create an object for calculating destination choice attraction size + // terms + // and managing shadow price calculations. + schoolDcSizeObj = new DestChoiceSize(propertyMap, schoolSegmentIndexNameMap, + schoolSegmentNameIndexMap, schoolSizeTerms, maxShadowPriceIterations); + + // get the set of segment indices for which shadow pricing should be + // skipped. + skipSegmentIndexSet = aggAcc.getNoShadowPriceSchoolSegmentIndexSet(); + schoolDcSizeObj.setNoShadowPriceSchoolSegmentIndices(skipSegmentIndexSet); + + // set the school segment external factors calculated for university + // segment in the method that called this one. + schoolDcSizeObj.setExternalFactors(schoolFactors); + + householdDataManager.setSchoolDistrictMappings(schoolSegmentNameIndexMap, + aggAcc.getMgraGsDistrict(), aggAcc.getMgraHsDistrict(), + aggAcc.getGsDistrictIndexMap(), aggAcc.getHsDistrictIndexMap()); + + int[][] originLocationsByHomeMgra = householdDataManager.getStudentsByHomeMgra(); + + // balance the size variables + schoolDcSizeObj.balanceSizeVariables(originLocationsByHomeMgra); + + if (PACKET_SIZE == 0) PACKET_SIZE = householdDataManager.getNumHouseholds(); + + int currentIter = 0; + String fileName = propertyMap + .get(CtrampApplication.PROPERTIES_SCHOOL_LOCATION_CHOICE_SHADOW_PRICE_INPUT_FILE); + if (fileName != null) + if (fileName.length() > 2) + { + { + String projectDirectory = ResourceUtil.getProperty(resourceBundle, + CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + schoolDcSizeObj.restoreShadowPricingInfo(projectDirectory + fileName); + int underScoreIndex = fileName.lastIndexOf('_'); + int dotIndex = fileName.lastIndexOf('.'); + currentIter = Integer.parseInt(fileName + .substring(underScoreIndex + 1, dotIndex)); + currentIter++; + } + } + // String restartFlag = propertyMap.get( + // CtrampApplication.PROPERTIES_RESTART_WITH_HOUSEHOLD_SERVER ); + // if ( restartFlag == null ) + // restartFlag = "none"; + // if ( restartFlag.equalsIgnoreCase("none") ) + // currentIter = 0; + + long initTime = System.currentTimeMillis(); + + // shadow pricing iterations + for (int iter = 0; iter < schoolDcSizeObj.getMaxShadowPriceIterations(); iter++) + { + + // logger.info( String.format( "Size of Household[] in bytes = %d.", + // householdDataManager.getBytesUsedByHouseholdArray() ) ); + logger.info("School location choice shadow pricing iteration "+iter); + int innerLoop=0; + + while(true) { + ++innerLoop; + + try + { + JPPFJob job = new JPPFJob(); + job.setName("School Location Choice Job"); + + ArrayList startEndTaskIndicesList = getTaskHouseholdRanges(householdDataManager + .getNumHouseholds()); + + DataProvider dataProvider = new MemoryMapDataProvider(); + dataProvider.setParameter("propertyMap", propertyMap); + dataProvider.setParameter("ms", ms); + dataProvider.setParameter("hhDataManager", householdDataManager); + dataProvider.setParameter("modelStructure", modelStructure); + dataProvider.setParameter("tourCategory", ModelStructure.MANDATORY_CATEGORY); + dataProvider.setParameter("dcSizeObj", schoolDcSizeObj); + dataProvider.setParameter("dcUecFileName", schoolLocUecFileName); + dataProvider.setParameter("soaUecFileName", soaUecFileName); + dataProvider.setParameter("soaSampleSize", soaSchoolSampleSize); + dataProvider.setParameter("dmuFactory", dmuFactory); + dataProvider.setParameter("restartModelString", restartModelString); + + job.setDataProvider(dataProvider); + + int startIndex = 0; + int endIndex = 0; + int taskIndex = 1; + SchoolLocationChoiceTaskJppf myTask = null; + SchoolLocationChoiceTaskJppfNew myTaskNew = null; + for (int[] startEndIndices : startEndTaskIndicesList) + { + startIndex = startEndIndices[0]; + endIndex = startEndIndices[1]; + + if (innerLoop == 1) { + resetSchoolLocationResults(startIndex,endIndex,householdDataManager); + } + //check if there's work to do (JEF) + if( schoolLocationResultsOK(startIndex, endIndex, householdDataManager)) + continue; + + if (useNewSoaMethod) + { + myTaskNew = new SchoolLocationChoiceTaskJppfNew(taskIndex, startIndex, + endIndex, iter); + job.add(myTaskNew); + } else + { + myTask = new SchoolLocationChoiceTaskJppf(taskIndex, startIndex, endIndex, + iter); + job.add(myTask); + } + taskIndex++; + } + + //nothing to do, so break out of this loop (JEF) + if(job.getJobTasks().isEmpty()) { + logger.info("School location choice tasks completed successfully after "+(innerLoop-1)+" loops"); + break; + }else { + logger.info("School location choice tasks need to be executed in loop "+innerLoop); + } + + List> results = jppfClient.submitJob(job); + for (Task task : results) + { + //if (task.getException() != null) throw task.getException(); + //wu modefied for jppf 6.1.4 + if (task.getThrowable() != null) { + Throwable t = task.getThrowable(); + t.printStackTrace(); + } + try + { + String stringResult = (String) task.getResult(); + logger.info(stringResult); + System.out.println(stringResult); + } catch (Exception e) + { + logger.error("", e); + throw new RuntimeException(); + } + + } + + } catch (Exception e) + { + e.printStackTrace(); + } + } + // sum the chosen destinations by purpose, dest zone and subzone for + // shadow pricing adjustment + int[][] finalModeledDestChoiceLocationsByDestMgra = householdDataManager + .getSchoolToursByDestMgra(); + + int[] numChosenDests = new int[schoolSegmentIndexNameMap.size()]; + + for (int i = 0; i < numChosenDests.length; i++) + { + for (int j = 1; j <= mgraManager.getMaxMgra(); j++) + numChosenDests[i] += finalModeledDestChoiceLocationsByDestMgra[i][j]; + } + + logger.info(String.format( + "Usual school location choice tasks completed for shadow price iteration %d.", + iter)); + logger.info(String.format("Chosen dests by segment:")); + double total = 0; + for (int i = 0; i < numChosenDests.length; i++) + { + String segmentString = schoolSegmentIndexNameMap.get(i); + logger.info(String.format("\t%-8d%-20s = %10d", i + 1, segmentString, + numChosenDests[i])); + total += numChosenDests[i]; + } + logger.info(String.format("\t%-8s%-20s = %10.0f", "total", "", total)); + + logger.info(String + .format("Usual school location choice tasks completed for shadow price iteration %d in %d seconds.", + iter, ((System.currentTimeMillis() - initTime) / 1000))); + + // apply the shadow price adjustments + schoolDcSizeObj.reportMaxDiff(iter, finalModeledDestChoiceLocationsByDestMgra); + schoolDcSizeObj + .saveSchoolMaxDiffValues(iter, finalModeledDestChoiceLocationsByDestMgra); + schoolDcSizeObj.updateShadowPrices(finalModeledDestChoiceLocationsByDestMgra); + schoolDcSizeObj.updateSizeVariables(); + schoolDcSizeObj.updateShadowPricingInfo(currentIter, originLocationsByHomeMgra, + finalModeledDestChoiceLocationsByDestMgra, "school"); + + householdDataManager.setUwslRandomCount(currentIter); + + currentIter++; + + } // iter + + logger.info("Usual school location choices computed in " + + ((System.currentTimeMillis() - initTime) / 1000) + " seconds."); + + } + + /** + * Loops through the households in the HouseholdDataManager, gets the + * households and persons and writes a row with detail on each of these in a + * file. + * + * @param householdDataManager + * is the object from which the array of household objects can be + * retrieved. + * @param projectDirectory + * is the root directory for the output file named + */ + public void saveResults(HouseholdDataManagerIf householdDataManager, String projectDirectory, + int globalIteration) + { + + HashMap workSegmentNameIndexMap = modelStructure + .getWorkSegmentNameIndexMap(); + HashMap schoolSegmentNameIndexMap = modelStructure + .getSchoolSegmentNameIndexMap(); + + FileWriter writer; + PrintWriter outStream = null; + + if (wsLocResultsFileName != null) + { + + // insert '_' and the global iteration number at end of filename or + // before '.' if there is a file extension in the name. + int dotIndex = wsLocResultsFileName.indexOf('.'); + if (dotIndex < 0) + { + wsLocResultsFileName = String + .format("%s_%d", wsLocResultsFileName, globalIteration); + } else + { + String base = wsLocResultsFileName.substring(0, dotIndex); + String extension = wsLocResultsFileName.substring(dotIndex); + wsLocResultsFileName = String.format("%s_%d%s", base, globalIteration, extension); + } + + wsLocResultsFileName = projectDirectory + wsLocResultsFileName; + + try + { + writer = new FileWriter(new File(wsLocResultsFileName)); + outStream = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) + { + logger.fatal(String.format("Exception occurred opening wsLoc results file: %s.", + wsLocResultsFileName)); + throw new RuntimeException(e); + } + + // write header + outStream + .println("HHID,HomeMGRA,Income,PersonID,PersonNum,PersonType,PersonAge,EmploymentCategory,StudentCategory,WorkSegment,SchoolSegment,WorkLocation,WorkLocationDistance,WorkLocationLogsum,SchoolLocation,SchoolLocationDistance,SchoolLocationLogsum"); + + ArrayList startEndTaskIndicesList = getWriteHouseholdRanges(householdDataManager + .getNumHouseholds()); + + for (int[] startEndIndices : startEndTaskIndicesList) + { + + int startIndex = startEndIndices[0]; + int endIndex = startEndIndices[1]; + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + for (int i = 0; i < householdArray.length; ++i) + { + + Household household = householdArray[i]; + + int hhId = household.getHhId(); + int homeMgra = household.getHhMgra(); + int income = household.getIncomeInDollars(); + + Person[] personArray = household.getPersons(); + + for (int j = 1; j < personArray.length; ++j) + { + + Person person = personArray[j]; + + int personId = person.getPersonId(); + int personNum = person.getPersonNum(); + int personType = person.getPersonTypeNumber(); + int personAge = person.getAge(); + int employmentCategory = person.getPersonEmploymentCategoryIndex(); + int studentCategory = person.getPersonStudentCategoryIndex(); + + int schoolSegmentIndex = person.getSchoolLocationSegmentIndex(); + int workSegmentIndex = person.getWorkLocationSegmentIndex(); + + int workLocation = person.getWorkLocation(); + int schoolLocation = person.getUsualSchoolLocation(); + + // write data record + outStream.println(String.format( + "%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%d,%.5e,%.5e,%d,%.5e,%.5e", hhId, + homeMgra, income, personId, personNum, personType, personAge, + employmentCategory, studentCategory, workSegmentIndex, + schoolSegmentIndex, workLocation, person.getWorkLocationDistance(), + person.getWorkLocationLogsum(), schoolLocation, + person.getSchoolLocationDistance(), + person.getSchoolLocationLogsum())); + + } + + } + + } + + outStream.close(); + + } + + // save the mappings between segment index and segment labels to a file + // for + // workers and students + String fileName = projectDirectory + WORK_SCHOOL_SEGMENTS_FILE_NAME; + + try + { + writer = new FileWriter(new File(fileName)); + outStream = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) + { + logger.fatal(String.format( + "Exception occurred opening work/school segment definitions file: %s.", + fileName)); + throw new RuntimeException(e); + } + + outStream + .println("Correspondence table for work location segment indices and work location segment names"); + outStream.println(String.format("%-15s %-20s", "Index", "Segment Name")); + + String[] names = new String[workSegmentNameIndexMap.size() + 1]; + for (String key : workSegmentNameIndexMap.keySet()) + { + int index = workSegmentNameIndexMap.get(key); + names[index] = key; + } + + for (int i = 0; i < names.length; i++) + { + if (names[i] != null) outStream.println(String.format("%-15d %-20s", i, names[i])); + } + + outStream.println(""); + outStream.println(""); + outStream.println(""); + + outStream + .println("Correspondence table for school location segment indices and school location segment names"); + outStream.println(String.format("%-15s %-20s", "Index", "Segment Name")); + + names = new String[schoolSegmentNameIndexMap.size() + 1]; + for (String key : schoolSegmentNameIndexMap.keySet()) + { + int index = schoolSegmentNameIndexMap.get(key); + names[index] = key; + } + + for (int i = 0; i < names.length; i++) + { + if (names[i] != null) outStream.println(String.format("%-15d %-20s", i, names[i])); + } + + outStream.println(""); + + outStream.close(); + + } + + private ArrayList getTaskHouseholdRanges(int numberOfHouseholds) + { + + ArrayList startEndIndexList = new ArrayList(); + + int numInitializationHouseholds = NUM_INITIALIZATION_PACKETS * INITIALIZATION_PACKET_SIZE; + + int startIndex = 0; + int endIndex = 0; + if (numInitializationHouseholds < numberOfHouseholds) + { + + while (endIndex < numInitializationHouseholds) + { + endIndex = startIndex + INITIALIZATION_PACKET_SIZE - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += INITIALIZATION_PACKET_SIZE; + } + + } + + while (endIndex < numberOfHouseholds - 1) + { + endIndex = startIndex + PACKET_SIZE - 1; + if (endIndex + PACKET_SIZE > numberOfHouseholds) endIndex = numberOfHouseholds - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += PACKET_SIZE; + } + + return startEndIndexList; + + } + + private ArrayList getWriteHouseholdRanges(int numberOfHouseholds) + { + + ArrayList startEndIndexList = new ArrayList(); + + int startIndex = 0; + int endIndex = 0; + + while (endIndex < numberOfHouseholds - 1) + { + endIndex = startIndex + NUM_WRITE_PACKETS - 1; + if (endIndex + NUM_WRITE_PACKETS > numberOfHouseholds) + endIndex = numberOfHouseholds - 1; + + int[] startEndIndices = new int[2]; + startEndIndices[0] = startIndex; + startEndIndices[1] = endIndex; + startEndIndexList.add(startEndIndices); + + startIndex += NUM_WRITE_PACKETS; + } + + return startEndIndexList; + + } + + + /** + * Returns true if work location results are OK, else returns false. + * + * @param startIndex starting range of households + * @param endIndex ending range of households + * @param HouseholdDataManagerIf household data manager + * @return true or false + */ + public boolean workLocationResultsOK(int startIndex, int endIndex, HouseholdDataManagerIf householdDataManager) { + + + // get the array of households + Household[] householdArray = householdDataManager.getHhArray(startIndex, endIndex); + + //iterate through hhs + for(Household thisHousehold:householdArray) { + + Person[] persons = thisHousehold.getPersons(); + + //iterate through persons + for(int k=1;k rbMap, String key) + { + boolean returnValue; + String value = rbMap.get(key); + if (value.equalsIgnoreCase("true") || value.equalsIgnoreCase("false")) + { + returnValue = Boolean.parseBoolean(value); + } else + { + logger.info("property file key: " + key + " = " + value + + " should be either 'true' or 'false'."); + throw new RuntimeException(); + } + + return returnValue; + } + + public static String getStringValueFromPropertyMap(HashMap rbMap, String key) + { + String returnValue = rbMap.get(key); + if (returnValue == null) returnValue = ""; + + return returnValue; + } + + public static String[] getStringArrayFromPropertyMap(HashMap rbMap, String key) { + String[] values = getStringValueFromPropertyMap(rbMap,key).split(","); + return values; + } + + + public static int getIntegerValueFromPropertyMap(HashMap rbMap, String key) + { + String value = rbMap.get(key); + if (value != null) + { + return Integer.parseInt(value); + } else + { + logger.info("property file key: " + key + + " missing. No integer value can be determined."); + throw new RuntimeException(); + } + } + + public static float getFloatValueFromPropertyMap(HashMap rbMap, String key) + { + String value = rbMap.get(key); + if (value != null) + { + return Float.parseFloat(value); + } else + { + logger.info("property file key: " + key + + " missing. No float value can be determined."); + throw new RuntimeException(); + } + } + + public static int[] getIntegerArrayFromPropertyMap(HashMap rbMap, String key) + { + + int[] returnArray; + String valueList = rbMap.get(key); + if (valueList != null) + { + + ArrayList valueSet = new ArrayList(); + + if (valueSet != null) + { + StringTokenizer valueTokenizer = new StringTokenizer(valueList, ","); + while (valueTokenizer.hasMoreTokens()) + { + String listValue = valueTokenizer.nextToken(); + int intValue = Integer.parseInt(listValue.trim()); + valueSet.add(intValue); + } + } + + returnArray = new int[valueSet.size()]; + int i = 0; + for (int v : valueSet) + returnArray[i++] = v; + + } else + { + logger.info("property file key: " + key + + " missing. No integer value can be determined."); + throw new RuntimeException(); + } + + return returnArray; + + } + + public static float[] getFloatArrayFromPropertyMap(HashMap rbMap, String key) + { + + float[] returnArray; + String valueList = rbMap.get(key); + if (valueList != null) + { + + ArrayList valueSet = new ArrayList(); + + StringTokenizer valueTokenizer = new StringTokenizer(valueList, ","); + while (valueTokenizer.hasMoreTokens()) + { + String listValue = valueTokenizer.nextToken(); + float floatValue = Float.parseFloat(listValue.trim()); + valueSet.add(floatValue); + } + + returnArray = new float[valueSet.size()]; + int i = 0; + for (float v : valueSet) + returnArray[i++] = v; + + } else + { + logger.info("property file key: " + key + + " missing. No float value can be determined."); + throw new RuntimeException(); + } + + return returnArray; + + } + + public static double[] getDoubleArrayFromPropertyMap(HashMap rbMap, String key) + { + + double[] returnArray; + String valueList = rbMap.get(key); + if (valueList != null) + { + + ArrayList valueSet = new ArrayList(); + + StringTokenizer valueTokenizer = new StringTokenizer(valueList, ","); + while (valueTokenizer.hasMoreTokens()) + { + String listValue = valueTokenizer.nextToken(); + double doubleValue = Double.parseDouble(listValue.trim()); + valueSet.add(doubleValue); + } + + returnArray = new double[valueSet.size()]; + int i = 0; + for (double v : valueSet) + returnArray[i++] = v; + + } else + { + logger.info("property file key: " + key + + " missing. No double value can be determined."); + throw new RuntimeException(); + } + + return returnArray; + + } + + /** + * + * @param cumProbabilities + * cumulative probabilities array + * @param entry + * target to search for in array + * @return the array index i where cumProbabilities[i] < entry and + * cumProbabilities[i-1] <= entry. + */ + public static int binarySearchDouble(double[] cumProbabilities, double entry) + { + + // lookup index for 0 <= entry < 1.0 in cumProbabilities + // cumProbabilities values are assumed to be in range: [0,1], and + // cumProbabilities[cumProbabilities.length-1] must equal 1.0 + + // if entry is outside the allowed range, return -1 + if (entry < 0 || entry >= 1.0) + { + System.out.println("entry = " + entry + + " is outside of allowable range for cumulative distribution [0,...,1.0)"); + return -1; + } + + // if cumProbabilities[cumProbabilities.length-1] is not equal to 1.0, + // return -1 + double epsilon = .0000001; + if (!(Math.abs(cumProbabilities[cumProbabilities.length - 1] - 1.0) < epsilon)) + { + System.out.println("cumProbabilities[cumProbabilities.length-1] = " + + cumProbabilities[cumProbabilities.length - 1] + " must equal 1.0"); + return -1; + } + + int hi = cumProbabilities.length; + int lo = 0; + int mid = (hi - lo) / 2; + + int safetyCount = 0; + + // if mid is 0, + if (mid == 0) + { + if (entry < cumProbabilities[0]) return 0; + else return 1; + } else if (entry < cumProbabilities[mid] && entry >= cumProbabilities[mid - 1]) + { + return mid; + } + + while (true) + { + + if (entry < cumProbabilities[mid]) + { + hi = mid; + mid = (hi + lo) / 2; + } else + { + lo = mid; + mid = (hi + lo) / 2; + } + + // if mid is 0, + if (mid == 0) + { + if (entry < cumProbabilities[0]) return 0; + else return 1; + } else if (entry < cumProbabilities[mid] && entry >= cumProbabilities[mid - 1]) + { + return mid; + } + + if (safetyCount++ > cumProbabilities.length) + { + logger.info("binary search stuck in the while loop"); + throw new RuntimeException("binary search stuck in the while loop"); + } + + } + + } + + /** + * + * @param cumProbabilities + * cumulative probabilities array + * @param numIndices + * are the number of probability values to consider in the + * cumulative probabilities array + * @param entry + * target to search for in array between indices 1 and numValues. + * @return the array index i where cumProbabilities[i] < entry and + * cumProbabilities[i-1] <= entry. + */ + public static int binarySearchDouble(double cumProbabilityLowerBound, + double[] cumProbabilities, int numIndices, double entry) + { + + // search for 0-based index i for cumProbabilities such that + // cumProbabilityLowerBound <= entry < cumProbabilities[0], i = 0; + // or + // cumProbabilities[i-1] <= entry < cumProbabilities[i], for i = + // 1,...numIndices-1; + + // if entry is outside the allowed range, return -1 + if (entry < cumProbabilityLowerBound || entry >= cumProbabilities[numIndices - 1]) + { + logger.info("entry = " + entry + + " is outside of allowable range of cumulative probabilities."); + logger.info("cumProbabilityLowerBound = " + cumProbabilityLowerBound + + ", cumProbabilities[numIndices-1] = " + cumProbabilities[numIndices - 1] + + ", numIndices = " + numIndices); + return -1; + } + + int hi = numIndices; + int lo = 0; + int mid = (hi - lo) / 2; + + int safetyCount = 0; + + // if mid is 0, + if (mid == 0) + { + if (entry < cumProbabilities[0]) return 0; + else return 1; + } else if (entry < cumProbabilities[mid] && entry >= cumProbabilities[mid - 1]) + { + return mid; + } + + while (true) + { + + if (entry < cumProbabilities[mid]) + { + hi = mid; + mid = (hi + lo) / 2; + } else + { + lo = mid; + mid = (hi + lo) / 2; + } + + // if mid is 0, + if (mid == 0) + { + if (entry < cumProbabilities[0]) return 0; + else return 1; + } else if (entry < cumProbabilities[mid] && entry >= cumProbabilities[mid - 1]) + { + return mid; + } + + if (safetyCount++ > numIndices) + { + logger.info("binary search stuck in the while loop"); + throw new RuntimeException("binary search stuck in the while loop"); + } + + } + + } + + /** + * REad a tabledataset from a CSV file and return it. + * + * @param fileName + * @return + */ + public static TableDataSet readTableDataSet(String fileName) { + + + TableDataSet tableData; + + try + { + CSVFileReader csvFile = new CSVFileReader(); + tableData = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + logger.fatal("Error trying to read table data set from csv file: "+ fileName); + throw new RuntimeException(e); + } + + return tableData; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/UtilRmi.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/UtilRmi.java new file mode 100644 index 0000000..a3f10a0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/UtilRmi.java @@ -0,0 +1,137 @@ +package org.sandag.abm.ctramp; + +import gnu.cajo.invoke.Remote; +import java.io.IOException; +import java.lang.reflect.InvocationTargetException; +import java.net.MalformedURLException; +import java.rmi.ConnectIOException; +import java.rmi.NotBoundException; +import java.rmi.RemoteException; +import org.apache.log4j.Logger; + +/** + * User: Jim Date: Jul 3, 2008 Time: 2:27:02 PM + * + * Utility class for applying remote methods of various types + * + */ + +public class UtilRmi + implements java.io.Serializable +{ + + private transient Logger logger = Logger.getLogger(UtilRmi.class); + private String connectString; + + private static int MAX_RETRY_COUNT = 100; + private static int MAX_RETRY_TIME = 1000; // milliseconds + + public UtilRmi(String connectString) + { + this.connectString = connectString; + } + + public Object method(String name, Object[] args) + { + + int connectExceptionCount = 0; + + Object itemObject = null; + Object returnObject = null; + + while (connectExceptionCount < MAX_RETRY_COUNT) + { + + try + { + itemObject = Remote.getItem(connectString); + break; + } catch (ConnectIOException e) + { + + try + { + Thread.currentThread().wait(MAX_RETRY_TIME); + } catch (InterruptedException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + connectExceptionCount++; + + } catch (RemoteException e) + { + logger.error("RemoteException exception making RMI method call: " + connectString + + "." + name + "().", e); + throw new RuntimeException(); + } catch (MalformedURLException e) + { + logger.error("MalformedURLException exception making RMI method call: " + + connectString + "." + name + "().", e); + throw new RuntimeException(); + } catch (NotBoundException e) + { + logger.error("NotBoundException exception making RMI method call: " + connectString + + "." + name + "().", e); + throw new RuntimeException(); + } catch (IOException e) + { + logger.error("IOException exception making RMI method call: " + connectString + "." + + name + "().", e); + throw new RuntimeException(); + } catch (ClassNotFoundException e) + { + logger.error("ClassNotFoundException exception making RMI method call: " + + connectString + "." + name + "().", e); + throw new RuntimeException(); + } catch (InstantiationException e) + { + logger.error("InstantiationException exception making RMI method call: " + + connectString + "." + name + "().", e); + throw new RuntimeException(); + } catch (IllegalAccessException e) + { + logger.error("IllegalAccessException exception making RMI method call: " + + connectString + "." + name + "().", e); + throw new RuntimeException(); + } catch (UnsatisfiedLinkError e) + { + logger.error("UnsatisfiedLinkError exception making RMI method call: " + + connectString + "." + name + "().", e); + throw new RuntimeException(); + } + + } + + if (connectExceptionCount > 0) + { + logger.warn("UtilRmi.method() timed out " + connectExceptionCount + + "times connecting to: " + connectString + "." + name + "()."); + } + if (connectExceptionCount == MAX_RETRY_COUNT) + { + logger.error("UtilRmi.method() connection was never made."); + throw new RuntimeException(); + } + + try + { + returnObject = Remote.invoke(itemObject, name, args); + } catch (InvocationTargetException e) + { + logger.error("InvocationTargetException exception making RMI method call: " + + connectString + "." + name + "().", e); + throw new RuntimeException(); + } catch (Exception e) + { + logger.error("Exception exception making RMI method call: " + connectString + "." + + name + "().", e); + throw new RuntimeException(); + } + + return returnObject; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/WorkLocationChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/WorkLocationChoiceModel.java new file mode 100644 index 0000000..18af3b5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/WorkLocationChoiceModel.java @@ -0,0 +1,692 @@ +package org.sandag.abm.ctramp; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import java.util.Random; +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.modechoice.MgraDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class WorkLocationChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(MandatoryDestChoiceModel.class); + private transient Logger dcManLogger = Logger.getLogger("tourDcMan"); + + // this constant used as a dimension for saving distance and logsums for + // alternatives in samples + private static final int MAXIMUM_SOA_ALTS_FOR_ANY_MODEL = 200; + + private static final int DC_DATA_SHEET = 0; + private static final int DC_WORK_AT_HOME_SHEET = 1; + + // private TazDataManager tazs; + private MgraDataManager mgraManager; + private DestChoiceSize dcSizeObj; + + private DestChoiceTwoStageModelDMU dcTwoStageDmuObject; + + private DestChoiceTwoStageModel dcTwoStageModelObject; + private TourModeChoiceModel mcModel; + + private String[] segmentNameList; + private HashMap workOccupValueSegmentIndexMap; + + private int[] dcModelIndices; + + // A ChoiceModelApplication object and modeAltsAvailable[] is needed for + // each purpose + private ChoiceModelApplication[] locationChoiceModels; + private ChoiceModelApplication locationChoiceModel; + private ChoiceModelApplication worksAtHomeModel; + + private boolean[] dcModelAltsAvailable; + private int[] dcModelAltsSample; + private int[] dcModelSampleValues; + + private int[] uecSheetIndices; + + int origMgra; + + private int modelIndex; + + private double[] sampleAlternativeDistances; + private double[] sampleAlternativeLogsums; + + private BuildAccessibilities aggAcc; + + private double[] mgraDistanceArray; + + private int soaSampleSize; + + private long soaRunTime; + + public WorkLocationChoiceModel(int index, HashMap propertyMap, + DestChoiceSize dcSizeObj, BuildAccessibilities aggAcc, String dcUecFileName, + String soaUecFile, int soaSampleSize, String modeChoiceUecFile, + CtrampDmuFactoryIf dmuFactory, TourModeChoiceModel mcModel, double[][][] workSizeProbs, + double[][][] workTazDistProbs) + { + + this.aggAcc = aggAcc; + this.dcSizeObj = dcSizeObj; + this.mcModel = mcModel; + this.soaSampleSize = soaSampleSize; + + modelIndex = index; + + mgraManager = MgraDataManager.getInstance(); + + dcTwoStageDmuObject = dmuFactory.getDestChoiceSoaTwoStageDMU(); + dcTwoStageDmuObject.setAggAcc(this.aggAcc); + + dcTwoStageModelObject = new DestChoiceTwoStageModel(propertyMap, soaSampleSize); + dcTwoStageModelObject.setTazDistProbs(workTazDistProbs); + dcTwoStageModelObject.setMgraSizeProbs(workSizeProbs); + + sampleAlternativeDistances = new double[MAXIMUM_SOA_ALTS_FOR_ANY_MODEL]; + sampleAlternativeLogsums = new double[MAXIMUM_SOA_ALTS_FOR_ANY_MODEL]; + + workOccupValueSegmentIndexMap = aggAcc.getWorkOccupValueIndexMap(); + + } + + public void setupWorkSegments(int[] myUecSheetIndices, int[] mySoaUecSheetIndices) + { + uecSheetIndices = myUecSheetIndices; + segmentNameList = aggAcc.getWorkSegmentNameList(); + } + + public void setupDestChoiceModelArrays(HashMap propertyMap, + String dcUecFileName, String soaUecFile, int soaSampleSize) + { + + // create the works-at-home ChoiceModelApplication object + worksAtHomeModel = new ChoiceModelApplication(dcUecFileName, DC_WORK_AT_HOME_SHEET, + DC_DATA_SHEET, propertyMap, (VariableTable) dcTwoStageDmuObject); + + // create a lookup array to map purpose index to model index + dcModelIndices = new int[uecSheetIndices.length]; + + // get a set of unique model sheet numbers so that we can create + // ChoiceModelApplication objects once for each model sheet used + // also create a HashMap to relate size segment index to SOA Model + // objects + HashMap modelIndexMap = new HashMap(); + int dcModelIndex = 0; + int dcSegmentIndex = 0; + for (int uecIndex : uecSheetIndices) + { + // if the uec sheet for the model segment is not in the map, add it, + // otherwise, get it from the map + if (!modelIndexMap.containsKey(uecIndex)) + { + modelIndexMap.put(uecIndex, dcModelIndex); + dcModelIndices[dcSegmentIndex] = dcModelIndex++; + } else + { + dcModelIndices[dcSegmentIndex] = modelIndexMap.get(uecIndex); + } + + dcSegmentIndex++; + } + // the value of dcModelIndex is the number of ChoiceModelApplication + // objects to create + // the modelIndexMap keys are the uec sheets to use in building + // ChoiceModelApplication objects + + locationChoiceModels = new ChoiceModelApplication[modelIndexMap.size()]; + + int i = 0; + for (int uecIndex : modelIndexMap.keySet()) + { + + int modelIndex = -1; + try + { + modelIndex = modelIndexMap.get(uecIndex); + locationChoiceModels[modelIndex] = new ChoiceModelApplication(dcUecFileName, + uecIndex, DC_DATA_SHEET, propertyMap, (VariableTable) dcTwoStageDmuObject); + } catch (RuntimeException e) + { + logger.error(String + .format("exception caught setting up DC ChoiceModelApplication[%d] for modelIndex=%d of %d models", + i, modelIndex, modelIndexMap.size())); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + } + + dcModelAltsAvailable = new boolean[soaSampleSize + 1]; + dcModelAltsSample = new int[soaSampleSize + 1]; + dcModelSampleValues = new int[soaSampleSize]; + + mgraDistanceArray = new double[mgraManager.getMaxMgra() + 1]; + + } + + public boolean applyWorkLocationChoice(Household hh) + { + boolean result=true; + + if (hh.getDebugChoiceModels()) + { + String label = String.format("Pre Work Location Choice HHId=%d Object", hh.getHhId()); + hh.logHouseholdObject(label, dcManLogger); + } + + // declare these variables here so their values can be logged if a + // RuntimeException occurs. + int i = -1; + int occupSegmentIndex = -1; + int occup = -1; + String occupSegmentName = ""; + + int homeMgra = hh.getHhMgra(); + Person[] persons = hh.getPersons(); + + int tourNum = 0; + for (i = 1; i < persons.length; i++) + { + + Person p = persons[i]; + + // skip person if they are not a worker + if (p.getPersonIsWorker() != 1) + { + p.setWorkLocationSegmentIndex(-1); + p.setWorkLocation(0); + p.setWorkLocDistance(0); + p.setWorkLocLogsum(-999); + continue; + } + + // skip person if their work at home choice was work in the home + // (alternative 2 in choice model) + int worksAtHomeChoice = selectWorksAtHomeChoice(dcTwoStageDmuObject, hh, p); + if (worksAtHomeChoice == ModelStructure.WORKS_AT_HOME_ALTERNATUVE_INDEX) + { + p.setWorkLocationSegmentIndex(ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR); + p.setWorkLocation(ModelStructure.WORKS_AT_HOME_LOCATION_INDICATOR); + p.setWorkLocDistance(0); + p.setWorkLocLogsum(-999); + continue; + } + + // save person information in decision maker label, and log person + // object + if (hh.getDebugChoiceModels()) + { + String decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", p + .getHouseholdObject().getHhId(), p.getPersonNum(), p.getPersonType()); + hh.logPersonObject(decisionMakerLabel, dcManLogger, p); + } + + double[] results = null; + int modelIndex = 0; + try + { + + origMgra = homeMgra; + + occup = p.getPersPecasOccup(); + occupSegmentIndex = workOccupValueSegmentIndexMap.get(occup); + occupSegmentName = segmentNameList[occupSegmentIndex]; + + p.setWorkLocationSegmentIndex(occupSegmentIndex); + + // update the DC dmuObject for this person + dcTwoStageDmuObject.setHouseholdObject(hh); + dcTwoStageDmuObject.setPersonObject(p); + dcTwoStageDmuObject.setDmuIndexValues(hh.getHhId(), homeMgra, origMgra, 0); + + double[] homeMgraSizeArray = dcSizeObj.getDcSizeArray()[occupSegmentIndex]; + mcModel.getAnmSkimCalculator().getAmPkSkimDistancesFromMgra(homeMgra, + mgraDistanceArray); + + // set size array for the tour segment and distance array from + // the home mgra to all destinaion mgras. + dcTwoStageDmuObject.setMgraSizeArray(homeMgraSizeArray); + dcTwoStageDmuObject.setMgraDistanceArray(mgraDistanceArray); + + modelIndex = dcModelIndices[occupSegmentIndex]; + locationChoiceModel = locationChoiceModels[modelIndex]; + + // get the work location alternative chosen from the sample + results = selectLocationFromSampleOfAlternatives("work", -1, p, occupSegmentName, + occupSegmentIndex, tourNum++, homeMgraSizeArray, mgraDistanceArray); + + soaRunTime += dcTwoStageModelObject.getSoaRunTime(); + + } catch (RuntimeException e) + { + logger.fatal(String + .format("Exception caught in dcModel selecting location for i=%d, hh.hhid=%d, person i=%d, in work location choice, modelIndex=%d, occup=%d, segmentIndex=%d, segmentName=%s", + i, hh.getHhId(), i, modelIndex, occup, occupSegmentIndex, + occupSegmentName)); + logger.fatal("Exception caught:", e); + logger.fatal("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(); + } + + p.setWorkLocation((int) results[0]); + p.setWorkLocDistance((float) results[1]); + p.setWorkLocLogsum((float) results[2]); + + if(p.getWorkLocationSegmentIndex()>-1 && p.getWorkLocation()==0){ + logger.error("***********************************************************************************************************************************"); + logger.error("!!!!!!!Worker in worksegmetn "+p.getWorkLocationSegmentIndex()+" can't find a work location!!!!! RESTART Work location choice!!!!"); + result=false; + } + + } + return result; + + } + /** + * + * @return an array with chosen mgra, distance to chosen mgra, and logsum to + * chosen mgra. + */ + private double[] selectLocationFromSampleOfAlternatives(String segmentType, + int segmentTypeIndex, Person person, String segmentName, int sizeSegmentIndex, + int tourNum, double[] homeMgraSizeArray, double[] homeMgraDistanceArray) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcManLogger; + + Household household = person.getHouseholdObject(); + + // get sample of locations and correction factors for sample using the + // alternate method + // for work location, the sizeSegmentType INdex and sizeSegmentIndex are + // the same values. + dcTwoStageModelObject.chooseSample(household.getHhTaz(), sizeSegmentIndex, + sizeSegmentIndex, soaSampleSize, household.getHhRandom(), + household.getDebugChoiceModels()); + int[] finalSample = dcTwoStageModelObject.getUniqueSampleMgras(); + double[] sampleCorrectionFactors = dcTwoStageModelObject + .getUniqueSampleMgraCorrectionFactors(); + int numUniqueAlts = dcTwoStageModelObject.getNumberofUniqueMgrasInSample(); + + Arrays.fill(dcModelAltsAvailable, false); + Arrays.fill(dcModelAltsSample, 0); + Arrays.fill(dcModelSampleValues, 999999); + + // set sample of alternatives correction factors used in destination + // choice utility for the sampled alternatives. + dcTwoStageDmuObject.setDcSoaCorrections(sampleCorrectionFactors); + + // for the destination mgras in the sample, compute mc logsums and save + // in dmuObject. + // also save correction factor and set availability and sample value for + // the + // sample alternative to true. 1, respectively. + for (int i = 0; i < numUniqueAlts; i++) + { + + int destMgra = finalSample[i]; + dcModelSampleValues[i] = finalSample[i]; + + // set logsum value in DC dmuObject for the logsum index, sampled + // zone and subzone. + double logsum = getModeChoiceLogsum(household, person, destMgra, segmentTypeIndex); + dcTwoStageDmuObject.setMcLogsum(i, logsum); + + sampleAlternativeLogsums[i] = logsum; + sampleAlternativeDistances[i] = homeMgraDistanceArray[finalSample[i]]; + + // set availaibility and sample values for the purpose, dcAlt. + dcModelAltsAvailable[i + 1] = true; + dcModelAltsSample[i + 1] = 1; + + } + + dcTwoStageDmuObject.setSampleArray(dcModelSampleValues); + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format( + "Usual %s Location Choice Model for: Segment=%s", segmentType, segmentName); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s, TourNum=%d", + person.getHouseholdObject().getHhId(), person.getPersonNum(), + person.getPersonType(), tourNum); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Usual " + segmentType + " Location Choice Model for: Segment=" + + segmentName + ", Person Num: " + person.getPersonNum() + ", Person Type: " + + person.getPersonType() + ", TourNum=" + tourNum); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + locationChoiceModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + locationChoiceModel.computeUtilities(dcTwoStageDmuObject, + dcTwoStageDmuObject.getDmuIndexValues(), dcModelAltsAvailable, dcModelAltsSample); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (locationChoiceModel.getAvailabilityCount() > 0) + { + try + { + chosen = locationChoiceModel.getChoiceResult(rn); + } catch (Exception e) + { + } + } else + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, no available %s destination choice alternatives to choose from in choiceModelApplication.", + dcTwoStageDmuObject.getHouseholdObject().getHhId(), dcTwoStageDmuObject + .getPersonObject().getPersonNum(), segmentName)); + } + + if (household.getDebugChoiceModels() || chosen <= 0) + { + + double[] utilities = locationChoiceModel.getUtilities(); + double[] probabilities = locationChoiceModel.getProbabilities(); + boolean[] availabilities = locationChoiceModel.getAvailabilities(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- -------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 0; j < finalSample.length; j++) + { + int alt = finalSample[j]; + cumProb += probabilities[j]; + String altString = String.format("j=%d, mgra=%d", j, alt); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j + 1], utilities[j], probabilities[j], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("j=%d, mgra=%d", chosen - 1, finalSample[chosen - 1]); + modelLogger.info(String.format("Choice: %s with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + locationChoiceModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + locationChoiceModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, + chosen); + + // write UEC calculation results to separate model specific log file + locationChoiceModel.logUECResults(modelLogger, loggingHeader); + + if (chosen < 0) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, workSegment=%d, no available %s destination choice alternatives to choose from in ChoiceModelApplication.", + dcTwoStageDmuObject.getHouseholdObject().getHhId(), + dcTwoStageDmuObject.getPersonObject().getPersonNum(), segmentName)); + throw new RuntimeException(); + } + + } + + double[] returnArray = new double[3]; + + returnArray[0] = finalSample[chosen - 1]; + returnArray[1] = sampleAlternativeDistances[chosen - 1]; + returnArray[2] = sampleAlternativeLogsums[chosen - 1]; + + return returnArray; + + } + + private int selectWorksAtHomeChoice(DestChoiceTwoStageModelDMU dcTwoStageDmuObject, + Household household, Person person) + { + + // set tour origin taz/subzone and start/end times for calculating mode + // choice logsum + Logger modelLogger = dcManLogger; + + dcTwoStageDmuObject.setHouseholdObject(household); + dcTwoStageDmuObject.setPersonObject(person); + dcTwoStageDmuObject.setDmuIndexValues(household.getHhId(), household.getHhMgra(), origMgra, + 0); + + double accessibility = aggAcc.getAccessibilitiesTableObject().getAggregateAccessibility( + "totEmp", household.getHhMgra()); + dcTwoStageDmuObject.setWorkAccessibility(accessibility); + + // log headers to traceLogger if the person making the destination + // choice is + // from a household requesting trace information + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + if (household.getDebugChoiceModels()) + { + + // null tour means the DC is a mandatory usual location choice + choiceModelDescription = String.format("Usual Work Location Is At Home Choice Model"); + decisionMakerLabel = String.format("HH=%d, PersonNum=%d, PersonType=%s", person + .getHouseholdObject().getHhId(), person.getPersonNum(), person.getPersonType()); + + modelLogger.info(" "); + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info("Usual Work Location Is At Home Choice Model: Person Num: " + + person.getPersonNum() + ", Person Type: " + person.getPersonType()); + + loggingHeader = String.format("%s for %s", choiceModelDescription, decisionMakerLabel); + + worksAtHomeModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, + decisionMakerLabel); + + } + + // compute destination choice proportions and choose alternative + float logsum = (float) worksAtHomeModel.computeUtilities(dcTwoStageDmuObject, + dcTwoStageDmuObject.getDmuIndexValues()); + person.setWorksFromHomeLogsum(logsum); + + Random hhRandom = household.getHhRandom(); + int randomCount = household.getHhRandomCount(); + double rn = hhRandom.nextDouble(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen = -1; + if (worksAtHomeModel.getAvailabilityCount() > 0) + { + chosen = worksAtHomeModel.getChoiceResult(rn); + } + + // write choice model alternative info to log file + if (household.getDebugChoiceModels() || chosen < 0) + { + + double[] utilities = worksAtHomeModel.getUtilities(); + double[] probabilities = worksAtHomeModel.getProbabilities(); + boolean[] availabilities = worksAtHomeModel.getAvailabilities(); + + String[] altNames = worksAtHomeModel.getAlternativeNames(); + + String personTypeString = person.getPersonType(); + int personNum = person.getPersonNum(); + + modelLogger.info("Person num: " + personNum + ", Person type: " + personTypeString); + modelLogger + .info("Alternative Availability Utility Probability CumProb"); + modelLogger + .info("--------------------- -------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int j = 0; j < utilities.length; j++) + { + cumProb += probabilities[j]; + String altString = String.format("%d, %s", j + 1, altNames[j]); + modelLogger.info(String.format("%-21s%15s%18.6e%18.6e%18.6e", altString, + availabilities[j + 1], utilities[j], probabilities[j], cumProb)); + } + + modelLogger.info(" "); + String altString = String.format("j=%d, alt=%s", chosen, + (chosen < 0 ? "N/A, no available alternatives" : altNames[chosen - 1])); + modelLogger.info(String.format("Choice: %s, with rn=%.8f, randomCount=%d", altString, + rn, randomCount)); + + modelLogger + .info("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++"); + modelLogger.info(" "); + + worksAtHomeModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + worksAtHomeModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, + chosen); + + // write UEC calculation results to separate model specific log file + worksAtHomeModel.logUECResults(modelLogger, loggingHeader); + + } + + if (chosen < 0) + { + logger.error(String + .format("Exception caught for HHID=%d, PersonNum=%d, no available works at home alternatives to choose from in choiceModelApplication.", + dcTwoStageDmuObject.getHouseholdObject().getHhId(), dcTwoStageDmuObject + .getPersonObject().getPersonNum())); + throw new RuntimeException(); + } + + return chosen; + + } + + private double getModeChoiceLogsum(Household household, Person person, int sampleDestMgra, + int segmentTypeIndex) + { + + int purposeIndex = 0; + String purpose = ""; + if (segmentTypeIndex < 0) + { + purposeIndex = ModelStructure.WORK_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.WORK_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.PRESCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.GRADE_SCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.HIGH_SCHOOL_ALT_INDEX) + { + purposeIndex = ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.UNIV_TYPICAL_ALT_INDEX) + { + purposeIndex = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME; + } else if (segmentTypeIndex == BuildAccessibilities.UNIV_NONTYPICAL_ALT_INDEX) + { + purposeIndex = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX; + purpose = ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME; + } + + // create a temporary tour to use to calculate mode choice logsum + Tour mcLogsumTour = new Tour(person, 0, purposeIndex); + mcLogsumTour.setTourPurpose(purpose); + mcLogsumTour.setTourOrigMgra(household.getHhMgra()); + mcLogsumTour.setTourDestMgra(sampleDestMgra); + mcLogsumTour.setTourDepartPeriod(Person.DEFAULT_MANDATORY_START_PERIOD); + mcLogsumTour.setTourArrivePeriod(Person.DEFAULT_MANDATORY_END_PERIOD); + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + + if (household.getDebugChoiceModels()) + { + dcManLogger.info(""); + dcManLogger.info(""); + choiceModelDescription = "location choice logsum for segmentTypeIndex=" + + segmentTypeIndex + ", temp tour PurposeIndex=" + purposeIndex; + decisionMakerLabel = "HHID: " + household.getHhId() + ", PersNum: " + + person.getPersonNum(); + household.logPersonObject(choiceModelDescription + ", " + decisionMakerLabel, + dcManLogger, person); + } + + double logsum = -1; + try + { + logsum = mcModel.getModeChoiceLogsum(household, person, mcLogsumTour, dcManLogger, + choiceModelDescription, decisionMakerLabel); + } catch (Exception e) + { + choiceModelDescription = "location choice logsum for segmentTypeIndex=" + + segmentTypeIndex + ", temp tour PurposeIndex=" + purposeIndex; + decisionMakerLabel = "HHID: " + household.getHhId() + ", PersNum: " + + person.getPersonNum(); + logger.fatal("exception caught calculating ModeChoiceLogsum for usual work/school location choice."); + logger.fatal("choiceModelDescription = " + choiceModelDescription); + logger.fatal("decisionMakerLabel = " + decisionMakerLabel); + e.printStackTrace(); + System.exit(-1); + } + + return logsum; + } + + public int getModelIndex() + { + return modelIndex; + } + + public void setDcSizeObject(DestChoiceSize dcSizeObj) + { + this.dcSizeObj = dcSizeObj; + } + + public long getSoaRunTime() + { + return soaRunTime; + } + + public void resetSoaRunTime() + { + soaRunTime = 0; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/ctramp/WorkLocationChoiceTaskJppf.java b/sandag_abm/src/main/java/org/sandag/abm/ctramp/WorkLocationChoiceTaskJppf.java new file mode 100644 index 0000000..99ccb09 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/ctramp/WorkLocationChoiceTaskJppf.java @@ -0,0 +1,246 @@ +package org.sandag.abm.ctramp; + +import java.net.UnknownHostException; +import java.util.Date; +import java.util.HashMap; +import org.jppf.node.protocol.AbstractTask; +import org.jppf.node.protocol.DataProvider; +import com.pb.common.calculator.MatrixDataServerIf; + +import nl.tudelft.simulation.logger.Logger; + +public class WorkLocationChoiceTaskJppf + extends AbstractTask +{ + + private static String VERSION = "Task.1.0.3"; + + private transient HashMap propertyMap; + private transient MatrixDataServerIf ms; + private transient ModelStructure modelStructure; + private transient HouseholdDataManagerIf hhDataManager; + private transient String tourCategory; + private transient DestChoiceSize dcSizeObj; + private transient int[] uecIndices; + private transient int[] soaUecIndices; + private transient String dcUecFileName; + private transient String soaUecFileName; + private transient int soaSampleSize; + private transient CtrampDmuFactoryIf dmuFactory; + private transient String restartModelString; + + private int iteration; + private int startIndex; + private int endIndex; + private int taskIndex = -1; + + public WorkLocationChoiceTaskJppf(int taskIndex, int startIndex, int endIndex, int iteration) + { + this.startIndex = startIndex; + this.endIndex = endIndex; + this.taskIndex = taskIndex; + this.iteration = iteration; + } + + public void run() + { + + String start = (new Date()).toString(); + long startTime = System.currentTimeMillis(); + + String threadName = null; + try + { + threadName = "[" + java.net.InetAddress.getLocalHost().getHostName() + "] " + + Thread.currentThread().getName(); + } catch (UnknownHostException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + try + { + DataProvider dataProvider = getDataProvider(); + + this.propertyMap = (HashMap) dataProvider.getParameter("propertyMap"); + this.ms = (MatrixDataServerIf) dataProvider.getParameter("ms"); + this.hhDataManager = (HouseholdDataManagerIf) dataProvider.getParameter("hhDataManager"); + this.modelStructure = (ModelStructure) dataProvider.getParameter("modelStructure"); + this.uecIndices = (int[]) dataProvider.getParameter("uecIndices"); + this.soaUecIndices = (int[]) dataProvider.getParameter("soaUecIndices"); + this.tourCategory = (String) dataProvider.getParameter("tourCategory"); + this.dcSizeObj = (DestChoiceSize) dataProvider.getParameter("dcSizeObj"); + this.dcUecFileName = (String) dataProvider.getParameter("dcUecFileName"); + this.soaUecFileName = (String) dataProvider.getParameter("soaUecFileName"); + this.soaSampleSize = (Integer) dataProvider.getParameter("soaSampleSize"); + this.dmuFactory = (CtrampDmuFactoryIf) dataProvider.getParameter("dmuFactory"); + this.restartModelString = (String) dataProvider.getParameter("restartModelString"); + + } catch (Exception e) + { + e.printStackTrace(); + throw new RuntimeException(e); + } + + // get the factory object used to create and recycle dcModel objects. + DestChoiceModelManager modelManager = DestChoiceModelManager.getInstance(); + + // one of tasks needs to initialize the manager object by passing + // attributes + // needed to create a destination choice model object. + modelManager.managerSetup(propertyMap, modelStructure, ms, dcUecFileName, soaUecFileName, + soaSampleSize, dmuFactory, restartModelString); + + // get a dcModel object from manager, which either creates one or + // returns one + // for re-use. + MandatoryDestChoiceModel dcModel = modelManager.getDcWorkModelObject(taskIndex, iteration, + dcSizeObj, uecIndices, soaUecIndices); + + // logger.info( String.format( + // "%s, task=%d run(), thread=%s, start=%d, end=%d.", VERSION, + // taskIndex, + // threadName, startIndex, endIndex ) ); + System.out.println(String.format("%s: %s, task=%d run(), thread=%s, start=%d, end=%d.", + new Date(), VERSION, taskIndex, threadName, startIndex, endIndex)); + + long setup1 = (System.currentTimeMillis() - startTime) / 1000; + + Household[] householdArray = hhDataManager.getHhArray(startIndex, endIndex); + + long setup2 = (System.currentTimeMillis() - startTime) / 1000; + // logger.info( String.format( + // "task=%d processing households[%d:%d], thread=%s, setup1=%d, setup2=%d.", + // taskIndex, startIndex, endIndex, + // threadName, setup1, setup2 ) ); + System.out.println(String.format("%s: task=%d processing households[%d:%d], thread=%s.", + new Date(), taskIndex, startIndex, endIndex, threadName)); + + int i = -1; + try + { + + boolean runDebugHouseholdsOnly = Util.getBooleanValueFromPropertyMap(propertyMap, + HouseholdDataManager.DEBUG_HHS_ONLY_KEY); + + for (i = 0; i < householdArray.length; i++) + { + // for debugging only - process only household objects specified + // for debugging, if property key was set to true + if (runDebugHouseholdsOnly && !householdArray[i].getDebugChoiceModels()) continue; + + dcModel.applyWorkLocationChoice(householdArray[i]); + } + + boolean worked=false; + int tries=0; + do{ + ++tries; + try{ + hhDataManager.setHhArray(householdArray, startIndex); + worked=true; + }catch(Exception e) { + System.out.println("Error trying to set households in hh manager for start index "+startIndex+" (tried "+tries+" times"); + if(tries<1000) + System.out.println("Trying again!"); + } + }while(!worked && (tries<1000)); + + //check to make sure hh array got set in hhDataManager + boolean allHouseholdsAreSame = false; + while(!allHouseholdsAreSame) { + Household[] householdArrayRemote = hhDataManager.getHhArray(startIndex, endIndex); + for(int j = 0; j< householdArrayRemote.length;++j) { + + Household remoteHousehold = householdArrayRemote[j]; + Household localHousehold = householdArray[j]; + + allHouseholdsAreSame = checkIfSameWorkLocationResults(remoteHousehold, localHousehold); + + if(!allHouseholdsAreSame) + break; + } + if(!allHouseholdsAreSame) { + System.out.println("Warning: found households in household manager (starting array index "+startIndex+") not updated with work location choice results; updating"); + hhDataManager.setHhArray(householdArray, startIndex); + + } + } + + + } catch (Exception e) + { + if (i >= 0 && i < householdArray.length) System.out + .println(String + .format("exception caught in taskIndex=%d applying dc model for i=%d, hhId=%d, startIndex=%d.", + taskIndex, i, householdArray[i].getHhId(), startIndex)); + else System.out.println(String.format( + "exception caught in taskIndex=%d applying dc model for i=%d, startIndex=%d.", + taskIndex, i, startIndex)); + System.out.println("Exception caught:"); + e.printStackTrace(); + System.out.println("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(e); + } + + long getHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup1; + long processHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup2 - getHhs; + // logger.info( String.format( + // "task=%d finished, thread=%s, getHhs=%d, processHhs=%d.", taskIndex, + // threadName, getHhs, processHhs ) ); + System.out.println(String.format("%s: task=%d finished, thread=%s.", new Date(), taskIndex, + threadName)); + + long total = (System.currentTimeMillis() - startTime) / 1000; + String resultString = String + .format("result for thread=%s, task=%d, startIndex=%d, endIndex=%d, startTime=%s, endTime=%s, setup1=%d, setup2=%d, getHhs=%d, run=%d, total=%d.", + threadName, taskIndex, startIndex, endIndex, start, new Date(), setup1, + setup2, getHhs, processHhs, total); + // logger.info( resultString ); + setResult(resultString); + + modelManager.returnDcWorkModelObject(dcModel, taskIndex, startIndex, endIndex); + + } + + /** + * Returns true if work location results are the same, else returns false. + * + * @param thisHousehold + * @param thatHousehold + * @return true or false + */ + public boolean checkIfSameWorkLocationResults(Household thisHousehold, Household thatHousehold) { + + Person[] thisPersons = thisHousehold.getPersons(); + Person[] thatPersons = thatHousehold.getPersons(); + + if(thisPersons.length!=thatPersons.length) + return false; + + for(int k=1;k +{ + + private static String VERSION = "Task.1.0.3"; + + private transient HashMap propertyMap; + private transient MatrixDataServerIf ms; + private transient ModelStructure modelStructure; + private transient HouseholdDataManagerIf hhDataManager; + private transient String tourCategory; + private transient DestChoiceSize dcSizeObj; + private transient int[] uecIndices; + private transient int[] soaUecIndices; + private transient String dcUecFileName; + private transient String soaUecFileName; + private transient int soaSampleSize; + private transient CtrampDmuFactoryIf dmuFactory; + private transient String restartModelString; + + private int iteration; + private int startIndex; + private int endIndex; + private int taskIndex = -1; + + public WorkLocationChoiceTaskJppfNew(int taskIndex, int startIndex, int endIndex, int iteration) + { + this.startIndex = startIndex; + this.endIndex = endIndex; + this.taskIndex = taskIndex; + this.iteration = iteration; + } + + public void run() + { + + String start = (new Date()).toString(); + long startTime = System.currentTimeMillis(); + + String threadName = null; + try + { + threadName = "[" + java.net.InetAddress.getLocalHost().getHostName() + "] " + + Thread.currentThread().getName(); + } catch (UnknownHostException e1) + { + // TODO Auto-generated catch block + e1.printStackTrace(); + } + + try + { + DataProvider dataProvider = getDataProvider(); + + this.propertyMap = (HashMap) dataProvider.getParameter("propertyMap"); + this.ms = (MatrixDataServerIf) dataProvider.getParameter("ms"); + this.hhDataManager = (HouseholdDataManagerIf) dataProvider.getParameter("hhDataManager"); + this.modelStructure = (ModelStructure) dataProvider.getParameter("modelStructure"); + this.uecIndices = (int[]) dataProvider.getParameter("uecIndices"); + this.soaUecIndices = (int[]) dataProvider.getParameter("soaUecIndices"); + this.tourCategory = (String) dataProvider.getParameter("tourCategory"); + this.dcSizeObj = (DestChoiceSize) dataProvider.getParameter("dcSizeObj"); + this.dcUecFileName = (String) dataProvider.getParameter("dcUecFileName"); + this.soaUecFileName = (String) dataProvider.getParameter("soaUecFileName"); + this.soaSampleSize = (Integer) dataProvider.getParameter("soaSampleSize"); + this.dmuFactory = (CtrampDmuFactoryIf) dataProvider.getParameter("dmuFactory"); + this.restartModelString = (String) dataProvider.getParameter("restartModelString"); + + } catch (Exception e) + { + e.printStackTrace(); + } + + // get the factory object used to create and recycle dcModel objects. + DestChoiceModelManager modelManager = DestChoiceModelManager.getInstance(); + + // one of tasks needs to initialize the manager object by passing + // attributes + // needed to create a destination choice model object. + modelManager.managerSetup(propertyMap, modelStructure, ms, dcUecFileName, soaUecFileName, + soaSampleSize, dmuFactory, restartModelString); + + // get a dcModel object from manager, which either creates one or + // returns one for re-use. + WorkLocationChoiceModel dcModel = modelManager.getWorkLocModelObject(taskIndex, iteration, + dcSizeObj, uecIndices, soaUecIndices); + + // logger.info( String.format( + // "%s, task=%d run(), thread=%s, start=%d, end=%d.", VERSION, + // taskIndex, + // threadName, startIndex, endIndex ) ); + System.out.println(String.format("%s: %s, task=%d run(), thread=%s, start=%d, end=%d.", + new Date(), VERSION, taskIndex, threadName, startIndex, endIndex)); + + long setup1 = (System.currentTimeMillis() - startTime) / 1000; + + Household[] householdArray = hhDataManager.getHhArray(startIndex, endIndex); + + long setup2 = (System.currentTimeMillis() - startTime) / 1000; + // logger.info( String.format( + // "task=%d processing households[%d:%d], thread=%s, setup1=%d, setup2=%d.", + // taskIndex, startIndex, endIndex, + // threadName, setup1, setup2 ) ); + System.out.println(String.format("%s: task=%d processing households[%d:%d], thread=%s.", + new Date(), taskIndex, startIndex, endIndex, threadName)); + + int i = -1; + try + { + + boolean runDebugHouseholdsOnly = Util.getBooleanValueFromPropertyMap(propertyMap, + HouseholdDataManager.DEBUG_HHS_ONLY_KEY); + + for (i = 0; i < householdArray.length; i++) + { + // for debugging only - process only household objects specified + // for debugging, if property key was set to true + if (runDebugHouseholdsOnly && !householdArray[i].getDebugChoiceModels()) + // if ( householdArray[i].getHhTaz() % 200 != 0 ) + continue; + + if(!dcModel.applyWorkLocationChoice(householdArray[i])){ + i=0; + String restartMsg="A Worker in this HH batch didn't get valid work location. REPROCESSING HH batch, startIndex:"+startIndex+" endIndex="+endIndex; + setResult(restartMsg); + System.out.println(restartMsg); + } + } + + hhDataManager.setHhArray(householdArray, startIndex); + + //check to make sure hh array got set in hhDataManager + boolean allHouseholdsAreSame = false; + while(!allHouseholdsAreSame) { + Household[] householdArrayRemote = hhDataManager.getHhArray(startIndex, endIndex); + for(int j = 0; j< householdArrayRemote.length;++j) { + + Household remoteHousehold = householdArrayRemote[j]; + Household localHousehold = householdArray[j]; + + allHouseholdsAreSame = checkIfSameWorkLocationResults(remoteHousehold, localHousehold); + + if(!allHouseholdsAreSame) + break; + } + if(!allHouseholdsAreSame) { + System.out.println("Warning: found households in household manager (starting array index "+startIndex+") not updated with work location choice results; updating"); + hhDataManager.setHhArray(householdArray, startIndex); + } + } + + + } catch (Exception e) + { + if (i >= 0 && i < householdArray.length) System.out + .println(String + .format("exception caught in taskIndex=%d applying dc model for i=%d, hhId=%d, startIndex=%d.", + taskIndex, i, householdArray[i].getHhId(), startIndex)); + else System.out.println(String.format( + "exception caught in taskIndex=%d applying dc model for i=%d, startIndex=%d.", + taskIndex, i, startIndex)); + System.out.println("Exception caught:"); + e.printStackTrace(); + System.out.println("Throwing new RuntimeException() to terminate."); + throw new RuntimeException(e); + } + + long getHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup1; + long processHhs = ((System.currentTimeMillis() - startTime) / 1000) - setup2 - getHhs; + // logger.info( String.format( + // "task=%d finished, thread=%s, getHhs=%d, processHhs=%d.", taskIndex, + // threadName, getHhs, processHhs ) ); + System.out.println(String.format("%s: task=%d finished, thread=%s.", new Date(), taskIndex, + threadName)); + + long total = (System.currentTimeMillis() - startTime) / 1000; + String resultString = String + .format("result for thread=%s, task=%d, startIndex=%d, endIndex=%d, startTime=%s, endTime=%s, setup1=%d, setup2=%d, getHhs=%d, run=%d, total=%d.", + threadName, taskIndex, startIndex, endIndex, start, new Date(), setup1, + setup2, getHhs, processHhs, total); + // logger.info( resultString ); + setResult(resultString); + + modelManager.returnWorkLocModelObject(dcModel, taskIndex, startIndex, endIndex); + + clearClassAttributes(); + } + + /** + * Returns true if work location results are the same, else returns false. + * + * @param thisHousehold + * @param thatHousehold + * @return true or false + */ + public boolean checkIfSameWorkLocationResults(Household thisHousehold, Household thatHousehold) { + + Person[] thisPersons = thisHousehold.getPersons(); + Person[] thatPersons = thatHousehold.getPersons(); + + if(thisPersons.length!=thatPersons.length) + return false; + + for(int k=1;k rbMap; + public HashSet householdTraceSet; + public HashSet originTraceSet; + + public String outputsPath; + public String disaggTODPath; + public String todType; + public String outputFile; + + public String inputFile; + public String marketSegment; + public double SampleRate; + + public PrintWriter tripWriter; + + private static Logger logger = Logger.getLogger("postprocessModel"); + + + /** + * Default constructor. + */ + public PostprocessModel(HashMap rbMap, String timeType, double sampleRate, String inputFile, String marketSegment){ + + this.rbMap = rbMap; + this.SampleRate = sampleRate; + this.inputFile = inputFile; + this.marketSegment = marketSegment; + this.todType = timeType; + + } + + + public void runModel(){ + + disaggTODPath = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_DISAGGPATHTOD); + outputFile = disaggTODPath + Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_TRIPOUT); + outputsPath = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_OUTPUTSPATH); + outputFile = outputsPath + Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_TRIPOUT); + + setDebugHouseholdsFromPropertyMap(); + setDebugOrigZonesFromPropertyMap(); + + logger.info("Trip file being written to "+outputFile); + // Write the trip header to the output file + boolean fileExists = new File(outputFile).isFile(); + + FileWriter writer; + + if(fileExists){ + logger.info("Output file already exists. New data will be appended."); + try { + writer = new FileWriter(new File(outputFile), true); + tripWriter = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) { + logger.fatal(String.format("Exception occurred opening Postprocessing output file: %s.", + outputFile)); + throw new RuntimeException(e); + } + }else{ + logger.info("Output file does not exist. New file being created."); + try { + writer = new FileWriter(new File(outputFile)); + tripWriter = new PrintWriter(new BufferedWriter(writer)); + } catch (IOException e) { + logger.fatal(String.format("Exception occurred opening Postprocessing output file: %s.", + outputFile)); + throw new RuntimeException(e); + } + dtaTrip Trip = new dtaTrip(); + Trip.writeHeader(tripWriter); + } + + if(todType.equalsIgnoreCase("broad")){ + logger.info("Processing Broad TOD Model"); + TableDataSet broadFiles = TableDataSet.readFile(disaggTODPath+inputFile); + int numFiles = broadFiles.getRowCount(); + for (int i=0; i(); + + // get the household ids for which debug info is required + String householdTraceStringList = rbMap.get(PROPERTIES_HOUSEHOLD_TRACE_LIST); + + if (householdTraceStringList != null) + { + StringTokenizer householdTokenizer = new StringTokenizer(householdTraceStringList, ","); + while(householdTokenizer.hasMoreTokens()) + { + String listValue = householdTokenizer.nextToken(); + int idValue = Integer.parseInt(listValue.trim()); + householdTraceSet.add(idValue); + } + } + + } + + /** + * Set the HashSet for debugging households, which contains the IDs of the households to debug. + */ + private void setDebugOrigZonesFromPropertyMap() + { + originTraceSet = new HashSet(); + + // get the household ids for which debug info is required + String originTraceStringList = rbMap.get(PROPERTIES_ORIGIN_TRACE_LIST); + + if (originTraceStringList != null) + { + StringTokenizer originTokenizer = new StringTokenizer(originTraceStringList, ","); + while(originTokenizer.hasMoreTokens()) + { + String listValue = originTokenizer.nextToken(); + int idValue = Integer.parseInt(listValue.trim()); + originTraceSet.add(idValue); + } + } + + } + + /** + * Check if this is a trace household. + * + * @param householdId + * @return True if a trace household, else false + */ + public boolean isTraceHousehold(int householdId){ + + return householdTraceSet.contains(householdId); + + } + + /** + * Check if this is a trace origin. + * + * @param householdId + * @return True if a trace household, else false + */ + public boolean isTraceOrigin(int origTAZ){ + + return originTraceSet.contains(origTAZ); + + } + + /** + * @param args + */ + public static void main(String[] args) { + + String propertiesFile = null; + HashMap pMap; + String todType = null; + String inputFile = null; + String marketSegment = null; + double sampleRate = 1.0; + + if (args.length == 0) { + logger.error( String.format("no properties file base name (without .properties extension) was specified as an argument.") ); + return; + } else{ + propertiesFile = args[0]; + } + for (int i = 1; i< args.length;++i){ + if (args[i].equalsIgnoreCase("-todType")){ + todType = (String) args[i + 1]; + } + if (args[i].equalsIgnoreCase("-sampleRate")){ + sampleRate = new Double(args[i+1]); + } + if (args[i].equalsIgnoreCase("-inputFile")){ + inputFile = (String) args[i+1]; + } + if (args[i].equalsIgnoreCase("-marketSegment")){ + marketSegment = (String) args[i+1]; + } + } + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + + logger.info("Running SANDAG Trip TOD Disaggregation Model"); + + logger.info("todType = "+todType); + logger.info("Sample Rate = "+sampleRate); + logger.info("Input File = "+inputFile); + logger.info("Market Segment = "+marketSegment); + + PostprocessModel postprocessingModel = new PostprocessModel(pMap,todType,sampleRate,inputFile,marketSegment); + postprocessingModel.runModel(); + } + +} + + diff --git a/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/broadTODProcessing.java b/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/broadTODProcessing.java new file mode 100644 index 0000000..855582c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/broadTODProcessing.java @@ -0,0 +1,224 @@ +package org.sandag.abm.dta.postprocessing; + +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; + +import java.io.File; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.HashSet; + +import org.apache.log4j.Logger; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; + +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.dta.postprocessing.dtaTrip; +import org.sandag.abm.dta.postprocessing.todDisaggregationModel; +import org.sandag.abm.dta.postprocessing.PostprocessModel; +import org.sandag.abm.dta.postprocessing.spatialDisaggregationModel; + +public class broadTODProcessing { + + private static final String PROPERTIES_DISAGGPATHTOD = "dta.postprocessing.disaggregateTOD.path"; + private static final String PROPERTIES_DISAGGPATHZONE = "dta.postprocessing.disaggregateZone.path"; + private static final String PROPERTIES_DISAGGPATHNODE = "dta.postprocessing.disaggregateNode.path"; + private static final String PROPERTIES_BROADTODPROBABILITIES = "dta.postprocessing.BroadTODFile"; + private static final String PROPERTIES_ZONEPROBABILITIES = "dta.postprocessing.ZoneFile"; + private static final String PROPERTIES_NODEPROBABILITIES = "dta.postprocessing.NodeFile"; + private static final String PROPERTIES_RANDOMSEED = "dta.postprocessing.RandomSeed"; + + private HashMap rbMap; + private HashSet originTraceSet; + private MersenneTwister random; + private long randomSeed; + + private String disaggTODPath; + private String disaggZonePath; + private String disaggNodePath; + + private double sampleRate; + private String inputFile; + private String marketSegment; + + private int[] broadTODMap; + private int[] tazMap; + private int[] mgraTAZMap; + private int[] mgraNodeMap; + private int[] nodeMap; + private double[] broadProbabilities; + private double[] mgraProdProbabilities; + private double[] mgraAttrProbabilities; + private double[] nodeProbabilities; + + private todDisaggregationModel todDisaggregationModel; + private spatialDisaggregationModel spatialDisaggregationModel; + + private dtaTrip Trip; + private PrintWriter tripWriter; + + + private transient Logger logger = Logger.getLogger("postprocessModel"); + + + /** + * Default constructor. + */ + public broadTODProcessing(HashMap rbMap, double sampleRate, String inputFile, String marketSegment, HashSet originTraceSet, PrintWriter tripWriter){ + + this.rbMap = rbMap; + this.sampleRate = sampleRate; + this.inputFile = inputFile; + this.marketSegment = marketSegment; + this.tripWriter = tripWriter; + this.originTraceSet = originTraceSet; + + todDisaggregationModel = new todDisaggregationModel(rbMap); + spatialDisaggregationModel = new spatialDisaggregationModel(rbMap); + + randomSeed = Util.getIntegerValueFromPropertyMap(rbMap, PROPERTIES_RANDOMSEED); + random = new MersenneTwister(); + random.setSeed(randomSeed); + + //Read in factors and maps to aggregate time periods + String broadFactorsFile = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_BROADTODPROBABILITIES); + + TableDataSet BroadData = TableDataSet.readFile(broadFactorsFile); + int numPeriods = BroadData.getRowCount(); + broadProbabilities = todDisaggregationModel.getTODProbabilities(BroadData, numPeriods, marketSegment); + broadTODMap = todDisaggregationModel.getTODMap(BroadData, numPeriods); + + String mgraFactorsFile = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_ZONEPROBABILITIES); + TableDataSet MGRAData = TableDataSet.readFile(mgraFactorsFile); + int numMGRAs = MGRAData.getRowCount(); + mgraProdProbabilities = spatialDisaggregationModel.getSpatialProbabilities(MGRAData, numMGRAs, "Prods", marketSegment); + mgraAttrProbabilities = spatialDisaggregationModel.getSpatialProbabilities(MGRAData, numMGRAs, "Attrs", marketSegment); + tazMap = spatialDisaggregationModel.getSpatialMap(MGRAData, numMGRAs, "taz"); + mgraTAZMap = spatialDisaggregationModel.getSpatialMap(MGRAData, numMGRAs, "mgra"); + + String nodeFactorsFile = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_NODEPROBABILITIES); + TableDataSet NodeData = TableDataSet.readFile(nodeFactorsFile); + int numNodes = NodeData.getRowCount(); + nodeProbabilities = spatialDisaggregationModel.getSpatialProbabilities(NodeData, numNodes, "Probability", null); + nodeMap = spatialDisaggregationModel.getSpatialMap(NodeData, numNodes, "NodeId"); + mgraNodeMap = spatialDisaggregationModel.getSpatialMap(NodeData, numNodes, "MGRA"); + + } + + + /** + * Create trip record from and disaggregate tod, mgra, and node for broad tod files + */ + public void createBroadTODTrips(String inputFileName,String MarketSegment,String matrixName,int broadTOD,String vehType,int occ,int toll){ + + //Read TransCAD matrix and create a trip for each record in each cell + File inputFile = new File(inputFileName); + Matrix m = MatrixReader.readMatrix(inputFile,matrixName); + int intTrips = 0; + double expansionFactor=1.0; + int totalTrips = 0; + boolean debug=false; + + logger.info("*************************************"); + logger.info("Summary info for TransCAD Matrix"); + logger.info("Market Segment = "+MarketSegment); + logger.info("TNCVehicle Type = "+vehType); + logger.info("TNCVehicle Occupancy = "+occ); + logger.info("Toll Eligibility = "+toll); + logger.info("Number of Trips = "+m.getSum()); + logger.info("*************************************"); + + + for (int i=1; i<=m.getRowCount();++i){ + for (int j=1; j<=m.getColumnCount();++j){ + + double numTrips = m.getValueAt(i,j); + + if (numTrips==0.0) + continue; + + intTrips = (int) Math.floor(numTrips); + double fracTrips = numTrips - intTrips; + double rn = random.nextDouble(); + // Check if a trip should be created for the fractional trip value + if (rn rbMap; + private HashSet householdTraceSet; + private HashSet originTraceSet; + private MgraDataManager mgraManager; + //private final AutoAndNonMotorizedSkimsCalculator autoNonMotSkims; + private MersenneTwister random; + private long randomSeed; + + private todDisaggregationModel todDisaggregationModel; + private spatialDisaggregationModel spatialDisaggregationModel; + + private String disaggTODPath; + private String disaggNodePath; + private String outputsPath; + + private double sampleRate; + private String inputFile; + private String marketSegment; + + private int[] detailTODMap; + private int[] mgraNodeMap; + private int[] nodeMap; + private int[] tazMap; + private int[] mgraTAZMap; + + private double[] detailProbabilities; + private double[] nodeProbabilities; + private double[] mgraProdProbabilities; + private double[] mgraAttrProbabilities; + + private dtaTrip Trip; + private PrintWriter tripWriter; + + + private transient Logger logger = Logger.getLogger("postprocessModel"); + + + /** + * Default constructor. + */ + public detailedTODProcessing(HashMap rbMap, double sampleRate, String inputFile, String marketSegment, HashSet householdTraceSet, HashSet originTraceSet, PrintWriter tripWriter){ + + this.sampleRate = sampleRate; + this.rbMap = rbMap; + this.inputFile = inputFile; + this.marketSegment = marketSegment; + this.tripWriter = tripWriter; + this.householdTraceSet = householdTraceSet; + this.originTraceSet = originTraceSet; + + todDisaggregationModel = new todDisaggregationModel(rbMap); + + spatialDisaggregationModel = new spatialDisaggregationModel(rbMap); + + mgraManager = MgraDataManager.getInstance(rbMap); + //autoNonMotSkims = new AutoAndNonMotorizedSkimsCalculator(rbMap); + + outputsPath = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_OUTPUTSPATH); + + //Read in factors and maps to aggregate time periods + String detailedFactorsFile = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_DETAILPROBABILITIES); + + TableDataSet DetailedData = TableDataSet.readFile(detailedFactorsFile); + int numDetailedPeriods = DetailedData.getRowCount(); + detailProbabilities = todDisaggregationModel.getTODProbabilities(DetailedData, numDetailedPeriods, null); + detailTODMap = todDisaggregationModel.getTODMap(DetailedData, numDetailedPeriods); + + String nodeFactorsFile = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_NODEPROBABILITIES); + TableDataSet NodeData = TableDataSet.readFile(nodeFactorsFile); + int numNodes = NodeData.getRowCount(); + nodeProbabilities = spatialDisaggregationModel.getSpatialProbabilities(NodeData, numNodes, "Probability", null); + nodeMap = spatialDisaggregationModel.getSpatialMap(NodeData, numNodes, "NodeId"); + mgraNodeMap = spatialDisaggregationModel.getSpatialMap(NodeData, numNodes, "MGRA"); + + randomSeed = Util.getIntegerValueFromPropertyMap(rbMap, PROPERTIES_RANDOMSEED); + random = new MersenneTwister(); + random.setSeed(randomSeed); + + // read skims - AshishK + String skimPath = Util.getStringValueFromPropertyMap(rbMap, "skims.path"); + String skimPrefix = Util.getStringValueFromPropertyMap(rbMap, "dta.skims.prefix"); + String skimSuffix = Util.getStringValueFromPropertyMap(rbMap, "dta.skims.mat.name.suffix"); + skimMatrix = new Matrix[ModelStructure.MODEL_PERIOD_LABELS.length]; + + for(int p=0; p rbMap){ + SandagModelStructure modelStructure = new SandagModelStructure(); + TableDataSet tripRecords = TableDataSet.readFile(inputFile); + int numRecords = tripRecords.getRowCount(); + int period = -1; + int periodLast = -1; + int hhidLast = -1; + int persidLast = -1; + int touridLast = -1; + int modeLast = -1; + + double expansionFactor=1.0; + boolean debug = false; + boolean addSOVTrip = false; + int tripExp=0; + int offset = 0; + int scheduleCount = 0; + int tripsCount = 0; + int [] dtaTimes; + int [] dtaTimesPrev; + dtaTimes = new int[10]; + dtaTimesPrev = new int[10]; + + Arrays.fill(dtaTimesPrev, 0); + + if(inputFile.contains("TripMatrices.csv")) { + String mgraFactorsFile = Util.getStringValueFromPropertyMap(rbMap, PROPERTIES_ZONEPROBABILITIES); + TableDataSet MGRAData = TableDataSet.readFile(mgraFactorsFile); + int numMGRAs = MGRAData.getRowCount(); + mgraProdProbabilities = spatialDisaggregationModel.getSpatialProbabilities(MGRAData, numMGRAs, "Prods", marketSegment); + mgraAttrProbabilities = spatialDisaggregationModel.getSpatialProbabilities(MGRAData, numMGRAs, "Attrs", marketSegment); + tazMap = spatialDisaggregationModel.getSpatialMap(MGRAData, numMGRAs, "taz"); + mgraTAZMap = spatialDisaggregationModel.getSpatialMap(MGRAData, numMGRAs, "mgra"); + + } + + + logger.info("Reading "+numRecords+" trip records from disaggregate file: "+inputFile); + + // Create a trip record for each record in the input file + for (int i=0; i0){ + destMGRA = parkingMGRA; + } + } + if (tripRecords.containsColumn("originMGRA")){ + origMGRA = (int) tripRecords.getValueAt(i+1, "originMGRA"); + } + if (tripRecords.containsColumn("destinationMGRA")){ + destMGRA = (int) tripRecords.getValueAt(i+1, "destinationMGRA"); + } + + if (tripRecords.containsColumn("originTAZ")){ + origTAZ = (int) tripRecords.getValueAt(i+1, "originTAZ"); + }else{ + origTAZ = mgraManager.getTaz(origMGRA); + } + if (tripRecords.containsColumn("destinationTAZ")){ + destTAZ = (int) tripRecords.getValueAt(i+1, "destinationTAZ"); + }else{ + destTAZ = mgraManager.getTaz(destMGRA); + } + + if(origMGRA==0) + origMGRA = spatialDisaggregationModel.selectMGRAfromTAZ(Trip.getOriginTaz(),mgraTAZMap,tazMap,mgraProdProbabilities,debug); + + if(destMGRA==0) + destMGRA = spatialDisaggregationModel.selectMGRAfromTAZ(Trip.getOriginTaz(),mgraTAZMap,tazMap,mgraAttrProbabilities,debug); + + if (origMGRA==0){ + origMGRA = 50000+Trip.getOriginTaz(); + } + if (destMGRA==0){ + destMGRA = 50000+Trip.getDestinationTaz(); + } + + //JEF 2021-04-21: not sure what the following code intended - removing + /* + if (tripRecords.containsColumn("arrivalMode")){ + int arriveMode = (int) tripRecords.getValueAt(i+1, "arrivalMode"); + if((occ>1 && arriveMode==5)||(mode>=16 && mode<26)){ + addSOVTrip = true; + } + } + */ + if (tripRecords.containsColumn("driver")){ + tourDriver = (int) tripRecords.getValueAt(i+1, "driver"); + } + + if (tripRecords.containsColumn("stop_period")){ + period = (int) tripRecords.getValueAt(i+1,"stop_period"); + } + if (tripRecords.containsColumn("period")){ + period = (int) tripRecords.getValueAt(i+1,"period"); + } + if (tripRecords.containsColumn("departTime")){ + period = (int) tripRecords.getValueAt(i+1,"departTime"); + } + if(tripRecords.containsColumn("departTimeAbmHalfHour")) { + period = (int) tripRecords.getValueAt(i+1,"departTimeAbmHalfHour"); + + } + + if(period==0) + period=1; + + //Calculate number of trips to generate from the record (at a tour level where possible) + + if (tourid!=touridLast || persid!=persidLast || hhid!=hhidLast || (tourid==0 && hhid==0)){ + tripExp = (int) Math.floor(expansionFactor); + double tripsFrac = expansionFactor - tripExp; + double rn = random.nextDouble(); + if (rnfractionalTrips) + tripExp += 0; + }else if(fractionalTrips<1.0 && mode==modeLast){ + double rn = random.nextDouble(); + if (rn>fractionalTrips) + tripExp += 0; + }else if((fractionalTrips<1.0 && mode!=modeLast) || (fractionalTrips==1.0 && modelStructure.getTourModeIsHov(modeLast))){ + tripExp = (int) Math.floor(expansionFactor); + double tripsFrac = expansionFactor - tripExp; + double rn = random.nextDouble(); + if (rnfractionalTrips) + tripExp += 0; + } + + //logger.info("expansionFactor " + expansionFactor + ", fractionalTrips " + fractionalTrips + ", tripExp " + tripExp); + // Reset the dtaTimes array + Arrays.fill(dtaTimes,0); + + // Create a number of integer trip instances based on the expansion factor + for (int k=0; k=1 & dtaPer<=36){ + tod = EA_SKIM_PERIOD_INDEX; + }else if(dtaPer>36 & dtaPer<=72){ + tod = AM_SKIM_PERIOD_INDEX; + }else if(dtaPer>72 & dtaPer<=150){ + tod = MD_SKIM_PERIOD_INDEX; + }else if(dtaPer>150 & dtaPer<=192){ + tod = PM_SKIM_PERIOD_INDEX; + }else{ + tod = EV_SKIM_PERIOD_INDEX; + } + + //dtaPeriod = todDisaggregationModel.calculateDisaggregateTOD(period, detailTODMap, detailProbabilities,debug); + + //double[] autoSkims = autoNonMotSkims.getAutoSkims(tripOrig, tripDest, tod, false, logger); + //double travTime = autoSkims[DA_TIME_INDEX]; + + //changed the code to directly read the values from skim matrices - AshishK + double travTime = skimMatrix[tod].getValueAt(origTAZ, destTAZ); + + int travPer = (int) Math.ceil(travTime/5.0); + + if (direction==1){ + dtaPeriod = dtaPer + travPer + 2; + }else{ + dtaPeriod = dtaPer - (travPer + 2); + } + + // limit the dta period between 1 and 288 - AshishK + if(dtaPeriod < 1) { + dtaPeriod = 1; + } + if(dtaPeriod > detailProbabilities.length) { + dtaPeriod = detailProbabilities.length; + } + + int origNode = spatialDisaggregationModel.selectNodeFromMGRA(tripOrig, nodeMap, mgraNodeMap, nodeProbabilities, debug); + int destNode = spatialDisaggregationModel.selectNodeFromMGRA(tripDest, nodeMap, mgraNodeMap, nodeProbabilities, debug); + + Trip = new dtaTrip(); + Trip.setMarketSegment(marketSegment); + Trip.setOriginMGRA(tripOrig); + Trip.setDestinationMGRA(tripDest); + Trip.setOriginTaz(origTAZ); + Trip.setDestinationTaz(destTAZ); + Trip.setOriginNode(origNode); + Trip.setDestinationNode(destNode); + Trip.setDetailedPeriod(period); + Trip.setDTAPeriod(dtaPeriod); + Trip.setVehicleType("passengerCar"); + Trip.setVehicleOccupancy(1); + Trip.setTollEligible(toll); + Trip.setExpansionFactor(1.0); + tripWriter.print("\r\n"); + Trip.writeTrip(tripWriter); + + } + + /** + * Check if this is a trace household. + * + * @param householdId + * @return True if a trace household, else false + */ + public boolean isTraceHousehold(int householdId){ + + return householdTraceSet.contains(householdId); + + } + + /** + * Check if this is a trace origin. + * + * @param householdId + * @return True if a trace household, else false + */ + public boolean isTraceOrigin(int origTAZ){ + + return originTraceSet.contains(origTAZ); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/dtaTrip.java b/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/dtaTrip.java new file mode 100644 index 0000000..44b6e34 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/dtaTrip.java @@ -0,0 +1,386 @@ +package org.sandag.abm.dta.postprocessing; + +import java.io.PrintWriter; +import java.io.Serializable; + +public class dtaTrip implements Serializable { + + private int id; + private int hhid; + private int persid; + private int tourid; + private int originTaz; + private int destinationTaz; + private int originMGRA; + private int destinationMGRA; + private int originNode; + private int destinationNode; + private String vehicleType; + private int vehOccupancy; + private int tollEligible; + private String marketSegment; + private int broadPeriod; + private int detailedPeriod; + private int dtaPeriod; + private int driver; + private double expansionFactor; + + + + /** + * Default constructor; nothing initialized. + */ + public dtaTrip(){ + + } + /** + * Initialize a trip will zero values for all fields + */ + public void initializeTrip() { + this.id=0; + this.hhid=0; + this.persid=0; + this.tourid=0; + this.originTaz=0; + this.destinationTaz=0; + this.originMGRA=0; + this.destinationMGRA=0; + this.originNode=0; + this.destinationNode=0; + this.vehicleType="na"; + this.vehOccupancy=0; + this.tollEligible=0; + this.marketSegment="na"; + this.broadPeriod=0; + this.detailedPeriod=0; + this.dtaPeriod=0; + this.driver=-1; + this.expansionFactor=1.0; + + } + /** + * @return the household id + */ + public int getHHId() { + return hhid; + } + /** + * @param hhid the household id to set + */ + public void setHHId(int hhid) { + this.hhid = hhid; + } + /** + * @return the person id + */ + public int getPersonId() { + return persid; + } + /** + * @param persid the person id to set + */ + public void setPersonId(int persid) { + this.persid = persid; + } + /** + * @return the tour id + */ + public int getTourId() { + return tourid; + } + /** + * @param tourid the tour id to set + */ + public void setTourId(int tourid) { + this.tourid = tourid; + } + /** + * @return the id + */ + public int getId() { + return id; + } + /** + * @param id the id to set + */ + public void setId(int id) { + this.id = id; + } + + /** + * @return the originTaz + */ + public int getOriginTaz() { + return originTaz; + } + /** + * @param originTaz the originTaz to set + */ + public void setOriginTaz(int originTaz) { + this.originTaz = originTaz; + } + /** + * @return the destinationTaz + */ + public int getDestinationTaz() { + return destinationTaz; + } + /** + * @param destinationTaz the destinationTaz to set + */ + public void setDestinationTaz(int destinationTaz) { + this.destinationTaz = destinationTaz; + } + + /** + * @return the originMGRA + */ + public int getOriginMGRA() { + return originMGRA; + } + /** + * @param originMGRA the originMGRA to set + */ + public void setOriginMGRA(int originMGRA) { + this.originMGRA = originMGRA; + } + /** + * @return the destinationMGRA + */ + public int getDestinationMGRA() { + return destinationMGRA; + } + /** + * @param destinationMGRA the destinationMGRA to set + */ + public void setDestinationMGRA(int destinationMGRA) { + this.destinationMGRA = destinationMGRA; + } + + /** + * @return the originNode + */ + public int getOriginNode() { + return originNode; + } + /** + * @param originNode the originNode to set + */ + public void setOriginNode(int originNode) { + this.originNode = originNode; + } + /** + * @return the destinationNode + */ + public int getDestinationNode() { + return destinationNode; + } + /** + * @param destinationMGRA the destinationMGRA to set + */ + public void setDestinationNode(int destinationNode) { + this.destinationNode = destinationNode; + } + /** + * set trip mode values based on trip mode in input file + */ + public void setTripMode(int mode) { + if(mode<=8||mode>=27){ + setVehicleType("passengerCar"); + setVehicleOccupancy(1); + setTollEligible(0); + if(mode==2){ + setTollEligible(1); + } + if((mode>=3 && mode<=5)||mode==27){ + setVehicleOccupancy(2); + } + if(mode==5){ + setTollEligible(1); + } + if(mode>=6 && mode<=8){ + setVehicleOccupancy(3); + } + if(mode==8){ + setTollEligible(1); + } + } + if(mode>8 && mode<11){ + setVehicleType("nonMotorized"); + setVehicleOccupancy(0); + setTollEligible(0); + } + if(mode>=11 && mode<16){ + setVehicleType("WalkTransit"); + setVehicleOccupancy(0); + setTollEligible(0); + } + if(mode>=16 && mode<26){ + setVehicleType("DriveTransit"); + setVehicleOccupancy(1); + setTollEligible(0); + } + if(mode==26){ + setVehicleType("SchoolBus"); + } + } + /** + * @return the person number of the driver + */ + public int getTourDriver() { + return driver; + } + /** + * @param driver the tour driver to set + */ + public void setTourDriver(int tourDriver) { + this.driver = tourDriver; + } + + /** + * @return the vehicleType + */ + public String getVehicleType() { + return vehicleType; + } + /** + * @param vehicleType the vehicleType to set + */ + public void setVehicleType(String vehicleType) { + this.vehicleType = vehicleType; + } + /** + * @return the vehicleOccupancy + */ + public int getVehicleOccupancy() { + return vehOccupancy; + } + /** + * @param vecOccupancy the vehOccupancy to set + */ + public void setVehicleOccupancy(int vehOccupancy) { + this.vehOccupancy = vehOccupancy; + } + /** + * @return the tollEligibility + */ + public int getTollEligible() { + return tollEligible; + } + /** + * @param tollEligible the tollEligible to set + */ + public void setTollEligible(int tollEligible) { + this.tollEligible = tollEligible; + } + /** + * @return the market segment + */ + public String getMarketSegment() { + return marketSegment; + } + + /** + * @param marketSegment the marketSegment to set + */ + public void setMarketSegment(String marketSegment){ + this.marketSegment = marketSegment; + } + + /** + * @return the broad time period + */ + public int getBroadPeriod() { + return broadPeriod; + } + /** + * @param broadPeriod the broadPeriod to set + */ + public void setBroadPeriod(int Period) { + this.broadPeriod = Period; + } + + /** + * @return the detailed time period + */ + public int getDetailedPeriod() { + return detailedPeriod; + } + /** + * @param detailedPeriod the detailedPeriod to set + */ + public void setDetailedPeriod(int Period) { + this.detailedPeriod = Period; + } + + /** + * @return the dta time period + */ + public int getDTAPeriod() { + return dtaPeriod; + } + /** + * @param dtaPeriod the dtaPeriod to set + */ + public void setDTAPeriod(int Period) { + this.dtaPeriod = Period; + } + /** + * @return the trip expansion factor + */ + public double getExpansionFactor() { + return expansionFactor; + } + /** + * @param dtaPeriod the dtaPeriod to set + */ + public void setExpansionFactor(double expansionFactor) { + this.expansionFactor = expansionFactor; + } + + /** + * Write the trip + * + * @param writer + */ + public void writeTrip(PrintWriter writer){ + String record = new String( + hhid + "," + + persid + "," + + tourid + "," + + id + "," + + originTaz + "," + + destinationTaz + "," + + originMGRA + "," + + destinationMGRA + "," + + originNode + "," + + destinationNode + "," + + vehicleType + "," + + vehOccupancy + "," + + tollEligible + "," + + marketSegment + "," + + detailedPeriod + "," + + broadPeriod + "," + + dtaPeriod + "," + + driver + "," + + expansionFactor + ); + writer.print(record); + } + + /** + * Write a header record + * + * @param writer + */ + /** + * Write a header record + * + * @param writer + */ + public void writeHeader(PrintWriter writer){ + String header = "hh_id,person_id,tour_id,trip_id,originTaz,destinationTaz,originMGRA,destinationMGRA,originNode,destinationNode,vehicleType,vehicleOccupancy,tollEligibility,marketSegment,detailedPeriod,broadPeriod,dtaPeriod,driver,expansionFactor"; + writer.print(header); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/spatialDisaggregationModel.java b/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/spatialDisaggregationModel.java new file mode 100644 index 0000000..fd22ba1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/dta/postprocessing/spatialDisaggregationModel.java @@ -0,0 +1,144 @@ +package org.sandag.abm.dta.postprocessing; + +import java.io.PrintWriter; +import java.util.HashMap; + +import org.apache.log4j.Logger; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import org.sandag.abm.ctramp.Util; + +public class spatialDisaggregationModel { + + private static final String PROPERTIES_RANDOMSEED = "dta.postprocessing.RandomSeed"; + + private HashMap rbMap; + private MersenneTwister random; + private long randomSeed; + + public PrintWriter tripWriter; + + + private transient Logger logger = Logger.getLogger("postprocessModel"); + + + /** + * Default constructor. + */ + public spatialDisaggregationModel(HashMap rbMap){ + + this.rbMap = rbMap; + randomSeed = Util.getIntegerValueFromPropertyMap(rbMap, PROPERTIES_RANDOMSEED); + random = new MersenneTwister(); + random.setSeed(randomSeed); + } + + /** + * Read the probability by spatial data file, return an array of probabilities. + */ + public double[] getSpatialProbabilities(TableDataSet SpatialData, int numRecords, String inputField, String marketSegment){ + + // read the spatial factors file + double [] probabilities; + probabilities = new double [numRecords]; + + String fieldName = null; + if (marketSegment==null){ + fieldName = inputField; + }else{ + fieldName = marketSegment+inputField; + } + //fill in probabilities array + for(int i = 0;i rbMap; + private MersenneTwister random; + private long randomSeed; + + + public PrintWriter tripWriter; + + + private transient Logger logger = Logger.getLogger("postprocessModel"); + + + /** + * Default constructor. + */ + public todDisaggregationModel(HashMap rbMap){ + this.rbMap = rbMap; + randomSeed = Util.getIntegerValueFromPropertyMap(rbMap, PROPERTIES_RANDOMSEED); + random = new MersenneTwister(); + random.setSeed(randomSeed); + } + + /** + * Read the probability by tod data file, return an array of probabilities. + */ + public double[] getTODProbabilities(TableDataSet TODData, int numPeriods, String marketSegment){ + + // read the tod factors file + double [] probabilities; + probabilities = new double [numPeriods]; + + //fill in probabilities array + for(int i = 0;i1) + startLoc = (period-1)*6 + 18; + + // loop through the array of probabilities + for (int i=startLoc;i rbMap; + private McLogsumsCalculator logsumsCalculator; + private AutoTazSkimsCalculator tazDistanceCalculator; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + + private boolean seek; + private int traceId; + + private static float sampleRate=0; + private int iteration = 1; + + /** + * Constructor + * + * @param rbMap + */ + public InternalExternalModel(HashMap rbMap) + { + this.rbMap = rbMap; + mgraManager = MgraDataManager.getInstance(rbMap); + tazManager = TazDataManager.getInstance(rbMap); + seek = new Boolean(Util.getStringValueFromPropertyMap(rbMap, "internalExternal.seek")); + traceId = new Integer(Util.getStringValueFromPropertyMap(rbMap, "internalExternal.trace")); + + } + + public int getIteration() + { + return iteration; + } + + public void setIteration(int iteration) + { + this.iteration = iteration; + } + + /** + * Run InternalExternal model. + */ + public void runModel() + { + + InternalExternalModelStructure modelStructure = new InternalExternalModelStructure(); + + InternalExternalDmuFactoryIf dmuFactory = new InternalExternalDmuFactory(modelStructure); + + InternalExternalTourManager tourManager = new InternalExternalTourManager(rbMap, iteration); + + tourManager.generateTours(); + + InternalExternalTour[] tours = tourManager.getTours(); + + tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + logsumsCalculator = new McLogsumsCalculator(); + logsumsCalculator.setupSkimCalculators(rbMap); + logsumsCalculator.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + InternalExternalTourTimeOfDayChoiceModel todChoiceModel = new InternalExternalTourTimeOfDayChoiceModel( + rbMap); + InternalExternalTourDestChoiceModel destChoiceModel = new InternalExternalTourDestChoiceModel( + rbMap, modelStructure, dmuFactory); + destChoiceModel.calculateTazProbabilities(dmuFactory); + + InternalExternalTripModeChoiceModel tripModeChoiceModel = new InternalExternalTripModeChoiceModel( + rbMap, modelStructure, dmuFactory); + + // Run models for array of tours + for (int i = 0; i < tours.length; ++i) + { + + InternalExternalTour tour = tours[i]; + + if (i < 10 || i % 1000 == 0) logger.info("Processing tour " + i); + + if (seek && tour.getID() != traceId) continue; + + if (tour.getID() == traceId) tour.setDebugChoiceModels(true); + + todChoiceModel.calculateTourTOD(tour); + destChoiceModel.chooseDestination(tour); + + // generate trips and choose mode for them - note this assumes two + // trips per tour + InternalExternalTrip[] trips = new InternalExternalTrip[2]; + int tripNumber = 0; + + // generate an outbound trip from the tour origin to the destination + // and choose a mode + trips[tripNumber] = new InternalExternalTrip(tour, true, mgraManager); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + + // generate an inbound trip from the tour destination to the origin + // and choose a mode + trips[tripNumber] = new InternalExternalTrip(tour, false, mgraManager); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + + // set the trips in the tour object + tour.setTrips(trips); + + } + + tourManager.writeOutputFile(rbMap); + + logger.info("Internal-External Model successfully completed!"); + + } + + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * @param args + */ + public static void main(String[] args) + { + Runtime gfg = Runtime.getRuntime(); + long memory1; + // checking the total memeory + System.out.println("Total memory is: "+ gfg.totalMemory()); + // checking free memory + memory1 = gfg.freeMemory(); + System.out.println("Initial free memory at IE model: "+ memory1); + // calling the garbage collector on demand + gfg.gc(); + memory1 = gfg.freeMemory(); + System.out.println("Free memory after garbage "+ "collection: " + memory1); + + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running InternalExternal Model")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + + // sampleRate is not relevant for internal-external model, since + // sampling + // would have been applied in CT-RAMP model + int iteration = 1; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + + logger.info("IE Model:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + InternalExternalModel internalExternalModel = new InternalExternalModel(pMap); + internalExternalModel.setIteration(iteration); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = internalExternalModel.startMatrixServerProcess( + matrixServerAddress, serverPort, mt); + internalExternalModel.ms = matrixServer; + } else + { + internalExternalModel.ms = new MatrixDataServerRmi(matrixServerAddress, + serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + internalExternalModel.ms.testRemote("InternalExternalModel"); + + // these methods need to be called to set the matrix data + // manager in the matrix data server + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(internalExternalModel.ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + internalExternalModel.runModel(); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalModelStructure.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalModelStructure.java new file mode 100644 index 0000000..f97bed3 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalModelStructure.java @@ -0,0 +1,95 @@ +package org.sandag.abm.internalexternal; + +import org.sandag.abm.application.SandagModelStructure; + +public class InternalExternalModelStructure + extends SandagModelStructure +{ + + public static final byte NUMBER_VISITOR_PURPOSES = 6; + public static final byte WORK = 0; + public static final byte RECREATION = 1; + public static final byte DINING = 2; + + public static final String[] VISITOR_PURPOSES = {"WORK", "RECREATE", "DINING"}; + + // override on max tour mode, since we have taxi in this model. + public static final int MAXIMUM_TOUR_MODE_ALT_INDEX = 27; + + public static final byte NUMBER_VISITOR_SEGMENTS = 2; + public static final byte BUSINESS = 0; + public static final byte PERSONAL = 1; + + public static final String[] VISITOR_SEGMENTS = {"BUSINESS", "PERSONAL"}; + public static final byte DEPARTURE = 0; + public static final byte ARRIVAL = 1; + + public static final byte INCOME_SEGMENTS = 5; + + // note that time periods start at 1 and go to 40 + public static final byte TIME_PERIODS = 40; + + public static final int AM = 0; + public static final int PM = 1; + public static final int OP = 2; + public static final int[] SKIM_PERIODS = {AM, PM, OP}; + public static final String[] SKIM_PERIOD_STRINGS = {"AM", "PM", "OP"}; + public static final int UPPER_EA = 3; + public static final int UPPER_AM = 9; + public static final int UPPER_MD = 22; + public static final int UPPER_PM = 29; + public static final String[] MODEL_PERIOD_LABELS = {"EA", "AM", "MD", "PM", "EV"}; + + public static final byte TAXI = 13; + + /** + * Taxi tour mode + * + * @param tourMode + * @return + */ + public boolean getTourModeIsTaxi(int tourMode) + { + + if (tourMode == TAXI) return true; + else return false; + + } + + /** + * return the Skim period index 0=am, 1=pm, 2=off-peak + */ + public static int getSkimPeriodIndex(int departPeriod) + { + + int skimPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_AM) skimPeriodIndex = AM; + else if (departPeriod <= UPPER_MD) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_PM) skimPeriodIndex = PM; + else skimPeriodIndex = OP; + + return skimPeriodIndex; + + } + + /** + * return the Model period index 0=EA, 1=AM, 2=MD, 3=PM, 4=EV + */ + public static int getModelPeriodIndex(int departPeriod) + { + + int modelPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) modelPeriodIndex = 0; + else if (departPeriod <= UPPER_AM) modelPeriodIndex = 1; + else if (departPeriod <= UPPER_MD) modelPeriodIndex = 2; + else if (departPeriod <= UPPER_PM) modelPeriodIndex = 3; + else modelPeriodIndex = 4; + + return modelPeriodIndex; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTour.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTour.java new file mode 100644 index 0000000..97a7dc8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTour.java @@ -0,0 +1,307 @@ +package org.sandag.abm.internalexternal; + +import java.io.Serializable; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Household; +import com.pb.common.math.MersenneTwister; + +public class InternalExternalTour + implements Serializable +{ + + private MersenneTwister random; + private int ID; + private int hhID; + private int personID; + private int pnum; + + // following variables set from household and person objects + private int income; + private int autos; + private int age; + private int female; + private double nonWorkTimeFactor; + + private boolean avAvailable; + + // private InternalExternalStop[] outboundStops; + // private InternalExternalStop[] inboundStops; + + private InternalExternalTrip[] trips; + + private int departTime; + private int arriveTime; + + private boolean debugChoiceModels; + + // following variables chosen via choice models + private int originMGRA; + private int destinationMGRA; + private int destinationTAZ; // the external TAZ may be + // different from the + // external MGRA + + /** + * Public constructor. + * + * @param seed + * A seed for the random number generator. + */ + public InternalExternalTour(long seed) + { + + random = new MersenneTwister(seed); + } + + /** + * @return the destinationTAZ + */ + public int getDestinationTAZ() + { + return destinationTAZ; + } + + /** + * @param destinationTAZ + * the destinationTAZ to set + */ + public void setDestinationTAZ(int destinationTAZ) + { + this.destinationTAZ = destinationTAZ; + } + + /** + * @return the iD + */ + public int getID() + { + return ID; + } + + /** + * @param iD + * the iD to set + */ + public void setID(int iD) + { + ID = iD; + } + + /** + * @return the departTime + */ + public int getDepartTime() + { + return departTime; + } + + /** + * @param departTime + * the departTime to set + */ + public void setDepartTime(int departTime) + { + this.departTime = departTime; + } + + public InternalExternalTrip[] getTrips() + { + return trips; + } + + public void setTrips(InternalExternalTrip[] trips) + { + this.trips = trips; + } + + /** + * @return the originMGRA + */ + public int getOriginMGRA() + { + return originMGRA; + } + + /** + * @param originMGRA + * the originMGRA to set + */ + public void setOriginMGRA(int originMGRA) + { + this.originMGRA = originMGRA; + } + + /** + * Get a random number from the parties random class. + * + * @return A random number. + */ + public double getRandom() + { + return random.nextDouble(); + } + + /** + * @return the debugChoiceModels + */ + public boolean getDebugChoiceModels() + { + return debugChoiceModels; + } + + /** + * @param debugChoiceModels + * the debugChoiceModels to set + */ + public void setDebugChoiceModels(boolean debugChoiceModels) + { + this.debugChoiceModels = debugChoiceModels; + } + + /** + * Get the number of outbound stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberOutboundStops() + { + return 0; + + } + + /** + * Get the number of return stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberInboundStops() + { + return 0; + + } + + /** + * @return the destinationMGRA + */ + public int getDestinationMGRA() + { + return destinationMGRA; + } + + /** + * @param destinationMGRA + * the destinationMGRA to set + */ + public void setDestinationMGRA(int destinationMGRA) + { + this.destinationMGRA = destinationMGRA; + } + + public void setArriveTime(int arriveTime) + { + this.arriveTime = arriveTime; + } + + public int getArriveTime() + { + return arriveTime; + } + + /** + * @return the income + */ + public int getIncome() + { + return income; + } + + /** + * @param income + * the income to set + */ + public void setIncome(int income) + { + this.income = income; + } + + public int getAutos() + { + return autos; + } + + public void setAutos(int autos) + { + this.autos = autos; + } + + public int getAge() + { + return age; + } + + public void setAge(int age) + { + this.age = age; + } + + public int getFemale() + { + return female; + } + + public void setFemale(int female) + { + this.female = female; + } + + public int getHhID() { + return hhID; + } + + public void setHhID(int hhID) { + this.hhID = hhID; + } + + public int getPersonID() { + return personID; + } + + public void setPersonID(int personID) { + this.personID = personID; + } + + public int getPnum() { + return pnum; + } + + public void setPnum(int pnum) { + this.pnum = pnum; + } + + public double getNonWorkTimeFactor() { + return nonWorkTimeFactor; + } + + public void setNonWorkTimeFactor(double nonWorkTimeFactor) { + this.nonWorkTimeFactor = nonWorkTimeFactor; + } + + public boolean isAvAvailable() { + return avAvailable; + } + + public void setAvAvailable(boolean avAvailable) { + this.avAvailable = avAvailable; + } + + public void logTourObject(Logger logger, int totalChars) + { + + Household.logHelper(logger, "tourId: ", ID, totalChars); + Household.logHelper(logger, "tourOrigMgra: ", originMGRA, totalChars); + Household.logHelper(logger, "tourDestMgra: ", destinationMGRA, totalChars); + Household.logHelper(logger, "tourDepartPeriod: ", departTime, totalChars); + Household.logHelper(logger, "tourArrivePeriod: ", arriveTime, totalChars); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourDestChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourDestChoiceDMU.java new file mode 100644 index 0000000..05886cc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourDestChoiceDMU.java @@ -0,0 +1,114 @@ +package org.sandag.abm.internalexternal; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class InternalExternalTourDestChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger("internalExternalModel"); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + public InternalExternalTourDestChoiceDMU(InternalExternalModelStructure modelStructure) + { + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + // methodIndexMap.put("getTimeOutbound", 0); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + /* + * + * switch (variableIndex) { + * + * case 0: returnValue = getTimeOutbound(); break; + * + * default: logger.error("method number = " + variableIndex + + * " not found"); throw new RuntimeException("method number = " + + * variableIndex + " not found"); + * + * } + */ + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourDestChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourDestChoiceModel.java new file mode 100644 index 0000000..83e952a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourDestChoiceModel.java @@ -0,0 +1,172 @@ +package org.sandag.abm.internalexternal; + +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +/** + * This class is used for external station destination choice model for IE + * tours. + * + * + * @author Freedman + * + */ +public class InternalExternalTourDestChoiceModel +{ + + private transient Logger logger = Logger.getLogger("internalExternalModel"); + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private ChoiceModelApplication destModel; + + private HashMap rbMap; + + private InternalExternalTourDestChoiceDMU dcDmu; + + private Matrix tazProbabilities; + private TableDataSet altData; + + /** + * Constructor + * + * @param propertyMap + * Resource properties file map. + * @param dmuFactory + * Factory object for creation of airport model DMUs + */ + public InternalExternalTourDestChoiceModel(HashMap rbMap, + InternalExternalModelStructure modelStructure, InternalExternalDmuFactoryIf dmuFactory) + { + + this.rbMap = rbMap; + + tazManager = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + + // initiate a DMU + dcDmu = dmuFactory.getInternalExternalTourDestChoiceDMU(); + + // create the full model UECs + // read the model pages from the property file, create one choice model + // for each full model + String internalExternalDCFileName = Util.getStringValueFromPropertyMap(rbMap, + "internalExternal.dc.uec.file"); + internalExternalDCFileName = uecFileDirectory + internalExternalDCFileName; + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, + "internalExternal.dc.uec.data.page"); + int destModelPage = Util.getIntegerValueFromPropertyMap(rbMap, + "internalExternal.dc.uec.model.page"); + destModel = new ChoiceModelApplication(internalExternalDCFileName, destModelPage, dataPage, + rbMap, (VariableTable) dcDmu); + + } + + /** + * Calculate taz probabilities. This method initializes and calculates the + * tazProbabilities array. + */ + public void calculateTazProbabilities(InternalExternalDmuFactoryIf dmuFactory) + { + + logger.info("Calculating IE Model TAZ Probabilities Arrays"); + + // iterate through the alternatives in the alternatives file and set the + // size term and station logsum for each alternative + UtilityExpressionCalculator soaModelUEC = destModel.getUEC(); + altData = soaModelUEC.getAlternativeData(); + + // initialize the arrays + int maxTaz = tazManager.getMaxTaz(); + + tazProbabilities = new Matrix("Prob_Matrix", "Probability Matrix", maxTaz + 1, maxTaz + 1); + + // iterate through origin zones, solve the UEC and store the results in + // the matrix + for (int taz = 1; taz <= maxTaz; ++taz) + { + + int originTaz = taz; + + // set origin taz in dmu (destination set in UEC by alternative) + dcDmu.setDmuIndexValues(originTaz, originTaz, originTaz, originTaz, false); + + // Calculate utilities & probabilities + destModel.computeUtilities(dcDmu, dcDmu.getDmuIndexValues()); + + // Store probabilities (by purpose) + double[] probabilities = destModel.getCumulativeProbabilities(); + + for (int i = 0; i < probabilities.length; ++i) + { + + double cumProb = probabilities[i]; + int destTaz = (int) altData.getValueAt(i + 1, "taz"); + tazProbabilities.setValueAt(originTaz, destTaz, (float) cumProb); + } + } + logger.info("Finished Calculating IE Model TAZ Probabilities Arrays"); + } + + /** + * Choose a destination TAZ and MGRA for the tour. + * + * @param tour + * An IE tour with a tour origin. + */ + public void chooseDestination(InternalExternalTour tour) + { + + double random = tour.getRandom(); + int originTaz = mgraManager.getTaz(tour.getOriginMGRA()); + + if (tour.getDebugChoiceModels()) + { + logger.info("***"); + logger.info("Choosing destination alternative"); + tour.logTourObject(logger, 1000); + + } + + // cycle through probability array for origin taz and find destination + // station & corresponding MGRA + int chosenTaz = -1; + int chosenMgra = -1; + for (int i = 1; i <= altData.getRowCount(); ++i) + { + int destTaz = (int) altData.getValueAt(i, "taz"); + if (random < tazProbabilities.getValueAt(originTaz, destTaz)) + { + chosenTaz = destTaz; + chosenMgra = (int) altData.getValueAt(i, "mgraOut"); + break; + } + } + + if (chosenTaz == -1) + { + logger.error("Error: IE Tour Destination Choice Model for tour " + tour.getID()); + throw new RuntimeException(); + } + + tour.setDestinationMGRA(chosenMgra); + tour.setDestinationTAZ(chosenTaz); + + if (tour.getDebugChoiceModels()) + logger.info("Chose taz " + chosenTaz + " mgra " + chosenMgra + " with random " + random); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourManager.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourManager.java new file mode 100644 index 0000000..3d5d669 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourManager.java @@ -0,0 +1,377 @@ +package org.sandag.abm.internalexternal; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import com.pb.common.util.ResourceUtil; + +public class InternalExternalTourManager +{ + + private static Logger logger = Logger.getLogger("internalExternalModel"); + + private InternalExternalTour[] tours; + public static final String PROPERTIES_DISTRIBUTED_TIME = "distributedTimeCoefficients"; + protected boolean readTimeFactors; + public static final String PERSON_TIMEFACTOR_NONWORK_FIELD_NAME = "timeFactorNonWork"; + + InternalExternalModelStructure modelStructure; + + TableDataSet personData; + + private boolean seek; + private int traceId; + + private MersenneTwister random; + + private class HouseholdClass + { + + int autos; + int income; + int homeMGRA; + int autonomousVehicles; + } + + private HashMap householdData; + + /** + * Constructor. Reads properties file and opens/stores all probability + * distributions for sampling. Estimates number of airport travel parties + * and initializes parties[]. + * + * @param resourceFile + * Property file. + * + * Creates the array of cross-border tours. + */ + public InternalExternalTourManager(HashMap rbMap, int iteration) + { + + modelStructure = new InternalExternalModelStructure(); + + // append _iteration to file + String iterationString = "_" + new Integer(iteration).toString(); + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + + String personFile = Util.getStringValueFromPropertyMap(rbMap, "Results.PersonDataFile"); + // Remove extension from filename + String extension = getFileExtension(personFile); + personFile = removeFileExtension(personFile) + iterationString + extension; + + personFile = directory + personFile; + + String householdFile = Util.getStringValueFromPropertyMap(rbMap, + "Results.HouseholdDataFile"); + + householdFile = directory + householdFile; + // Remove extension from filename + extension = getFileExtension(householdFile); + householdFile = removeFileExtension(householdFile) + iterationString + extension; + + readHouseholdFile(householdFile); + personData = readFile(personFile); + + seek = new Boolean(Util.getStringValueFromPropertyMap(rbMap, "internalExternal.seek")); + traceId = new Integer(Util.getStringValueFromPropertyMap(rbMap, "internalExternal.trace")); + + random = new MersenneTwister(1000001); + //check if we want to read distributed time factors from the person file + String readTimeFactorsString = rbMap.get(PROPERTIES_DISTRIBUTED_TIME); + if (readTimeFactorsString != null) + { + readTimeFactors = Boolean.valueOf(readTimeFactorsString); + logger.info("Distributed time coefficients = "+Boolean.toString(readTimeFactors)); + } + + } + + /** + * Get the file extension + * + * @param fileName + * with the extension + * @return The extension + */ + public String getFileExtension(String fileName) + { + + int index = fileName.lastIndexOf("."); + int length = fileName.length(); + + String extension = fileName.substring(index, length); + + return extension; + + } + + /** + * Get the file name without the extension + * + * @param fileName + * The filename with the extension + * @return The filename without the extension + */ + public String removeFileExtension(String fileName) + { + int index = fileName.lastIndexOf("."); + String name = fileName.substring(0, index); + + return name; + + } + + /** + * Read household records and store autos owned. + * + * @param fileName + * household file path/name. + */ + public void readHouseholdFile(String fileName) + { + + householdData = new HashMap(); + + logger.info("Begin reading the data in file " + fileName); + + TableDataSet hhData; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + hhData = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + // iterate through the table and save number of autos + for (int i = 1; i <= hhData.getRowCount(); ++i) + { + long hhID = (long) hhData.getValueAt(i, "hh_id"); + int autos = (int) hhData.getValueAt(i, "autos"); + int income = (int) hhData.getValueAt(i, "income"); + int mgra = (int) hhData.getValueAt(i, "home_mgra"); + + int AVs = (int) hhData.getValueAt(i,"AVs"); + + // new household + HouseholdClass hh = new HouseholdClass(); + hh.autos = autos; + hh.income = income; + hh.homeMGRA = mgra; + hh.autonomousVehicles = AVs; + + // store in HashMap + householdData.put(hhID, hh); + } + logger.info("End reading the data in file " + fileName); + } + + /** + * Read the file and return the TableDataSet. + * + * @param fileName + * @return data + */ + private TableDataSet readFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet data; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + data = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + return data; + } + + /** + * Generate and attribute IE tours + */ + public void generateTours() + { + + ArrayList tourList = new ArrayList(); + + int rows = personData.getRowCount(); + + int tourCount = 0; + for (int i = 1; i <= rows; ++i) + { + + // TODO: generate IE tours here + if (((int) personData.getValueAt(i, "ie_choice")) == 2) + { + + InternalExternalTour tour = new InternalExternalTour(i + 100001); + tour.setID(i); + + // get the household for the person + long ID = (long) personData.getValueAt(i, "hh_id"); + HouseholdClass hh = householdData.get(ID); + tour.setHhID((int)ID); + + int pID = (int) personData.getValueAt(i, "person_id"); + tour.setPersonID(pID); + + int pnum=(int) personData.getValueAt(i, "person_num"); + tour.setPnum(pnum); + + int age = (int) personData.getValueAt(i, "age"); + String gender = (String) personData.getStringValueAt(i, "gender"); + + tour.setOriginMGRA(hh.homeMGRA); + tour.setIncome(hh.income); + tour.setAutos(hh.autos); + tour.setAge(age); + + if(hh.autonomousVehicles>0) + tour.setAvAvailable(true); + else + tour.setAvAvailable(false); + + if (gender.equals("f")) tour.setFemale(1); + else tour.setFemale(0); + + double timeFactorNonWork = 1.0; + if(readTimeFactors){ + timeFactorNonWork = (double) personData.getValueAt(i, + personData.getColumnPosition(PERSON_TIMEFACTOR_NONWORK_FIELD_NAME)); + } + tour.setNonWorkTimeFactor(timeFactorNonWork); + + tourList.add(tour); + + ++tourCount; + } + + } + if (tourList.isEmpty()) + { + logger.error("Internal-external tour list is empty!!"); + throw new RuntimeException(); + } + + tours = new InternalExternalTour[tourList.size()]; + for (int i = 0; i < tours.length; ++i) + tours[i] = tourList.get(i); + + logger.info("Total IE tours: " + tourCount); + + } + + /** + * Create a text file and write all records to the file. + * + */ + public void writeOutputFile(HashMap rbMap) + { + + // Open file and print header + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String tripFileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "internalExternal.trip.output.file"); + + logger.info("Writing IE trips to file " + tripFileName); + + PrintWriter tripWriter = null; + try + { + tripWriter = new PrintWriter(new BufferedWriter(new FileWriter(tripFileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + tripFileName + " for writing\n"); + throw new RuntimeException(); + } + String tripHeaderString = new String( + "hhID,pnum,personID,tourID,originMGRA,destinationMGRA,originTAZ,destinationTAZ,inbound,originIsTourDestination,destinationIsTourDestination,period,tripMode,av_avail,boardingTap,alightingTap,set,valueOfTime\n"); + tripWriter.print(tripHeaderString); + + for (int i = 0; i < tours.length; ++i) + { + InternalExternalTrip[] trips = tours[i].getTrips(); + for (int j = 0; j < trips.length; ++j) + writeTrip(tours[i].getHhID(), tours[i].getPnum(),tours[i].getPersonID(), tours[i].getID(), tours[i],trips[j], tripWriter); + } + + tripWriter.close(); + + } + + /** + * Write the trip to the PrintWriter + * + * @param tour + * @param trip + * @param tripNumber + * @param writer + */ + private void writeTrip(int hhID, int pnum, int personID, int tourID, InternalExternalTour tour, InternalExternalTrip trip, PrintWriter writer) + { + + String record = new String(hhID+","+pnum+","+personID+","+tourID+","+trip.getOriginMgra() + "," + trip.getDestinationMgra() + "," + + trip.getOriginTaz() + "," + trip.getDestinationTaz() + "," + trip.isInbound() + + "," + trip.isOriginIsTourDestination() + "," + + trip.isDestinationIsTourDestination() + "," + trip.getPeriod() + "," + + trip.getTripMode() + "," + (tour.isAvAvailable() ? 1 : 0) + "," + + trip.getBoardTap() + "," + trip.getAlightTap() + "," + trip.getSet()+ "," + +String.format("%9.2f",trip.getValueOfTime()) + "\n"); + writer.print(record); + } + + /** + * @return the trips + */ + public InternalExternalTour[] getTours() + { + return tours; + } + + public static void main(String[] args) + { + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running IE Model Trip Manager")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + InternalExternalTourManager apm = new InternalExternalTourManager(pMap, 1); + apm.generateTours(); + apm.writeOutputFile(pMap); + + logger.info("IE Trip Manager successfully completed!"); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourTimeOfDayChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourTimeOfDayChoiceModel.java new file mode 100644 index 0000000..189a548 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTourTimeOfDayChoiceModel.java @@ -0,0 +1,182 @@ +package org.sandag.abm.internalexternal; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the TOD choice model for IE tours. It is currently based on a + * static probability distribution stored in an input file, and indexed into by + * purpose. Since there are no IE purposes, the purpose is 0. + * + * @author Freedman + * + */ +public class InternalExternalTourTimeOfDayChoiceModel +{ + private transient Logger logger = Logger.getLogger("internalExternalModel"); + + private double[][] cumProbability; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + private int[][] outboundPeriod; // by + // purpose, + // alternative: + // outbound + // period + private int[][] returnPeriod; // by + // purpose, + // alternative: + // return + // period + InternalExternalModelStructure modelStructure; + + /** + * Constructor. + */ + public InternalExternalTourTimeOfDayChoiceModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String stationDiurnalFile = Util.getStringValueFromPropertyMap(rbMap, + "internalExternal.tour.tod.file"); + stationDiurnalFile = directory + stationDiurnalFile; + + modelStructure = new InternalExternalModelStructure(); + + readTODFile(stationDiurnalFile); + + } + + /** + * Read the TOD distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readTODFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating tour TOD probability distribution"); + + int purposes = 1; // start at 0 + int periods = modelStructure.TIME_PERIODS; // start at 1 + int periodCombinations = periods * (periods + 1) / 2; + + cumProbability = new double[purposes][periodCombinations]; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + outboundPeriod = new int[purposes][periodCombinations]; // by purpose, + // alternative: + // outbound + // period + returnPeriod = new int[purposes][periodCombinations]; // by purpose, + // alternative: + // return period + + // fill up arrays + int rowCount = probabilityTable.getRowCount(); + int lastPurpose = -99; + double cumProb = 0; + int alt = 0; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose"); + int outPer = (int) probabilityTable.getValueAt(row, "EntryPeriod"); + int retPer = (int) probabilityTable.getValueAt(row, "ReturnPeriod"); + + // continue if return period before outbound period + if (retPer < outPer) continue; + + // reset if new purpose + if (purpose != lastPurpose) + { + + // log cumulative probability just in case + if (lastPurpose != -99) + logger.info("Cumulative probability for purpose " + purpose + " is " + cumProb); + cumProb = 0; + alt = 0; + } + + // calculate cumulative probability and store in array + cumProb += probabilityTable.getValueAt(row, "Percent"); + cumProbability[purpose][alt] = cumProb; + outboundPeriod[purpose][alt] = outPer; + returnPeriod[purpose][alt] = retPer; + + ++alt; + + lastPurpose = purpose; + } + + logger.info("End calculating tour TOD probability distribution"); + + } + + /** + * Calculate tour time of day for the tour. + * + * @param tour + * An IE tour + */ + public void calculateTourTOD(InternalExternalTour tour) + { + + int purpose = 0; + double random = tour.getRandom(); + + if (tour.getDebugChoiceModels()) + { + logger.info("Choosing tour time of day for tour ID " + tour.getID() + + " using random number " + random); + tour.logTourObject(logger, 100); + } + + for (int i = 0; i < cumProbability[purpose].length; ++i) + { + + if (random < cumProbability[purpose][i]) + { + int depart = outboundPeriod[purpose][i]; + int arrive = returnPeriod[purpose][i]; + tour.setDepartTime(depart); + tour.setArriveTime(arrive); + break; + } + } + + if (tour.getDebugChoiceModels()) + { + logger.info(""); + logger.info("Chose depart period " + tour.getDepartTime() + " and arrival period " + + tour.getArriveTime()); + logger.info(""); + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTrip.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTrip.java new file mode 100644 index 0000000..c347392 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTrip.java @@ -0,0 +1,313 @@ +package org.sandag.abm.internalexternal; + +import java.io.Serializable; +import org.sandag.abm.modechoice.MgraDataManager; + +public class InternalExternalTrip + implements Serializable +{ + + private int originMgra; + private int destinationMgra; + + + private int originTaz; + private int destinationTaz; + + private int tripMode; + private byte period; + private boolean inbound; + private boolean firstTrip; + private boolean lastTrip; + private boolean originIsTourDestination; + private boolean destinationIsTourDestination; + + private int boardTap; + private int alightTap; + private int set = -1; + + private double valueOfTime; + + /** + * Default constructor; nothing initialized. + */ + public InternalExternalTrip() + { + + } + + /** + * Create a cross border trip from a tour leg (no stops). + * + * @param tour + * The tour. + * @param outbound + * Outbound direction + */ + public InternalExternalTrip(InternalExternalTour tour, boolean outbound, + MgraDataManager mgraManager) + { + + initializeFromTour(tour, outbound, mgraManager); + } + + /** + * Initilize from the tour. + * + * @param tour + * The tour. + * @param outbound + * Outbound direction. + */ + public void initializeFromTour(InternalExternalTour tour, boolean outbound, + MgraDataManager mgraManager) + { + // Note: mode is unknown + if (outbound) + { + this.originMgra = tour.getOriginMGRA(); + this.originTaz = mgraManager.getTaz(tour.getOriginMGRA()); + this.destinationMgra = tour.getDestinationMGRA(); + this.destinationTaz = tour.getDestinationTAZ(); + this.period = (byte) tour.getDepartTime(); + this.inbound = false; + this.firstTrip = true; + this.lastTrip = false; + this.originIsTourDestination = false; + this.destinationIsTourDestination = true; + } else + { + this.originMgra = tour.getDestinationMGRA(); + this.originTaz = tour.getDestinationTAZ(); + this.destinationMgra = tour.getOriginMGRA(); + this.destinationTaz = mgraManager.getTaz(tour.getOriginMGRA()); + this.period = (byte) tour.getArriveTime(); + this.inbound = true; + this.firstTrip = false; + this.lastTrip = true; + this.originIsTourDestination = true; + this.destinationIsTourDestination = false; + } + + } + /** + * @param destinationTaz + * the destinationTaz to set + */ + public void setDestinationTaz(int destinationTaz) + { + this.destinationTaz = destinationTaz; + } + + + /** + * @return the period + */ + public byte getPeriod() + { + return period; + } + + /** + * @param period + * the period to set + */ + public void setPeriod(byte period) + { + this.period = period; + } + + /** + * @return the originMgra + */ + public int getOriginMgra() + { + return originMgra; + } + + /** + * @param originMgra + * the originMgra to set + */ + public void setOriginMgra(int originMgra) + { + this.originMgra = originMgra; + } + + /** + * @return the destinationMgra + */ + public int getDestinationMgra() + { + return destinationMgra; + } + + /** + * @param destinationMgra + * the destinationMgra to set + */ + public void setDestinationMgra(int destinationMgra) + { + this.destinationMgra = destinationMgra; + } + + /** + * @return the tripMode + */ + public int getTripMode() + { + return tripMode; + } + + /** + * @param tripMode + * the tripMode to set + */ + public void setTripMode(int tripMode) + { + this.tripMode = tripMode; + } + public int getBoardTap() { + return boardTap; + } + + public void setBoardTap(int boardTap) { + this.boardTap = boardTap; + } + + public int getAlightTap() { + return alightTap; + } + + public void setAlightTap(int alightTap) { + this.alightTap = alightTap; + } + + public int getSet() { + return set; + } + + public void setSet(int set) { + this.set = set; + } + + + /** + * @return the inbound + */ + public boolean isInbound() + { + return inbound; + } + + /** + * @param inbound + * the inbound to set + */ + public void setInbound(boolean inbound) + { + this.inbound = inbound; + } + + /** + * @return the firstTrip + */ + public boolean isFirstTrip() + { + return firstTrip; + } + + /** + * @param firstTrip + * the firstTrip to set + */ + public void setFirstTrip(boolean firstTrip) + { + this.firstTrip = firstTrip; + } + + /** + * @return the lastTrip + */ + public boolean isLastTrip() + { + return lastTrip; + } + + /** + * @param lastTrip + * the lastTrip to set + */ + public void setLastTrip(boolean lastTrip) + { + this.lastTrip = lastTrip; + } + + /** + * @return the originIsTourDestination + */ + public boolean isOriginIsTourDestination() + { + return originIsTourDestination; + } + + /** + * @param originIsTourDestination + * the originIsTourDestination to set + */ + public void setOriginIsTourDestination(boolean originIsTourDestination) + { + this.originIsTourDestination = originIsTourDestination; + } + + /** + * @return the destinationIsTourDestination + */ + public boolean isDestinationIsTourDestination() + { + return destinationIsTourDestination; + } + + /** + * @param destinationIsTourDestination + * the destinationIsTourDestination to set + */ + public void setDestinationIsTourDestination(boolean destinationIsTourDestination) + { + this.destinationIsTourDestination = destinationIsTourDestination; + } + + /** + * @return the originTaz + */ + public int getOriginTaz() + { + return originTaz; + } + + /** + * @param originTaz + * the originTaz to set + */ + public void setOriginTaz(int originTaz) + { + this.originTaz = originTaz; + } + + /** + * @return the destinationTaz + */ + public int getDestinationTaz() + { + return destinationTaz; + } + + public double getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(double valueOfTime) { + this.valueOfTime = valueOfTime; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripModeChoiceDMU.java new file mode 100644 index 0000000..1f1f864 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripModeChoiceDMU.java @@ -0,0 +1,551 @@ +package org.sandag.abm.internalexternal; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class InternalExternalTripModeChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(InternalExternalTripModeChoiceDMU.class); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + + protected int tourDepartPeriod; + protected int tourArrivePeriod; + protected int tripPeriod; + protected int outboundStops; + protected int returnStops; + protected int firstTrip; + protected int lastTrip; + + protected int income; + protected int female; + protected int age; + protected int autos; + protected int hhSize; + protected int tripOrigIsTourDest; + protected int tripDestIsTourDest; + + protected double nonWorkTimeFactor; + + protected double nmWalkTime; + protected double nmBikeTime; + + + protected double ivtCoeff; + protected double costCoeff; + + protected double walkTransitLogsum; + protected double pnrTransitLogsum; + protected double knrTransitLogsum; + + protected int outboundHalfTourDirection; + + protected int avAvailable; + + public InternalExternalTripModeChoiceDMU(InternalExternalModelStructure modelStructure, + Logger aLogger) + { + if (aLogger == null) + { + aLogger = Logger.getLogger("internalExternalModel"); + } + logger = aLogger; + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the tripPeriod + */ + public int getTripPeriod() + { + return tripPeriod; + } + + /** + * @param tripPeriod + * the tripPeriod to set + */ + public void setTripPeriod(int tripPeriod) + { + this.tripPeriod = tripPeriod; + } + + /** + * @return the outboundStops + */ + public int getOutboundStops() + { + return outboundStops; + } + + /** + * @param outboundStops + * the outboundStops to set + */ + public void setOutboundStops(int outboundStops) + { + this.outboundStops = outboundStops; + } + + /** + * @return the returnStops + */ + public int getReturnStops() + { + return returnStops; + } + + /** + * @param returnStops + * the returnStops to set + */ + public void setReturnStops(int returnStops) + { + this.returnStops = returnStops; + } + + /** + * @return the firstTrip + */ + public int getFirstTrip() + { + return firstTrip; + } + + /** + * @param firstTrip + * the firstTrip to set + */ + public void setFirstTrip(int firstTrip) + { + this.firstTrip = firstTrip; + } + + /** + * @return the lastTrip + */ + public int getLastTrip() + { + return lastTrip; + } + + /** + * @param lastTrip + * the lastTrip to set + */ + public void setLastTrip(int lastTrip) + { + this.lastTrip = lastTrip; + } + + /** + * @return the tripOrigIsTourDest + */ + public int getTripOrigIsTourDest() + { + return tripOrigIsTourDest; + } + + /** + * @param tripOrigIsTourDest + * the tripOrigIsTourDest to set + */ + public void setTripOrigIsTourDest(int tripOrigIsTourDest) + { + this.tripOrigIsTourDest = tripOrigIsTourDest; + } + + /** + * @return the tripDestIsTourDest + */ + public int getTripDestIsTourDest() + { + return tripDestIsTourDest; + } + + /** + * @param tripDestIsTourDest + * the tripDestIsTourDest to set + */ + public void setTripDestIsTourDest(int tripDestIsTourDest) + { + this.tripDestIsTourDest = tripDestIsTourDest; + } + + /** + * @return the outboundHalfTourDirection + */ + public int getOutboundHalfTourDirection() + { + return outboundHalfTourDirection; + } + + /** + * @param outboundHalfTourDirection + * the outboundHalfTourDirection to set + */ + public void setOutboundHalfTourDirection(int outboundHalfTourDirection) + { + this.outboundHalfTourDirection = outboundHalfTourDirection; + } + + /** + * @return the tourDepartPeriod + */ + public int getTourDepartPeriod() + { + return tourDepartPeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(int tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(int tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + /** + * @return the tourArrivePeriod + */ + public int getTourArrivePeriod() + { + return tourArrivePeriod; + } + + public double getNm_walkTime() + { + return nmWalkTime; + } + + public void setNonMotorizedWalkTime(double nmWalkTime) + { + this.nmWalkTime = nmWalkTime; + } + + public void setNonMotorizedBikeTime(double nmBikeTime) + { + this.nmBikeTime = nmBikeTime; + } + + public double getNm_bikeTime() + { + return nmBikeTime; + } + + /** + * @return the income + */ + public int getIncome() + { + return income; + } + + /** + * @param income + * the income to set + */ + public void setIncome(int income) + { + this.income = income; + } + + public int getFemale() + { + return female; + } + + public void setFemale(int female) + { + this.female = female; + } + + public int getAge() + { + return age; + } + + public void setAge(int age) + { + this.age = age; + } + + public int getAutos() + { + return autos; + } + + public void setAutos(int autos) + { + this.autos = autos; + } + + public int getHhSize() + { + return hhSize; + } + + public void setHhSize(int hhSize) + { + this.hhSize = hhSize; + } + public double getNonWorkTimeFactor(){ + return nonWorkTimeFactor; + } + + public void setNonWorkTimeFactor(double nonWorkTimeFactor){ + this.nonWorkTimeFactor=nonWorkTimeFactor; + } + + public double getIvtCoeff() { + return ivtCoeff; + } + + public void setIvtCoeff(double ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + public double getCostCoeff() { + return costCoeff; + } + + public void setCostCoeff(double costCoeff) { + this.costCoeff = costCoeff; + } + + public double getWalkTransitLogsum() { + return walkTransitLogsum; + } + + public void setWalkTransitLogsum(double walkTransitLogsum) { + this.walkTransitLogsum = walkTransitLogsum; + } + + public double getPnrTransitLogsum() { + return pnrTransitLogsum; + } + + public void setPnrTransitLogsum(double pnrTransitLogsum) { + this.pnrTransitLogsum = pnrTransitLogsum; + } + + public double getKnrTransitLogsum() { + return knrTransitLogsum; + } + + public void setKnrTransitLogsum(double knrTransitLogsum) { + this.knrTransitLogsum = knrTransitLogsum; + } + + + public int getAvAvailable() { + return avAvailable; + } + + public void setAvAvailable(int avAvailable) { + this.avAvailable = avAvailable; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTourDepartPeriod", 0); + methodIndexMap.put("getTourArrivePeriod", 1); + methodIndexMap.put("getTripPeriod", 2); + methodIndexMap.put("getOutboundStops", 5); + methodIndexMap.put("getReturnStops", 6); + methodIndexMap.put("getFirstTrip", 7); + methodIndexMap.put("getLastTrip", 8); + methodIndexMap.put("getIncome", 9); + methodIndexMap.put("getFemale", 10); + methodIndexMap.put("getAutos", 11); + methodIndexMap.put("getHhSize", 12); + methodIndexMap.put("getAge", 13); + methodIndexMap.put("getNonWorkTimeFactor", 14); + + methodIndexMap.put("getTripOrigIsTourDest", 23); + methodIndexMap.put("getTripDestIsTourDest", 24); + + methodIndexMap.put("getIvtCoeff", 60); + methodIndexMap.put("getCostCoeff", 61); + + methodIndexMap.put("getWalkSetLogSum", 62); + methodIndexMap.put("getPnrSetLogSum", 63); + methodIndexMap.put("getKnrSetLogSum", 64); + + methodIndexMap.put("getAvAvailable",70); + + methodIndexMap.put("getNm_walkTime", 90); + methodIndexMap.put("getNm_bikeTime", 91); + + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getTourDepartPeriod(); + break; + case 1: + returnValue = getTourArrivePeriod(); + break; + case 2: + returnValue = getTripPeriod(); + break; + case 5: + returnValue = getOutboundStops(); + break; + case 6: + returnValue = getReturnStops(); + break; + case 7: + returnValue = getFirstTrip(); + break; + case 8: + returnValue = getLastTrip(); + break; + case 9: + returnValue = getIncome(); + break; + case 10: + returnValue = getFemale(); + break; + case 11: + returnValue = getAutos(); + break; + case 12: + returnValue = getHhSize(); + break; + case 13: + returnValue = getAge(); + break; + case 14: + returnValue = getNonWorkTimeFactor(); + break; + case 23: + returnValue = getTripOrigIsTourDest(); + break; + case 24: + returnValue = getTripDestIsTourDest(); + break; + + case 60: + returnValue = getIvtCoeff(); + break; + case 61: + returnValue = getCostCoeff(); + break; + case 62: + returnValue = getWalkTransitLogsum(); + break; + case 63: + returnValue = getPnrTransitLogsum(); + break; + case 64: + returnValue = getKnrTransitLogsum(); + break; + case 70: + returnValue = getAvAvailable(); + break; + case 90: + returnValue = getNm_walkTime(); + break; + case 91: + returnValue = getNm_bikeTime(); + break; + default: + logger.error( "method number = " + variableIndex + " not found" ); + throw new RuntimeException( "method number = " + variableIndex + " not found" ); + } + return returnValue; + } + + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripModeChoiceModel.java new file mode 100644 index 0000000..f9dc39d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripModeChoiceModel.java @@ -0,0 +1,277 @@ +package org.sandag.abm.internalexternal; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.airport.AirportModelStructure; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.TripModeChoiceDMU; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class InternalExternalTripModeChoiceModel +{ + + private transient Logger logger = Logger.getLogger("internalExternalModel"); + + private AutoTazSkimsCalculator tazDistanceCalculator; + + private McLogsumsCalculator logsumHelper; + private InternalExternalModelStructure modelStructure; + private TazDataManager tazs; + private MgraDataManager mgraManager; + private InternalExternalTripModeChoiceDMU dmu; + private ChoiceModelApplication tripModeChoiceModel; + double logsum = 0; + + private static final String PROPERTIES_UEC_DATA_SHEET = "internalExternal.trip.mc.data.page"; + private static final String PROPERTIES_UEC_MODEL_SHEET = "internalExternal.trip.mc.model.page"; + private static final String PROPERTIES_UEC_FILE = "internalExternal.trip.mc.uec.file"; + private TripModeChoiceDMU mcDmuObject; + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public InternalExternalTripModeChoiceModel(HashMap propertyMap, + InternalExternalModelStructure myModelStructure, + InternalExternalDmuFactoryIf dmuFactory) + { + tazs = TazDataManager.getInstance(propertyMap); + mgraManager = MgraDataManager.getInstance(propertyMap); + + modelStructure = myModelStructure; + + tazDistanceCalculator = new AutoTazSkimsCalculator(propertyMap); + tazDistanceCalculator.computeTazDistanceArrays(); + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + SandagModelStructure modelStructure = new SandagModelStructure(); + mcDmuObject = new TripModeChoiceDMU(modelStructure, logger); + + setupTripModeChoiceModel(propertyMap, dmuFactory); + + } + + /** + * Read the UEC file and set up the trip mode choice model. + * + * @param propertyMap + * @param dmuFactory + */ + private void setupTripModeChoiceModel(HashMap propertyMap, + InternalExternalDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up IE trip mode choice model.")); + + dmu = dmuFactory.getInternalExternalTripModeChoiceDMU(); + + int dataPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_DATA_SHEET)); + int modelPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_MODEL_SHEET)); + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String tripModeUecFile = propertyMap.get(PROPERTIES_UEC_FILE); + tripModeUecFile = uecPath + tripModeUecFile; + + tripModeChoiceModel = new ChoiceModelApplication(tripModeUecFile, modelPage, dataPage, + propertyMap, (VariableTable) dmu); + + } + + /** + * Calculate utilities and return logsum for the tour and stop. + * + * @param tour + * @param trip + */ + public double computeUtilities(InternalExternalTour tour, InternalExternalTrip trip) + { + + setDmuAttributes(tour, trip); + + tripModeChoiceModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + if (tour.getDebugChoiceModels()) + { + tour.logTourObject(logger, 100); + tripModeChoiceModel.logUECResults(logger, "IE trip mode choice model"); + + } + + logsum = tripModeChoiceModel.getLogsum(); + + if (tour.getDebugChoiceModels()) logger.info("Returning logsum " + logsum); + + return logsum; + + } + + /** + * Choose a mode and store in the trip object. + * + * @param tour + * InternalExternalTour + * @param trip + * InternalExternalTrip + * + */ + public void chooseMode(InternalExternalTour tour, InternalExternalTrip trip) + { + + computeUtilities(tour, trip); + + double rand = tour.getRandom(); + int mode = tripModeChoiceModel.getChoiceResult(rand); + + trip.setTripMode(mode); + + //value of time; lookup vot, votS2, or votS3 from the UEC depending on chosen mode + UtilityExpressionCalculator uec = tripModeChoiceModel.getUEC(); + + double vot = 0.0; + + if(modelStructure.getTripModeIsS2(mode)){ + int votIndex = uec.lookupVariableIndex("votS2"); + vot = uec.getValueForIndex(votIndex); + }else if (modelStructure.getTripModeIsS3(mode)){ + int votIndex = uec.lookupVariableIndex("votS3"); + vot = uec.getValueForIndex(votIndex); + }else{ + int votIndex = uec.lookupVariableIndex("vot"); + vot = uec.getValueForIndex(votIndex); + } + trip.setValueOfTime(vot); + + + if(modelStructure.getTripModeIsTransit(mode)){ + double[][] bestTapPairs = null; + + if (modelStructure.getTripModeIsWalkTransit(mode)){ + bestTapPairs = logsumHelper.getBestWtwTripTaps(); + } + else if (modelStructure.getTripModeIsPnrTransit(mode)||modelStructure.getTripModeIsKnrTransit(mode)){ + if (!trip.isInbound()) + bestTapPairs = logsumHelper.getBestDtwTripTaps(); + else + bestTapPairs = logsumHelper.getBestWtdTripTaps(); + } + double rn = tour.getRandom(); + int pathIndex = logsumHelper.chooseTripPath(rn, bestTapPairs, tour.getDebugChoiceModels(), logger); + int boardTap = (int) bestTapPairs[pathIndex][0]; + int alightTap = (int) bestTapPairs[pathIndex][1]; + int set = (int) bestTapPairs[pathIndex][2]; + trip.setBoardTap(boardTap); + trip.setAlightTap(alightTap); + trip.setSet(set); + } + + + + + + } + + /** + * Set DMU attributes. + * + * @param tour + * @param trip + */ + public void setDmuAttributes(InternalExternalTour tour, InternalExternalTrip trip) + { + + int tripOriginTaz = trip.getOriginTaz(); + int tripDestinationTaz = trip.getDestinationTaz(); + + dmu.setDmuIndexValues(tripOriginTaz, tripDestinationTaz, tripOriginTaz, tripDestinationTaz, + tour.getDebugChoiceModels()); + + dmu.setTourDepartPeriod(tour.getDepartTime()); + dmu.setTourArrivePeriod(tour.getArriveTime()); + dmu.setTripPeriod(trip.getPeriod()); + + dmu.setAutos(tour.getAutos()); + dmu.setIncome(tour.getIncome()); + dmu.setAge(tour.getAge()); + dmu.setFemale(tour.getFemale()); + + dmu.setNonWorkTimeFactor(tour.getNonWorkTimeFactor()); + + // set trip mc dmu values for transit logsum (gets replaced below by uec values) + double c_ivt = -0.03; + double c_cost = - 0.003; + + // Solve trip mode level utilities + mcDmuObject.setIvtCoeff(c_ivt * tour.getNonWorkTimeFactor()); + mcDmuObject.setCostCoeff(c_cost); + + dmu.setIvtCoeff(c_ivt * tour.getNonWorkTimeFactor()); + dmu.setCostCoeff(c_cost); + double walkTransitLogsum = -999.0; + double driveTransitLogsum = -999.0; + + logsumHelper.setNmTripMcDmuAttributes(mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + dmu.setNonMotorizedWalkTime(mcDmuObject.getNm_walkTime()); + dmu.setNonMotorizedBikeTime(mcDmuObject.getNm_bikeTime()); + + logsumHelper.setWtwTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(),tour.getDebugChoiceModels()); + walkTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTW); + + dmu.setWalkTransitLogsum(walkTransitLogsum); + if (!trip.isInbound()) + { + logsumHelper.setDtwTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.DTW); + } else + { + logsumHelper.setWtdTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTD); + } + + dmu.setPnrTransitLogsum(driveTransitLogsum); + dmu.setKnrTransitLogsum(driveTransitLogsum); + + dmu.setOutboundStops(tour.getNumberInboundStops()); + dmu.setReturnStops(tour.getNumberInboundStops()); + + if (trip.isFirstTrip()) dmu.setFirstTrip(1); + else dmu.setFirstTrip(0); + + if (trip.isLastTrip()) dmu.setLastTrip(1); + else dmu.setLastTrip(0); + + if (trip.isOriginIsTourDestination()) dmu.setTripOrigIsTourDest(1); + else dmu.setTripOrigIsTourDest(0); + + if (trip.isDestinationIsTourDestination()) dmu.setTripDestIsTourDest(1); + else dmu.setTripDestIsTourDest(0); + + if(tour.isAvAvailable()) + dmu.setAvAvailable(1); + else + dmu.setAvAvailable(0); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripTables.java b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripTables.java new file mode 100644 index 0000000..3594539 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/internalexternal/InternalExternalTripTables.java @@ -0,0 +1,698 @@ +package org.sandag.abm.internalexternal; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.util.ResourceUtil; + +public class InternalExternalTripTables +{ + + private static Logger logger = Logger.getLogger("tripTables"); + public static final int MATRIX_DATA_SERVER_PORT = 1171; + + private TableDataSet tripData; + + // Some parameters + private int[] modeIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // total + // modes, + // returns + // 0=auto + // modes, + // 1=non-motor, + // 2=transit, + // 3= + // other + private int[] matrixIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // modes, + // returns + // the + // element + // of + // the + // matrix + // array + // to + // store + // value + + // array modes: AUTO, NON-MOTORIZED, TRANSIT, OTHER + private int autoModes = 0; + private int tranModes = 0; + private int nmotModes = 0; + private int othrModes = 0; + + // one file per time period + private int numberOfPeriods; + + private HashMap rbMap; + private static final String VOT_THRESHOLD_LOW = "valueOfTime.threshold.low"; + private static final String VOT_THRESHOLD_MED = "valueOfTime.threshold.med"; + + // matrices are indexed by modes, votbins, tables + private Matrix[][][] matrix; + private float averageOcc3Plus = 3.5f; + + private ResourceBundle rb; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private TapDataManager tapManager; + private SandagModelStructure modelStructure; + + private MatrixDataServerRmi ms; + private float sampleRate = 1; + private static int iteration=1; + private float valueOfTimeThresholdLow = 0; + private float valueOfTimeThresholdMed = 0; + //value of time bins by mode group + int[] votBins = {3,1,1,1}; + + public int numSkimSets; + + + /** + * @return the sampleRate + */ + public float getSampleRate() + { + return sampleRate; + } + + /** + * @param sampleRate + * the sampleRate to set + */ + public void setSampleRate(float sampleRate) + { + this.sampleRate = sampleRate; + } + + public InternalExternalTripTables(HashMap rbMap) + { + + this.rbMap = rbMap; + tazManager = TazDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + modelStructure = new SandagModelStructure(); + + // Time period limits + numberOfPeriods = modelStructure.getNumberModelPeriods(); + + // number of modes + modeIndex = new int[modelStructure.MAXIMUM_TOUR_MODE_ALT_INDEX + 1]; + matrixIndex = new int[modeIndex.length]; + + numSkimSets = Util.getIntegerValueFromPropertyMap(rbMap,"utility.bestTransitPath.skim.sets"); + + + // set the mode arrays + for (int i = 1; i < modeIndex.length; ++i) + { + if (modelStructure.getTourModeIsSovOrHov(i)) + { + modeIndex[i] = 0; + matrixIndex[i] = autoModes; + ++autoModes; + } else if (modelStructure.getTourModeIsNonMotorized(i)) + { + modeIndex[i] = 1; + matrixIndex[i] = nmotModes; + ++nmotModes; + } else if (modelStructure.getTourModeIsWalkTransit(i) + || modelStructure.getTourModeIsDriveTransit(i)) + { + modeIndex[i] = 2; + matrixIndex[i] = tranModes; + ++tranModes; + } else + { + modeIndex[i] = 3; + matrixIndex[i] = othrModes; + ++othrModes; + } + } + //value of time thresholds + valueOfTimeThresholdLow = new Float(rbMap.get(VOT_THRESHOLD_LOW)); + valueOfTimeThresholdMed = new Float(rbMap.get(VOT_THRESHOLD_MED)); + } + + /** + * Initialize all the matrices for the given time period. + * + * @param periodName + * The name of the time period. + */ + public void initializeMatrices(String periodName) + { + + /* + * This won't work because external stations aren't listed in the MGRA + * file int[] tazIndex = tazManager.getTazsOneBased(); int tazs = + * tazIndex.length-1; + */ + // Instead, use maximum taz number + int maxTaz = tazManager.getMaxTaz(); + int[] tazIndex = new int[maxTaz + 1]; + + // assume zone numbers are sequential + for (int i = 1; i < tazIndex.length; ++i) + tazIndex[i] = i; + + // get the tap index + int[] tapIndex = tapManager.getTaps(); + int taps = tapIndex.length - 1; + + // Initialize matrices; one for each mode group (auto, non-mot, tran, + // other) + // All matrices will be dimensioned by TAZs except for transit, which is + // dimensioned by TAPs + int numberOfModes = 4; + matrix = new Matrix[numberOfModes][][]; + for (int i = 0; i < numberOfModes; ++i) + { + matrix[i] = new Matrix[votBins[i]][]; + + String modeName; + for(int j = 0; j< votBins[i];++j){ + + if (i == 0) + { + matrix[i][j] = new Matrix[autoModes]; + for (int k = 0; k < autoModes; ++k) + { + modeName = modelStructure.getModeName(k + 1); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 1) + { + matrix[i][j] = new Matrix[nmotModes]; + for (int k = 0; k < nmotModes; ++k) + { + modeName = modelStructure.getModeName(k + 1 + autoModes); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 2) + { + matrix[i][j] = new Matrix[tranModes*numSkimSets]; + for (int k = 0; k < tranModes; ++k) + { + for(int l=0;l1) + votBin = getValueOfTimeBin(valueOfTime); + + if (mode == 0) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + vehicleTrips)); + } else if (mode == 1) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } else if (mode == 2) + { + + if (boardTap == 0 || alightTap == 0) continue; + + //store transit trips in matrices + mat = (matrixIndex[tripMode]*numSkimSets)+set; + float value = matrix[mode][votBin][mat].getValueAt(boardTap, alightTap); + matrix[mode][votBin][mat].setValueAt(boardTap, alightTap, (value + personTrips)); + + // Store PNR transit trips in SOV free mode skim (mode 0 mat 0) + if (modelStructure.getTourModeIsDriveTransit(tripMode)) + { + + // add the tNCVehicle trip portion to the trip table + if (!inbound) + { // from origin to lot (boarding tap) + int PNRTAZ = tapManager.getTazForTap(boardTap); + value = matrix[0][votBin][0].getValueAt(originTAZ, PNRTAZ); + matrix[0][votBin][0].setValueAt(originTAZ, PNRTAZ, (value + vehicleTrips)); + + } else + { // from lot (alighting tap) to destination + int PNRTAZ = tapManager.getTazForTap(alightTap); + value = matrix[0][votBin][0].getValueAt(PNRTAZ, destinationTAZ); + matrix[0][votBin][0].setValueAt(PNRTAZ, destinationTAZ, (value + vehicleTrips)); + } + + } + } else + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } + + //logger.info("End creating trip tables for period " + timePeriod); + } + } + + /** + * Get the output trip table file names from the properties file, and write + * trip tables for all modes for the given time period. + * + * @param period + * Time period, which will be used to find the period time string + * to append to each trip table matrix file + */ + public void writeTrips(int period, MatrixType mt) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "scenario.path"); + String per = modelStructure.getModelPeriodLabel(period); + String[][] end = new String[4][]; + String[] fileName = new String[4]; + + fileName[0] = directory + + Util.getStringValueFromPropertyMap(rbMap, + "internalExternal.results.autoTripMatrix"); + fileName[1] = directory + + Util.getStringValueFromPropertyMap(rbMap, + "internalExternal.results.nMotTripMatrix"); + fileName[2] = directory + + Util.getStringValueFromPropertyMap(rbMap, + "internalExternal.results.tranTripMatrix"); + fileName[3] = directory + + Util.getStringValueFromPropertyMap(rbMap, + "internalExternal.results.othrTripMatrix"); + + //the end of the name depends on whether there are multiple vot bins or not + String[] votBinName = {"low","med","high"}; + + for(int i = 0; i<4;++i){ + end[i] = new String[votBins[i]]; + for(int j = 0; j < votBins[i];++j){ + if(votBins[i]>1) + end[i][j] = "_" + per + "_"+ votBinName[j]+ ".omx"; + else + end[i][j] = "_" + per + ".omx"; + } + } + + for (int i = 0; i < 4; ++i) + { + for(int j = 0; j < votBins[i];++j){ + try + { + //Delete the file if it exists + File f = new File(fileName[i]+end[i][j]); + if(f.exists()){ + logger.info("Deleting existing trip file: "+fileName[i]+end[i][j]); + f.delete(); + } + + if (ms != null) ms.writeMatrixFile(fileName[i]+end[i][j], matrix[i][j], mt); + else writeMatrixFile(fileName[i]+end[i][j], matrix[i][j]); + } catch (Exception e) + { + logger.error("exception caught writing " + mt.toString() + " matrix file = " + + fileName[i] +end[i][j] + ", for mode index = " + i, e); + throw new RuntimeException(); + } + } + } + } + + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + public void writeMatrixFile(String fileName, Matrix[] m) + { + + // auto trips + MatrixWriter writer = MatrixWriter.createWriter(fileName); + String[] names = new String[m.length]; + + for (int i = 0; i < m.length; i++) + { + names[i] = m[i].getName(); + logger.info(m[i].getName() + " has " + m[i].getRowCount() + " rows, " + + m[i].getColumnCount() + " cols, and a total of " + m[i].getSum()); + } + + writer.writeMatrices(names, m); + } + + /** + * Start matrix server + * + * @param serverAddress + * @param serverPort + * @param mt + * @return + */ + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * @param args + */ + public static void main(String[] args) + { + + HashMap pMap; + String propertiesFile = null; + + logger.info(String.format( + "SANDAG IE Model Trip Table Generation Program using CT-RAMP version %s", + CtrampApplication.VERSION)); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + InternalExternalTripTables tripTables = new InternalExternalTripTables(pMap); + float sampleRate = 1.0f; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + + logger.info("IE Model Trip Table:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + tripTables.setSampleRate(sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = tripTables.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + tripTables.ms = matrixServer; + } else + { + tripTables.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + tripTables.ms.testRemote("InternalExternalTripTables"); + + // mdm = MatrixDataManager.getInstance(); + // mdm.setMatrixDataServerObject(ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + tripTables.createTripTables(mt); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationManager.java b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationManager.java new file mode 100644 index 0000000..120dbef --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationManager.java @@ -0,0 +1,1496 @@ +package org.sandag.abm.maas; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.HashSet; +import java.util.Iterator; +import java.util.Set; +import java.util.StringTokenizer; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.util.PropertyMap; + +public class HouseholdAVAllocationManager { + + HashMap householdMap; //by hh_id + private static final Logger logger = Logger.getLogger(HouseholdAVAllocationModelRunner.class); + protected HashMap propertyMap = null; + protected MersenneTwister random; + protected ModelStructure modelStructure; + protected int iteration; + protected static final String ModelSeedProperty = "Model.Random.Seed"; + protected static final String DirectoryProperty = "Project.Directory"; + protected static final String HouseholdDataFileProperty = "Results.HouseholdDataFile"; + protected static final String PersonDataFileProperty = "Results.PersonDataFile"; + protected static final String IndivTripDataFileProperty = "Results.IndivTripDataFile"; + protected static final String JointTripDataFileProperty = "Results.JointTripDataFile"; + protected static final String VEHICLETRIP_OUTPUT_FILE_PROPERTY = "Maas.AVAllocationModel.vehicletrip.output.file"; + protected static final String VEHICLETRIP_OUTPUT_MATRIX_PROPERTY = "Maas.AVAllocationModel.vehicletrip.output.matrix"; + protected static final String REMOTE_PARKING_COST_PROPERTY = "Mobility.AV.RemoteParkingCostPerHour"; + + protected HashSet householdTraceSet; + public static final String PROPERTIES_HOUSEHOLD_TRACE_LIST = "Debug.Trace.HouseholdIdList"; + // one file per time period + // matrices are indexed by periods + private Matrix[] emptyVehicleTripMatrix; + MgraDataManager mazManager; + TazDataManager tazManager; + + protected static final int[] AutoModes = {1,2,3}; + protected static final int MaxAutoMode = 3; + private long randomSeed = 198761; + protected String vehicleTripOutputFile; + + protected float remoteParkingCostAtDest; + + boolean sortByPerson; + + HashMap personTypeMap; + String[] personTypes = {"Full-time worker","Part-time worker","University student", + "Non-worker", "Retired","Student of driving age","Student of non-driving age", + "Child too young for school"}; + + class Household { + + HashMap personMap; //by person_num + int id; + int homeMaz; + int income; + int autos; + int HVs; + int AVs; + ArrayList trips; + ArrayList autonomousVehicles; + int seed; + boolean debug; + + public void writeDebug(Logger logger, boolean logAVs) { + + logger.info("******** HH DEBUG **************"); + logger.info("HH ID: "+ id); + logger.info("Home MAZ: "+homeMaz); + logger.info("Income: "+income); + logger.info("Autos: "+ autos); + logger.info("HVs: "+HVs); + logger.info("AVs: "+AVs); + logger.info("Seed: "+seed); + + //log persons + if(personMap.size()==0) { + logger.info(" No persons to log"); + }else { + Set keySet = personMap.keySet(); + for(Integer key: keySet) { + Person person = personMap.get(key); + person.writeDebug(logger); + } + } + + //log trips + if(trips.size()==0) { + logger.info(" No trips to log"); + }else { + + for(int i=0;i0 && logAVs) { + for(int i=0;i(); + personMap = new HashMap(); + autonomousVehicles = new ArrayList(); + + } + + public ArrayList getTrips() { + return trips; + } + public void setTrips(ArrayList trips) { + this.trips = trips; + } + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public int getHomeMaz() { + return homeMaz; + } + + public void setHomeMaz(int homeMaz) { + this.homeMaz = homeMaz; + } + + public int getIncome() { + return income; + } + + public void setIncome(int income) { + this.income = income; + } + + public int getAutos() { + return autos; + } + + public void setAutos(int autos) { + this.autos = autos; + } + + public int getHVs() { + return HVs; + } + + public void setHVs(int hVs) { + HVs = hVs; + } + + public int getAVs() { + return AVs; + } + + public void setAVs(int aVs) { + AVs = aVs; + } + + public ArrayList getAutonomousVehicles() { + return autonomousVehicles; + } + + public void setAutonomousVehicles(ArrayList autonomousVehicles) { + this.autonomousVehicles = autonomousVehicles; + } + + public int getSeed() { + return seed; + } + + public void setSeed(int seed) { + this.seed = seed; + } + + public boolean isDebug() { + return debug; + } + + public void setDebug(boolean debug) { + this.debug = debug; + } + + + } + + class Person { + + int hh_id; + int person_id; + int person_num; + int age; + int gender; + int type; + float value_of_time; + float reimb_pct; + float timeFactorWork; + float timeFactorNonWork; + int fp_choice; + + public void writeDebug(Logger logger) { + + logger.info("******** PERSON DEBUG **************"); + logger.info("HH ID: "+ hh_id); + logger.info("Person ID: "+person_id); + logger.info("Person Num: "+person_num); + logger.info("Age: "+age); + logger.info("Gender: "+gender); + logger.info("Type: "+type); + logger.info("Value of time: "+value_of_time); + logger.info("Reimb percent: "+reimb_pct); + logger.info("Time factor work: "+timeFactorWork); + logger.info("Time factor nonwork: "+timeFactorNonWork); + logger.info("Free parking choice: "+fp_choice); + + } + + + public int getHh_id() { + return hh_id; + } + public void setHh_id(int hh_id) { + this.hh_id = hh_id; + } + public int getPerson_id() { + return person_id; + } + public void setPerson_id(int person_id) { + this.person_id = person_id; + } + public int getPerson_num() { + return person_num; + } + public void setPerson_num(int person_num) { + this.person_num = person_num; + } + public int getAge() { + return age; + } + public void setAge(int age) { + this.age = age; + } + public int getGender() { + return gender; + } + public void setGender(int gender) { + this.gender = gender; + } + public int getType() { + return type; + } + public void setType(int type) { + this.type = type; + } + public float getValue_of_time() { + return value_of_time; + } + public void setValue_of_time(float value_of_time) { + this.value_of_time = value_of_time; + } + public float getReimb_pct() { + return reimb_pct; + } + public void setReimb_pct(float reimb_pct) { + this.reimb_pct = reimb_pct; + } + public float getTimeFactorWork() { + return timeFactorWork; + } + public void setTimeFactorWork(float timeFactorWork) { + this.timeFactorWork = timeFactorWork; + } + public float getTimeFactorNonWork() { + return timeFactorNonWork; + } + public void setTimeFactorNonWork(float timeFactorNonWork) { + this.timeFactorNonWork = timeFactorNonWork; + } + public int getFp_choice() { + return fp_choice; + } + public void setFp_choice(int fp_choice) { + this.fp_choice = fp_choice; + } + } + + class Trip implements Comparable{ + + int hh_id; + int person_id; + int person_num; + int tour_id; + int stop_id; + int inbound; + String tour_purpose; + String orig_purpose; + String dest_purpose; + int orig_maz; + int dest_maz; + int parking_maz; + int stop_period; + int periodsUntilNextTrip; + int trip_mode; + int av_avail; + int tour_mode; + int driver_pnum; + float valueOfTime; + int transponder_avail; + int num_participants; //for joint trips + ArrayList persons; + int veh_used; //the number of the vehicle used (1,2,3 or 0 for no AV used) + + public Trip() { + + tour_purpose=""; + orig_purpose=""; + dest_purpose=""; + + } + public void writeDebug(Logger logger) { + + logger.info("******** TRIP DEBUG *******"); + logger.info("HH ID: "+ hh_id); + logger.info("Person ID: "+person_id); + logger.info("Person Num: "+person_num); + logger.info("Tour ID: "+tour_id); + logger.info("Stop ID: "+stop_id); + logger.info("Inbound: "+inbound); + logger.info("Tour purpose: "+tour_purpose); + logger.info("Orig purpose: "+orig_purpose); + logger.info("Dest purpose: "+dest_purpose); + logger.info("Orig MAZ : "+orig_maz); + logger.info("Dest MAZ : "+dest_maz); + logger.info("Parking MAZ: "+parking_maz); + logger.info("Stop Period: "+stop_period); + logger.info("Periods Until Next Trip: "+periodsUntilNextTrip); + logger.info("Trip mode: "+trip_mode); + logger.info("AV avail: "+av_avail); + logger.info("Tour mode: "+tour_mode); + logger.info("Driver pnum: "+driver_pnum); + logger.info("Value Of Time: "+valueOfTime); + logger.info("Transponder Avail: "+transponder_avail); + logger.info("Num participants: "+num_participants); //for joint trips + logger.info("Veh used: "+veh_used); //the number of the vehicle used (1,2,3 or 0 for no AV used) + + } + + + /** + * Return true if its the same person and the same tour id and purpose + * @param thatTrip + * @return true or false + */ + public boolean sameTour(Trip thatTrip) { + + if((person_id==thatTrip.getPerson_id()) && + (tour_id==thatTrip.getTour_id()) && + (num_participants==thatTrip.getNum_participants()) && + (tour_purpose.compareTo(thatTrip.getTour_purpose())==0)) + return true; + return false; + } + + @Override + public int compareTo(Trip thatTrip) { + + if (this == thatTrip) return 0; + + if(sortByPerson) { + + if(person_idthatTrip.getPerson_id()) + return 1; + else if(person_id==thatTrip.getPerson_id()) { + if(stop_periodthatTrip.getStop_period()) + return 1; + else if(stop_period==thatTrip.getStop_period()) { + if(tour_purpose.compareTo("Work")==0 && thatTrip.getTour_purpose().compareTo("Work-Based")==0) { + if(inbound==0) + return -1; + else + return 1; + }else if(tour_purpose.compareTo("Work-based")==0 && thatTrip.getTour_purpose().compareTo("Work")==0) { + if(thatTrip.getInbound()==0) + return 1; + else + return -1; + } + if(tour_idthatTrip.getTour_id()) + return 1; + if(inbound==0 && thatTrip.getInbound()==1) + return -1; + } + + } + return 0; + } + + /* + //if its the same person and the same tour, use the stop ID + if(sameTour(thatTrip)){ + int thisTourTripSeq = inbound * 1000+stop_id; + int thatTourTripSeq = thatTrip.getInbound() * 1000+thatTrip.getStop_id(); + + if(thisTourTripSeqthatTourTripSeq) + return 1; + else + return 0; + } + + //its not the same tour + */ if(stop_periodthatTrip.getStop_period()) + return 1; + else if(stop_period==thatTrip.getStop_period()) { //its the same stop period + if((person_id==thatTrip.getPerson_id())) { //same person + if(tour_purpose.compareTo("Work")==0 && thatTrip.getTour_purpose().compareTo("Work-Based")==0) { + if(inbound==0) + return -1; + else + return 1; + }else if(tour_purpose.compareTo("Work-based")==0 && thatTrip.getTour_purpose().compareTo("Work")==0) { + if(thatTrip.getInbound()==0) + return 1; + else + return -1; + } + + } + /* + * if(periodsUntilNextTripthatTrip.getPeriodsUntilNextTrip()) + return 1; + */ + } + + return 0; + } + + public int getHh_id() { + return hh_id; + } + public void setHh_id(int hh_id) { + this.hh_id = hh_id; + } + public int getPerson_id() { + return person_id; + } + public void setPerson_id(int person_id) { + this.person_id = person_id; + } + public int getPerson_num() { + return person_num; + } + public void setPerson_num(int person_num) { + this.person_num = person_num; + } + public int getTour_id() { + return tour_id; + } + public void setTour_id(int tour_id) { + this.tour_id = tour_id; + } + public int getStop_id() { + return stop_id; + } + public void setStop_id(int stop_id) { + this.stop_id = stop_id; + } + public int getInbound() { + return inbound; + } + public void setInbound(int inbound) { + this.inbound = inbound; + } + public String getTour_purpose() { + return tour_purpose; + } + public void setTour_purpose(String tour_purpose) { + this.tour_purpose = tour_purpose; + } + public String getOrig_purpose() { + return orig_purpose; + } + public void setOrig_purpose(String orig_purpose) { + this.orig_purpose = orig_purpose; + } + public String getDest_purpose() { + return dest_purpose; + } + public void setDest_purpose(String dest_purpose) { + this.dest_purpose = dest_purpose; + } + public int getOrig_maz() { + return orig_maz; + } + public void setOrig_maz(int orig_maz) { + this.orig_maz = orig_maz; + } + public int getDest_maz() { + return dest_maz; + } + public void setDest_maz(int dest_maz) { + this.dest_maz = dest_maz; + } + public int getParking_maz() { + return parking_maz; + } + public void setParking_maz(int parking_maz) { + this.parking_maz = parking_maz; + } + public int getStop_period() { + return stop_period; + } + public void setStop_period(int stop_period) { + this.stop_period = stop_period; + } + public int getTrip_mode() { + return trip_mode; + } + public void setTrip_mode(int trip_mode) { + this.trip_mode = trip_mode; + } + public int getAv_avail() { + return av_avail; + } + public void setAv_avail(int av_avail) { + this.av_avail = av_avail; + } + public int getTour_mode() { + return tour_mode; + } + public void setTour_mode(int tour_mode) { + this.tour_mode = tour_mode; + } + public int getDriver_pnum() { + return driver_pnum; + } + public void setDriver_pnum(int driver_pnum) { + this.driver_pnum = driver_pnum; + } + public float getValueOfTime() { + return valueOfTime; + } + public void setValueOfTime(float valueOfTime) { + this.valueOfTime = valueOfTime; + } + public int getTransponder_avail() { + return transponder_avail; + } + public void setTransponder_avail(int transponder_avail) { + this.transponder_avail = transponder_avail; + } + public int getNum_participants() { + return num_participants; + } + public void setNum_participants(int num_participants) { + this.num_participants = num_participants; + } + public ArrayList getPersons() { + return persons; + } + public void setPersons(ArrayList persons) { + this.persons = persons; + } + + public int getPeriodsUntilNextTrip() { + return periodsUntilNextTrip; + } + + public void setPeriodsUntilNextTrip(int periodsUntilNextTrip) { + this.periodsUntilNextTrip = periodsUntilNextTrip; + } + + public int getVeh_used() { + return veh_used; + } + + public void setVeh_used(int veh_used) { + this.veh_used = veh_used; + } + + } + + public class VehicleTrip{ + + int origMaz; + int destMaz; + int period; + int occupants; + boolean originIsHome; + boolean destinationIsHome; + boolean originIsRemoteParking; + boolean destinationIsRemoteParking; + int parkingChoiceAtDestination; + + Trip tripServed; + + public void writeDebug(Logger logger) { + + logger.info("*** VEHICLE TRIP DEBUG ***"); + logger.info("Orig MAZ: "+origMaz); + logger.info("Dest MAZ: "+destMaz); + logger.info("Period: "+period); + logger.info("Occupants: "+occupants); + logger.info("Orig is home: "+originIsHome); + logger.info("Dest is home: "+destinationIsHome); + logger.info("Orig is remote park: "+originIsRemoteParking); + logger.info("Dest is remote park: "+destinationIsRemoteParking); + logger.info("Parking choice at dest: "+parkingChoiceAtDestination); + + } + + public VehicleTrip() { + } + + public int getOrigMaz() { + return origMaz; + } + + public void setOrigMaz(int origMaz) { + this.origMaz = origMaz; + } + + public int getDestMaz() { + return destMaz; + } + + public void setDestMaz(int destMaz) { + this.destMaz = destMaz; + } + + public int getPeriod() { + return period; + } + + public void setPeriod(int period) { + this.period = period; + } + + public int getOccupants() { + return occupants; + } + + public void setOccupants(int occupants) { + this.occupants = occupants; + } + + public boolean isOriginIsHome() { + return originIsHome; + } + + public void setOriginIsHome(boolean originIsHome) { + this.originIsHome = originIsHome; + } + + public boolean isDestinationIsHome() { + return destinationIsHome; + } + + public void setDestinationIsHome(boolean destinationIsHome) { + this.destinationIsHome = destinationIsHome; + } + + public boolean isOriginIsRemoteParking() { + return originIsRemoteParking; + } + + public void setOriginIsRemoteParking(boolean originIsRemoteParking) { + this.originIsRemoteParking = originIsRemoteParking; + } + + public boolean isDestinationIsRemoteParking() { + return destinationIsRemoteParking; + } + + public void setDestinationIsRemoteParking(boolean destinationIsRemoteParking) { + this.destinationIsRemoteParking = destinationIsRemoteParking; + } + + public int getParkingChoiceAtDestination() { + return parkingChoiceAtDestination; + } + + public void setParkingChoiceAtDestination(int parkingChoiceAtDestination) { + this.parkingChoiceAtDestination = parkingChoiceAtDestination; + } + + public Trip getTripServed() { + return tripServed; + } + + public void setTripServed(Trip tripServed) { + this.tripServed = tripServed; + } + + } + + /** + * This method writes AV vehicle trips to the output file. + * + */ + public void writeVehicleTrips(float sampleRate){ + + logger.info("Writing AV trips to file " + vehicleTripOutputFile); + PrintWriter printWriter = null; + try + { + printWriter = new PrintWriter(new BufferedWriter(new FileWriter(vehicleTripOutputFile))); + } catch (IOException e) + { + logger.fatal("Could not open file " + vehicleTripOutputFile + " for writing\n"); + throw new RuntimeException(); + } + + printHeader(printWriter); + Set keySet = householdMap.keySet(); + for(Integer key: keySet) { + Household hh = householdMap.get(key); + printVehicleTrips(printWriter,hh, sampleRate); + printWriter.flush(); + } + + printWriter.close(); + + } + + + public void printHeader(PrintWriter writer) { + + writer.println("hh_id,veh_id,vehicleTrip_id,orig_mgra,dest_gra,period,occupants," + + "originIsHome,destinationIsHome,originIsRemoteParking,destinationIsRemoteParking," + + "parkingChoiceAtDestination,remoteParkingCostAtDest," + + "person_id,person_num,tour_id,stop_id,inbound,tour_purpose,orig_purpose,dest_purpose," + + "trip_orig_mgra,trip_dest_mgra,stop_period,periodsUntilNextTrip,trip_mode"); + + } + + /** + * Write output to the printwriter. + * + * @param writer + * @param hh + */ + public void printVehicleTrips(PrintWriter writer, Household hh, float sampleRate) { + + int hhid=hh.getId(); + ArrayList vehicles = hh.getAutonomousVehicles(); + if(vehicles==null) + return; + for(int i=0;i vehicleTrips = vehicle.getVehicleTrips(); + + if(vehicleTrips==null) + continue; + + if(vehicleTrips.size()==0) + continue; + + for(int j=0;j vehicleTrips; + + public Vehicle() { + + vehicleTrips = new ArrayList(); + } + + public void writeDebug(Logger logger) { + + logger.info("*** Vehicle debug **"); + logger.info("MAZ: "+maz); + logger.info("Is home: "+isHome); + logger.info("Period available: "+periodAvailable); + + if(vehicleTrips.size()>0) { + for(int i =0;i0) { + VehicleTrip lastTrip = vehicleTrips.get(vehicleTrips.size()-1); + vehicleTrip.setOrigMaz(lastTrip.getDestMaz()); + vehicleTrip.setOriginIsHome(lastTrip.isDestinationIsHome()); + }else { + vehicleTrip.setOriginIsHome(true); + } + + vehicleTrips.add(vehicleTrip); + + return vehicleTrip; + } + + public VehicleTrip createNewVehicleTrip() { + return new VehicleTrip(); + } + + public int getMaz() { + return maz; + } + public void setMaz(int maz) { + this.maz = maz; + } + public boolean isHome() { + return isHome; + } + public void setHome(boolean isHome) { + this.isHome = isHome; + } + public int getPeriodAvailable() { + return periodAvailable; + } + public void setPeriodAvailable(int periodAvailable) { + this.periodAvailable = periodAvailable; + } + + public ArrayList getVehicleTrips() { + return vehicleTrips; + } + + public void setVehicleTrips(ArrayList vehicleTrips) { + this.vehicleTrips = vehicleTrips; + } + + public int getWithPersonId() { + return withPersonId; + } + + public void setWithPersonId(int withPersonId) { + this.withPersonId = withPersonId; + } + + } + + public HouseholdAVAllocationManager(HashMap propertyMap, int iteration,MgraDataManager mazManager,TazDataManager tazManager){ + this.iteration = iteration; + this.propertyMap = propertyMap; + this.tazManager = tazManager; + this.mazManager = mazManager; + modelStructure = new SandagModelStructure(); + + } + + + public void setup() { + + random = new MersenneTwister(); + random.setSeed(randomSeed); + String directory = Util.getStringValueFromPropertyMap(propertyMap, "Project.Directory"); + vehicleTripOutputFile = directory + Util.getStringValueFromPropertyMap(propertyMap, VEHICLETRIP_OUTPUT_FILE_PROPERTY); + + householdMap = new HashMap(); + + personTypeMap = new HashMap(); + + for(int i = 0;i keySet = householdMap.keySet(); + + for(Integer key: keySet) { + + Household hh = householdMap.get(key); + if(hh.isDebug()) { + + logger.info("***********************************************"); + logger.info("AV allocation model trace (After reading) for household "+hh.getId()); + logger.info(""); + hh.writeDebug(logger, false); + logger.info("***********************************************"); + + } + } + + + } + + /* + * Drop households from the map that don't have AVs + */ + public void dropHouseholdsWithoutAVs() { + + logger.info("Dropping non-AV households"); + + Set keys = householdMap.keySet(); + ArrayList hhIdsToRemove = new ArrayList(); + + for(Integer key: keys) { + + Household hh = householdMap.get(key); + if(hh.getAVs()<=0) { + hhIdsToRemove.add(key); + } + } + if(hhIdsToRemove.size()>0) { + for(Integer hhId : hhIdsToRemove) { + householdMap.remove(hhId); + } + } + logger.info("Completed dropping non-AV households"); + + } + + /* + * Drop trips from the map that aren't auto trips with AVs + */ + public void dropNonAVTrips() { + + logger.info("Dropping non-AV trips from households"); + Set keys = householdMap.keySet(); + + for(Integer key: keys) { + + Household hh = householdMap.get(key); + ArrayList trips = hh.getTrips(); + if(trips.size()==0) + continue; + + Iterator itr = trips.iterator(); + while (itr.hasNext()){ + Trip trip = itr.next(); + + if(trip.getAv_avail()==0) + itr.remove(); + + else if(trip.trip_mode>MaxAutoMode) + itr.remove(); + } + } + logger.info("Completed dropping non-AV trips from households"); + + } + + + public void sortTrips() { + + Set keys = householdMap.keySet(); + for(Integer key: keys) { + + Household hh = householdMap.get(key); + ArrayList trips = hh.getTrips(); + if(trips.size()==0) + continue; + + sortByPerson=true; + Collections.sort(trips); + + //first calculate time before next AV trip made by same person + for(int i = 0 ; i< trips.size();++i) { + Trip trip = trips.get(i); + if(i<(trips.size()-1)) { + Trip nextTrip = trips.get(i+1); + if(trip.getPerson_id()==nextTrip.getPerson_id()) { + int periods = nextTrip.getStop_period()-trip.getStop_period(); + trip.setPeriodsUntilNextTrip(periods); + }else + trip.setPeriodsUntilNextTrip(99);//last trip of the day + }else + trip.setPeriodsUntilNextTrip(99); //last trip of the household + + } + sortByPerson=false; + + Collections.sort(trips); + + } + + } + + + public void readHouseholds() { + + + setDebugHhIdsFromHashmap(); + + String directory = Util.getStringValueFromPropertyMap(propertyMap, DirectoryProperty); + String householdFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, HouseholdDataFileProperty); + householdFile = insertIterationNumber(householdFile,iteration); + + //get the household table and fill up the householdMap with households. + TableDataSet householdDataSet = readTableData(householdFile); + + for(int row=1;row<=householdDataSet.getRowCount();++row) { + + int seed = Math.abs(random.nextInt()); + + //read data + int hhId = (int) householdDataSet.getValueAt(row, "hh_id"); + int hhMgra = (int) householdDataSet.getValueAt(row,"home_mgra"); + int income = (int) householdDataSet.getValueAt(row,"income"); + int autos = (int) householdDataSet.getValueAt(row,"autos"); + int HVs = (int) householdDataSet.getValueAt(row,"HVs"); + int AVs = (int) householdDataSet.getValueAt(row,"AVs"); + + //create household object + Household hh = new Household(); + hh.setId(hhId); + hh.setHomeMaz(hhMgra); + hh.setIncome(income); + hh.setAutos(autos); + hh.setHVs(HVs); + hh.setAVs(AVs); + hh.setSeed(seed); + + if(householdTraceSet.contains(hhId)) + hh.setDebug(true); + else + hh.setDebug(false); + + //generate a set of vehicles and store in h + if(AVs>0) { + for(int i=0;i vehicles = hh.getAutonomousVehicles(); + vehicles.add(AV); + } + } + + //put hh in map + householdMap.put(hhId, hh); + + } + + + } + + public void readPersons() { + + + String directory = Util.getStringValueFromPropertyMap(propertyMap, DirectoryProperty); + String personFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, PersonDataFileProperty); + personFile = insertIterationNumber(personFile,iteration); + + //get the household table and fill up the householdMap with households. + TableDataSet personDataSet = readTableData(personFile); + + for(int row=1;row<=personDataSet.getRowCount();++row) { + + + int hh_id = (int) personDataSet.getValueAt(row,"hh_id"); + int person_id = (int) personDataSet.getValueAt(row,"person_id"); + int person_num = (int) personDataSet.getValueAt(row,"person_num"); + int age = (int) personDataSet.getValueAt(row,"age"); + String gender = personDataSet.getStringValueAt(row,"gender"); + String type = personDataSet.getStringValueAt(row,"type"); + float value_of_time = personDataSet.getValueAt(row,"value_of_time"); + float reimb_pct = personDataSet.getValueAt(row,"reimb_pct"); + int parkingChoice = (int) personDataSet.getValueAt(row, "fp_choice"); + float timeFactorWork = personDataSet.getValueAt(row,"timeFactorWork"); + float timeFactorNonWork = personDataSet.getValueAt(row,"timeFactorNonWork"); + + Person person = new Person(); + person.setHh_id(hh_id); + person.setPerson_id(person_id); + person.setPerson_num(person_num); + person.setAge(age); + person.setGender(gender.compareToIgnoreCase("m")==0 ? 1 : 2); + person.setType(personTypeMap.get(type)); + person.setValue_of_time(value_of_time); + person.setReimb_pct(reimb_pct); + person.setFp_choice(parkingChoice); + person.setTimeFactorWork(timeFactorWork); + person.setTimeFactorNonWork(timeFactorNonWork); + + if(householdMap.containsKey(hh_id)) { + Household hh = householdMap.get(hh_id); + hh.personMap.put(person_num,person); + }else { + logger.fatal("Error: No household ID "+hh_id+" in householdMap. Cannot add person object"); + throw new RuntimeException(); + } + + } + + } + + public void readTrips(String filename, boolean isJoint) { + + + //get the household table and fill up the householdMap with households. + TableDataSet tripDataSet = readTableData(filename); + + for(int row=1;row<=tripDataSet.getRowCount();++row) { + + + int hh_id = (int) tripDataSet.getValueAt(row, "hh_id"); + int person_id=-9; + int person_num=-9; + int num_participants = 1; + int driver_pnum=-9; + if(!isJoint) { + person_id = (int) tripDataSet.getValueAt(row,"person_id"); + person_num = (int) tripDataSet.getValueAt(row,"person_num"); + driver_pnum = (int) tripDataSet.getValueAt(row,"driver_pnum"); + }else { + num_participants = (int) tripDataSet.getValueAt(row,"num_participants"); + person_id = hh_id*100+num_participants; + } + int tour_id = (int) tripDataSet.getValueAt(row,"tour_id"); + int stop_id = (int) tripDataSet.getValueAt(row,"stop_id"); + int inbound = (int) tripDataSet.getValueAt(row,"inbound"); + String tour_purpose = tripDataSet.getStringValueAt(row,"tour_purpose"); + String orig_purpose = tripDataSet.getStringValueAt(row,"orig_purpose"); + String dest_purpose = tripDataSet.getStringValueAt(row,"dest_purpose"); + int orig_maz= (int) tripDataSet.getValueAt(row,"orig_mgra"); + int dest_maz= (int) tripDataSet.getValueAt(row,"dest_mgra"); + int parking_maz = (int) tripDataSet.getValueAt(row,"parking_mgra"); + int stop_period = (int) tripDataSet.getValueAt(row,"stop_period"); + int trip_mode = (int) tripDataSet.getValueAt(row,"trip_mode"); + int av_avail = (int) tripDataSet.getValueAt(row,"av_avail"); + int tour_mode = (int) tripDataSet.getValueAt(row,"tour_mode"); + float valueOfTime = tripDataSet.getValueAt(row,"valueOfTime"); + int transponder_avail = (int) tripDataSet.getValueAt(row,"transponder_avail"); + + Trip trip = new Trip(); + trip.setHh_id(hh_id); + trip.setPerson_id(person_id); + trip.setPerson_num(person_num); + trip.setTour_id(tour_id); + trip.setStop_id(stop_id); + trip.setInbound(inbound); + trip.setTour_purpose(tour_purpose); + trip.setOrig_purpose(orig_purpose); + trip.setDest_purpose(dest_purpose); + trip.setOrig_maz(orig_maz); + trip.setDest_maz(dest_maz); + trip.setParking_maz(parking_maz); + trip.setStop_period(stop_period); + trip.setTrip_mode(trip_mode); + trip.setAv_avail(av_avail); + trip.setTour_mode(tour_mode); + trip.setDriver_pnum(driver_pnum); + trip.setValueOfTime(valueOfTime); + trip.setTransponder_avail(transponder_avail); + trip.setNum_participants(num_participants); + + if(householdMap.containsKey(hh_id)){ + Household hh = householdMap.get(hh_id); + + //following code only handles individual trips right now + //TODO: Revise trip file to include participants, and modify code to + //add all participants. + if(person_num!=-99) { + HashMap personMap = hh.personMap; + Person person = personMap.get(person_num); + ArrayList personsOnTrip = trip.getPersons(); + if(personsOnTrip==null) + personsOnTrip = new ArrayList(); + personsOnTrip.add(person); + } + hh.trips.add(trip); + }else { + logger.fatal("Error: No household ID "+hh_id+" in householdMap. Cannot add trip object"); + throw new RuntimeException(); + + } + + } + + + + } + + /** + * Read data into inputDataTable tabledataset. + * + */ + private TableDataSet readTableData(String inputFile){ + + TableDataSet tableDataSet = null; + + logger.info("Begin reading the data in file " + inputFile); + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + tableDataSet = csvFile.readFile(new File(inputFile)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + logger.info("End reading the data in file " + inputFile); + + return tableDataSet; + } + /** + * A simple helper function to insert the iteration number into the file name. + * + * @param filename The input file name (ex: inputFile.csv) + * @param iteration The iteration number (ex: 3) + * @return The new string (ex: inputFile_3.csv) + */ + private String insertIterationNumber(String filename, int iteration){ + + String newFileName = filename.replace(".csv", "_"+new Integer(iteration).toString()+".csv"); + return newFileName; + } + + public HashMap getHouseholdMap() { + return householdMap; + } + + public void setDebugHhIdsFromHashmap() + { + + householdTraceSet = new HashSet(); + + // get the household ids for which debug info is required + String householdTraceStringList = propertyMap.get(PROPERTIES_HOUSEHOLD_TRACE_LIST); + + if (householdTraceStringList != null) + { + StringTokenizer householdTokenizer = new StringTokenizer(householdTraceStringList, ","); + while (householdTokenizer.hasMoreTokens()) + { + String listValue = householdTokenizer.nextToken(); + int idValue = Integer.parseInt(listValue.trim()); + householdTraceSet.add(idValue); + } + } + + } + + /** + * Get the output trip table file names from the properties file, and write + * trip tables for all modes for the given time period. + * + * @param period + * Time period, which will be used to find the period time string + * to append to each trip table matrix file + */ + public void writeTripTable(MatrixDataServerRmi ms) + { + + String directory = Util.getStringValueFromPropertyMap(propertyMap, "scenario.path"); + String matrixTypeName = Util.getStringValueFromPropertyMap(propertyMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + String fileName = directory + Util.getStringValueFromPropertyMap(propertyMap, VEHICLETRIP_OUTPUT_MATRIX_PROPERTY) + ".omx"; + try{ + //Delete the file if it exists + File f = new File(fileName); + if(f.exists()){ + logger.info("Deleting existing trip file: "+fileName); + f.delete(); + } + + if (ms != null) + ms.writeMatrixFile(fileName, emptyVehicleTripMatrix, mt); + else + writeMatrixFile(fileName, emptyVehicleTripMatrix); + } catch (Exception e){ + logger.error("exception caught writing " + mt.toString() + " matrix file = " + + fileName, e); + throw new RuntimeException(); + } + + } + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + private void writeMatrixFile(String fileName, Matrix[] m) + { + + // auto trips + MatrixWriter writer = MatrixWriter.createWriter(fileName); + String[] names = new String[m.length]; + + for (int i = 0; i < m.length; i++) + { + names[i] = m[i].getName(); + logger.info(m[i].getName() + " has " + m[i].getRowCount() + " rows, " + + m[i].getColumnCount() + " cols, and a total of " + m[i].getSum()); + } + + writer.writeMatrices(names, m); + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModel.java b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModel.java new file mode 100644 index 0000000..8101a57 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModel.java @@ -0,0 +1,671 @@ +package org.sandag.abm.maas; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.ListIterator; +import java.util.Random; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.MicromobilityChoiceDMU; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.maas.HouseholdAVAllocationManager.Household; +import org.sandag.abm.maas.HouseholdAVAllocationManager.Person; +import org.sandag.abm.maas.HouseholdAVAllocationManager.Trip; +import org.sandag.abm.maas.HouseholdAVAllocationManager.Vehicle; +import org.sandag.abm.maas.HouseholdAVAllocationManager.VehicleTrip; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import com.pb.common.matrix.MatrixType; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.ResourceUtil; + +public class HouseholdAVAllocationModel { + + private static final Logger logger = Logger.getLogger(HouseholdAVAllocationModel.class); + private HashMap propertyMap = null; + HouseholdAVAllocationManager avManager; + private static final String MODEL_SEED_PROPERTY = "Model.Random.Seed"; + private static final String MINUTES_PER_SIMULATION_PERIOD_PROPERTY = "Maas.RoutingModel.minutesPerSimulationPeriod"; + + private static final String AV_CONTROL_FILE_TARGET = "Maas.AVAllocation.uec.file"; + private static final String AV_DATA_SHEET_TARGET = "Maas.AVAllocation.data.page"; + private static final String AV_VEHICLECHOICE_SHEET_TARGET = "Maas.AVAllocation.vehiclechoice.model.page"; + private static final String AV_PARKINGCHOICE_SHEET_TARGET = "Maas.AVAllocation.parkingchoice.model.page"; + private static final String AV_TRIPUTILITY_SHEET_TARGET = "Maas.AVAllocation.triputility.model.page"; + + private static final int parkingChoiceStay =1; + private static final int parkingChoiceRemote=2; + private static final int parkingChoiceHome=3; + + private static final int vehicleChoiceOther=4; + + private MersenneTwister random; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + + private ChoiceModelApplication parkingChoiceModel; + private ChoiceModelApplication vehicleChoiceModel; + private ChoiceModelApplication tripUtilityModel; + + private HouseholdAVAllocationModelParkingChoiceDMU parkingChoiceDMU; + private HouseholdAVAllocationModelVehicleChoiceDMU vehicleChoiceDMU; + private HouseholdAVAllocationModelTripUtilityDMU tripUtilityDMU; + + int vehicleChoiceOffset = 23942345; + int parkingChoiceOffset =984388432; + int[] closestRemoteLotToMaz; + + + /** + * Constructor. + * + * @param propertyMap + * @param iteration + */ + public HouseholdAVAllocationModel(HashMap propertyMap, MgraDataManager mgraManager, + TazDataManager tazManager, int[] closestRemoteLotToMaz){ + this.propertyMap = propertyMap; + this.mgraManager = mgraManager; + this.tazManager = tazManager; + this.closestRemoteLotToMaz=closestRemoteLotToMaz; + } + + /** + * Initialize all the data members. + * + */ + public void initialize(){ + + + //seed the random number generator so that results can be replicated if desired. + int seed = Util.getIntegerValueFromPropertyMap(propertyMap, MODEL_SEED_PROPERTY); + + random = new MersenneTwister(seed + 4292); + + //create the model UECs + // locate the micromobility choice UEC + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String avUecFile = uecFileDirectory + propertyMap.get(AV_CONTROL_FILE_TARGET); + + int dataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, AV_DATA_SHEET_TARGET); + int vehicleModelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, AV_VEHICLECHOICE_SHEET_TARGET); + int parkingModelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, AV_PARKINGCHOICE_SHEET_TARGET); + int tripModelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, AV_TRIPUTILITY_SHEET_TARGET); + + // create the DMU objects. + vehicleChoiceDMU = new HouseholdAVAllocationModelVehicleChoiceDMU(); + parkingChoiceDMU = new HouseholdAVAllocationModelParkingChoiceDMU(); + tripUtilityDMU = new HouseholdAVAllocationModelTripUtilityDMU(); + + // create the choice model objects + vehicleChoiceModel= new ChoiceModelApplication(avUecFile, vehicleModelSheet, dataSheet, propertyMap, + (VariableTable) vehicleChoiceDMU); + parkingChoiceModel= new ChoiceModelApplication(avUecFile, parkingModelSheet, dataSheet, propertyMap, + (VariableTable) parkingChoiceDMU); + tripUtilityModel= new ChoiceModelApplication(avUecFile, tripModelSheet, dataSheet, propertyMap, + (VariableTable) tripUtilityDMU); + + + } + + /** + * Run the AV allocation model for all households in HashMap. + * + * @param hhMap A hashmap of households + * @return the completed hashmap + */ + public HashMap runModel(HashMap hhMap){ + + //iterate through map + Set keySet = hhMap.keySet(); + for(Integer key : keySet) { + + Household hh = hhMap.get(key); + ArrayList trips = hh.getTrips(); + if(trips==null) + continue; + if(trips.size()==0) + continue; + + ArrayList hhVehicles = hh.getAutonomousVehicles(); + + //iterate through trips, choose vehicle + for(int i =0;i vehicleTrips = vehicle.getVehicleTrips(); + VehicleTrip newVehicleTrip = vehicle.createNewVehicleTrip(); + + if(trip.getOrig_purpose().compareToIgnoreCase("Home")==0) + newVehicleTrip.setOriginIsHome(true); + else + newVehicleTrip.setOriginIsHome(false); + + if(trip.getDest_purpose().compareToIgnoreCase("Home")==0) + newVehicleTrip.setDestinationIsHome(true); + else + newVehicleTrip.setDestinationIsHome(false); + + newVehicleTrip.setOrigMaz(trip.getOrig_maz()); + newVehicleTrip.setDestMaz(trip.getDest_maz()); + newVehicleTrip.setOccupants(trip.getNum_participants()); + newVehicleTrip.setPeriod(trip.getStop_period()); + newVehicleTrip.setTripServed(trip); + vehicleTrips.add(newVehicleTrip); + + //update the time for which the vehicle will be available if it + //is an AV, and update the vehicle location + int period = trip.getStop_period(); + if(period>1 && period<40) { + float timeInMinutes = getTravelTime(hh.getId(),trip.getOrig_maz(),trip.getDest_maz(),period); + int additionalPeriods = (int) (timeInMinutes/30); + vehicle.setPeriodAvailable(period + additionalPeriods); + }else { + vehicle.setPeriodAvailable(period); + } + vehicle.setMaz(trip.getDest_maz()); + if(trip.getDest_purpose().compareToIgnoreCase("Home")==0) + vehicle.setHome(true); + else + vehicle.setHome(false); + + vehicle.setWithPersonId(trip.getPerson_id()); + + } + + if(hh.isDebug()) { + + logger.info("***********************************************"); + logger.info("AV allocation model trace (After vehicle choice) for household "+hh.getId()); + logger.info(""); + hh.writeDebug(logger, true); + logger.info("***********************************************"); + + } + + //iterate through vehicles, choose parking location for each trip in each vehicle. + for(int i =0;i vehicleTrips = veh.getVehicleTrips(); + if(vehicleTrips.size()==0) + continue; + + for(int j =0; j persons = trip.getPersons(); + Person person=null; + if(persons!=null) + person = persons.get(0); + + setParkingChoiceDMUAttributes(hh,person,trip, nextTrip); + parkingChoiceModel.computeUtilities(parkingChoiceDMU, parkingChoiceDMU.getDmuIndexValues()); + int parkingChoice = getParkingChoice(hh,trip); + vehicleTrip.setParkingChoiceAtDestination(parkingChoice); + } + } + + if(hh.isDebug()) { + + logger.info("***********************************************"); + logger.info("AV allocation model trace (After parking choice) for household "+hh.getId()); + logger.info(""); + hh.writeDebug(logger, true); + logger.info("***********************************************"); + + } + + //iterate through vehicles, generate empty vehicle trips. + for(int i =0;i vehicleTrips = vehicle.getVehicleTrips(); + if(vehicleTrips.size()==0) + return; + + int homeMaz = hh.getHomeMaz(); + + ArrayList newVehicleTrips = new ArrayList(); + for(int i =0; i < vehicleTrips.size();++i) { + VehicleTrip vehicleTrip = vehicleTrips.get(i); + Trip tripServed = vehicleTrip.getTripServed(); + int personId = tripServed.getPerson_id(); + + //first vehicle trip + if(i==0) { + + //vehicle is home, but first trip is NOT home, create a trip to it + if(tripServed.orig_purpose.compareToIgnoreCase("Home")!=0) { + VehicleTrip newTrip = vehicle.createNewVehicleTrip(); + newTrip.setOriginIsHome(true); + newTrip.setOrigMaz(homeMaz); + newTrip.setDestMaz(tripServed.getOrig_maz()); + newTrip.setPeriod(tripServed.getStop_period()); + newTrip.setOccupants(0); + newTrip.setOriginIsRemoteParking(false); + newTrip.setDestinationIsRemoteParking(false); + newTrip.setDestinationIsHome(false); + newTrip.setOccupants(0); + newVehicleTrips.add(newTrip); + } + } + newVehicleTrips.add(vehicleTrip); + + //generate empty trip to remote lot if parking is remote lot + int parkingChoice = vehicleTrip.getParkingChoiceAtDestination(); + if(parkingChoice==parkingChoiceRemote) { + VehicleTrip newTrip = vehicle.createNewVehicleTrip(); + newTrip.setOriginIsHome(false); + newTrip.setOrigMaz(vehicleTrip.getDestMaz()); + newTrip.setDestMaz(closestRemoteLotToMaz[vehicleTrip.getDestMaz()]); + newTrip.setPeriod(tripServed.getStop_period()); + newTrip.setDestinationIsHome(false); + newTrip.setOccupants(0); + newTrip.setOriginIsRemoteParking(false); + newTrip.setDestinationIsRemoteParking(true); + newTrip.setDestinationIsHome(false); + newVehicleTrips.add(newTrip); + //or a trip to home if parking choice is home + }else if(parkingChoice==parkingChoiceHome) { + VehicleTrip newTrip = vehicle.createNewVehicleTrip(); + newTrip.setOriginIsHome(false); + newTrip.setOrigMaz(vehicleTrip.getDestMaz()); + newTrip.setDestMaz(homeMaz); + newTrip.setPeriod(tripServed.getStop_period()); + newTrip.setDestinationIsHome(true); + newTrip.setOccupants(0); + newTrip.setOriginIsRemoteParking(false); + newTrip.setDestinationIsRemoteParking(false); + newTrip.setDestinationIsHome(true); + newVehicleTrips.add(newTrip); + } + //next trip + if(i<(vehicleTrips.size()-1)) { + VehicleTrip nextTrip = vehicleTrips.get(i+1); + Trip nextTripServed = nextTrip.getTripServed(); + VehicleTrip lastTrip = newVehicleTrips.get(newVehicleTrips.size()-1); + //if the trip is not already in the same MAZ generate an empty trip + if(lastTrip.getDestMaz()!=nextTrip.getOrigMaz()) { + VehicleTrip newTrip = vehicle.createNewVehicleTrip(); + newTrip.setOriginIsHome(lastTrip.isDestinationIsHome()); + newTrip.setOrigMaz(lastTrip.getDestMaz()); + newTrip.setDestMaz(nextTripServed.getOrig_maz()); + newTrip.setPeriod(nextTripServed.getStop_period()); + newTrip.setDestinationIsHome(nextTripServed.getOrig_purpose().compareToIgnoreCase("home")==0); + newTrip.setOccupants(0); + newTrip.setOriginIsRemoteParking(lastTrip.isDestinationIsRemoteParking()); + newTrip.setDestinationIsRemoteParking(false); + newTrip.setDestinationIsHome(nextTripServed.orig_purpose.compareToIgnoreCase("Home")==0); + newVehicleTrips.add(newTrip); + } + } + } + vehicle.setVehicleTrips(newVehicleTrips); + } + + + /** + * Set attributes for the vehicle allocation model. + * @param hh + * @param thisTrip + */ + public void setVehicleChoiceDMUAttributes(Household hh,Trip thisTrip) { + int[] vehicleIsAvailable= {0,0,0}; + float[] travelUtilityToPerson= {0,0,0}; + int[] vehicleIsWithPerson = {0,0,0}; + + int[] avail = {1,1,1}; + + ArrayList vehicles = hh.getAutonomousVehicles(); + for(int i = 0;iveh.getPeriodAvailable()) + vehicleIsAvailable[i]=1; + else { + vehicleIsAvailable[i]=0; + continue; + } + + //if the vehicle is with the person + if(thisTrip.getPerson_id()==veh.getWithPersonId()) + vehicleIsWithPerson[i]=1; + + int origMgra=veh.getMaz(); + int origTaz = mgraManager.getTaz(origMgra); + int destMgra=thisTrip.getDest_maz(); + int destTaz=mgraManager.getTaz(destMgra); + vehicleChoiceDMU.setDmuIndexValues(hh.getId(), origTaz, origTaz, destTaz); + + //the utility to the person is 0, so don't calculate anything + if(veh.isHome() && thisTrip.orig_purpose.compareToIgnoreCase("Home")==0) + continue; + + float utility= getTravelUtility(hh, origMgra,destMgra,period); + + travelUtilityToPerson[i]=utility; + + } + + vehicleChoiceDMU.setVehicle1IsAvailable(vehicleIsAvailable[0]); + vehicleChoiceDMU.setVehicle2IsAvailable(vehicleIsAvailable[1]); + vehicleChoiceDMU.setVehicle3IsAvailable(vehicleIsAvailable[2]); + + vehicleChoiceDMU.setPersonWithVehicle1(vehicleIsWithPerson[0]); + vehicleChoiceDMU.setPersonWithVehicle2(vehicleIsWithPerson[1]); + vehicleChoiceDMU.setPersonWithVehicle3(vehicleIsWithPerson[2]); + + vehicleChoiceDMU.setTravelUtilityToPersonVeh1(travelUtilityToPerson[0]); + vehicleChoiceDMU.setTravelUtilityToPersonVeh2(travelUtilityToPerson[1]); + vehicleChoiceDMU.setTravelUtilityToPersonVeh3(travelUtilityToPerson[2]); + + vehicleChoiceDMU.setMinutesUntilNextTrip(thisTrip.getPeriodsUntilNextTrip()*30); + + + } + + /** + * After the trip is complete, a parking choice is made for the vehicle used for + * the trip. This should only be called for trips for which an AV was used. + * + * @param hh + * @param person + * @param thisTrip + * @param nextTrip + */ + public void setParkingChoiceDMUAttributes(Household hh, Person person, Trip thisTrip, Trip nextTrip) { + + int[] parkArea = mgraManager.getMgraParkAreas(); + float[] monthlyCosts =mgraManager.getMParkCost(); + float[] dailyCosts = mgraManager.getDParkCost(); + float[] hourlyCosts = mgraManager.getHParkCost(); + + int id = hh.getId(); + int hhMaz = hh.getHomeMaz(); + int destMaz = thisTrip.getDest_maz(); + int period = thisTrip.getStop_period(); + + float durationBeforeNextTrip=8*60; //assume 8 hrs before the next trip if there isn't one + if(nextTrip!=null) + durationBeforeNextTrip=(nextTrip.getStop_period()- thisTrip.getStop_period())*30; + + int personType=0; + int atWork=0; + float reimburseProportion=0; + int freeParkingEligibility=0; + if(person!=null) { + personType = person.getType(); + atWork = thisTrip.getDest_purpose().compareToIgnoreCase("Work")==0? 1 : 0; + reimburseProportion = person.getReimb_pct(); + freeParkingEligibility = person.getFp_choice()==1 ? 1 : 0; + } + int parkingArea= parkArea[destMaz]; + float dailyParkingCost= dailyCosts[destMaz]; + float hourlyParkingCost=hourlyCosts[destMaz]; + float monthlyParkingCost=monthlyCosts[destMaz]; + + float utilityToClosestRemoteLot = getTravelUtility(hh, destMaz,destMaz,period); + float utilityToHome = getTravelUtility(hh, destMaz,hhMaz,period); + + float utilityFromHomeToNextTrip =0; + if(nextTrip!=null) { + int nextMaz = nextTrip.getOrig_maz(); + utilityFromHomeToNextTrip = getTravelUtility(hh, destMaz,nextMaz,period); + } + + parkingChoiceDMU.setDurationBeforeNextTrip(durationBeforeNextTrip); + parkingChoiceDMU.setPersonType(personType); + parkingChoiceDMU.setAtWork(atWork); + parkingChoiceDMU.setFreeParkingEligibility(freeParkingEligibility); + parkingChoiceDMU.setReimburseProportion(reimburseProportion); + parkingChoiceDMU.setDailyParkingCost(dailyParkingCost); + parkingChoiceDMU.setHourlyParkingCost(hourlyParkingCost); + parkingChoiceDMU.setMonthlyParkingCost(monthlyParkingCost); + parkingChoiceDMU.setParkingArea(parkingArea); + parkingChoiceDMU.setUtilityToClosestRemoteLot(utilityToClosestRemoteLot); + parkingChoiceDMU.setUtilityToHome(utilityToHome); + parkingChoiceDMU.setUtilityFromHomeToNextTrip(utilityFromHomeToNextTrip); + + } + + /** + * Get the travel time for the origin and destination. + * + * @param id An ID for the trip + * @param originMaz origin MAZ + * @param destMaz destination MAZ + * @param period departure period + * @return Time from the tripUtilityUEC (2nd alternative) + */ + public float getTravelTime(int id, int originMaz,int destMaz,int period) { + + int[] avail = {1,1,1}; + + //calculate when the vehicle would be available for the next trip given the current + //period and the travel time to the next trip. + int origTaz = mgraManager.getTaz(originMaz); + int destTaz=mgraManager.getTaz(destMaz); + tripUtilityDMU.setDmuIndexValues(id, origTaz, origTaz, destTaz); + vehicleChoiceDMU.setDmuIndexValues(id, origTaz, origTaz, destTaz); + tripUtilityDMU.setTimeTrip(period); + + UtilityExpressionCalculator tripUtilityUEC = tripUtilityModel.getUEC(); + double[] util = tripUtilityUEC.solve(tripUtilityDMU.getDmuIndexValues(), tripUtilityDMU, avail); + + return (float) util[1]; + } + + /** + * Get the travel utility for the origin and destination. + * + * @param id An ID for the trip + * @param originMaz origin MAZ + * @param destMaz destination MAZ + * @param period departure period + * @return Utility from the tripUtilityUEC (1st alternative) + */ + public float getTravelUtility(Household hh, int originMaz,int destMaz,int period) { + + int[] avail = {1,1,1}; + + //calculate when the vehicle would be available for the next trip given the current + //period and the travel time to the next trip. + int origTaz = mgraManager.getTaz(originMaz); + int destTaz=mgraManager.getTaz(destMaz); + tripUtilityDMU.setDmuIndexValues(hh.getId(), origTaz, origTaz, destTaz); + vehicleChoiceDMU.setDmuIndexValues(hh.getId(), origTaz, origTaz, destTaz); + tripUtilityDMU.setTimeTrip(period); + + UtilityExpressionCalculator tripUtilityUEC = tripUtilityModel.getUEC(); + double[] util = tripUtilityUEC.solve(tripUtilityDMU.getDmuIndexValues(), tripUtilityDMU, avail); + + // write choice model alternative info to log file + if (hh.isDebug()) + { + logger.info("Calculating travel utility calculation for household " + hh.getId()+ " trip in period " + period +" from MAZ "+originMaz+" to MAZ "+destMaz); + tripUtilityUEC.logAnswersArray( logger, "Trip utility"); + } + + + return (float) util[0]; + } + + /** + * Select the vehicle choice from the UEC. This is helper code for applyModel(), where utilities have already been calculated. + + * @return The vehicle alternative 1,2,3,4.1-3 are AV veh numbers, 4 is other + */ + private int getVehicleChoice(Household hh, Trip trip) { + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + long seed = hh.getSeed() + (vehicleChoiceOffset + trip.getStop_id()*23 +trip.getPerson_id()*34 + trip.getStop_period()*23); + random.setSeed(seed); + + if (vehicleChoiceModel.getAvailabilityCount() > 0) + { + double randomNumber = random.nextDouble(); + chosenAlt = vehicleChoiceModel.getChoiceResult(randomNumber); + + // write choice model alternative info to log file + if (hh.isDebug()) + { + String decisionMaker = String.format("Household " + hh.getId()+ " trip in period " + trip.stop_period +" from MAZ "+trip.getOrig_maz()+" to MAZ "+trip.getDest_maz()); + vehicleChoiceModel.logAlternativesInfo("Vehicle Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Vehicle Choice", decisionMaker, chosenAlt)); + vehicleChoiceModel.logUECResults(logger, decisionMaker); + } + + + return chosenAlt; + } else + { + String decisionMaker = String.format("Household " + hh.getId()+" "+trip.getStop_id()); + String errorMessage = String + .format("Exception caught for %s, no available vehicle choice alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.error(errorMessage); + + vehicleChoiceModel.logUECResults(logger, decisionMaker); + throw new RuntimeException(); + } + + } + + + /** + * Select the parking choice from the UEC. This is helper code for applyModel(), where utilities have already been calculated. + + * @return The parking alternative + */ + private int getParkingChoice(Household hh, Trip trip) { + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + long seed = hh.getSeed() + (parkingChoiceOffset + trip.getStop_id()*123 +trip.getPerson_id()*23 + trip.getStop_period()*18); + random.setSeed(seed); + + if (parkingChoiceModel.getAvailabilityCount() > 0) + { + double randomNumber = random.nextDouble(); + chosenAlt = parkingChoiceModel.getChoiceResult(randomNumber); + + // write choice model alternative info to log file + if (hh.isDebug()) + { + String decisionMaker = String.format("Household " + hh.getId()+ " trip in period " + trip.stop_period +" from MAZ "+trip.getOrig_maz()+" to MAZ "+trip.getDest_maz()); + parkingChoiceModel.logAlternativesInfo("Parking Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Parking Choice", decisionMaker, chosenAlt)); + parkingChoiceModel.logUECResults(logger, decisionMaker); + } + + + + return chosenAlt; + } else + { + String decisionMaker = String.format("Household " + hh.getId()+" "+trip.getStop_id()); + String errorMessage = String + .format("Exception caught for %s, no available vehicle choice alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.error(errorMessage); + + parkingChoiceModel.logUECResults(logger, decisionMaker); + throw new RuntimeException(); + } + + } + + + + + /** + * Main run method + * @param args + */ + public static void main(String[] args) { + + + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelParkingChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelParkingChoiceDMU.java new file mode 100644 index 0000000..f9d0f26 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelParkingChoiceDMU.java @@ -0,0 +1,239 @@ +package org.sandag.abm.maas; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + */ +public class HouseholdAVAllocationModelParkingChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(HouseholdAVAllocationModelParkingChoiceDMU.class); + + protected HashMap methodIndexMap; + + private IndexValues dmuIndex; + float durationBeforeNextTrip; + int personType; + int atWork; + int freeParkingEligibility; + float reimburseProportion; + float dailyParkingCost; + float hourlyParkingCost; + float monthlyParkingCost; + int parkingArea; + float utilityToClosestRemoteLot; + float utilityToHome; + float utilityFromHomeToNextTrip; + + + public HouseholdAVAllocationModelParkingChoiceDMU() + { + dmuIndex = new IndexValues(); + setupMethodIndexMap(); + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + } + + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getDurationBeforeNextTrip",1); + methodIndexMap.put("getPersonType",2); + methodIndexMap.put("getAtWork",3); + methodIndexMap.put("getFreeParkingEligibility",4); + methodIndexMap.put("getReimburseProportion",5); + methodIndexMap.put("getDailyParkingCost",6); + methodIndexMap.put("getHourlyParkingCost",7); + methodIndexMap.put("getMonthlyParkingCost",8); + methodIndexMap.put("getParkingArea",9); + methodIndexMap.put("getUtilityToClosestRemoteLot",10); + methodIndexMap.put("getUtilityToHome",11); + methodIndexMap.put("getUtilityFromHomeToNextTrip",12); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 1: + return getDurationBeforeNextTrip(); + case 2: + return getPersonType(); + case 3: + return getAtWork(); + case 4: + return getFreeParkingEligibility(); + case 5: + return getReimburseProportion(); + case 6: + return getDailyParkingCost(); + case 7: + return getHourlyParkingCost(); + case 8: + return getMonthlyParkingCost(); + case 9: + return getParkingArea(); + case 10: + return getUtilityToClosestRemoteLot(); + case 11: + return getUtilityToHome(); + case 12: + return getUtilityFromHomeToNextTrip(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public float getDurationBeforeNextTrip() { + return durationBeforeNextTrip; + } + + public void setDurationBeforeNextTrip(float durationBeforeNextTrip) { + this.durationBeforeNextTrip = durationBeforeNextTrip; + } + + public int getPersonType() { + return personType; + } + + public void setPersonType(int personType) { + this.personType = personType; + } + + public int getAtWork() { + return atWork; + } + + public void setAtWork(int atWork) { + this.atWork = atWork; + } + + public int getFreeParkingEligibility() { + return freeParkingEligibility; + } + + public void setFreeParkingEligibility(int freeParkingEligibility) { + this.freeParkingEligibility = freeParkingEligibility; + } + + public float getReimburseProportion() { + return reimburseProportion; + } + + public void setReimburseProportion(float reimburseProportion) { + this.reimburseProportion = reimburseProportion; + } + + public float getDailyParkingCost() { + return dailyParkingCost; + } + + public void setDailyParkingCost(float dailyParkingCost) { + this.dailyParkingCost = dailyParkingCost; + } + + public float getHourlyParkingCost() { + return hourlyParkingCost; + } + + public void setHourlyParkingCost(float hourlyParkingCost) { + this.hourlyParkingCost = hourlyParkingCost; + } + + public float getMonthlyParkingCost() { + return monthlyParkingCost; + } + + public void setMonthlyParkingCost(float monthlyParkingCost) { + this.monthlyParkingCost = monthlyParkingCost; + } + + public int getParkingArea() { + return parkingArea; + } + + public void setParkingArea(int parkingArea) { + this.parkingArea = parkingArea; + } + + public float getUtilityToClosestRemoteLot() { + return utilityToClosestRemoteLot; + } + + public void setUtilityToClosestRemoteLot(float utilityToClosestRemoteLot) { + this.utilityToClosestRemoteLot = utilityToClosestRemoteLot; + } + + public float getUtilityToHome() { + return utilityToHome; + } + + public void setUtilityToHome(float utilityToHome) { + this.utilityToHome = utilityToHome; + } + + public float getUtilityFromHomeToNextTrip() { + return utilityFromHomeToNextTrip; + } + + public void setUtilityFromHomeToNextTrip(float utilityFromHomeToNextTrip) { + this.utilityFromHomeToNextTrip = utilityFromHomeToNextTrip; + } + + + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelRunner.java b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelRunner.java new file mode 100644 index 0000000..cc4c03f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelRunner.java @@ -0,0 +1,260 @@ +package org.sandag.abm.maas; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Set; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.MicromobilityChoiceDMU; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.maas.HouseholdAVAllocationManager.Household; +import org.sandag.abm.maas.HouseholdAVAllocationManager.Trip; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import com.pb.common.matrix.MatrixType; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.ResourceUtil; + +public class HouseholdAVAllocationModelRunner { + + private static final Logger logger = Logger.getLogger(HouseholdAVAllocationModelRunner.class); + private HashMap propertyMap = null; + HouseholdAVAllocationManager avManager; + private static final String MODEL_SEED_PROPERTY = "Model.Random.Seed"; + + private int iteration; + private float sampleRate; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private HouseholdAVAllocationModel AVAllocationModel; //one for now, can multi-thread later + private int[] closestMazWithRemoteLot; + MatrixDataServerRmi ms; + private UtilityExpressionCalculator distanceUEC; + protected VariableTable dmu = null; + protected float[][] tazDistanceSkims; //travel distance + + /** + * Constructor. + * + * @param propertyMap + * @param iteration + */ + public HouseholdAVAllocationModelRunner(HashMap propertyMap, int iteration, float sampleRate){ + this.propertyMap = propertyMap; + this.iteration = iteration; + this.sampleRate = sampleRate; + } + + /** + * Initialize all the data members. + * + */ + public void initialize(){ + + startMatrixServer(propertyMap); + + //managers for MAZ and TAZ data + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + + //create a household AV manager, read trips + avManager = new HouseholdAVAllocationManager(propertyMap, iteration, mgraManager, tazManager); + avManager.setup(); + avManager.readInputFiles(); + + calculateDistanceSkims(); + calculateClosestRemoteLotMazs(); + + } + + /** + * Creates a midday distance UEC, solves it for all zones, stores results in tazDistanceSkims[][]. + */ + public void calculateDistanceSkims() { + + logger.info("Calculating distance skims"); + // Create the distance UEC + String uecPath = Util.getStringValueFromPropertyMap(propertyMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = uecPath + + Util.getStringValueFromPropertyMap(propertyMap, "taz.distance.uec.file"); + int dataPage = Util.getIntegerValueFromPropertyMap(propertyMap, "taz.distance.data.page"); + int distancePage = Util.getIntegerValueFromPropertyMap(propertyMap, "taz.od.distance.md.page"); + distanceUEC = new UtilityExpressionCalculator(new File(uecFileName), distancePage, dataPage, + propertyMap, dmu); + IndexValues iv = new IndexValues(); + + int maxTaz = tazManager.getMaxTaz(); + tazDistanceSkims = new float[maxTaz+1][maxTaz+1]; + + for (int oTaz = 1; oTaz <= maxTaz; oTaz++){ + + iv.setOriginZone(oTaz); + + double[] autoDist = distanceUEC.solve(iv, dmu, null); + for (int d = 0; d < maxTaz; d++){ + tazDistanceSkims[oTaz][d + 1] = (float) autoDist[d]; + } + } + logger.info("Completed calculating distance skims"); + + } + + public void runModel(){ + + //iterate through map + HashMap hhMap = avManager.getHouseholdMap(); + AVAllocationModel = new HouseholdAVAllocationModel(propertyMap, mgraManager,tazManager,closestMazWithRemoteLot); + AVAllocationModel.initialize(); + + AVAllocationModel.runModel(hhMap); + + avManager.writeVehicleTrips(sampleRate); + + avManager.writeTripTable(ms); + + } + + + + /** + * Start a matrix server + * + * @param properties + */ + private void startMatrixServer(HashMap properties) { + String serverAddress = (String) properties.get("RunModel.MatrixServerAddress"); + int serverPort = new Integer((String) properties.get("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try{ + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) { + logger.error("could not connect to matrix server", e); + throw new RuntimeException(e); + + } + + } + + + /** + * Iterate through the zones for each MAZ and find the closest MAZ with a remote parking lot. + * + */ + public void calculateClosestRemoteLotMazs() { + + int maxMaz = mgraManager.getMaxMgra(); + + //initialize the array + closestMazWithRemoteLot = new int[maxMaz+1]; + + //iterate through origin MAZs + for(int originMaz=1;originMaz<=maxMaz;++originMaz) { + + float minDist = 99999; //initialize to a really high value + + int originTaz = mgraManager.getTaz(originMaz); + if(originTaz<=0) + continue; + + //iterate through destination MAZs + for(int destinationMaz=1;destinationMaz<=maxMaz;++destinationMaz) { + + //no refueling stations in the destination, keep going + if(mgraManager.getRemoteParkingLot(originMaz)==0) + continue; + + int destinationTaz = mgraManager.getTaz(destinationMaz); + if(destinationTaz<=0) + continue; + + float dist = getDistance(originTaz, destinationTaz); + + //lowest distance, so reset the closest MAZ + if(dist pMap; + + logger.info(String.format("Household AV Fleet Allocation Program using CT-RAMP version ", + CtrampApplication.VERSION)); + + int iteration=0; + float sampleRate=1; + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else { + propertiesFile = args[0]; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.valueOf(args[i + 1]); + } + + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.valueOf(args[i + 1]); + } + + } + } + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + HouseholdAVAllocationModelRunner householdAVModel = new HouseholdAVAllocationModelRunner(pMap, iteration, sampleRate); + householdAVModel.initialize(); + householdAVModel.runModel(); + + + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelTripUtilityDMU.java b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelTripUtilityDMU.java new file mode 100644 index 0000000..fa1c6bb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelTripUtilityDMU.java @@ -0,0 +1,101 @@ +package org.sandag.abm.maas; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + */ +public class HouseholdAVAllocationModelTripUtilityDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(HouseholdAVAllocationModelTripUtilityDMU.class); + + protected HashMap methodIndexMap; + + private IndexValues dmuIndex; + int timeTrip; //trip period + + public HouseholdAVAllocationModelTripUtilityDMU() + { + dmuIndex = new IndexValues(); + setupMethodIndexMap(); + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + } + + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + methodIndexMap.put("getTimeTrip", 1); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 1: + return getTimeTrip(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public int getTimeTrip() { + return timeTrip; + } + + public void setTimeTrip(int timeTrip) { + this.timeTrip = timeTrip; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelVehicleChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelVehicleChoiceDMU.java new file mode 100644 index 0000000..91373a0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/HouseholdAVAllocationModelVehicleChoiceDMU.java @@ -0,0 +1,212 @@ +package org.sandag.abm.maas; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + */ +public class HouseholdAVAllocationModelVehicleChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(HouseholdAVAllocationModelVehicleChoiceDMU.class); + + protected HashMap methodIndexMap; + + private IndexValues dmuIndex; + int vehicle1IsAvailable; + int vehicle2IsAvailable; + int vehicle3IsAvailable; + int personWithVehicle1; + int personWithVehicle2; + int personWithVehicle3; + float travelUtilityToPersonVeh1; + float travelUtilityToPersonVeh2; + float travelUtilityToPersonVeh3; + float minutesUntilNextTrip; + + public HouseholdAVAllocationModelVehicleChoiceDMU() + { + dmuIndex = new IndexValues(); + setupMethodIndexMap(); + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + } + + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + methodIndexMap.put("getVehicle1IsAvailable",1); + methodIndexMap.put("getVehicle2IsAvailable",2); + methodIndexMap.put("getVehicle3IsAvailable",3); + methodIndexMap.put("getPersonWithVehicle1",4); + methodIndexMap.put("getPersonWithVehicle2",5); + methodIndexMap.put("getPersonWithVehicle3",6); + methodIndexMap.put("getTravelUtilityToPersonVeh1",7); + methodIndexMap.put("getTravelUtilityToPersonVeh2",8); + methodIndexMap.put("getTravelUtilityToPersonVeh3",9); + methodIndexMap.put("getMinutesUntilNextTrip",10); + + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 1: + return getVehicle1IsAvailable(); + case 2: + return getVehicle2IsAvailable(); + case 3: + return getVehicle3IsAvailable(); + case 4: + return getPersonWithVehicle1(); + case 5: + return getPersonWithVehicle2(); + case 6: + return getPersonWithVehicle3(); + case 7: + return getTravelUtilityToPersonVeh1(); + case 8: + return getTravelUtilityToPersonVeh2(); + case 9: + return getTravelUtilityToPersonVeh3(); + case 10: + return getMinutesUntilNextTrip(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + + + + public float getTravelUtilityToPersonVeh1() { + return travelUtilityToPersonVeh1; + } + + public void setTravelUtilityToPersonVeh1(float travelUtilityToPersonVeh1) { + this.travelUtilityToPersonVeh1 = travelUtilityToPersonVeh1; + } + + public float getTravelUtilityToPersonVeh2() { + return travelUtilityToPersonVeh2; + } + + public void setTravelUtilityToPersonVeh2(float travelUtilityToPersonVeh2) { + this.travelUtilityToPersonVeh2 = travelUtilityToPersonVeh2; + } + + public float getTravelUtilityToPersonVeh3() { + return travelUtilityToPersonVeh3; + } + + public void setTravelUtilityToPersonVeh3(float travelUtilityToPersonVeh3) { + this.travelUtilityToPersonVeh3 = travelUtilityToPersonVeh3; + } + + public int getVehicle1IsAvailable() { + return vehicle1IsAvailable; + } + + public void setVehicle1IsAvailable(int vehicle1IsAvailable) { + this.vehicle1IsAvailable = vehicle1IsAvailable; + } + + public int getVehicle2IsAvailable() { + return vehicle2IsAvailable; + } + + public void setVehicle2IsAvailable(int vehicle2IsAvailable) { + this.vehicle2IsAvailable = vehicle2IsAvailable; + } + + public int getVehicle3IsAvailable() { + return vehicle3IsAvailable; + } + + public void setVehicle3IsAvailable(int vehicle3IsAvailable) { + this.vehicle3IsAvailable = vehicle3IsAvailable; + } + + public int getPersonWithVehicle1() { + return personWithVehicle1; + } + + public void setPersonWithVehicle1(int personWithVehicle1) { + this.personWithVehicle1 = personWithVehicle1; + } + + public int getPersonWithVehicle2() { + return personWithVehicle2; + } + + public void setPersonWithVehicle2(int personWithVehicle2) { + this.personWithVehicle2 = personWithVehicle2; + } + + public int getPersonWithVehicle3() { + return personWithVehicle3; + } + + public void setPersonWithVehicle3(int personWithVehicle3) { + this.personWithVehicle3 = personWithVehicle3; + } + + public float getMinutesUntilNextTrip() { + return minutesUntilNextTrip; + } + + public void setMinutesUntilNextTrip(float minutesUntilNextTrip) { + this.minutesUntilNextTrip = minutesUntilNextTrip; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/PersonTrip.java b/sandag_abm/src/main/java/org/sandag/abm/maas/PersonTrip.java new file mode 100644 index 0000000..b1e0c6a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/PersonTrip.java @@ -0,0 +1,277 @@ +package org.sandag.abm.maas; + +/** + * A holder class for trips. + * @author joel.freedman + * + */ +class PersonTrip implements Comparable, Cloneable{ + protected String uniqueId; + protected long hhid; + protected long personId; + protected int personNumber; + protected int tourid; + protected int stopid; + protected int inbound; + protected int joint; + + protected int originMaz; + protected int destinationMaz; + protected short departPeriod; + protected float departTime; //minutes after 3 AM + protected float sampleRate; + protected int mode; + protected int parkingMaz; + protected byte avAvailable; + protected boolean rideSharer; + protected int pickupMaz; + protected int dropoffMaz; + + public PersonTrip(String uniqueId,long hhid,long personId,int personNumber, int tourid,int stopid,int inbound,int joint,int originMaz, int destinationMaz, int departPeriod, float departTime, float sampleRate, int mode, int boardingTap, int alightingTap, int set, boolean rideSharer){ + this.uniqueId = uniqueId; + this.hhid = hhid; + this.personId = personId; + this.personNumber = personNumber; + this.tourid = tourid; + this.stopid = stopid; + this.inbound = inbound; + this.joint = joint; + + this.originMaz = originMaz; + this.destinationMaz = destinationMaz; + this.departPeriod = (short) departPeriod; + this.departTime = departTime; + this.sampleRate = sampleRate; + this.mode = mode; + this.rideSharer = rideSharer; + + //set the pickup MAZ to the originMaz and dropoff MAZ to the destinationMaz + this.pickupMaz = originMaz; + this.dropoffMaz = destinationMaz; + + + + + } + + public String getUniqueId() { + return uniqueId; + } + + public void setUniqueId(String uniqueId) { + this.uniqueId = uniqueId; + } + public long getHhid() { + return hhid; + } + + public void setHhid(long hhid) { + this.hhid = hhid; + } + + public long getPersonId() { + return personId; + } + + public void setPersonId(long personId) { + this.personId = personId; + } + + public int getPersonNumber() { + return personNumber; + } + + public void setPersonNumber(int personNumber) { + this.personNumber = personNumber; + } + + public int getTourid() { + return tourid; + } + + public void setTourid(int tourid) { + this.tourid = tourid; + } + + public int getStopid() { + return stopid; + } + + public void setStopid(int stopid) { + this.stopid = stopid; + } + + public int getInbound() { + return inbound; + } + + public void setInbound(int inbound) { + this.inbound = inbound; + } + + public int getJoint() { + return joint; + } + + public void setJoint(int joint) { + this.joint = joint; + } + + public int getOriginMaz() { + return originMaz; + } + + public void setOriginMaz(int originMaz) { + this.originMaz = originMaz; + } + + public int getPickupMaz() { + return pickupMaz; + } + + public void setPickupMaz(int pickupMaz) { + this.pickupMaz = pickupMaz; + } + + public int getDestinationMaz() { + return destinationMaz; + } + + public void setDestinationMaz(int destinationMaz) { + this.destinationMaz = destinationMaz; + } + + public int getDropoffMaz() { + return dropoffMaz; + } + + public void setDropoffMaz(int dropoffMaz) { + this.dropoffMaz = dropoffMaz; + } + + public short getDepartPeriod() { + return departPeriod; + } + + public void setDepartPeriod(short departPeriod) { + this.departPeriod = departPeriod; + } + + public float getDepartTime() { + return departTime; + } + + public void setDepartTime(float departTime) { + this.departTime = departTime; + } + + public float getSampleRate() { + return sampleRate; + } + + public void setSampleRate(float sampleRate) { + this.sampleRate = sampleRate; + } + + public int getMode() { + return mode; + } + + public void setMode(int mode) { + this.mode = mode; + } + + + public int getParkingMaz() { + return parkingMaz; + } + + public void setParkingMaz(int parkingMaz) { + this.parkingMaz = parkingMaz; + } + + public int getAvAvailable() { + return avAvailable; + } + + public void setAvAvailable(byte avAvailable) { + this.avAvailable = avAvailable; + } + + public boolean isRideSharer() { + return rideSharer; + } + + public void setRideSharer(boolean rideSharer) { + this.rideSharer=rideSharer; + } + + + /** + * Compare based on departure time. + */ + public int compareTo(Object aThat) { + final int BEFORE = -1; + final int EQUAL = 0; + final int AFTER = 1; + + final PersonTrip that = (PersonTrip)aThat; + + //primitive numbers follow this form + if (this.departTime < that.departTime) return BEFORE; + if (this.departTime > that.departTime) return AFTER; + + return EQUAL; + } + + /** + * Override equals. + */ + public boolean equals(Object aThat){ + final PersonTrip that = (PersonTrip)aThat; + + if(this.uniqueId.compareTo(that.getUniqueId())==0) + return true; + + return false; + } + + + /** + * If this trip and thatTrip are both joint trips from the same travel party, return true, else return false + * the comparison is done based on uniqueID, where the end of the unique id is the participant number, + * for example "_1" versus "_2". The method compares the part of the unique ID before the participant number, + * and returns true if they are the same. + * + * @param thatTrip + * @return True if both from same party, else false + */ + public boolean sameParty(PersonTrip thatTrip) { + + if(joint==0) + return false; + + if(thatTrip.getJoint()==0) + return false; + + int lastIndex = uniqueId.lastIndexOf("_"); + String thisUniqueIdMinusParticipantID = uniqueId.substring(0, lastIndex); + + lastIndex = thatTrip.getUniqueId().lastIndexOf("_"); + String thatUniqueIdMinusParticipantID = thatTrip.getUniqueId().substring(0, lastIndex); + + if(thisUniqueIdMinusParticipantID.compareTo(thatUniqueIdMinusParticipantID)==0) + return true; + + return false; + + } + + public Object clone() throws + CloneNotSupportedException + { + PersonTrip trip = (PersonTrip) super.clone(); + trip.uniqueId= new String(); + return trip; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/PersonTripManager.java b/sandag_abm/src/main/java/org/sandag/abm/maas/PersonTripManager.java new file mode 100644 index 0000000..5cffb2c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/PersonTripManager.java @@ -0,0 +1,1087 @@ +package org.sandag.abm.maas; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Collection; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; + +public class PersonTripManager { + + protected static final Logger logger = Logger.getLogger(PersonTripManager.class); + protected HashMap propertyMap = null; + protected MersenneTwister random; + protected ModelStructure modelStructure; + protected HashMap personTripMap; + protected ArrayList[][] personTripArrayByDepartureBinAndMaz; //an array of PersonTrips by departure time increment and origin MAZ. + protected ArrayList[] personTripArrayByDepartureBin; //an array of PersonTrips by departure time increment + protected double[] endTimeMinutes; // the period end time in number of minutes past 3 AM , starting in period 1 (index 1) + protected int iteration; + protected MgraDataManager mgraManager; + protected TazDataManager tazManager; + protected int idNumber; + protected int[] modesToKeep; + protected int[] rideShareEligibleModes; + protected int numberOfTimeBins; + protected int periodLengthInMinutes; + protected int minTaz; //the minimum taz number with mazs; any origin or destination person trip less than this will be skipped. + protected float maxWalkDistance; + + protected static final String ModelSeedProperty = "Model.Random.Seed"; + protected static final String DirectoryProperty = "Project.Directory"; + protected static final String IndivTripDataFileProperty = "Results.IndivTripDataFile"; + protected static final String JointTripDataFileProperty = "Results.JointTripDataFile"; + protected static final String ModesToKeepProperty = "Maas.RoutingModel.Modes"; + protected static final String SharedEligibleProperty = "Maas.RoutingModel.SharedEligible"; + protected static final String MaxWalkDistance = "Maas.RoutingModel.maxWalkDistance"; + + protected static final String MexResTripDataFileProperty ="crossBorder.trip.output.file"; + protected static final String VisitorTripDataFileProperty ="visitor.trip.output.file"; + protected static final String AirportSANTripDataFileProperty ="airport.SAN.output.file"; + protected static final String AirportCBXTripDataFileProperty ="airport.CBX.output.file"; + protected static final String IETripDataFileProperty ="internalExternal.trip.output.file"; + + + /** + * Constructor. + * + * @param propertyMap + * @param iteration + */ + public PersonTripManager(HashMap propertyMap, int iteration){ + this.iteration = iteration; + this.propertyMap = propertyMap; + + modelStructure = new SandagModelStructure(); + + } + + /** + * Initialize (not done by default). + * Initializes array to simulate actual departure time + * Reads in individual and joint person trips + */ + public void initialize(int periodLengthInMinutes){ + logger.info("Initializing PersonTripManager"); + + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + //find minimum TAZ with mazs + int maxTaz = tazManager.getMaxTaz(); + minTaz = -1; + for(int i=1;i<=maxTaz;++i){ + int[] mazs = tazManager.getMgraArray(i); + + if(mazs==null|| mazs.length==0) + minTaz = Math.max(i, minTaz); + } + + logger.info("Minimum TAZ number is "+minTaz); + logger.info("Maximum TAZ number is "+maxTaz); + + //initialize the end time in minutes (stored in double so no overlap between periods) + endTimeMinutes = new double[40+1]; + endTimeMinutes[1]=119.999999; //first period is 3-3:59:99:99 + for(int period=2;period 0, implement hotspots + if(maxWalkDistance>0) + moveRidesharersToHotspots(); + + logger.info("Completed Initializing PersonTripManager"); + + + } + + /** + * Read the input individual and joint trip files. This function calls the method + * @readTripList for each table. This method is called from {@initialize()} + */ + private void readInputFiles(){ + + String directory = Util.getStringValueFromPropertyMap(propertyMap, DirectoryProperty); + String indivTripFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, IndivTripDataFileProperty); + indivTripFile = insertIterationNumber(indivTripFile,iteration); + String jointTripFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, JointTripDataFileProperty); + jointTripFile = insertIterationNumber(jointTripFile,iteration); + + //start with individual trips + TableDataSet indivTripDataSet = readTableData(indivTripFile); + personTripMap = readResidentTripList(personTripMap, indivTripDataSet, false); + int tripsSoFar=personTripMap.size(); + + logger.info("Read "+tripsSoFar+" individual person trips"); + + //now read joint trip data + TableDataSet jointTripDataSet = readTableData(jointTripFile); + personTripMap = readResidentTripList(personTripMap, jointTripDataSet, true); + + logger.info("Read "+(personTripMap.size()-tripsSoFar)+" joint person trips"); + tripsSoFar=personTripMap.size(); + + + String mexicanResidentTripFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, MexResTripDataFileProperty); + TableDataSet mexicanResidentTripDataSet = readTableData(mexicanResidentTripFile); + personTripMap = readMexicanResidentTripList(personTripMap, mexicanResidentTripDataSet); + logger.info("Read "+(personTripMap.size()-tripsSoFar)+" mexican resident person trips"); + tripsSoFar=personTripMap.size(); + + + String visitorTripFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, VisitorTripDataFileProperty); + TableDataSet visitorTripDataSet = readTableData(visitorTripFile); + personTripMap = readVisitorTripList(personTripMap, visitorTripDataSet); + logger.info("Read "+(personTripMap.size()-tripsSoFar)+" visitor person trips"); + tripsSoFar=personTripMap.size(); + + String airportSANTripFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, AirportSANTripDataFileProperty); + TableDataSet airportSANTripDataSet = readTableData(airportSANTripFile); + personTripMap = readAirportTripList(personTripMap, airportSANTripDataSet, -6,"SAN"); + logger.info("Read "+(personTripMap.size()-tripsSoFar)+" SAN airport person trips"); + tripsSoFar=personTripMap.size(); + + String airportCBXTripFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, AirportCBXTripDataFileProperty); + TableDataSet airportCBXTripDataSet = readTableData(airportCBXTripFile); + personTripMap = readAirportTripList(personTripMap, airportCBXTripDataSet, -5,"CBX"); + logger.info("Read "+(personTripMap.size()-tripsSoFar)+" CBX airport person trips"); + tripsSoFar=personTripMap.size(); + + String ieTripFile = directory + + Util.getStringValueFromPropertyMap(propertyMap, IETripDataFileProperty); + TableDataSet ieTripDataSet = readTableData(ieTripFile); + personTripMap = readIETripList(personTripMap, ieTripDataSet); + logger.info("Read "+(personTripMap.size()-tripsSoFar)+" IE person trips"); + tripsSoFar=personTripMap.size(); + + logger.info("Read "+personTripMap.size()+" total person trips"); + + } + + /** + * Read the CTRAMP trip list in the TableDataSet. + * + * @param personTripList A HashMap of PersonTrips. If null will be instantiated in this method. + * @param inputTripTableData The TableDataSet containing the CT-RAMP output trip file. + * @param jointTripData A boolean indicating whether the data is for individual or joint trips. + */ + public HashMap readResidentTripList(HashMap personTripMap, TableDataSet inputTripTableData, boolean jointTripData){ + + if(personTripMap==null) + personTripMap = new HashMap(); + + for(int row = 1; row <= inputTripTableData.getRowCount();++row){ + + + int mode = (int) inputTripTableData.getValueAt(row,"trip_mode"); + if(modesToKeep[mode]!=1) + continue; + + boolean rideShare=false; + if(rideShareEligibleModes[mode]==1) + rideShare=true; + + int oMaz = (int) inputTripTableData.getValueAt(row,"orig_mgra"); + int dMaz = (int) inputTripTableData.getValueAt(row,"dest_mgra"); + + int oTaz = mgraManager.getTaz(oMaz); + int dTaz = mgraManager.getTaz(dMaz); + + if((oTaz1) { + personTrip.setJoint(1); + personTrip.setUniqueId(uniqueID+"_1"); + } + personTripMap.put(idNumber, personTrip); + + //replicate joint trips + if(num_participants>1) + for(int i=2;i<=num_participants;++i){ + ++idNumber; + PersonTrip newTrip = null; + try { + newTrip = (PersonTrip) personTrip.clone(); + }catch(Exception e) { + + logger.fatal("Error attempting to clone joint trip object "+uniqueID); + throw new RuntimeException(e); + } + newTrip.setUniqueId(uniqueID+"_"+i); + personTripMap.put(idNumber, newTrip); + } + } + + return personTripMap; + } + + + /** + * Read the visitor trip list in the TableDataSet. + * + * @param personTripList A HashMap of PersonTrips. If null will be instantiated in this method. + * @param inputTripTableData The TableDataSet containing the visitor output trip file. + */ + public HashMap readVisitorTripList(HashMap personTripMap, TableDataSet inputTripTableData){ + + if(personTripMap==null) + personTripMap = new HashMap(); + + for(int row = 1; row <= inputTripTableData.getRowCount();++row){ + + + int mode = (int) inputTripTableData.getValueAt(row,"tripMode"); + if(modesToKeep[mode]!=1) + continue; + + boolean rideShare=false; + if(rideShareEligibleModes[mode]==1) + rideShare=true; + + int oMaz = (int) inputTripTableData.getValueAt(row,"originMGRA"); + int dMaz = (int) inputTripTableData.getValueAt(row,"destinationMGRA"); + + int oTaz = mgraManager.getTaz(oMaz); + int dTaz = mgraManager.getTaz(dMaz); + + if((oTaz1) { + personTrip.setJoint(1); + personTrip.setUniqueId(uniqueID+"_1"); + } + personTripMap.put(idNumber, personTrip); + + //replicate joint trips + if(num_participants>1) + for(int i=2;i<=num_participants;++i){ + ++idNumber; + PersonTrip newTrip = null; + try { + newTrip = (PersonTrip) personTrip.clone(); + }catch(Exception e) { + + logger.fatal("Error attempting to clone joint trip object "+uniqueID); + throw new RuntimeException(e); + } + newTrip.setUniqueId(uniqueID+"_"+i); + personTripMap.put(idNumber, newTrip); + } + + } + + return personTripMap; + } + + /** + * Read the Mexican resident trip list in the TableDataSet. + * + * @param personTripList A HashMap of PersonTrips. If null will be instantiated in this method. + * @param inputTripTableData The TableDataSet containing the visitor output trip file. + */ + public HashMap readMexicanResidentTripList(HashMap personTripMap, TableDataSet inputTripTableData){ + + if(personTripMap==null) + personTripMap = new HashMap(); + + for(int row = 1; row <= inputTripTableData.getRowCount();++row){ + + int mode = (int) inputTripTableData.getValueAt(row,"tripMode"); + if(modesToKeep[mode]!=1) + continue; + + boolean rideShare=false; + if(rideShareEligibleModes[mode]==1) + rideShare=true; + + int oMaz = (int) inputTripTableData.getValueAt(row,"originMGRA"); + int dMaz = (int) inputTripTableData.getValueAt(row,"destinationMGRA"); + + int oTaz = mgraManager.getTaz(oMaz); + int dTaz = mgraManager.getTaz(dMaz); + + if((oTaz1) { + personTrip.setJoint(1); + personTrip.setUniqueId(uniqueID+"_1"); + } + personTripMap.put(idNumber, personTrip); + + //replicate joint trips + if(num_participants>1) + for(int i=2;i<=num_participants;++i){ + ++idNumber; + PersonTrip newTrip = null; + try { + newTrip = (PersonTrip) personTrip.clone(); + }catch(Exception e) { + + logger.fatal("Error attempting to clone joint trip object "+uniqueID); + throw new RuntimeException(e); + } + newTrip.setUniqueId(uniqueID+"_"+i); + personTripMap.put(idNumber, newTrip); + } + + + } + + return personTripMap; + } + + /** + * Read the airport trip list in the TableDataSet. + * + * @param personTripList A HashMap of PersonTrips. If null will be instantiated in this method. + * @param inputTripTableData The TableDataSet containing the visitor output trip file. + */ + public HashMap readAirportTripList(HashMap personTripMap, TableDataSet inputTripTableData, int default_id, String airportCode){ + + if(personTripMap==null) + personTripMap = new HashMap(); + + for(int row = 1; row <= inputTripTableData.getRowCount();++row){ + + int mode = (int) inputTripTableData.getValueAt(row,"tripMode"); + if(modesToKeep[mode]!=1) + continue; + + boolean rideShare=false; + if(rideShareEligibleModes[mode]==1) + rideShare=true; + + int oMaz = (int) inputTripTableData.getValueAt(row,"originMGRA"); + int dMaz = (int) inputTripTableData.getValueAt(row,"destinationMGRA"); + + int oTaz = mgraManager.getTaz(oMaz); + int dTaz = mgraManager.getTaz(dMaz); + + if((oTaz1) { + personTrip.setJoint(1); + personTrip.setUniqueId(uniqueID+"_1"); + + } + personTripMap.put(idNumber, personTrip); + + //replicate joint trips + if(num_participants>1) + for(int i=2;i<=num_participants;++i){ + ++idNumber; + PersonTrip newTrip = null; + try { + newTrip = (PersonTrip) personTrip.clone(); + }catch(Exception e) { + + logger.fatal("Error attempting to clone joint trip object "+uniqueID); + throw new RuntimeException(e); + } + newTrip.setUniqueId(uniqueID+"_"+i); + personTripMap.put(idNumber, newTrip); + } + + + } + + return personTripMap; + } + + + /** + * Read the IE trip list in the TableDataSet. + * + * @param personTripList A HashMap of PersonTrips. If null will be instantiated in this method. + * @param inputTripTableData The TableDataSet containing the visitor output trip file. + */ + public HashMap readIETripList(HashMap personTripMap, TableDataSet inputTripTableData){ + + if(personTripMap==null) + personTripMap = new HashMap(); + + for(int row = 1; row <= inputTripTableData.getRowCount();++row){ + + int mode = (int) inputTripTableData.getValueAt(row,"tripMode"); + if(modesToKeep[mode]!=1) + continue; + + boolean rideShare=false; + if(rideShareEligibleModes[mode]==1) + rideShare=true; + + int oMaz = (int) inputTripTableData.getValueAt(row,"originMGRA"); + int dMaz = (int) inputTripTableData.getValueAt(row,"destinationMGRA"); + + int oTaz = (int) inputTripTableData.getValueAt(row,"originTAZ"); + int dTaz = (int) inputTripTableData.getValueAt(row,"destinationTAZ"); + + if((oTaz1) { + personTrip.setJoint(1); + personTrip.setUniqueId(uniqueID+"_1"); + } + personTripMap.put(idNumber, personTrip); + + //replicate joint trips + if(num_participants>1) + for(int i=2;i<=num_participants;++i){ + ++idNumber; + PersonTrip newTrip = null; + try { + newTrip = (PersonTrip) personTrip.clone(); + }catch(Exception e) { + + logger.fatal("Error attempting to clone joint trip object "+uniqueID); + throw new RuntimeException(e); + } + newTrip.setUniqueId(uniqueID+"_"+i); + personTripMap.put(idNumber, newTrip); + } + + } + + return personTripMap; + } + /** + * Simulate the exact time for the period. + * + * @param period The time period (1->40) + * @return The exact time in double precision (number of minutes past 3 AM) + */ + public float simulateExactTime(int period){ + + double lowerEnd = endTimeMinutes[period-1]; + double upperEnd = endTimeMinutes[period]; + double randomNumber = random.nextDouble(); + + float time = (float) ((upperEnd - lowerEnd) * randomNumber + lowerEnd); + + return time; + } + + /** + * A simple helper function to insert the iteration number into the file name. + * + * @param filename The input file name (ex: inputFile.csv) + * @param iteration The iteration number (ex: 3) + * @return The new string (ex: inputFile_3.csv) + */ + private String insertIterationNumber(String filename, int iteration){ + + String newFileName = filename.replace(".csv", "_"+new Integer(iteration).toString()+".csv"); + return newFileName; + } + + /** + * Read data into inputDataTable tabledataset. + * + */ + private TableDataSet readTableData(String inputFile){ + + TableDataSet tableDataSet = null; + + logger.info("Begin reading the data in file " + inputFile); + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + tableDataSet = csvFile.readFile(new File(inputFile)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + logger.info("End reading the data in file " + inputFile); + + return tableDataSet; + } + + /** + * Go through the person trip list, sort the person trips by departure time and MAZ. + * + */ + @SuppressWarnings("unchecked") + public void groupPersonTripsByDepartureTimePeriodAndOrigin(){ + + numberOfTimeBins = ((24*60)/periodLengthInMinutes); + int maxMaz = mgraManager.getMaxMgra(); + + logger.info("Calculated "+numberOfTimeBins+" simulation periods using a period length of "+periodLengthInMinutes+" minutes"); + personTripArrayByDepartureBinAndMaz = new ArrayList[numberOfTimeBins][maxMaz+1]; + personTripArrayByDepartureBin = new ArrayList[numberOfTimeBins]; + + //initialize + for(int i = 0; i < numberOfTimeBins;++i){ + personTripArrayByDepartureBin[i] = new ArrayList(); + for(int j = 0; j <=maxMaz;++j){ + personTripArrayByDepartureBinAndMaz[i][j] = new ArrayList(); + } + + } + + Collection personTripList = personTripMap.values(); + for(PersonTrip personTrip : personTripList){ + + int originMaz = personTrip.getPickupMaz(); + + float departTime = personTrip.getDepartTime(); + int bin = (int) Math.floor(departTime/((float) periodLengthInMinutes)); + + personTripArrayByDepartureBinAndMaz[bin][originMaz].add(personTrip); + personTripArrayByDepartureBin[bin].add(personTrip); + + + } + } + + + /** + * Get the person trips for the period bin (indexed from 0) and the origin MAZ. + * + * @param periodBin The number of the departure time period bin based on the period length used to group person trips. + * @param maz The number of the origin MAZ. + * + * @return An arraylist of person trips. + */ + public ArrayList getPersonTripsByDepartureTimePeriodAndMaz(int periodBin, int maz){ + + return personTripArrayByDepartureBinAndMaz[periodBin][maz]; + + } + + /** + * Sample a person trip from the array for the given period. REMOVE IT from the person trip arrays. + * + * @param simulationPeriod The simulation period to sample a trip from. + * @param rnum A random number to be used in sampling. + * @return A person trip, or null if the ArrayList is null or empty. + */ + PersonTrip samplePersonTrip(int simulationPeriod, double rnum){ + + ArrayList personTripArray = personTripArrayByDepartureBin[simulationPeriod]; + + if(personTripArray==null) + return null; + + int listSize = personTripArray.size(); + + if(listSize==0) + return null; + + int element = (int) Math.floor(rnum * listSize); + PersonTrip personTrip = personTripArray.get(element); + personTripArrayByDepartureBin[simulationPeriod].remove(personTrip); + personTripArrayByDepartureBinAndMaz[simulationPeriod][personTrip.getPickupMaz()].remove(personTrip); + + return personTrip; + } + + /** + * Sample a person trip from the array for the given period. REMOVE IT from the array. + * + * @param simulationPeriod The period to sample a trip from. + * @param maz The maz to sample a trip from. + * @param rnum A random number to be used in sampling. + * @return A person trip, or null if the ArrayList is null or empty. + */ + PersonTrip samplePersonTrip(int simulationPeriod, int maz, double rnum){ + + ArrayList personTripArray = personTripArrayByDepartureBinAndMaz[simulationPeriod][maz]; + + if(personTripArray==null) + return null; + + int listSize = personTripArray.size(); + + if(listSize==0) + return null; + + int element = (int) Math.floor(rnum * listSize); + PersonTrip personTrip = personTripArray.get(element); + personTripArrayByDepartureBinAndMaz[simulationPeriod][maz].remove(personTrip); + personTripArrayByDepartureBin[simulationPeriod].remove(personTrip); + + return personTrip; + } + + /** + * Check if there are more person trips in this simulation period. + * + * @param simulationPeriod + * @return true if there are more person trips, false if not. + */ + public boolean morePersonTripsInSimulationPeriod(int simulationPeriod){ + ArrayList personTripArray = personTripArrayByDepartureBin[simulationPeriod]; + + if(personTripArray==null) + return false; + + int listSize = personTripArray.size(); + + if(listSize==0) + return false; + + return true; + + } + + /** + * Check if there are more person trips in this simulation period and maz. + * + * @param simulationPeriod + * @return true if there are more person trips, false if not. + */ + public boolean morePersonTripsInSimulationPeriodAndMaz(int simulationPeriod, int maz){ + ArrayList personTripArray = personTripArrayByDepartureBinAndMaz[simulationPeriod][maz]; + + if(personTripArray==null) + return false; + + int listSize = personTripArray.size(); + + if(listSize==0) + return false; + + return true; + + } + /** + * Remove the person trip. + * + * @param trip + * @param simulationPeriod + */ + public void removePersonTrip(PersonTrip trip, int simulationPeriod){ + + int originMaz = trip.getPickupMaz(); + personTripArrayByDepartureBin[simulationPeriod].remove(trip); + personTripArrayByDepartureBinAndMaz[simulationPeriod][originMaz].remove(trip); + + } + + /** + * Pre-process the array of person trips by moving nearby ridesharers to hotspots. + * The algorithm finds the maz in each TAZ and simulation period with the most ridesharers. + * It moves the ridesharers within the maximum walking distance to that MAZ. + */ + public void moveRidesharersToHotspots() { + + logger.info("Hotspots - moving ride-sharers to high demand MAZs"); + + int[] tazs = tazManager.getTazs(); + int maxTaz = tazManager.getMaxTaz(); + + //store the hotspot Maz for each period and taz + int[][] hotspotMazs = new int[numberOfTimeBins][maxTaz+1]; + + //track the number of ridesharers moved + int totalRidesharersMoved = 0; + + for(int simulationPeriod=0;simulationPeriod personTrips = personTripArrayByDepartureBinAndMaz[simulationPeriod][maz]; + if(personTrips==null) + continue; + + //set maz and max ridesharers + if(personTrips.size()>maxRideSharers) { + maxRideSharers= personTrips.size(); + hotspotMaz = maz; + hotspotMazs[simulationPeriod][taz] = hotspotMaz; + } + } // end mazs + + //no mazs with ridesharers in this taz and simulation period + if(maxRideSharers==-1) + continue; + else { + + //get nearby ridesharers and move them to hotspot + ArrayList nearbySharers = findNearbyRideSharersByOriginMaz(hotspotMaz, simulationPeriod, mgraManager.getTaz(hotspotMaz)); + + if(nearbySharers==null) + continue; + + if(nearbySharers.size()==0) + continue; + + // logger.info("TAZ "+taz+": found "+nearbySharers.size()+" to move to hotspot MAZ "+hotspotMaz+" in period "+simulationPeriod); + + //add each ridesharer to the person trip array at the hotspot maz, and remove them from their origin + for(PersonTrip personTrip : nearbySharers) { + int originMaz = personTrip.getOriginMaz(); + personTrip.setPickupMaz(hotspotMaz); + personTripArrayByDepartureBinAndMaz[simulationPeriod][originMaz].remove(personTrip); + personTripArrayByDepartureBinAndMaz[simulationPeriod][hotspotMaz].add(personTrip); + ++ridesharersMoved; + ++totalRidesharersMoved; + } + } + } //end for zones + + + + logger.info("Simulation period "+ simulationPeriod+" moved "+ridesharersMoved+" ridesharers"); + } // end for simulation periods + + //now move dropoffs to hotspot locations + int movedDropoffs = 0; + Collection personTripList = personTripMap.values(); + for(PersonTrip personTrip : personTripList){ + + //skip non-ride shareres + if(!personTrip.isRideSharer()) + continue; + + int destinationMaz = personTrip.getDestinationMaz(); + int destinationTaz = mgraManager.getTaz(destinationMaz); + float departTime = personTrip.getDepartTime(); + int departBin = (int) Math.floor(departTime/((float) periodLengthInMinutes)); + int hotspotMaz = hotspotMazs[departBin][destinationTaz]; + + //no hotspot for this person's destination taz + if(hotspotMaz==0) + continue; + + float distance = ((float) mgraManager.getMgraToMgraWalkDistFrom(destinationMaz,hotspotMaz))/((float)5280.0); + + if(distance==0) + continue; + + //distance between destination and hotspot is less than max walk distance, so move this person + if(distance<=maxWalkDistance) { + personTrip.setDropoffMaz(hotspotMaz); + ++movedDropoffs; + } + } + + logger.info("Hotspots moved "+totalRidesharersMoved+" ride-share pickups and "+movedDropoffs+" dropoffs"); + } + + + + /** + * Cycle through all the MAZs within maximum walk distance of the origin MAZ, and find + * rideshare passengers departing within the same period. Add them to an ArrayList and + * return it. + * + * @param originMaz The origin for searching + * @param simulationPeriod The simulation period + * @return The ArrayList of ridesharers. + */ + public ArrayList findNearbyRideSharersByOriginMaz(int originMaz, int simulationPeriod, int constraintTaz) { + + int[] walkMgras = mgraManager.getMgrasWithinWalkDistanceFrom(originMaz); + + if(walkMgras==null) + return null; + + ArrayList nearbyRideSharers = new ArrayList(); + + //cycle through walk mgras + for(int walkMgra : walkMgras) { + + //skip intrazonal + if(walkMgra==originMaz) + continue; + + if(constraintTaz>0) + if(mgraManager.getTaz(walkMgra)!=constraintTaz) + continue; + + //walk mgra is less than max walk distance + float distance = ((float) mgraManager.getMgraToMgraWalkDistFrom(originMaz,walkMgra))/((float)5280.0); + + if(distance==0) + continue; + if(distance<=maxWalkDistance) { + + ArrayList personTrips = personTripArrayByDepartureBinAndMaz[simulationPeriod][walkMgra]; + + //cycle through person trips in this mgra and add them to the array if they are willing to rideshare + for(PersonTrip personTrip : personTrips) { + + if(personTrip.isRideSharer()) { + nearbyRideSharers.add(personTrip); + } + } + } + } + + return nearbyRideSharers; + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/TNCFleetModel.java b/sandag_abm/src/main/java/org/sandag/abm/maas/TNCFleetModel.java new file mode 100644 index 0000000..66e2cd1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/TNCFleetModel.java @@ -0,0 +1,448 @@ +package org.sandag.abm.maas; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +public class TNCFleetModel { + + private static final Logger logger = Logger.getLogger(TNCFleetModel.class); + private HashMap propertyMap = null; + TransportCostManager transportCostManager; //manages transport costs! + PersonTripManager personTripManager; //manages person trips! + TNCVehicleManager tNCVehicleManager; //manages vehicles! + + private int iteration; + private float sampleRate; + private int minutesPerSimulationPeriod; + private int numberOfSimulationPeriods; + private MersenneTwister random; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private byte maxSharedTNCPassengers; + + MatrixDataServerRmi ms; + private byte[] skimPeriodLookup; //an array indexed by number of periods that corresponds to the skim period + + private boolean routeIntrazonal; + + private static final String MAX_PICKUP_DISTANCE_PROPERTY = "Maas.RoutingModel.maxDistanceForPickup"; + private static final String MAX_PICKUP_DIVERSON_TIME_PROPERTY = "Maas.RoutingModel.maxDiversionTimeForPickup"; + private static final String MINUTES_PER_SIMULATION_PERIOD_PROPERTY = "Maas.RoutingModel.minutesPerSimulationPeriod"; + private static final String MAX_SHARED_TNC_PASSENGERS_PROPERTY = "Maas.RoutingModel.maxPassengers"; + private static final String ROUTE_INTRAZONAL_PROPERTY = "Maas.RoutingModel.routeIntrazonal"; + private static final String MODEL_SEED_PROPERTY = "Model.Random.Seed"; + + int vehicleDebug; + /** + * Constructor. + * + * @param propertyMap + * @param iteration + */ + public TNCFleetModel(HashMap propertyMap, int iteration, float sampleRate){ + this.propertyMap = propertyMap; + this.iteration = iteration; + this.sampleRate = sampleRate; + } + + /** + * Initialize all the data members. + * + */ + public void initialize(){ + + startMatrixServer(propertyMap); + + //managers for MAZ and TAZ data + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + //some controlling properties + float maxPickupDistance = Util.getFloatValueFromPropertyMap(propertyMap, MAX_PICKUP_DISTANCE_PROPERTY); + float maxDiversionTime = Util.getFloatValueFromPropertyMap(propertyMap, MAX_PICKUP_DIVERSON_TIME_PROPERTY); + maxSharedTNCPassengers = (byte) Util.getIntegerValueFromPropertyMap(propertyMap, MAX_SHARED_TNC_PASSENGERS_PROPERTY); + routeIntrazonal = Util.getBooleanValueFromPropertyMap(propertyMap, ROUTE_INTRAZONAL_PROPERTY); + + //set the length of a simulation period + minutesPerSimulationPeriod = Util.getIntegerValueFromPropertyMap(propertyMap, MINUTES_PER_SIMULATION_PERIOD_PROPERTY); + numberOfSimulationPeriods = ((24*60)/minutesPerSimulationPeriod); + logger.info("Running "+numberOfSimulationPeriods+" simulation periods using a period length of "+minutesPerSimulationPeriod+" minutes"); + calculateSkimPeriods(); + + //create a new transport cost manager and create data structures + transportCostManager = new TransportCostManager(propertyMap,maxDiversionTime,maxPickupDistance); + transportCostManager.initialize(); + transportCostManager.calculateTazsByTimeFromOrigin(); + + //create a person trip manager, read person trips + personTripManager = new PersonTripManager(propertyMap, iteration); + personTripManager.initialize(minutesPerSimulationPeriod); + + + //create a tNCVehicle manager + tNCVehicleManager = new TNCVehicleManager(propertyMap, transportCostManager, maxSharedTNCPassengers, minutesPerSimulationPeriod); + tNCVehicleManager.initialize(); + vehicleDebug = tNCVehicleManager.vehicleDebug; + + //seed the random number generator so that results can be replicated if desired. + int seed = Util.getIntegerValueFromPropertyMap(propertyMap, MODEL_SEED_PROPERTY); + random = new MersenneTwister(seed + 4292); + + } + + /** + * Relate simulation periods to skim periods. + * + */ + public void calculateSkimPeriods(){ + + skimPeriodLookup = new byte[numberOfSimulationPeriods]; + int numberSkimPeriods = ModelStructure.SKIM_PERIOD_INDICES.length; + int[] endSkimPeriod = new int[numberSkimPeriods]; + + int lastPeriodEnd = 0; + int lastEndSkimPeriod = 0; + for(int skimPeriod = 0;skimPeriod=0;--skimPeriod){ + if(period pMap; + + logger.info(String.format("TNC Fleet Simulation Program using CT-RAMP version ", + CtrampApplication.VERSION)); + + int iteration=0; + float sampleRate=1; + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else { + propertiesFile = args[0]; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.valueOf(args[i + 1]); + } + + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.valueOf(args[i + 1]); + } + + + + } + } + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + TNCFleetModel fleetModel = new TNCFleetModel(pMap, iteration, sampleRate); + fleetModel.initialize(); + fleetModel.runModel(); + + + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/TNCVehicle.java b/sandag_abm/src/main/java/org/sandag/abm/maas/TNCVehicle.java new file mode 100644 index 0000000..837d3f9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/TNCVehicle.java @@ -0,0 +1,156 @@ +package org.sandag.abm.maas; + +import java.util.ArrayList; + +public class TNCVehicle { + + + protected ArrayList personTripList; + + protected ArrayList tNCVehicleTrips; + protected byte maxPassengers; + protected short generationTaz; + protected short generationPeriod; + protected int id; + protected float maxDistanceBeforeRefuel; + protected float distanceSinceRefuel; + protected int periodsRefueling; + + /** + * Create a new tNCVehicle. + * + * @param id + * @param maxPassengers + * @param maxDistanceBeforeRefuel + */ + public TNCVehicle(int id, byte maxPassengers, float maxDistanceBeforeRefuel){ + this.id= id; + this.maxPassengers = maxPassengers; + personTripList = new ArrayList(); + tNCVehicleTrips = new ArrayList(); + this.maxDistanceBeforeRefuel = maxDistanceBeforeRefuel; + } + + /** + * Add a tNCVehicle trip to this tNCVehicle. + * + * @param tNCVehicleTrip + */ + public void addVehicleTrip(TNCVehicleTrip tNCVehicleTrip){ + tNCVehicleTrips.add(tNCVehicleTrip); + } + + /** + * Add an ArrayList of tNCVehicle trips to this tNCVehicle. + * + * @param tNCVehicleTrips + */ + public void addVehicleTrips(ArrayList tNCVehicleTrips){ + this.tNCVehicleTrips.addAll(tNCVehicleTrips); + } + + /** + * Clear all the person trips from this tNCVehicle. Used after routing the tNCVehicle. + * + */ + public void clearPersonTrips(){ + this.personTripList.clear(); + } + + /** + * Get all the tNCVehicle trips for this tNCVehicle. + * + * @return VehicleTrips + */ + public ArrayList getVehicleTrips(){ + + return tNCVehicleTrips; + } + + /** + * Get the tNCVehicle ID. + * + * @return + */ + public int getId(){ + return this.id; + } + + /** + * Add a passenger to the tNCVehicle. + * + * @param personTrip + */ + public void addPersonTrip(PersonTrip personTrip){ + + personTripList.add(personTrip); + + } + + /** + * Remove one person trip from the tNCVehicle. Used after routing. + * + * @param personTrip + */ + public void removePersonTrip(PersonTrip personTrip){ + + personTripList.remove(personTrip); + } + + /** + * Get number of passengers. + * + * @return The number of passengers + */ + public byte getNumberPassengers(){ + + return (byte) personTripList.size(); + } + + public byte getMaxPassengers() { + return maxPassengers; + } + + public void setMaxPassengers(byte maxPassengers) { + this.maxPassengers = maxPassengers; + } + + public short getGenerationTaz() { + return generationTaz; + } + + public void setGenerationTaz(short generationTaz) { + this.generationTaz = generationTaz; + } + + public short getGenerationPeriod() { + return generationPeriod; + } + + public void setGenerationPeriod(short generationPeriod) { + this.generationPeriod = generationPeriod; + } + + public ArrayList getPersonTripList() { + return personTripList; + } + + public float getDistanceSinceRefuel() { + return distanceSinceRefuel; + } + + public void setDistanceSinceRefuel(float distanceSinceRefuel) { + this.distanceSinceRefuel = distanceSinceRefuel; + } + + public int getPeriodsRefueling() { + return periodsRefueling; + } + + public void setPeriodsRefueling(int periodsRefueling) { + this.periodsRefueling = periodsRefueling; + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/TNCVehicleManager.java b/sandag_abm/src/main/java/org/sandag/abm/maas/TNCVehicleManager.java new file mode 100644 index 0000000..78e411f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/TNCVehicleManager.java @@ -0,0 +1,878 @@ +package org.sandag.abm.maas; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.maas.TNCVehicleTrip.Purpose; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.math.MersenneTwister; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; + +public class TNCVehicleManager { + + protected static final Logger logger = Logger.getLogger(TNCVehicleManager.class); + protected HashMap propertyMap = null; + protected ArrayList[] emptyVehicleList; //by taz + protected ArrayList vehiclesToRouteList; + protected ArrayList activeVehicleList; + protected ArrayList refuelingVehicleList; + + protected MersenneTwister random; + protected static final String MODEL_SEED_PROPERTY = "Model.Random.Seed"; + protected static final String VEHICLETRIP_OUTPUT_FILE_PROPERTY = "Maas.RoutingModel.vehicletrip.output.file"; + protected static final String VEHICLETRIP_OUTPUT_MATRIX_PROPERTY = "Maas.RoutingModel.vehicletrip.output.matrix"; + protected static final String MAX_DISTANCE_BEFORE_REFUEL_PROPERTY = "Maas.RoutingModel.maxDistanceBeforeRefuel"; + protected static final String TIME_REQUIRED_FOR_REFUEL_PROPERTY = "Maas.RoutingModel.timeRequiredForRefuel"; + + + protected String vehicleTripOutputFile; + protected TazDataManager tazManager; + protected MgraDataManager mazManager; + protected int maxTaz; + protected int maxMaz; + protected byte maxPassengers; + protected TransportCostManager transportCostManager; + protected int totalVehicles; + protected int minutesPerSimulationPeriod; + protected int vehicleDebug; + protected int totalVehicleTrips; + private byte[] skimPeriodLookup; //an array indexed by number of periods that corresponds to the skim period + private int numberOfSimulationPeriods; + protected float maxDistanceBeforeRefuel; + protected float timeRequiredForRefuel; + protected int periodsRequiredForRefuel; + protected int[] closestMazWithRefeulingStation ; //the closest MAZ with a refueling station + + // one file per time period + // matrices are indexed by periods, occupants + private Matrix[][] TNCTripMatrix; + + + + + /** + * + * @param propertyMap + * @param transportCostManager + */ + public TNCVehicleManager(HashMap propertyMap, TransportCostManager transportCostManager, byte maxPassengers, int minutesPerSimulationPeriod){ + + this.propertyMap = propertyMap; + this.transportCostManager = transportCostManager; + this.maxPassengers = maxPassengers; + this.minutesPerSimulationPeriod = minutesPerSimulationPeriod; + numberOfSimulationPeriods = ((24*60)/minutesPerSimulationPeriod); + + } + + @SuppressWarnings("unchecked") + public void initialize(){ + + int seed = Util.getIntegerValueFromPropertyMap(propertyMap, MODEL_SEED_PROPERTY); + random = new MersenneTwister(seed + 234324); + + tazManager = TazDataManager.getInstance(); + maxTaz = tazManager.getMaxTaz(); + + mazManager = MgraDataManager.getInstance(); + maxMaz = mazManager.getMaxMgra(); + + emptyVehicleList = new ArrayList[maxTaz+1]; + + activeVehicleList = new ArrayList(); + vehiclesToRouteList = new ArrayList(); + refuelingVehicleList = new ArrayList(); + + String directory = Util.getStringValueFromPropertyMap(propertyMap, "Project.Directory"); + vehicleTripOutputFile = directory + Util.getStringValueFromPropertyMap(propertyMap, VEHICLETRIP_OUTPUT_FILE_PROPERTY); + + maxDistanceBeforeRefuel = Util.getFloatValueFromPropertyMap(propertyMap, MAX_DISTANCE_BEFORE_REFUEL_PROPERTY); + timeRequiredForRefuel = Util.getFloatValueFromPropertyMap(propertyMap, TIME_REQUIRED_FOR_REFUEL_PROPERTY); + periodsRequiredForRefuel = (int) Math.ceil(timeRequiredForRefuel/minutesPerSimulationPeriod); + + vehicleDebug = 1; + + calculateClosestRefuelingMazs(); + + calculateSkimPeriods(); + + //initialize the matrices for writing trips + int maxTaz = tazManager.getMaxTaz(); + int[] tazIndex = new int[maxTaz + 1]; + + // assume zone numbers are sequential + for (int i = 1; i < tazIndex.length; ++i) + tazIndex[i] = i; + + TNCTripMatrix = new Matrix[transportCostManager.NUM_PERIODS][]; + + for(int i =0;i0){ + + TNCVehicle tNCVehicle = null; + double rnum = random.nextDouble(); + tNCVehicle = getRandomVehicleFromList(emptyVehicleList[taz], rnum); + + //generate an empty trip for the tNCVehicle + ArrayList trips = tNCVehicle.getVehicleTrips(); + + if(trips.size()==0){ + logger.warn("Weird: got an empty tNCVehicle (id:"+tNCVehicle.getId()+") but no trips in tNCVehicle trip list"); + return tNCVehicle; + } + + TNCVehicleTrip lastTrip = trips.get(trips.size()-1); + int originTaz = lastTrip.getDestinationTaz(); + int originMaz = lastTrip.getDestinationMaz(); + ArrayList pickupIdsAtOrigin = lastTrip.getPickupIdsAtDestination(); + ArrayList dropoffIdsAtOrigin = lastTrip.getDropoffIdsAtDestination(); + + ++totalVehicleTrips; + TNCVehicleTrip newTrip = new TNCVehicleTrip(tNCVehicle,totalVehicleTrips); + + newTrip.setOriginMaz(originMaz); + newTrip.setOriginTaz((short) originTaz); + newTrip.setDestinationMaz(departureMaz); + newTrip.setDestinationTaz((short)departureTaz); + newTrip.setStartPeriod(simulationPeriod); + newTrip.setEndPeriod(simulationPeriod); //instantaneous arrivals? Need traveling tNCVehicle queue... + if(lastTrip.getDestinationPurpose()==TNCVehicleTrip.Purpose.REFUEL) + newTrip.setOriginPurpose(TNCVehicleTrip.Purpose.REFUEL); + else { + newTrip.setPickupIdsAtOrigin(pickupIdsAtOrigin); + newTrip.setDropoffIdsAtOrigin(dropoffIdsAtOrigin); + } + newTrip.setDestinationPurpose(TNCVehicleTrip.Purpose.PICKUP_ONLY); + tNCVehicle.addVehicleTrip(newTrip); + + return tNCVehicle; + } + + } + + //Iterated through all TAZs, could not find an empty tNCVehicle. Return a new tNCVehicle. + return generateVehicle(simulationPeriod, departureTaz); + } + + /** + * Get a tNCVehicle at random from the arraylist of vehicles, remove it from the list, and return it. + * + * @param emptyVehicleList + * @param rnum a random number used to draw a tNCVehicle from the list. + * @return The tNCVehicle chosen. + */ + private TNCVehicle getRandomVehicleFromList(ArrayList vehicleList, double rnum){ + + + if(vehicleList==null) + return null; + + int listSize = vehicleList.size(); + int element = (int) Math.floor(rnum * listSize); + TNCVehicle tNCVehicle = vehicleList.get(element); + vehicleList.remove(element); + return tNCVehicle; + + } + + /** + * Encapsulating in method so that vehicles and some statistics can be tracked. + */ + private synchronized TNCVehicle generateVehicle(int simulationPeriod, int taz){ + ++totalVehicles; + TNCVehicle tNCVehicle = new TNCVehicle(totalVehicles, maxPassengers, maxDistanceBeforeRefuel); + tNCVehicle.setGenerationPeriod((short)simulationPeriod); + tNCVehicle.setGenerationTaz((short) taz); + return tNCVehicle; + + } + + public int getTotalVehicles(){ + return totalVehicles; + } + + /** + * Add empty tNCVehicle to the empty tNCVehicle list. + * + * @param tNCVehicle + * @param taz + */ + public void storeEmptyVehicle(TNCVehicle tNCVehicle, int taz){ + + if(emptyVehicleList[taz] == null) + emptyVehicleList[taz] = new ArrayList(); + + emptyVehicleList[taz].add(tNCVehicle); + + } + + public void addActiveVehicle(TNCVehicle tNCVehicle){ + + activeVehicleList.add(tNCVehicle); + } + + public void addVehicleToRoute(TNCVehicle tNCVehicle){ + + ArrayList personTrips = tNCVehicle.getPersonTripList(); + if(personTrips.size()==0){ + logger.info("Adding tNCVehicle "+tNCVehicle.getId()+" to vehicles to route list but no person trips"); + throw new RuntimeException(); + } + vehiclesToRouteList.add(tNCVehicle); + } + + /** + * All active vehicles are assigned passengers, now they must be routed through all pickups and dropoffs. + * THe method iterates through the vehiclesToRouteList and adds passengers based on the out-direction + * time required to pick them up and drop them off. + * + * @param skimPeriod + * @param simulationPeriod + * @param transportCostManager + */ + public synchronized void routeActiveVehicles(int skimPeriod, int simulationPeriod, TransportCostManager transportCostManager){ + + logger.info("Routing "+vehiclesToRouteList.size()+" vehicles in period "+simulationPeriod); + ArrayList vehiclesToRemove = new ArrayList(); + + + //iterate through vehicles to route list + for(TNCVehicle tNCVehicle: vehiclesToRouteList){ + + // get the person list, if it is empty throw a warning (should never be empty) + ArrayList personTrips = tNCVehicle.getPersonTripList(); + if(personTrips==null||personTrips.size()==0){ + logger.error("Attempting to route empty tNCVehicle "+tNCVehicle.getId()); + } + + if(tNCVehicle.getId()==vehicleDebug){ + logger.info("***********************************************************************************"); + logger.info("Debugging Vehicle routing for vehicle ID "+tNCVehicle.getId()); + logger.info("***********************************************************************************"); + logger.info("There are "+personTrips.size()+" person trips in vehicle ID "+tNCVehicle.getId()); + for(PersonTrip pTrip: personTrips){ + logger.info("Vehicle ID "+tNCVehicle.getId()+" person trip id: "+pTrip.getUniqueId()+" from pickup MAZ: "+pTrip.getPickupMaz()+ " to dropoff MAZ "+pTrip.getDropoffMaz()); + } + } + //some information on the first passenger + PersonTrip firstTrip = personTrips.get(0); + int firstOriginMaz = firstTrip.getPickupMaz(); + int firstOriginTaz = mazManager.getTaz(firstOriginMaz); + int firstDestinationMaz = firstTrip.getDropoffMaz(); + int firstDestinationTaz = mazManager.getTaz(firstDestinationMaz); + + // get the arraylist of tNCVehicle trips for this tNCVehicle + ArrayList existingVehicleTrips = tNCVehicle.getVehicleTrips(); + ArrayList newVehicleTrips = new ArrayList(); + + if(tNCVehicle.getId()==vehicleDebug) + logger.info("There are "+existingVehicleTrips.size()+" existing vehicle trips in vehicle ID "+tNCVehicle.getId()); + + //iterate through person list and save HashMap of other passenger pickups and dropoffs by MAZ + HashMap> pickupsByMaz = new HashMap>(); + HashMap> dropoffsByMaz = new HashMap>(); + + //save the dropoff location of the first passenger in the dropoffsByMaz array (the pickup location must be the trip origin) + ArrayList firstDropoffArray = new ArrayList(); + firstDropoffArray.add(personTrips.get(0)); + dropoffsByMaz.put(firstDestinationMaz, firstDropoffArray); + + //iterate through the rest of the person trips other than the first passenger + for(int i = 1; i < personTrips.size();++i){ + + PersonTrip personTrip = personTrips.get(i); + + int pickupMaz = personTrip.getPickupMaz(); + int dropoffMaz = personTrip.getDropoffMaz(); + + //only add pickup maz for passengers other than first passenger + if(!pickupsByMaz.containsKey(pickupMaz) ){ + ArrayList pickups = new ArrayList(); + pickups.add(personTrip); + pickupsByMaz.put(pickupMaz,pickups); + }else{ + ArrayList pickups = pickupsByMaz.get(pickupMaz); + pickups.add(personTrip); + pickupsByMaz.put(pickupMaz,pickups); + } + + if(!dropoffsByMaz.containsKey(dropoffMaz)){ + ArrayList dropoffs = new ArrayList(); + dropoffs.add(personTrip); + dropoffsByMaz.put(dropoffMaz,dropoffs); + }else{ + ArrayList dropoffs = dropoffsByMaz.get(dropoffMaz); + dropoffs.add(personTrip); + dropoffsByMaz.put(dropoffMaz,dropoffs); + } + } + + if(tNCVehicle.getId()==vehicleDebug){ + logger.info("There are "+pickupsByMaz.size()+" pickup mazs in vehicle ID "+tNCVehicle.getId()); + logger.info("There are "+dropoffsByMaz.size()+" dropoff mazs in vehicle ID "+tNCVehicle.getId()); + } + + // the list of TAZs in order from closest to furthest, that will determine tNCVehicle routing. + // any TAZ in the list with an origin or destination by a passenger will be visited. + short[] tazs = transportCostManager.getZonesWithinMaxDiversionTime(skimPeriod, firstOriginTaz, firstDestinationTaz); + + //create a new tNCVehicle trip, and populate it with information from the first passenger + ++totalVehicleTrips; + TNCVehicleTrip trip = new TNCVehicleTrip(tNCVehicle,totalVehicleTrips); + trip.setStartPeriod(simulationPeriod); + trip.addPickupAtOrigin(firstTrip.getUniqueId()); + trip.setOriginMaz(firstOriginMaz); + trip.setOriginTaz((short) firstOriginTaz); + trip.setPassengers(1); + + //iterate through tazs sorted by time from first passenger's origin, and + //assign person trips to pickup and dropoff arrays based on diversion time. + for(int i=0;i pickups = pickupsByMaz.get(maz); + for(int p = 0; p< pickups.size();++p){ + PersonTrip pTrip = pickups.get(p); + trip.addPickupAtDestination(pTrip.getUniqueId()); + } + } + + //there are dropoffs in this maz + if(dropoffsByMaz.containsKey(maz)){ + ArrayList dropoffs = dropoffsByMaz.get(maz); + for(int p = 0; p< dropoffs.size();++p){ + PersonTrip pTrip = dropoffs.get(p); + trip.addDropoffAtDestination(pTrip.getUniqueId()); + + //remove this person trip from the list of persons in this tNCVehicle since they are getting dropped off. + tNCVehicle.removePersonTrip(pTrip); + + } + } + + // this is not the first tNCVehicle trip for this tNCVehicle. So we need to find the last tNCVehicle trip + // occupancy and destination pickups and dropoffs to set the trip occupancy and origin pickups & dropoffs accordingly. + int lastTripPassengers=0; + TNCVehicleTrip lastTrip = null; + if(newVehicleTrips.size()==0 && existingVehicleTrips.size()>0){ + lastTrip = existingVehicleTrips.get(existingVehicleTrips.size()-1); + }else if(newVehicleTrips.size()>0){ + lastTrip = newVehicleTrips.get(newVehicleTrips.size()-1); + } + //set the origin and other values for the trip + if(lastTrip!=null){ + lastTripPassengers = lastTrip.getPassengers(); + ArrayList dropoffsAtDestinationOfLastTrip = lastTrip.getDropoffIdsAtDestination(); + ArrayList pickupsAtDestinationOfLastTrip = lastTrip.getPickupIdsAtDestination(); + + //add pickups and dropoffs at origin from last trip + trip.addDropoffIdsAtOrigin(dropoffsAtDestinationOfLastTrip); + trip.addPickupIdsAtOrigin(pickupsAtDestinationOfLastTrip); + + //add pickup and dropoffs at origin of this trip to destination of last trip. (commenting to test write problem) + //lastTrip.addDropoffIdsAtDestination(trip.getDropoffIdsAtOrigin()); + //lastTrip.addPickupIdsAtDestination(trip.getPickupIdsAtOrigin()); + + + + } + + int passengers = lastTripPassengers + trip.getNumberOfPickupsAtOrigin() - trip.getNumberOfDropoffsAtOrigin(); + trip.setPassengers(passengers); + trip.setDestinationMaz(maz); + trip.setDestinationTaz((short) tazs[i]); + + //measure time from first trip to destination (current) or track time in tNCVehicle explicitly for each trip? + float time = transportCostManager.getTime(skimPeriod, firstOriginTaz, trip.getDestinationTaz()); + float periods = time/(float)minutesPerSimulationPeriod; + int endPeriod = (int) Math.floor(simulationPeriod + periods); //currently measuring time as simulation period + straight time to dest. + trip.setEndPeriod(endPeriod); + + //measure distance for current trip origin and destination + float distance = transportCostManager.getDistance(skimPeriod, trip.getOriginTaz(), trip.getDestinationTaz()); + trip.setDistance(distance); + tNCVehicle.setDistanceSinceRefuel(tNCVehicle.getDistanceSinceRefuel()+distance); + + if(tNCVehicle.getId()==vehicleDebug){ + logger.info("Vehicle ID "+tNCVehicle.getId()+" now has vehicle trip ID "+trip.getId()); + trip.writeTrace(); + } + + newVehicleTrips.add(trip); + + //more trips to go! + if(tNCVehicle.getPersonTripList().size()>0){ + ++totalVehicleTrips; + TNCVehicleTrip newTrip = new TNCVehicleTrip(tNCVehicle,totalVehicleTrips); + newTrip.setOriginMaz(maz); + newTrip.setOriginTaz((short) tazs[i]); + newTrip.setStartPeriod(trip.getEndPeriod()); + trip = newTrip; + } + + } //end mazs + + } //end tazs + + //add tNCVehicle trips to tNCVehicle + tNCVehicle.addVehicleTrips(newVehicleTrips); + + //add tNCVehicle to active vehicles + activeVehicleList.add(tNCVehicle); + + //track tNCVehicle in vehicles to remove from route list. + vehiclesToRemove.add(tNCVehicle); + } //end vehicles + + //Remove vehicles that have been routed + vehiclesToRouteList.removeAll(vehiclesToRemove); + } + + /** + * Free vehicles from the active tNCVehicle list and put them in the free tNCVehicle list if + * the last trip in the tNCVehicle ends in the current simulation period. + * + * @param simulationPeriod + */ + public void freeVehicles(int simulationPeriod){ + + int freedVehicles=0; + + //no active vehicles in the simulation period + if(activeVehicleList.size()==0){ + logger.warn("Trying to free vehicles from active vehicle list in simulation period "+simulationPeriod+" but there are no active vehicles."); + }else{ + logger.info("There are "+activeVehicleList.size()+" active vehicles in period "+simulationPeriod); + } + + //track the vehicles to remove + ArrayList vehiclesToRemove = new ArrayList(); + // go through active vehicles (vehicles that have been routed and are picking up/dropping off passengers) + for(int i = 0; i< activeVehicleList.size();++i){ + TNCVehicle tNCVehicle = activeVehicleList.get(i); + + ArrayList trips = tNCVehicle.getVehicleTrips(); + + //this tNCVehicle has no trips; why is it in the active tNCVehicle list?? + if(trips.size()==0){ + logger.error("Vehicle ID "+tNCVehicle.getId()+" has no vehicle trips but is in active vehicle list"); + continue; + } + + //Find out when the last dropoff occurs (the end period of the last trip) + TNCVehicleTrip lastTrip = trips.get(trips.size()-1); + if(lastTrip.endPeriod==simulationPeriod){ + int taz = lastTrip.getDestinationTaz(); + vehiclesToRemove.add(tNCVehicle); + ++freedVehicles; + + //store the empty tNCVehicle in the last dropoff location (the last trip destination TAZ) + if(emptyVehicleList[taz]==null) + emptyVehicleList[taz]= new ArrayList(); + + emptyVehicleList[taz].add(tNCVehicle); + } + } + activeVehicleList.removeAll(vehiclesToRemove); + logger.info("Freed "+freedVehicles+" vehicles from active tNCVehicle list"); + logger.info("There are now "+activeVehicleList.size()+" vehicles in the active tNCVehicle list"); + } + + + /** + * First find vehicles that need to refuel, generate a trip to the closest refueling station, then + * remove them from the empty tNCVehicle list, and add them to the refueling tNCVehicle list. + * Next, for all refueling vehicles, check if they are done refueling, and if so, remove them + * from the refueling list and add them to the empty tNCVehicle list. + * + * @param skimPeriod + * @param simulationPeriod + */ + public synchronized void checkForRefuelingVehicles(int skimPeriod, int simulationPeriod) { + + //iterate through zones + for(int i = 1; i <= maxTaz; ++ i){ + if(emptyVehicleList[i]==null) + continue; + + //track the vehicles to remove + ArrayList vehiclesToRemove = new ArrayList(); + + //iterate through vehicles in this zone + for(TNCVehicle tNCVehicle : emptyVehicleList[i]) { + + //if distance since refueling is greater than max, generate a new trip to the closest refueling station. + if(tNCVehicle.getDistanceSinceRefuel()>=maxDistanceBeforeRefuel) { + + ArrayList currentTrips = tNCVehicle.getVehicleTrips(); + TNCVehicleTrip lastTrip = currentTrips.get(currentTrips.size()-1); + + TNCVehicleTrip trip = new TNCVehicleTrip(tNCVehicle,totalVehicleTrips+1); + trip.setStartPeriod(lastTrip.endPeriod); + trip.setOriginMaz(lastTrip.destinationMaz); + trip.setOriginTaz(lastTrip.originTaz); + trip.setPassengers(0); + trip.setOriginPurpose(lastTrip.destinationPurpose); + trip.setDestinationPurpose(Purpose.REFUEL); + + int refeulingMaz = closestMazWithRefeulingStation[trip.getOriginMaz()]; + trip.setDestinationMaz(refeulingMaz); + trip.setDestinationTaz((short) mazManager.getTaz(refeulingMaz)); + float time = transportCostManager.getTime(skimPeriod, trip.getOriginTaz(), trip.getDestinationTaz() ); + float distance = transportCostManager.getDistance(skimPeriod, trip.getOriginTaz(), trip.getDestinationTaz()); + float periods = time/(float)minutesPerSimulationPeriod; + int endPeriod = (int) Math.floor(simulationPeriod + periods); + trip.setEndPeriod(endPeriod); + trip.setDistance(distance); + + //add the tNCVehicle trip to the tNCVehicle + tNCVehicle.addVehicleTrip(trip); + + vehiclesToRemove.add(tNCVehicle); + + if(tNCVehicle.getId()==vehicleDebug) { + logger.info("*************"); + logger.info("Vehicle ID "+tNCVehicle.getId()+" refueling trip generated"); + logger.info("From origin MAZ "+trip.getOriginMaz()+" to refueling MAZ "+trip.getDestinationMaz()+" in TAZ "+trip.getDestinationTaz()); + logger.info("Start period "+trip.getStartPeriod()+" end period "+trip.getEndPeriod()); + logger.info("*************"); + + } + + } + + } + //remove all the refueling vehicles from the empty tNCVehicle list + emptyVehicleList[i].removeAll(vehiclesToRemove); + + //add them to the refueling tNCVehicle list + refuelingVehicleList.addAll(vehiclesToRemove); + } + + //track the vehicles to remove + ArrayList vehiclesToRemove = new ArrayList(); + + //iterate through the refueling vehicles + for(TNCVehicle tNCVehicle : refuelingVehicleList ) { + + ArrayList currentTrips = tNCVehicle.getVehicleTrips(); + TNCVehicleTrip lastTrip = currentTrips.get(currentTrips.size()-1); + + //trip is not refueling + if(lastTrip.destinationPurpose!=Purpose.REFUEL) + continue; + + //trip is still en-route to refueling + if(lastTrip.endPeriod>simulationPeriod) + continue; + + + //if its been refueling for appropriate periods, add to empty tNCVehicle list and remove it from the refueling tNCVehicle list + if(tNCVehicle.periodsRefueling==periodsRequiredForRefuel) { + tNCVehicle.setDistanceSinceRefuel(0); + vehiclesToRemove.add(tNCVehicle); + short refuelTaz = lastTrip.destinationTaz; + + if(emptyVehicleList[refuelTaz] == null) + emptyVehicleList[refuelTaz] = new ArrayList(); + + emptyVehicleList[refuelTaz].add(tNCVehicle); + + if(tNCVehicle.getId()==vehicleDebug) { + logger.info("*************"); + logger.info("Vehicle ID "+tNCVehicle.getId()+" has completed refueling in period "+simulationPeriod); + logger.info("Distance to refuel is reset to 0 and vehicle added to empty vehicle list in TAZ "+refuelTaz); + logger.info("*************"); + } + + + // else increment up the number of periods refueling + }else { + tNCVehicle.setPeriodsRefueling(tNCVehicle.getPeriodsRefueling()+1); + if(tNCVehicle.getId()==vehicleDebug) { + logger.info("*************"); + logger.info("Vehicle ID "+tNCVehicle.getId()+" is still refueling in period "+simulationPeriod); + logger.info("*************"); + } + + } + } + + refuelingVehicleList.removeAll(vehiclesToRemove); + } + + + /** + * This method writes tNCVehicle trips to the output file. + * + */ + public void writeVehicleTrips(float sampleRate){ + + logger.info("Writing tNCVehicle trips to file " + vehicleTripOutputFile); + PrintWriter printWriter = null; + try + { + printWriter = new PrintWriter(new BufferedWriter(new FileWriter(vehicleTripOutputFile))); + } catch (IOException e) + { + logger.fatal("Could not open file " + vehicleTripOutputFile + " for writing\n"); + throw new RuntimeException(); + } + + TNCVehicleTrip.printHeader(printWriter); + + //count the total empty vehicles + int totalEmptyVehicles =0; + for(int i = 1; i <= maxTaz; ++ i){ + if(emptyVehicleList[i]==null) + continue; + + totalEmptyVehicles+=emptyVehicleList[i].size(); + } + logger.info("Writing "+totalEmptyVehicles+" total vehicles to file"); + + //reset trip id;wsu + int tripid=0; + for(int i = 1; i <= maxTaz; ++ i){ + if(emptyVehicleList[i]==null) + continue; + + if(emptyVehicleList[i].size()==0) + continue; + + for(TNCVehicle tNCVehicle : emptyVehicleList[i] ){ + if(tNCVehicle.getId()==vehicleDebug) { + logger.info("Writing "+tNCVehicle.getVehicleTrips().size()+" vehicle trips for vehicle ID "+tNCVehicle.getId()); + } + + for(TNCVehicleTrip tNCVehicleTrip : tNCVehicle.getVehicleTrips()){ + + tripid++; + //reorder trip id by wsu + tNCVehicleTrip.setId(tripid); + tNCVehicleTrip.printData(printWriter); + + //save the data in the trip matrix + int startPeriod = tNCVehicleTrip.getStartPeriod(); + int skimPeriod = skimPeriodLookup[startPeriod]; + int origTaz = tNCVehicleTrip.getOriginTaz(); + int destTaz = tNCVehicleTrip.getDestinationTaz(); + int occ = Math.min(tNCVehicleTrip.getPassengers(),3); + + float existingTrips = TNCTripMatrix[skimPeriod][occ].getValueAt(origTaz,destTaz); + TNCTripMatrix[skimPeriod][occ].setValueAt(origTaz,destTaz,existingTrips + (1*(1/sampleRate))); + + + } + } + } + printWriter.close(); + } + + /** + * Get the output trip table file names from the properties file, and write + * trip tables for all modes for the given time period. + * + * @param period + * Time period, which will be used to find the period time string + * to append to each trip table matrix file + */ + public void writeTripTable(MatrixDataServerRmi ms) + { + + String directory = Util.getStringValueFromPropertyMap(propertyMap, "scenario.path"); + String matrixTypeName = Util.getStringValueFromPropertyMap(propertyMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + + for(int i =0;i< transportCostManager.NUM_PERIODS;++i) { + String fileName = directory + Util.getStringValueFromPropertyMap(propertyMap, VEHICLETRIP_OUTPUT_MATRIX_PROPERTY) + "_"+transportCostManager.PERIODS[i]+".omx"; + try{ + //Delete the file if it exists + File f = new File(fileName); + if(f.exists()){ + logger.info("Deleting existing trip file: "+fileName); + f.delete(); + } + + if (ms != null) + ms.writeMatrixFile(fileName, TNCTripMatrix[i], mt); + else + writeMatrixFile(fileName, TNCTripMatrix[i]); + } catch (Exception e){ + logger.error("exception caught writing " + mt.toString() + " matrix file = " + + fileName, e); + throw new RuntimeException(); + } + } + + } + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + private void writeMatrixFile(String fileName, Matrix[] m) + { + + // auto trips + MatrixWriter writer = MatrixWriter.createWriter(fileName); + String[] names = new String[m.length]; + + for (int i = 0; i < m.length; i++) + { + names[i] = m[i].getName(); + logger.info(m[i].getName() + " has " + m[i].getRowCount() + " rows, " + + m[i].getColumnCount() + " cols, and a total of " + m[i].getSum()); + } + + writer.writeMatrices(names, m); + } + + /** + * Relate simulation periods to skim periods. + * + */ + public void calculateSkimPeriods(){ + + skimPeriodLookup = new byte[numberOfSimulationPeriods]; + int numberSkimPeriods = ModelStructure.SKIM_PERIOD_INDICES.length; + int[] endSkimPeriod = new int[numberSkimPeriods]; + + int lastPeriodEnd = 0; + int lastEndSkimPeriod = 0; + for(int skimPeriod = 0;skimPeriod=0;--skimPeriod){ + if(period pickupIdsAtOrigin; + protected ArrayList dropoffIdsAtOrigin; + protected ArrayList pickupIdsAtDestination; + protected ArrayList dropoffIdsAtDestination; + protected Purpose originPurpose; + protected Purpose destinationPurpose; + protected float distance; + + protected enum Purpose { HOME, PICKUP_ONLY, DROPOFF_ONLY, PICKUP_AND_DROPOFF, REFUEL } + + + public TNCVehicleTrip(TNCVehicle tNCVehicle, int id){ + + this.id=id; + this.tNCVehicle = tNCVehicle; + pickupIdsAtOrigin = new ArrayList(); + dropoffIdsAtOrigin = new ArrayList(); + pickupIdsAtDestination = new ArrayList(); + dropoffIdsAtDestination = new ArrayList(); + originPurpose=Purpose.HOME; + destinationPurpose=Purpose.HOME; + + } + + public ArrayList getPickupIdsAtOrigin() { + return pickupIdsAtOrigin; + } + + public void setPickupIdsAtOrigin(ArrayList pickupIdsAtOrigin) { + this.pickupIdsAtOrigin = pickupIdsAtOrigin; + + if(pickupIdsAtOrigin.isEmpty()) + return; + + if(originPurpose==Purpose.DROPOFF_ONLY) + originPurpose = Purpose.PICKUP_AND_DROPOFF; + else + originPurpose = Purpose.PICKUP_ONLY; + } + + public void addPickupIdsAtOrigin(ArrayList pickupIdsAtOrigin) { + this.pickupIdsAtOrigin.addAll(pickupIdsAtOrigin); + + if(pickupIdsAtOrigin.isEmpty()) + return; + + if(originPurpose==Purpose.DROPOFF_ONLY) + originPurpose = Purpose.PICKUP_AND_DROPOFF; + else + originPurpose = Purpose.PICKUP_ONLY; + + } + public void addPickupIdsAtDestination(ArrayList pickupIdsAtDestination) { + this.pickupIdsAtDestination.addAll(pickupIdsAtDestination); + + if(pickupIdsAtDestination.isEmpty()) + return; + + if(destinationPurpose==Purpose.DROPOFF_ONLY) + destinationPurpose = Purpose.PICKUP_AND_DROPOFF; + else + destinationPurpose = Purpose.PICKUP_ONLY; + + } + public ArrayList getDropoffIdsAtOrigin() { + return dropoffIdsAtOrigin; + } + + public void setDropoffIdsAtOrigin(ArrayList dropoffIdsAtOrigin) { + this.dropoffIdsAtOrigin = dropoffIdsAtOrigin; + + if(dropoffIdsAtOrigin.isEmpty()) + return; + + if(originPurpose==Purpose.PICKUP_ONLY) + originPurpose = Purpose.PICKUP_AND_DROPOFF; + else + originPurpose = Purpose.DROPOFF_ONLY; + + } + + public void addDropoffIdsAtOrigin(ArrayList dropoffIdsAtOrigin) { + this.dropoffIdsAtOrigin.addAll(dropoffIdsAtOrigin); + + if(dropoffIdsAtOrigin.isEmpty()) + return; + + if(originPurpose==Purpose.PICKUP_ONLY) + originPurpose = Purpose.PICKUP_AND_DROPOFF; + else + originPurpose = Purpose.DROPOFF_ONLY; + + } + public void addDropoffIdsAtDestination(ArrayList dropoffIdsAtDestination) { + this.dropoffIdsAtDestination.addAll(dropoffIdsAtDestination); + + if(dropoffIdsAtDestination.isEmpty()) + return; + + if(destinationPurpose==Purpose.PICKUP_ONLY) + destinationPurpose = Purpose.PICKUP_AND_DROPOFF; + else + destinationPurpose = Purpose.DROPOFF_ONLY; + + } + public ArrayList getPickupIdsAtDestination() { + return pickupIdsAtDestination; + } + + public void setPickupIdsAtDestination(ArrayList pickupIdsAtDestination) { + this.pickupIdsAtDestination = pickupIdsAtDestination; + + if(pickupIdsAtDestination.isEmpty()) + return; + + if(destinationPurpose==Purpose.DROPOFF_ONLY) + destinationPurpose = Purpose.PICKUP_AND_DROPOFF; + else + destinationPurpose = Purpose.PICKUP_ONLY; + + } + + public ArrayList getDropoffIdsAtDestination() { + return dropoffIdsAtDestination; + } + + public void setDropoffIdsAtDestination( + ArrayList dropoffIdsAtDestination) { + this.dropoffIdsAtDestination = dropoffIdsAtDestination; + + if(dropoffIdsAtDestination.isEmpty()) + return; + + if(destinationPurpose==Purpose.PICKUP_ONLY) + destinationPurpose = Purpose.PICKUP_AND_DROPOFF; + else + destinationPurpose = Purpose.DROPOFF_ONLY; + + } + + + + public void addPickupAtOrigin(String id){ + pickupIdsAtOrigin.add(id); + + if(originPurpose==Purpose.DROPOFF_ONLY) + originPurpose = Purpose.PICKUP_AND_DROPOFF; + else + originPurpose = Purpose.PICKUP_ONLY; + } + + public void addPickupAtDestination(String id){ + pickupIdsAtDestination.add(id); + + if(destinationPurpose==Purpose.DROPOFF_ONLY) + destinationPurpose = Purpose.PICKUP_AND_DROPOFF; + else + destinationPurpose = Purpose.PICKUP_ONLY; + } + + public void addDropoffAtOrigin(String id){ + dropoffIdsAtOrigin.add(id); + + if(originPurpose==Purpose.PICKUP_ONLY) + originPurpose = Purpose.PICKUP_AND_DROPOFF; + else + originPurpose = Purpose.DROPOFF_ONLY; + + + } + + public void addDropoffAtDestination(String id){ + dropoffIdsAtDestination.add(id); + + if(destinationPurpose==Purpose.PICKUP_ONLY) + destinationPurpose = Purpose.PICKUP_AND_DROPOFF; + else + destinationPurpose = Purpose.DROPOFF_ONLY; +} + + public int getNumberOfPickupsAtOrigin(){ + return pickupIdsAtOrigin.size(); + } + + public int getNumberOfDropoffsAtOrigin(){ + return dropoffIdsAtOrigin.size(); + } + + public int getNumberOfPickupsAtDestination(){ + return pickupIdsAtDestination.size(); + } + + public int getNumberOfDropoffsAtDestination(){ + return dropoffIdsAtDestination.size(); + } + + public TNCVehicle getVehicle() { + return tNCVehicle; + } + + + public void setVehicle(TNCVehicle tNCVehicle) { + this.tNCVehicle = tNCVehicle; + } + + + public short getOriginTaz() { + return originTaz; + } + + + public void setOriginTaz(short originTaz) { + this.originTaz = originTaz; + } + + + public short getDestinationTaz() { + return destinationTaz; + } + + + public void setDestinationTaz(short destinationTaz) { + this.destinationTaz = destinationTaz; + } + + + public int getOriginMaz() { + return originMaz; + } + + + public void setOriginMaz(int originMaz) { + this.originMaz = originMaz; + } + + + public int getDestinationMaz() { + return destinationMaz; + } + + + public void setDestinationMaz(int destinationMaz) { + this.destinationMaz = destinationMaz; + } + + + public int getPassengers() { + return passengers; + } + + + public void setPassengers(int passengers) { + this.passengers = passengers; + } + + public int getStartPeriod() { + return startPeriod; + } + + public void setStartPeriod(int startPeriod) { + this.startPeriod = startPeriod; + } + + public int getEndPeriod() { + return endPeriod; + } + + public void setEndPeriod(int endPeriod) { + this.endPeriod = endPeriod; + } + + public int getId() { + return id; + } + + public void setId(int id) { + this.id = id; + } + + public static void printHeader(PrintWriter writer){ + String record = new String("trip_ID,vehicle_ID,originTaz,destinationTaz,originMgra,destinationMgra,totalPassengers,startPeriod,endPeriod,pickupIdsAtOrigin,dropoffIdsAtOrigin,pickupIdsAtDestination,dropoffIdsAtDestination, originPurpose, destinationPurpose"); + writer.println(record); + writer.flush(); + } + + public void printData(PrintWriter writer){ + + String pickupIdsAtOriginString = ""; + String dropoffIdsAtOriginString = ""; + String pickupIdsAtDestinationString = ""; + String dropoffIdsAtDestinationString = ""; + + if(pickupIdsAtOrigin.size()>0) + for(String pid : pickupIdsAtOrigin) + pickupIdsAtOriginString += (pid + " "); + + if(dropoffIdsAtOrigin.size()>0) + for(String pid : dropoffIdsAtOrigin) + dropoffIdsAtOriginString += (pid + " "); + + if(pickupIdsAtDestination.size()>0) + for(String pid : pickupIdsAtDestination) + pickupIdsAtDestinationString += (pid + " "); + + if(dropoffIdsAtDestination.size()>0) + for(String pid : dropoffIdsAtDestination) + dropoffIdsAtDestinationString += (pid + " "); + + String record = new String( + id + "," + + tNCVehicle.getId() +"," + + originTaz + "," + + destinationTaz + "," + + originMaz + "," + + destinationMaz + "," + + passengers + "," + + startPeriod + "," + + endPeriod + "," + + pickupIdsAtOriginString + "," + + dropoffIdsAtOriginString + "," + + pickupIdsAtDestinationString + "," + + dropoffIdsAtDestinationString + "," + + originPurpose.ordinal() + "," + + destinationPurpose.ordinal()); + + writer.println(record); + writer.flush(); + } + + public void writeTrace(){ + + String pickupIdsAtOriginString = ""; + String dropoffIdsAtOriginString = ""; + String pickupIdsAtDestinationString = ""; + String dropoffIdsAtDestinationString = ""; + + if(pickupIdsAtOrigin.size()>0) + for(String pid : pickupIdsAtOrigin) + pickupIdsAtOriginString += (pid + " "); + + if(dropoffIdsAtOrigin.size()>0) + for(String pid : dropoffIdsAtOrigin) + dropoffIdsAtOriginString += (pid + " "); + + if(pickupIdsAtDestination.size()>0) + for(String pid : pickupIdsAtDestination) + pickupIdsAtDestinationString += (pid + " "); + + if(dropoffIdsAtDestination.size()>0) + for(String pid : dropoffIdsAtDestination) + dropoffIdsAtDestinationString += (pid + " "); + + logger.info("*********************************************************"); + logger.info("Trace for tNCVehicle trip "+id+" in tNCVehicle "+tNCVehicle.getId()); + logger.info("Trip ID: " + id); + logger.info("TNCVehicle ID: "+tNCVehicle.getId()); + logger.info("Origin TAZ: "+originTaz); + logger.info("Destination TAZ: "+destinationTaz); + logger.info("Origin MAZ: "+originMaz); + logger.info("Destination MAZ: "+destinationMaz); + logger.info("Passengers: "+passengers); + logger.info("Start period: "+startPeriod); + logger.info("End period: "+endPeriod); + logger.info("Pickups at Origin: "+ pickupIdsAtOriginString); + logger.info("Dropoffs at Origin: "+ dropoffIdsAtOriginString); + logger.info("Pickups at Destination: "+ pickupIdsAtDestinationString); + logger.info("Dropoffs at Destination: "+ dropoffIdsAtDestinationString); + logger.info("Origin Purpose: "+ originPurpose); + logger.info("Destination Purpose: "+ destinationPurpose); + + logger.info("*********************************************************"); + + + } + + public Purpose getOriginPurpose() { + return originPurpose; + } + + public void setOriginPurpose(Purpose originPurpose) { + this.originPurpose = originPurpose; + } + + public Purpose getDestinationPurpose() { + return destinationPurpose; + } + + public void setDestinationPurpose(Purpose destinationPurpose) { + this.destinationPurpose = destinationPurpose; + } + + + public float getDistance() { + return distance; + } + + public void setDistance(float distance) { + this.distance = distance; + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/maas/TransportCostManager.java b/sandag_abm/src/main/java/org/sandag/abm/maas/TransportCostManager.java new file mode 100644 index 0000000..e0f64db --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/maas/TransportCostManager.java @@ -0,0 +1,438 @@ +package org.sandag.abm.maas; + +import java.io.File; +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.concurrent.Executors; +import java.util.concurrent.ThreadPoolExecutor; +import java.util.concurrent.TimeUnit; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +import drasys.or.util.Array; + +public class TransportCostManager { + + protected transient Logger logger = Logger.getLogger(TransportCostManager.class); + + protected static final int EA = ModelStructure.EA_SKIM_PERIOD_INDEX; + protected static final int AM = ModelStructure.AM_SKIM_PERIOD_INDEX; + protected static final int MD = ModelStructure.MD_SKIM_PERIOD_INDEX; + protected static final int PM = ModelStructure.PM_SKIM_PERIOD_INDEX; + protected static final int EV = ModelStructure.EV_SKIM_PERIOD_INDEX; + public static final int NUM_PERIODS = ModelStructure.SKIM_PERIOD_INDICES.length; + protected static final String[] PERIODS = ModelStructure.SKIM_PERIOD_STRINGS; + + protected static int TAZ_CALCULATOR_THREADS = 20; //default + + //by period, origin, destination - ragged array of zone numbers of zones within max time diversion + //sorted by time from origin (assuming pickups would be en-route) + protected short[][][][] tazsWithinOriginAndDestination; + // private float[][][][] addTimeWithinOriginAndDestination; + + //by period, origin, destination + protected float[][][] tazTimeSkims; //travel time + protected float[][][] tazDistanceSkims; //travel distance + + protected short[][][] tazsByTimeFromOrigin; //array of TAZs sorted by time from origin, by period and origin TAZ + + protected float maxTimeDiversion; + protected float maxDistanceToPickup; + protected int maxTaz; + + // declare an array of UEC objects, 1 for each time period + protected UtilityExpressionCalculator[] autoDistOD_UECs; + protected UtilityExpressionCalculator[] autoTimeOD_UECs; + + // The simple auto skims UEC does not use any DMU variables + protected VariableTable dmu = null; + protected TazDataManager tazManager; + int totalThreads; + + + /** + * Instantiate transport cost manager. + * + * @param rbMap + * @param maxTimeDiversion + */ + public TransportCostManager(HashMap rbMap, float maxTimeDiversion, float maxDistanceToPickup) + { + + this.maxTimeDiversion=maxTimeDiversion; + this.maxDistanceToPickup=maxDistanceToPickup; + + // Create the UECs + String uecPath = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String uecFileName = uecPath + + Util.getStringValueFromPropertyMap(rbMap, "taz.distance.uec.file"); + int dataPage = Util.getIntegerValueFromPropertyMap(rbMap, "taz.distance.data.page"); + + + //iterate thru settings in properties file and create time and distance UECs + autoDistOD_UECs = new UtilityExpressionCalculator[NUM_PERIODS]; + autoTimeOD_UECs = new UtilityExpressionCalculator[NUM_PERIODS]; + File uecFile = new File(uecFileName); + + for(int i =0; i stopTazList = new ArrayList(); + + for (int oTaz = startOriginTaz; oTaz <= endOriginTaz; oTaz++){ + + if((oTaz==startOriginTaz)||(oTaz % 100 == 0)) + logger.info("Thread "+threadName + " Period "+period+" Origin TAZ "+oTaz); + + for (int dTaz = 1; dTaz <= maxTaz; dTaz++){ + + stopTazList.clear(); + + //Stop TAZs + for(int kTaz = 1; kTaz <= maxTaz; ++kTaz){ + + //Calculate additional time to stop + float ikTime = tazTimeSkims[period][oTaz][kTaz]; + float kjTime = tazTimeSkims[period][kTaz][dTaz]; + float totalIKJTime = ikTime + kjTime; + float divertTime = totalIKJTime - tazTimeSkims[period][oTaz][dTaz]; + + //if time is less than max diversion time (or the stop zone is the origin or destination zone), add zone and time to arraylist + if( (divertTime < maxTimeDiversion) || (kTaz==oTaz) || (kTaz==dTaz)){ + StopTaz stopTaz = new StopTaz(); + stopTaz.tazNumber = kTaz; + stopTaz.diversionTime = divertTime; + stopTaz.originStopTime = ikTime; + stopTazList.add(stopTaz); + } + + } //end for stops + + //initialize arrays for saving tazs, time and set the values in the ragged arrays + if(!stopTazList.isEmpty()){ + Collections.sort(stopTazList); + int numberOfStops = stopTazList.size(); + tazsWithinOriginAndDestination[period][oTaz][dTaz] = new short[numberOfStops]; + //addTimeWithinOriginAndDestination[period][oTaz][dTaz] = new float[numberOfStops]; + + for(int k = 0; k < numberOfStops; ++k){ + StopTaz stopTaz = stopTazList.get(k); + tazsWithinOriginAndDestination[period][oTaz][dTaz][k] = (short) stopTaz.tazNumber; + //addTimeWithinOriginAndDestination[period][oTaz][dTaz][k] = stopTaz.diversionTime; + } + } + } + + } + + + + + } + } + + /** + * This method finds stop zones for each origin-destination zone pair and saves the zone number + * and diversion time, sorted by distance from origin. + * + */ + private void calculateTazsWithinDistanceThreshold(){ + + + tazsWithinOriginAndDestination = new short[NUM_PERIODS][maxTaz+1][maxTaz+1][]; + //addTimeWithinOriginAndDestination = new float[NUM_PERIODS][maxTaz+1][maxTaz+1][]; + int processors = Runtime.getRuntime().availableProcessors(); + //use 80% of the machine's processing power + TAZ_CALCULATOR_THREADS = totalThreads; + int chunkSize = (int) Math.floor(maxTaz / TAZ_CALCULATOR_THREADS); + + logger.info("...Calculating TAZs within distance thresholds with "+TAZ_CALCULATOR_THREADS+ " threads ("+processors+" processors)"); + + for( int period = 0; period < NUM_PERIODS;++period ){ + + int endZone = 0; + + ThreadPoolExecutor executor = (ThreadPoolExecutor) Executors.newFixedThreadPool(TAZ_CALCULATOR_THREADS); + + for(int i = 0; i < TAZ_CALCULATOR_THREADS; ++ i){ + + int startZone = endZone + 1; + + if(i==(TAZ_CALCULATOR_THREADS-1)) + endZone = maxTaz; + else + endZone = startZone+chunkSize; + + executor.execute(new TazDistanceCalculatorThread( "Thread-"+i,period,startZone,endZone)); + + } + executor.shutdown(); + try{ + executor.awaitTermination(60, TimeUnit.MINUTES); + }catch(InterruptedException e){ + throw new RuntimeException(e); + } + } + } + + /** + * Calculate zones sorted by time from origin. Always include intrazonal as within the maximum distance range. + * + */ + public void calculateTazsByTimeFromOrigin(){ + + ArrayList stopTazList = new ArrayList(); + + tazsByTimeFromOrigin = new short[NUM_PERIODS][maxTaz+1][]; + + for(int period = 0; period that.originStopTime) return AFTER; + + return EQUAL; + } + + + } + + /** + * Get the array of zones that are within the diversion time from the origin to the + * destination, sorted by time from origin. + * + * @param skimPeriod + * @param origTaz + * @param destTaz + * @return The array of zones, or null if there are no zones within the max diversion time. + */ + public short[] getZonesWithinMaxDiversionTime(int skimPeriod, int origTaz, int destTaz){ + + return tazsWithinOriginAndDestination[skimPeriod][origTaz][destTaz]; + + } + + /** + * Is the zone within the set of zones that is within maximum diversion time from the origin to the destination? + * + * @param skimPeriod + * @param origTaz The origin TAZ + * @param destTaz The destination TAZ + * @param taz The stop TAZ + * @return A boolean indicating whether the zone is within the maximum deviation time from the origin to the destination. + */ + public boolean stopZoneIsWithinMaxDiversionTime(int skimPeriod, int origTaz, int destTaz, int taz){ + + short[] tazArray = getZonesWithinMaxDiversionTime(skimPeriod, origTaz, destTaz); + for(int i = 0; i < tazArray.length; ++i) + if(tazArray[i]==taz) + return true; + return false; + + } + + + + /** + * Get the diversion times for the zones that are within the diversion time from the origin to the + * destination, sorted by time from origin. + * + * @param period + * @param origTaz + * @param destTaz + * @return The array of diversion times, or null if there are no zones within the max diversion time. + */ + public float[] getDiversionTimes(int period, int origTaz, int destTaz){ + + //return addTimeWithinOriginAndDestination[period][origTaz][destTaz]; + logger.fatal("Error trying to call getDiversionTimes when additional time array not initialized"); + throw new RuntimeException(); + } + + /** + * Get a ragged array of zone numbers sorted by time from the origin. The array is ragged + * because it is capped by the maximum distance for hailing a TNC\TAXI. + * + * @param period + * @param origTaz + * @return A sorted array of zone numbers, or null if there are no zones within the maximum distance. + */ + public short[] getZoneNumbersSortedByTime(int period, int origTaz){ + + return tazsByTimeFromOrigin[period][origTaz]; + } + + public float getTime(int period, int origTaz, int destTaz){ + + return tazTimeSkims[period][origTaz][destTaz]; + } + + public float getDistance(int period, int origTaz, int destTaz){ + + return tazDistanceSkims[period][origTaz][destTaz]; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/AutoDMU.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/AutoDMU.java new file mode 100644 index 0000000..59823a0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/AutoDMU.java @@ -0,0 +1,136 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.VariableTable; + +/** + * This class is used for ... + * + * @author Christi Willison + * @version Mar 9, 2009 + *

+ * Created by IntelliJ IDEA. + */ +public class AutoDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(AutoDMU.class); + + protected HashMap methodIndexMap; + + private double avgHourlyParkingCostAtDestTaz; + private float pTazTerminalTime; + private float aTazTerminalTime; + + public AutoDMU() + { + setupMethodIndexMap(); + } + + public double getAvgHourlyParkingCostAtDestTaz() + { + return avgHourlyParkingCostAtDestTaz; + } + + public void setAvgHourlyParkingCostAtDestTaz(double cost) + { + avgHourlyParkingCostAtDestTaz = cost; + } + + public float getPTazTerminalTime() + { + return pTazTerminalTime; + } + + public void setPTazTerminalTime(float pTazTerminalTime) + { + this.pTazTerminalTime = pTazTerminalTime; + } + + public float getATazTerminalTime() + { + return aTazTerminalTime; + } + + public void setATazTerminalTime(float aTazTerminalTime) + { + this.aTazTerminalTime = aTazTerminalTime; + } + + /** + * Log the DMU values. + * + * @param localLogger + * The logger to use. + */ + public void logValues(Logger localLogger) + { + + localLogger.info(""); + localLogger.info("Auto DMU Values:"); + localLogger.info(""); + localLogger.info(String.format("Average TAZ Parking cost at destination: %9f", + avgHourlyParkingCostAtDestTaz)); + localLogger.info(String.format("Production/Origin Terminal Time: %9.4f", pTazTerminalTime)); + localLogger.info(String.format("Attraction/Destin Terminal Time: %9.4f", aTazTerminalTime)); + + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getAvgHourlyParkingCostAtDestTaz", 0); + methodIndexMap.put("getATazTerminalTime", 1); + methodIndexMap.put("getPTazTerminalTime", 2); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getAvgHourlyParkingCostAtDestTaz(); + case 1: + return getATazTerminalTime(); + case 2: + return getPTazTerminalTime(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/AutoUEC.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/AutoUEC.java new file mode 100644 index 0000000..2481944 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/AutoUEC.java @@ -0,0 +1,138 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.calculator.IndexValues; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.LogitModel; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + +/** + * This class is used for ... + * + * @author Christi Willison + * @version Mar 9, 2009 + *

+ * Created by IntelliJ IDEA. + */ +public class AutoUEC + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(AutoUEC.class); + private TazDataManager tazs; + private UtilityExpressionCalculator uec; + private LogitModel model; + private ChoiceModelApplication modelApp; + + private IndexValues index = new IndexValues(); + private int[] availFlag; + private AutoDMU dmu; + + // seek and trace + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + protected Tracer tracer; + + /** + * Constructor. + * + * @param rb + * ResourceBundle + * @param UECFileName + * The path/name of the UEC containing the auto model. + * @param modelSheet + * The sheet (0-indexed) containing the model specification. + * @param dataSheet + * The sheet (0-indexed) containing the data specification. + */ + public AutoUEC(HashMap rbHashMap, String uecFileName, int modelSheet, + int dataSheet) + { + + dmu = new AutoDMU(); + + // use the choice model application to set up the model structure + modelApp = new ChoiceModelApplication(uecFileName, modelSheet, dataSheet, rbHashMap, dmu); + + // but return the logit model itself, so we can use compound utilities + model = modelApp.getRootLogitModel(); + uec = modelApp.getUEC(); + + tazs = TazDataManager.getInstance(); + trace = Util.getBooleanValueFromPropertyMap(rbHashMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbHashMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbHashMap, "Trace.dtaz"); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + } + + /** + * Solve auto utilities for a given zone-pair + * + * @param pTaz + * Production/Origin TAZ. + * @param aTaz + * Attraction/Destination TAZ. + * @return The root utility. + */ + public double calculateUtilitiesForTazPair(int pTaz, int aTaz, double avgTazHourlyParkingCost) + { + + trace = false; + if (tracer.isTraceOn() && tracer.isTraceZonePair(pTaz, aTaz)) + { + trace = true; + } + index.setOriginZone(pTaz); + index.setDestZone(aTaz); + availFlag = new int[uec.getNumberOfAlternatives() + 1]; + Arrays.fill(availFlag, 1); + + dmu.setAvgHourlyParkingCostAtDestTaz(avgTazHourlyParkingCost); + dmu.setPTazTerminalTime(tazs.getOriginTazTerminalTime(pTaz)); + dmu.setATazTerminalTime(tazs.getDestinationTazTerminalTime(aTaz)); + + // log DMU values + if (trace) + { + TapDataManager tapManager = TapDataManager.getInstance(); + if (Arrays.binarySearch(tapManager.getTaps(), pTaz) > 0 + && Arrays.binarySearch(tapManager.getTaps(), aTaz) > 0) + uec.logDataValues(logger, pTaz, aTaz, aTaz); + dmu.logValues(logger); + } + + modelApp.computeUtilities(dmu, index); + double utility = modelApp.getLogsum(); + + // logging + if (trace) + { + uec.logAnswersArray(logger, "Auto UEC"); + uec.logResultsArray(logger, pTaz, aTaz); + modelApp.logLogitCalculations("Auto UEC", "Trace"); + logger.info("Logsum = " + utility); + trace = false; + } + + return utility; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/Constants.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/Constants.java new file mode 100644 index 0000000..46c933d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/Constants.java @@ -0,0 +1,56 @@ +package org.sandag.abm.modechoice; + +/** + * This class is used for storing constants. Many of these are listed in the + * sandag.inc file associated with the FORTRAN code. We should eventually move + * these into a properties file and have this class set them from the prop file. + * + * I am just trying to not get bogged down in the details. + * + * @author Christi Willison + * @version Nov 6, 2008 + *

+ * Created by IntelliJ IDEA. + */ +public final class Constants +{ + + public static int MAX_EXTERNAL = 12; + public static float AutoCostPerMile = 10.0f; + + public static float[][] parkingCost = { {0.0f, 50.0f, 200.0f, 300.0f, 400.0f}, + {0.0f, 50.0f, 125.0f, 200.0f, 400.0f}, {0.0f, 50.0f, 100.0f, 200.0f, 400.0f}}; + + public static float walkMinutesPerMile = 20.0f; // 20 + // minutes + // per + // mile + // (dist + // is + // in + // feet) + // or + // 3 + // mph. + public static float bikeMinutesPerMile = 5.0f; // 5 + + // minutes + // per + // mile + // (dist + // is + // in + // feet) + // or + // 12 + // mph. + + public static float feetPerMile = 5280.0f; + public static double walkMinutesPerFoot = walkMinutesPerMile/feetPerMile; + public static double bikeMinutesPerFoot = bikeMinutesPerMile/feetPerMile; + + private Constants() + { + // Not Implemented + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/MaasDMU.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/MaasDMU.java new file mode 100644 index 0000000..52cd382 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/MaasDMU.java @@ -0,0 +1,128 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.VariableTable; + +/** + * This class is the DMU object for MAAS + * joel freedman + * RSG 2019-07-08 + **/ + +public class MaasDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(MaasDMU.class); + + protected HashMap methodIndexMap; + + protected float waitTimeTaxi; + protected float waitTimeSingleTNC; + protected float waitTimeSharedTNC; + + public MaasDMU() + { + setupMethodIndexMap(); + } + + public float getWaitTimeTaxi() { + return waitTimeTaxi; + } + + public void setWaitTimeTaxi(float waitTimeTaxi) { + this.waitTimeTaxi = waitTimeTaxi; + } + + public float getWaitTimeSingleTNC() { + return waitTimeSingleTNC; + } + + public void setWaitTimeSingleTNC(float waitTimeSingleTNC) { + this.waitTimeSingleTNC = waitTimeSingleTNC; + } + + public float getWaitTimeSharedTNC() { + return waitTimeSharedTNC; + } + + public void setWaitTimeSharedTNC(float waitTimeSharedTNC) { + this.waitTimeSharedTNC = waitTimeSharedTNC; + } + + + /** + * Log the DMU values. + * + * @param localLogger + * The logger to use. + */ + public void logValues(Logger localLogger) + { + + localLogger.info(""); + localLogger.info("Maas DMU Values:"); + localLogger.info(""); + localLogger.info(String.format("Taxi wait time: %9.2f", waitTimeTaxi)); + localLogger.info(String.format("Single TNC wait time: %9.2f", waitTimeSingleTNC)); + localLogger.info(String.format("Shared TNC wait time: %9.2f", waitTimeSharedTNC)); + + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getWaitTimeTaxi", 0); + methodIndexMap.put("getWaitTimeSingleTNC", 1); + methodIndexMap.put("getWaitTimeSharedTNC", 2); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getWaitTimeTaxi(); + case 1: + return getWaitTimeSingleTNC(); + case 2: + return getWaitTimeSharedTNC(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/MaasUEC.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/MaasUEC.java new file mode 100644 index 0000000..682f7b8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/MaasUEC.java @@ -0,0 +1,141 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.TNCAndTaxiWaitTimeCalculator; +import org.sandag.abm.ctramp.Util; +import com.pb.common.calculator.IndexValues; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.LogitModel; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + +/** + * This class is the UEC for MAAS + * Joel Freedman + * RSG 2019-07-08 + */ +public class MaasUEC + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(MaasUEC.class); + private TazDataManager tazs; + private UtilityExpressionCalculator uec; + private LogitModel model; + private ChoiceModelApplication modelApp; + + private IndexValues index = new IndexValues(); + private int[] availFlag; + private MaasDMU dmu; + + // seek and trace + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + protected Tracer tracer; + + + + + /** + * Constructor. + * + * @param rb + * ResourceBundle + * @param UECFileName + * The path/name of the UEC containing the auto model. + * @param modelSheet + * The sheet (0-indexed) containing the model specification. + * @param dataSheet + * The sheet (0-indexed) containing the data specification. + */ + public MaasUEC(HashMap rbHashMap, String uecFileName, int modelSheet, + int dataSheet) + { + + dmu = new MaasDMU(); + + // use the choice model application to set up the model structure + modelApp = new ChoiceModelApplication(uecFileName, modelSheet, dataSheet, rbHashMap, dmu); + + // but return the logit model itself, so we can use compound utilities + model = modelApp.getRootLogitModel(); + uec = modelApp.getUEC(); + + tazs = TazDataManager.getInstance(); + trace = Util.getBooleanValueFromPropertyMap(rbHashMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbHashMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbHashMap, "Trace.dtaz"); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + if (trace) + { + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + } + } + } + + + } + + /** + * Solve auto utilities for a given zone-pair + * + * @param pTaz + * Production/Origin TAZ. + * @param aTaz + * Attraction/Destination TAZ. + * @return The root utility. + */ + public double calculateUtilitiesForTazPair(int pTaz, int aTaz, float avgTaxiWaitTime, float avgSingleTNCWaitTime,float avgSharedTNCWaitTime) + { + + trace = false; + if (tracer.isTraceOn() && tracer.isTraceZonePair(pTaz, aTaz)) + { + trace = true; + } + index.setOriginZone(pTaz); + index.setDestZone(aTaz); + availFlag = new int[uec.getNumberOfAlternatives() + 1]; + Arrays.fill(availFlag, 1); + + dmu.setWaitTimeTaxi(avgTaxiWaitTime); + dmu.setWaitTimeSingleTNC(avgSingleTNCWaitTime); + dmu.setWaitTimeSharedTNC(avgSharedTNCWaitTime); + + // log DMU values + if (trace) + { + TapDataManager tapManager = TapDataManager.getInstance(); + if (Arrays.binarySearch(tapManager.getTaps(), pTaz) > 0 + && Arrays.binarySearch(tapManager.getTaps(), aTaz) > 0) + uec.logDataValues(logger, pTaz, aTaz, aTaz); + dmu.logValues(logger); + } + + modelApp.computeUtilities(dmu, index); + double utility = modelApp.getLogsum(); + + // logging + if (trace) + { + uec.logAnswersArray(logger, "Maas UEC"); + uec.logResultsArray(logger, pTaz, aTaz); + modelApp.logLogitCalculations("Maas UEC", "Trace"); + logger.info("Logsum = " + utility); + trace = false; + } + + return utility; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/MgraDataManager.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/MgraDataManager.java new file mode 100644 index 0000000..06a2bee --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/MgraDataManager.java @@ -0,0 +1,1551 @@ +package org.sandag.abm.modechoice; + + +import org.sandag.abm.active.sandag.SandagWalkPathAlternativeListGenerationConfiguration; +import org.sandag.abm.active.sandag.SandagWalkPathChoiceLogsumMatrixApplication; +import org.sandag.abm.ctramp.BikeLogsum; +import org.sandag.abm.ctramp.BikeLogsumSegment; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.Modes.AccessMode; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileNotFoundException; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.io.Serializable; +import java.nio.file.Paths; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.TreeSet; + +import org.apache.log4j.Logger; + +import com.pb.common.datafile.CSVFileReader; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +/** + * This class is used for ... + * + * @author Christi Willison + * @version Sep 4, 2008 + *

+ * Created by IntelliJ IDEA. + * + * Edited JEF May 2009 + */ +public final class MgraDataManager + implements Serializable +{ + + private static MgraDataManager instance; + protected transient Logger logger = Logger.getLogger(MgraDataManager.class); + + public static final double MAX_PARKING_WALK_DISTANCE = 0.75; + + private static final int LOG_MGRA = -4502; + private static final String LOG_MGRA_FILE = LOG_MGRA + + "debug"; + private static final String MGRA_MGRA_WALK_FILE_PROPERTY = "active.micromobility.file.walk.mgra"; + private static final String MGRA_TAP_WALK_FILE_PROPERTY = "active.micromobility.file.walk.mgratap"; + + + // create Strubg variables for the 4D land use data file field names + public static final String MGRA_4DDENSITY_DU_DEN_FIELD = "DUDen"; + public static final String MGRA_4DDENSITY_EMP_DEN_FIELD = "EmpDen"; + public static final String MGRA_4DDENSITY_TOT_INT_FIELD = "TotInt"; + + // public static final String MGRA_FIELD_NAME = "MGRASR10"; + public static final String MGRA_FIELD_NAME = "mgra"; + public static final String MGRA_TAZ_FIELD_NAME = "TAZ"; + public static final String MGRA_LUZ_FIELD_NAME = "luz_id"; + private static final String MGRA_POPULATION_FIELD_NAME = "pop"; + private static final String MGRA_HOUSEHOLDS_FIELD_NAME = "hh"; + private static final String MGRA_GRADE_SCHOOL_ENROLLMENT_FIELD_NAME = "EnrollGradeKto8"; + private static final String MGRA_HIGH_SCHOOL_ENROLLMENT_FIELD_NAME = "EnrollGrade9to12"; + private static final String MGRA_UNIVERSITY_ENROLLMENT_FIELD_NAME = "collegeEnroll"; + private static final String MGRA_OTHER_COLLEGE_ENROLLMENT_FIELD_NAME = "otherCollegeEnroll"; + private static final String MGRA_ADULT_SCHOOL_ENROLLMENT_FIELD_NAME = "AdultSchEnrl"; + private static final String MGRA_GRADE_SCHOOL_DISTRICT_FIELD_NAME = "ech_dist"; + private static final String MGRA_HIGH_SCHOOL_DISTRICT_FIELD_NAME = "hch_dist"; + private static final String MGRA_REFUELING_STATIONS_FIELD_NAME = "refueling_stations"; + private static final String MGRA_REMOTE_PARKING_LOT_FIELD_NAME = "remoteAVParking"; + + private static final String PROPERTIES_PARKING_COST_OUTPUT_FILE = "mgra.avg.cost.output.file"; + + + public static final String PROPERTIES_MGRA_DATA_FILE = "mgra.socec.file"; + private static final String MGRA_DISTANCE_COEFF_WORK = "mgra.avg.cost.dist.coeff.work"; + private static final String MGRA_DISTANCE_COEFF_OTHER = "mgra.avg.cost.dist.coeff.other"; + + public static final int PARK_AREA_ONE = 1; + private static final String MGRA_PARKAREA_FIELD = "parkarea"; + private static final String MGRA_HSTALLSOTH_FIELD = "hstallsoth"; + private static final String MGRA_HSTALLSSAM_FIELD = "hstallssam"; + private static final String MGRA_HPARKCOST_FIELD = "hparkcost"; + private static final String MGRA_NUMFREEHRS_FIELD = "numfreehrs"; + private static final String MGRA_DSTALLSOTH_FIELD = "dstallsoth"; + private static final String MGRA_DSTALLSSAM_FIELD = "dstallssam"; + private static final String MGRA_DPARKCOST_FIELD = "dparkcost"; + private static final String MGRA_MSTALLSOTH_FIELD = "mstallsoth"; + private static final String MGRA_MSTALLSSAM_FIELD = "mstallssam"; + private static final String MGRA_MPARKCOST_FIELD = "mparkcost"; + + //for TNC and Taxi wait time calculations + private static final String MGRA_POPEMPPERSQMI_FIELD = "PopEmpDenPerMi"; + private ArrayList mgras = new ArrayList(); + private int maxMgra; + private int maxLuz; + + private int maxTap; + private int nMgrasWithWlkTaps; + // [mgra], [0=tapID, 1=Distance], [tap number (0-number of taps)] + private int[][][] mgraWlkTapsDistArray; + private int[] mgraTaz; + private int[] mgraLuz; + + // An array of Hashmaps dimensioned by origin mgra, with distance in feet, + // in a ragged + // array (no key for mgra means no other mgras in walk distance) + private HashMap[] oMgraWalkDistance; + + // An array of Hashmaps dimensioned by destination mgra, with distance in + // feet, in a ragged + // array (no key for mgra means no other mgras in walk distance) + private HashMap[] dMgraWalkDistance; + + private BikeLogsum bls; + //segment doesn't matter as it is now just a passthrough + private BikeLogsumSegment defaultSegment = new BikeLogsumSegment(true,true,true); + + // An array dimensioned to maxMgra of ragged arrays of lists of TAPs + // accessible by driving + private Set[] driveAccessibleTaps; + private Set[] walkAccessibleTaps; + + //by TAP, closest mgra to the tap by walking distance. + private int[] closestMgraToTap; + + private TableDataSet mgraTableDataSet; + + private HashMap mgraDataTableMgraRowMap; + + private double[] duDen; + private double[] empDen; + private double[] totInt; + private double[] popEmpDenPerSqMi; + + private double[] lsWgtAvgCostM; + private double[] lsWgtAvgCostD; + private double[] lsWgtAvgCostH; + + private int[] mgraParkArea; + private int[] numfreehrs; + private int[] hstallsoth; + private int[] hstallssam; + private float[] hparkcost; + private int[] dstallsoth; + private int[] dstallssam; + private float[] dparkcost; + private int[] mstallsoth; + private int[] mstallssam; + private float[] mparkcost; + + private TableDataSet tapLinesTable; + private HashMap taplines; + + /** + * Constructor. + * + * @param rbMap + * A HashMap created from a resourcebundle with model properties. + * + */ + private MgraDataManager(HashMap rbMap) + { + System.out.println("I'm the MgraDataManager"); + readMgraTableData(rbMap); + readMgraWlkTaps(rbMap); + readMgraWlkDist(rbMap); + + readTapLines(rbMap); + trimTapSet(); + + + + bls = BikeLogsum.getBikeLogsum(rbMap); + + // pre-process the list of TAPS reachable by drive access for each MGRA + mapDriveAccessTapsToMgras(TazDataManager.getInstance(rbMap)); + + // create arrays from 4ddensity fields added to MGRA table used by + // TourModeChoice DMU methods + process4ddensityData(rbMap); + + calculateMgraAvgParkingCosts(rbMap); + + calculateClosestMgraToTap(); + + printMgraStats(); + } + + /** + * Find the closest mgra by walk time to the tap. + */ + public void calculateClosestMgraToTap() { + + closestMgraToTap = new int[maxTap+1]; + float[] minTimeToTap = new float[maxTap+1]; + Arrays.fill(minTimeToTap, 999999); + + for(int mgra = 1; mgra taps = walkAccessibleTaps[mgra]; + for(int tap : taps) { + int pos = getTapPosition(mgra, tap); + float time = getMgraToTapWalkTime(mgra,pos); + if(time rbMap) + { + if (instance == null) + { + instance = new MgraDataManager(rbMap); + return instance; + } else return instance; + } + + /** + * This method should only be used after the getInstance(ResourceBundle rb) + * method has been called since the rb is needed to read in all the data and + * populate the object. This method will return the instance that has + * already been populated. + * + * @return instance + * @throws RuntimeException + */ + public static MgraDataManager getInstance() + { + if (instance == null) + { + throw new RuntimeException( + "Must instantiate MgraDataManager with the getInstance(rb) method first"); + } else + { + return instance; + } + } + + /** + * Read the walk-transit taps for mgras. + * + * @param rb + * The resourcebundle with the scenario.path and + * mgra.wlkacc.taps.and.distance.file properties. + */ + public void readMgraWlkTaps(HashMap rbMap) + { + String mgraWlkTapTimeFile = rbMap.get(SandagWalkPathAlternativeListGenerationConfiguration.PROPERTIES_OUTPUT) + +rbMap.get(MGRA_TAP_WALK_FILE_PROPERTY); + + TableDataSet mgraTapData = Util.readTableDataSet(mgraWlkTapTimeFile); + + Map> mgraWlkTapList = new HashMap<>(); //mgra -> tap -> distance + + //mgra,tap,walkTime,dist,mmTime,mmCost,mtTime,mtCost,mmGenTime,mtGenTime,minTime + for(int row = 1; row <= mgraTapData.getRowCount();++row) { + + int mgra = (int) mgraTapData.getValueAt(row, "mgra"); + int tap = (int) mgraTapData.getValueAt(row, "tap"); + if (tap > maxTap) maxTap = tap; + float minTime = mgraTapData.getValueAt(row,"minTime"); + + int distance = Math.round(minTime / Constants.walkMinutesPerMile * Constants.feetPerMile); + + //reset 0 distances to 0.1 miles, and log potential error + if(distance==0){ + //logger.info("Potential error: Distance from mgra "+mgra+" to tap "+tap+" is 0; resetting to 0.1 miles"); + distance = Math.round(Constants.feetPerMile * (float)0.1); + } + + if (!mgraWlkTapList.containsKey(mgra)) + mgraWlkTapList.put(mgra,new HashMap()); + mgraWlkTapList.get(mgra).put(tap,distance); + } + + // now go thru the array of ArrayLists and convert the lists to arrays + // and + // store in the class variable mgraWlkTapsDistArrays. + mgraWlkTapsDistArray = new int[maxMgra + 1][2][]; + nMgrasWithWlkTaps = mgraWlkTapList.size(); + for (int mgra : mgraWlkTapList.keySet()) { + Map wlkTapList = mgraWlkTapList.get(mgra); + mgraWlkTapsDistArray[mgra][0] = new int[wlkTapList.size()]; + mgraWlkTapsDistArray[mgra][1] = new int[wlkTapList.size()]; + int counter = 0; + for (int tap : new TreeSet(wlkTapList.keySet())) { //get the taps in ascending order - not sure if this matters, but it is cleaner + int distance = wlkTapList.get(tap); + mgraWlkTapsDistArray[mgra][0][counter] = tap; + mgraWlkTapsDistArray[mgra][1][counter] = distance; + counter++; + } + } + } + + /** + * read tap lines table (tap, line names served) + * @param rbMap + */ + public void readTapLines(HashMap rbMap) { + + File tapLinesTableFile = Paths.get(Util.getStringValueFromPropertyMap(rbMap, "scenario.path"), + Util.getStringValueFromPropertyMap(rbMap, "maz.tap.tapLines")).toFile(); + try { + CSVFileReader csvReader = new CSVFileReader(); + tapLinesTable = csvReader.readFile( tapLinesTableFile); + } catch (IOException e) { + throw new RuntimeException(); + } + + //get tap lines table field names + int[] tapLinesTapIds = tapLinesTable.getColumnAsInt("TAP"); + String[] linesForTap = tapLinesTable.getColumnAsString("LINES"); + + //create lookups + taplines = new HashMap(); + for(int i=0; i maz2TapData = new ArrayList(); + for (int j=0; j linesServed = new HashMap(); + for (Maz2Tap m2t : maz2TapData) { + + //skip if no lines served + if(m2t.lines != null) { + + for (int k=0; k tapsToRemove = new ArrayList(); + for (Maz2Tap m2t : maz2TapData) { + mazToTaps = mazToTaps + 1; + if( m2t.servesNewLines == false) { + tapsToRemove.add(m2t.tap); + trimmedTaps = trimmedTaps + 1; + } + } + + int[] finalTaps = new int[taps.length-tapsToRemove.size()]; + int[] finalDistances = new int[taps.length-tapsToRemove.size()]; + + int tapCounter = 0; + for (int m=0; m rbMap) + { + String mgraWlkTimeFile = rbMap.get(SandagWalkPathAlternativeListGenerationConfiguration.PROPERTIES_OUTPUT) + + rbMap.get(MGRA_MGRA_WALK_FILE_PROPERTY); + oMgraWalkDistance = new HashMap[maxMgra + 1]; + dMgraWalkDistance = new HashMap[maxMgra + 1]; + + TableDataSet mgraWalkData = Util.readTableDataSet(mgraWlkTimeFile); + + //i,j,walkTime,dist,mmTime,mmCost,mtTime,mtCost,mmGenTime,mtGenTime,minTime + for(int row = 1; row <= mgraWalkData.getRowCount();++row) { + + int oMgra = (int) mgraWalkData.getValueAt(row, "i"); + int dMgra = (int) mgraWalkData.getValueAt(row, "j"); + int distance = Math.round( mgraWalkData.getValueAt(row, "minTime") / Constants.walkMinutesPerMile * Constants.feetPerMile); + + if (oMgraWalkDistance[oMgra] == null) + oMgraWalkDistance[oMgra] = new HashMap(); + oMgraWalkDistance[oMgra].put(dMgra, distance); + + if (dMgraWalkDistance[dMgra] == null) + dMgraWalkDistance[dMgra] = new HashMap(); + dMgraWalkDistance[dMgra].put(oMgra, distance); + } + + } + + /** + * Return an int array of mgras within walking distance of this mgra. + * + * @param mgra + * The mgra to look up + * @return The mgras within walking distance. Null is returned if no mgras + * are within walk distance. + */ + public int[] getMgrasWithinWalkDistanceFrom(int mgra) + { + + if (oMgraWalkDistance[mgra] == null) return null; + + Set keySet = oMgraWalkDistance[mgra].keySet(); + int[] walkMgras = new int[keySet.size()]; + Iterator it = keySet.iterator(); + int i = 0; + while (it.hasNext()) + { + walkMgras[i] = it.next(); + ++i; + } + return walkMgras; + + } + + /** + * Return an int array of mgras within walking distance of this mgra. + * + * @param mgra + * The mgra to look up + * @return The mgras within walking distance. Null is returned if no mgras + * are within walk distance. + */ + public int[] getMgrasWithinWalkDistanceTo(int mgra) + { + + if (dMgraWalkDistance[mgra] == null) return null; + + Set keySet = dMgraWalkDistance[mgra].keySet(); + int[] walkMgras = new int[keySet.size()]; + Iterator it = keySet.iterator(); + int i = 0; + while (it.hasNext()) + { + walkMgras[i] = it.next(); + ++i; + } + return walkMgras; + + } + + /** + * Return true if mgras are within walking distance of each other. + * + * @param oMgra + * The from mgra + * @param dMgra + * The to mgra + * @return The mgras are within walking distance - true or false. + */ + public boolean getMgrasAreWithinWalkDistance(int oMgra, int dMgra) + { + + if (dMgraWalkDistance[dMgra] == null) return false; + + return dMgraWalkDistance[dMgra].containsKey(oMgra); + + } + + + + /** + * Get the position of the tap in the mgra walk tap array. + * + * @param mgra + * The mgra to lookup + * @param tap + * The tap to lookup + * @return The position of the tap in the mgra array. -1 is returned if it + * is an invalid tap for the mgra, or if the tap is not within + * walking distance. + */ + public int getTapPosition(int mgra, int tap) + { + + if (mgraWlkTapsDistArray[mgra] != null) + { + if (mgraWlkTapsDistArray[mgra][0] != null) + { + for (int i = 0; i < mgraWlkTapsDistArray[mgra][0].length; ++i) + if (mgraWlkTapsDistArray[mgra][0][i] == tap) return i; + } + } + + return -1; + + } + + /** + * Get the walk board time from an MGRA to a TAP. + * + * @param mgra + * The number of the destination MGRA. + * @param pos + * The position of the TAP in the MGRA array (0+) + * @return The walk time in minutes. + */ + public float getMgraToTapWalkBoardTime(int mgra, int pos) + { + float distanceInFeet = (float) mgraWlkTapsDistArray[mgra][1][pos]; + float time = distanceInFeet/Constants.feetPerMile * Constants.walkMinutesPerMile; + return time; + } + + + //todo: delete this method: currently retained for compatibility (namely: abm_reports) + /** + * Get the walk time from an MGRA to a TAP. + * + * @param mgra The number of the destination MGRA. + * @param pos The position of the TAP in the MGRA array (0+) + * @return The walk time in minutes. + */ + public float getMgraToTapWalkTime(int mgra, int pos) + { + float distanceInFeet = (float) mgraWlkTapsDistArray[mgra][1][pos]; + float time = distanceInFeet/Constants.feetPerMile * Constants.walkMinutesPerMile; + return time; + } + + /** + * Get the walk distance from an MGRA to an MGRA. Return 0 if not within walking + * distance. + * + * @param oMgra + * The number of the production/origin MGRA. + * @param dMgra + * The number of the attraction/destination MGRA. + * @return The walk distance in feet. + */ + public int getMgraToMgraWalkDistFrom(int oMgra, int dMgra) + { + + if (oMgraWalkDistance[oMgra] == null) return 0; + else if (oMgraWalkDistance[oMgra].containsKey(dMgra)) + //return oMgraWalkDistance[oMgra].get(dMgra)[0]; + + return oMgraWalkDistance[oMgra].get(dMgra); + + return 0; + } + + /** + * Get the walk time from an MGRA to a TAP. + * + * @param mgra The MGRA + * @param tap The TAP + * @return The walk time in minutes, else -1 if there is no walk link between the MGRA and the TAP. + */ + public float getWalkTimeFromMgraToTap(int mgra, int tap){ + + int tapPosition = getTapPosition(mgra, tap); + float time = 0; + + if(tapPosition==-1){ + logger.info("Bad Tap Position for Walk Access From MAZ: "+mgra+" to TAP: "+tap); + return -1; + } + else{ + time = (float) (mgraWlkTapsDistArray[mgra][1][tapPosition] * Constants.walkMinutesPerFoot); + } + return time; + } + /** + * Get the walk distance from an MGRA to a TAP. + * + * @param mgra The MGRA + * @param tap The TAP + * @return The walk distance in miles, else -1 if there is no walk link between the MGRA and the TAP. + */ + public float getWalkDistanceFromMgraToTap(int mgra, int tap){ + + int tapPosition = getTapPosition(mgra, tap); + float distance = 0; + + if(tapPosition==-1){ + logger.info("Bad Tap Position for Walk Access From MAZ: "+mgra+" to TAP: "+tap); + return -1; + } + else{ + distance = (float) (mgraWlkTapsDistArray[mgra][1][tapPosition]/Constants.feetPerMile); + } + return distance; + } + /** + * Get the walk distance from an MGRA to an MGRA. Return 0 if not within + * walking distance. + * + * @param oMgra + * The number of the production/origin MGRA. + * @param dMgra + * The number of the attraction/destination MGRA. + * @return The walk distance in feet. + */ + public int getMgraToMgraWalkDistTo(int oMgra, int dMgra) + { + + if (dMgraWalkDistance[dMgra] == null) return 0; + else if (dMgraWalkDistance[dMgra].containsKey(oMgra)) + + return dMgraWalkDistance[dMgra].get(oMgra); + + return 0; + } + + /** + * Get the walk time from an MGRA to an MGRA. Return 0 if not within walking + * distance. + * + * @param oMgra + * The number of the production/origin MGRA. + * @param dMgra + * The number of the attraction/destination MGRA. + * @return The walk time in minutes. + */ + public float getMgraToMgraWalkTime(int oMgra, int dMgra) + { + + if (oMgraWalkDistance[oMgra] == null) return 0f; + else if (oMgraWalkDistance[oMgra].containsKey(dMgra)){ + float distanceInFeet = (float) oMgraWalkDistance[oMgra].get(dMgra); + float time = distanceInFeet/Constants.feetPerMile * Constants.walkMinutesPerMile; + return time; + } + return 0f; + } + + /** + * Get the bike time from an MGRA to an MGRA. Return 0 if not within walking + * distance. + * + * @param oMgra + * The number of the production/origin MGRA. + * @param dMgra + * The number of the attraction/destination MGRA. + * @return The bike time in minutes. + */ + public float getMgraToMgraBikeTime(int oMgra, int dMgra) + { + double time = bls.getTime(defaultSegment,oMgra,dMgra); + return (time == Double.POSITIVE_INFINITY) ? 0f : (float) time; + } + + /** + * Print mgra data to the log file for debugging purposes. + * + */ + public void printMgraStats() + { + logger.info("Number of MGRAs: " + mgras.size()); + logger.info("Max MGRA: " + maxMgra); + + // logger.info("Number of MGRAs with WalkAccessTaps: " + + // nMgrasWithWlkTaps); + // logger.info("Number of TAPs in MGRA 18 (should be 3): " + // + mgraWlkTapsDistArray[18][0].length); + // logger.info("Distance between MGRA 18 and TAP 1648 (should be 2728): " + // + mgraWlkTapsDistArray[18][1][1]); + // logger.info("MGRA 28435 is in what TAZ? (Should be 995)" + + // mgraTaz[28435]); + // logger.info("Number of mgras within walk distance of mgra 22573 (Should be 67)" + // + getMgrasWithinWalkDistanceFrom(22573).length); + + } + + /** + * + * @param mgra + * - the zone + * @return the taz that the tmgra is contained in + */ + public int getTaz(int mgra) + { + return mgraTaz[mgra]; + } + + /** + * + * @param mgra + * - the zone + * @return the luz that the mgra is contained in + */ + public int getMgraLuz(int mgra) + { + return mgraLuz[mgra]; + } + + /** + * Get the maximum LUZ. + * + * @return The highest LUZ number + */ + public int getMaxLuz() + { + return maxLuz; + } + + /** + * Get the maximum MGRA. + * + * @return The highest MGRA number + */ + public int getMaxMgra() + { + return maxMgra; + } + + /** + * Get the maximum TAP. + * + * @return The highest TAP number + */ + public int getMaxTap() + { + return maxTap; + } + + /** + * Get the ArrayList of MGRAs + * + * @return ArrayList mgras. + */ + public ArrayList getMgras() + { + return mgras; + } + + /** + * Get the MgraTaz correspondence array. Given an MGRA, returns its TAZ. + * + * @return int[] mgraTaz correspondence array. + */ + public int[] getMgraTaz() + { + return mgraTaz; + } + + /** + * Get the array of Taps within walk distance + * + * @return The int[][][] array of Taps within walk distance of MGRAs + */ + public int[][][] getMgraWlkTapsDistArray() + { + return mgraWlkTapsDistArray; + } + + /** + * get arrays of drive accessible TAPS for each MGRA and populate an array + * of sets so that later one can determine, for a given mgra, if a tap is + * contained in the set. + * + * @param args + * TazDataManager to get TAPs with drive access from TAZs + */ + public void mapDriveAccessTapsToMgras(TazDataManager tazDataManager) + { + + walkAccessibleTaps = new TreeSet[maxMgra + 1]; + driveAccessibleTaps = new TreeSet[maxMgra + 1]; + + for (int mgra = 1; mgra <= maxMgra; mgra++) + { + + // get the TAZ associated with this MGRA + int taz = getTaz(mgra); + + // store the array of walk accessible TAPS for this MGRA as a set so + // that contains can be called on it later + // to determine, for a given mgra, if a tap is contained in the set. + int[] mgraSet = getMgraWlkTapsDistArray()[mgra][0]; + if (mgraSet != null) + { + walkAccessibleTaps[mgra] = new TreeSet(); + for (int i = 0; i < mgraSet.length; i++) + walkAccessibleTaps[mgra].add(mgraSet[i]); + } + + // store the array of drive accessible TAPS for this MGRA as a set + // so that contains can be called on it later + // to determine, for a given mgra, if a tap is contained in the set. + int[] tapItems = tazDataManager.getParkRideOrKissRideTapsForZone(taz, + AccessMode.PARK_N_RIDE); + driveAccessibleTaps[mgra] = new TreeSet(); + for (int item : tapItems) + driveAccessibleTaps[mgra].add(item); + + } + + } + + /** + * @param mgra + * for which we want to know if TAP can be reached by drive + * access + * @param tap + * for which we want to know if the mgra can reach it by drive + * access + * @return true if reachable; false otherwise + */ + public boolean getTapIsDriveAccessibleFromMgra(int mgra, int tap) + { + if (driveAccessibleTaps[mgra] == null) return false; + else return driveAccessibleTaps[mgra].contains(tap); + } + + /** + * @param mgra + * for which we want to know if TAP can be reached by walk access + * @param tap + * for which we want to know if the mgra can reach it by walk + * access + * @return true if reachable; false otherwise + */ + public boolean getTapIsWalkAccessibleFromMgra(int mgra, int tap) + { + if (walkAccessibleTaps[mgra] == null) return false; + else return walkAccessibleTaps[mgra].contains(tap); + } + + /** + * return the duDen value for the mgra + * + * @param mgra + * is the MGRA value for which the duDen value is needed + * @return duDen[mgra] + */ + public double getDuDenValue(int mgra) + { + return duDen[mgra]; + } + + /** + * return the empDen value for the mgra + * + * @param mgra + * is the MGRA value for which the empDen value is needed + * @return empDen[mgra] + */ + public double getEmpDenValue(int mgra) + { + return empDen[mgra]; + } + + /** + * return the totInt value for the mgra + * + * @param mgra + * is the MGRA value for which the totInt value is needed + * @return totInt[mgra] + */ + public double getTotIntValue(int mgra) + { + return totInt[mgra]; + } + + + public double getPopEmpPerSqMi( int mgra ) { + return popEmpDenPerSqMi[mgra]; + } + + /** + * Process the 4D density land use data file and store the selected fields + * as arrays indexed by the mgra value. The data fields are in the mgra + * TableDataSet read from the MGRA csv file. + * + * @param rbMap + * is a HashMap for the resource bundle generated from the + * properties file. + */ + public void process4ddensityData(HashMap rbMap) + { + + try + { + + // allocate arrays for the land use data fields + duDen = new double[maxMgra + 1]; + empDen = new double[maxMgra + 1]; + totInt = new double[maxMgra + 1]; + + //added for Taxi/TNC + popEmpDenPerSqMi = new double[maxMgra+1]; + + // get the data fields needed for the mode choice utilities as + // 0-based double[] + double[] duDenField = mgraTableDataSet.getColumnAsDouble(MGRA_4DDENSITY_DU_DEN_FIELD); + double[] empDenField = mgraTableDataSet.getColumnAsDouble(MGRA_4DDENSITY_EMP_DEN_FIELD); + double[] totIntField = mgraTableDataSet.getColumnAsDouble(MGRA_4DDENSITY_TOT_INT_FIELD); + double[] popEmpField = mgraTableDataSet.getColumnAsDouble( MGRA_POPEMPPERSQMI_FIELD ); + + // create a HashMap to convert MGRA values to array indices for the + // data + // arrays above + int mgraCol = mgraTableDataSet.getColumnPosition(MGRA_FIELD_NAME); + + for (int row = 1; row <= mgraTableDataSet.getRowCount(); row++) + { + + int mgra = (int) mgraTableDataSet.getValueAt(row, mgraCol); + duDen[mgra] = duDenField[row - 1]; + empDen[mgra] = empDenField[row - 1]; + totInt[mgra] = totIntField[row - 1]; + popEmpDenPerSqMi [mgra] = popEmpField[row-1]; + + } + + } catch (Exception e) + { + logger.error( + String.format("Exception occurred processing 4ddensity data file from mgraData TableDataSet object."), + e); + throw new RuntimeException(e); + } + + } + + private void readMgraTableData(HashMap rbMap) + { + + // get the mgra data table from one of these UECs. + String projectPath = rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String mgraFile = rbMap.get(PROPERTIES_MGRA_DATA_FILE); + mgraFile = projectPath + mgraFile; + + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + mgraTableDataSet = reader.readFile(new File(mgraFile)); + } catch (IOException e) + { + logger.error("problem reading mgra data table for MgraDataManager.", e); + System.exit(1); + } + + HashMap tazs = new HashMap(); + HashMap luzs = new HashMap(); + + // create a HashMap between mgra values and the corresponding row number + // in the mgra TableDataSet. + mgraDataTableMgraRowMap = new HashMap(); + maxMgra = 0; + maxLuz = 0; + for (int i = 1; i <= mgraTableDataSet.getRowCount(); i++) + { + int mgra = (int) mgraTableDataSet.getValueAt(i, MGRA_FIELD_NAME); + int taz = (int) mgraTableDataSet.getValueAt(i, MGRA_TAZ_FIELD_NAME); + + int luz = (int) mgraTableDataSet.getValueAt(i, MGRA_LUZ_FIELD_NAME); + + mgraDataTableMgraRowMap.put(mgra, i); + + if (mgra > maxMgra) maxMgra = mgra; + mgras.add(mgra); + + tazs.put(mgra, taz); + + if (luz > 0) + { + if (luz > maxLuz) maxLuz = luz; + luzs.put(mgra, luz); + } + } + + mgraTaz = new int[maxMgra + 1]; + for (int mgra : mgras) + mgraTaz[mgra] = tazs.get(mgra); + + mgraLuz = new int[maxMgra + 1]; + for (int mgra : mgras) + mgraLuz[mgra] = luzs.get(mgra); + + } + + /** + * @param mgra + * for which table data is desired + * @return population for the specified mgra. + */ + public double getMgraPopulation(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_POPULATION_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return households for the specified mgra. + */ + public double getMgraHouseholds(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_HOUSEHOLDS_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return grade school enrollment for the specified mgra. + */ + public double getMgraGradeSchoolEnrollment(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_GRADE_SCHOOL_ENROLLMENT_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return high school enrollment for the specified mgra. + */ + public double getMgraHighSchoolEnrollment(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_HIGH_SCHOOL_ENROLLMENT_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return university enrollment for the specified mgra. + */ + public double getMgraUniversityEnrollment(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_UNIVERSITY_ENROLLMENT_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return other college enrollment for the specified mgra. + */ + public double getMgraOtherCollegeEnrollment(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_OTHER_COLLEGE_ENROLLMENT_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return adult school enrollment for the specified mgra. + */ + public double getMgraAdultSchoolEnrollment(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_ADULT_SCHOOL_ENROLLMENT_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return grade school district for the specified mgra. + */ + public int getMgraGradeSchoolDistrict(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return (int) mgraTableDataSet.getValueAt(row, MGRA_GRADE_SCHOOL_DISTRICT_FIELD_NAME); + } + + /** + * @param mgra + * for which table data is desired + * @return high school district for the specified mgra. + */ + public int getMgraHighSchoolDistrict(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return (int) mgraTableDataSet.getValueAt(row, MGRA_HIGH_SCHOOL_DISTRICT_FIELD_NAME); + } + + public HashMap getMgraDataTableMgraRowMap() + { + return mgraDataTableMgraRowMap; + } + + private void calculateMgraAvgParkingCosts(HashMap propertyMap) + { + + // open output file to write average parking costs for each mgra + PrintWriter out = null; + + String projectPath = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String outFile = propertyMap.get(PROPERTIES_PARKING_COST_OUTPUT_FILE); + outFile = projectPath + outFile; + + try + { + out = new PrintWriter(new BufferedWriter(new FileWriter(new File(outFile)))); + } catch (IOException e) + { + logger.error("Exception caught trying to create file " + outFile); + System.out.println("Exception caught trying to create file " + outFile); + e.printStackTrace(); + throw new RuntimeException(); + } + + // write the header record + out.println("mgra,mgraParkArea,lsWgtAvgCostM,lsWgtAvgCostD,lsWgtAvgCostH"); + + // open output files for writing debug info for a specific mgra + PrintWriter outM = null; + PrintWriter outD = null; + PrintWriter outH = null; + + if (LOG_MGRA > 0) + { + try + { + outM = new PrintWriter(new BufferedWriter(new FileWriter(new File(projectPath + + "output/" + LOG_MGRA_FILE + "M.csv")))); + outD = new PrintWriter(new BufferedWriter(new FileWriter(new File(projectPath + + "output/" + LOG_MGRA_FILE + "D.csv")))); + outH = new PrintWriter(new BufferedWriter(new FileWriter(new File(projectPath + + "output/" + LOG_MGRA_FILE + "H.csv")))); + } catch (IOException e) + { + // TODO Auto-generated catch block + e.printStackTrace(); + } + } + + float workDistCoeff = Float.parseFloat(propertyMap.get(MGRA_DISTANCE_COEFF_WORK)); + float otherDistCoeff = Float.parseFloat(propertyMap.get(MGRA_DISTANCE_COEFF_OTHER)); + + int[] mgraField = mgraTableDataSet.getColumnAsInt(MGRA_FIELD_NAME); + int[] mgraParkAreaField = mgraTableDataSet.getColumnAsInt(MGRA_PARKAREA_FIELD); + int[] hstallsothField = mgraTableDataSet.getColumnAsInt(MGRA_HSTALLSOTH_FIELD); + int[] hstallssamField = mgraTableDataSet.getColumnAsInt(MGRA_HSTALLSSAM_FIELD); + float[] hparkcostField = mgraTableDataSet.getColumnAsFloat(MGRA_HPARKCOST_FIELD); + int[] numfreehrsField = mgraTableDataSet.getColumnAsInt(MGRA_NUMFREEHRS_FIELD); + int[] dstallsothField = mgraTableDataSet.getColumnAsInt(MGRA_DSTALLSOTH_FIELD); + int[] dstallssamField = mgraTableDataSet.getColumnAsInt(MGRA_DSTALLSSAM_FIELD); + float[] dparkcostField = mgraTableDataSet.getColumnAsFloat(MGRA_DPARKCOST_FIELD); + int[] mstallsothField = mgraTableDataSet.getColumnAsInt(MGRA_MSTALLSOTH_FIELD); + int[] mstallssamField = mgraTableDataSet.getColumnAsInt(MGRA_MSTALLSSAM_FIELD); + float[] mparkcostField = mgraTableDataSet.getColumnAsFloat(MGRA_MPARKCOST_FIELD); + + mgraParkArea = new int[maxMgra + 1]; + numfreehrs = new int[maxMgra + 1]; + hstallsoth = new int[maxMgra + 1]; + hstallssam = new int[maxMgra + 1]; + hparkcost = new float[maxMgra + 1]; + dstallsoth = new int[maxMgra + 1]; + dstallssam = new int[maxMgra + 1]; + dparkcost = new float[maxMgra + 1]; + mstallsoth = new int[maxMgra + 1]; + mstallssam = new int[maxMgra + 1]; + mparkcost = new float[maxMgra + 1]; + + lsWgtAvgCostM = new double[maxMgra + 1]; + lsWgtAvgCostD = new double[maxMgra + 1]; + lsWgtAvgCostH = new double[maxMgra + 1]; + + // loop over the number of mgra records in the TableDataSet. + for (int k = 0; k < maxMgra; k++) + { + + // get the mgra value for TableDataSet row k from the mgra field. + int mgra = mgraField[k]; + + mgraParkArea[mgra] = mgraParkAreaField[k]; + numfreehrs[mgra] = numfreehrsField[k]; + hstallsoth[mgra] = hstallsothField[k]; + hstallssam[mgra] = hstallssamField[k]; + hparkcost[mgra] = hparkcostField[k]; + dstallsoth[mgra] = dstallsothField[k]; + dstallssam[mgra] = dstallssamField[k]; + dparkcost[mgra] = dparkcostField[k]; + mstallsoth[mgra] = mstallsothField[k]; + mstallssam[mgra] = mstallssamField[k]; + mparkcost[mgra] = mparkcostField[k]; + + // get the array of mgras within walking distance of m + int[] walkMgras = getMgrasWithinWalkDistanceFrom(mgra); + + // park area 1. + if (mgraParkArea[mgra] == PARK_AREA_ONE) + { + + // calculate weighted average cost from monthly costs + double dist = getMgraToMgraWalkDistFrom(mgra, mgra) / 5280.0; + + double numeratorM = mstallssam[mgra] * Math.exp(workDistCoeff * dist) + * mparkcost[mgra]; + double denominatorM = mstallssam[mgra] * Math.exp(workDistCoeff * dist); + + double numeratorD = dstallssam[mgra] * Math.exp(workDistCoeff * dist) + * dparkcost[mgra]; + double denominatorD = dstallssam[mgra] * Math.exp(workDistCoeff * dist); + + double discountFactor = Math.max(1 - (numfreehrs[mgra] / 4), 0); + double numeratorH = hstallssam[mgra] * Math.exp(workDistCoeff * dist) + * discountFactor * hparkcost[mgra]; + double denominatorH = hstallssam[mgra] * Math.exp(workDistCoeff * dist); + + if (mgra == LOG_MGRA) + { + // log the file header + outM.println("wMgra" + "," + "mgraParkArea" + "," + "workDistCoeff*dist" + "," + + "exp(workDistCoeff*dist)" + "," + "mstallsoth" + "," + "mparkcost" + + "," + "numeratorM" + "," + "denominatorM"); + outD.println("wMgra" + "," + "mgraParkArea" + "," + "otherDistCoeff*dist" + "," + + "exp(otherDistCoeff*dist)" + "," + "dstallsoth" + "," + "dparkcost" + + "," + "numeratorD" + "," + "denominatorD"); + outH.println("wMgra" + "," + "mgraParkArea" + "," + "otherDistCoeff*dist" + "," + + "exp(otherDistCoeff*dist)" + "," + "discountFactor" + "," + + "hstallsoth" + "," + "hparkcost" + "," + "numeratorH" + "," + + "denominatorH"); + + outM.println(mgra + "," + mgraParkArea[mgra] + "," + workDistCoeff * dist + "," + + Math.exp(workDistCoeff * dist) + "," + mstallsoth[mgra] + "," + + mparkcost[mgra] + "," + numeratorM + "," + denominatorM); + outD.println(mgra + "," + mgraParkArea[mgra] + "," + workDistCoeff * dist + "," + + Math.exp(workDistCoeff * dist) + "," + dstallsoth[mgra] + "," + + dparkcost[mgra] + "," + numeratorD + "," + denominatorD); + outH.println(mgra + "," + mgraParkArea[mgra] + "," + workDistCoeff * dist + "," + + Math.exp(workDistCoeff * dist) + "," + discountFactor + "," + + hstallsoth[mgra] + "," + hparkcost[mgra] + "," + numeratorH + "," + + denominatorH); + } + + if (walkMgras != null) + { + + for (int wMgra : walkMgras) + { + + // skip mgra if not in park area 1 or 2. + if (mgraParkArea[wMgra] > 2) + { + if (mgra == LOG_MGRA) + { + outM.println(wMgra + "," + mgraParkArea[wMgra]); + outD.println(wMgra + "," + mgraParkArea[wMgra]); + outH.println(wMgra + "," + mgraParkArea[wMgra]); + } + continue; + } + + if (wMgra != mgra) + { + dist = getMgraToMgraWalkDistFrom(mgra, wMgra) / 5280.0; + + if (dist > MAX_PARKING_WALK_DISTANCE) + { + if (mgra == LOG_MGRA) + { + outM.println(wMgra + "," + mgraParkArea[wMgra]); + outD.println(wMgra + "," + mgraParkArea[wMgra]); + outH.println(wMgra + "," + mgraParkArea[wMgra]); + } + continue; + } + + numeratorM += mstallsoth[wMgra] * Math.exp(workDistCoeff * dist) + * mparkcost[wMgra]; + denominatorM += mstallsoth[wMgra] * Math.exp(workDistCoeff * dist); + + numeratorD += dstallsoth[wMgra] * Math.exp(otherDistCoeff * dist) + * dparkcost[wMgra]; + denominatorD += dstallsoth[wMgra] * Math.exp(otherDistCoeff * dist); + + discountFactor = Math.max(1 - (numfreehrs[wMgra] / 4), 0); + numeratorH += hstallsoth[wMgra] * Math.exp(otherDistCoeff * dist) + * discountFactor * hparkcost[wMgra]; + denominatorH += hstallsoth[wMgra] * Math.exp(otherDistCoeff * dist); + + if (mgra == LOG_MGRA) + { + outM.println(wMgra + "," + mgraParkArea[wMgra] + "," + + workDistCoeff * dist + "," + + Math.exp(workDistCoeff * dist) + "," + mstallsoth[wMgra] + + "," + mparkcost[wMgra] + "," + numeratorM + "," + + denominatorM); + outD.println(wMgra + "," + mgraParkArea[wMgra] + "," + + otherDistCoeff * dist + "," + + Math.exp(otherDistCoeff * dist) + "," + dstallsoth[wMgra] + + "," + dparkcost[wMgra] + "," + numeratorD + "," + + denominatorD); + outH.println(wMgra + "," + mgraParkArea[wMgra] + "," + + otherDistCoeff * dist + "," + + Math.exp(otherDistCoeff * dist) + "," + discountFactor + + "," + hstallsoth[wMgra] + "," + hparkcost[wMgra] + "," + + numeratorH + "," + denominatorH); + } + + } + + } + + } + // jef: storing by mgra since they are indexed into by mgra + // wsu added if clauses. If denominators are 0, read costs directly from input file + if(denominatorM>0) + lsWgtAvgCostM[mgra] = numeratorM / denominatorM; + else + lsWgtAvgCostM[mgra] = mparkcost[mgra]; + if(denominatorD>0) + lsWgtAvgCostD[mgra] = numeratorD / denominatorD; + else + lsWgtAvgCostD[mgra] = dparkcost[mgra]; + if(denominatorH>0) + lsWgtAvgCostH[mgra] = numeratorH / denominatorH; + else + lsWgtAvgCostH[mgra] = hparkcost[mgra]; + } else + { + + lsWgtAvgCostM[mgra] = mparkcost[mgra]; + lsWgtAvgCostD[mgra] = dparkcost[mgra]; + lsWgtAvgCostH[mgra] = hparkcost[mgra]; + + } + + // write the data record + out.println(mgra + "," + mgraParkArea[mgra] + "," + lsWgtAvgCostM[mgra] + "," + + lsWgtAvgCostD[mgra] + "," + lsWgtAvgCostH[mgra]); + } + + if (LOG_MGRA > 0) + { + outM.close(); + outD.close(); + outH.close(); + } + + out.close(); + + } + + public double[] getLsWgtAvgCostM() + { + return lsWgtAvgCostM; + } + + public double[] getLsWgtAvgCostD() + { + return lsWgtAvgCostD; + } + + public double[] getLsWgtAvgCostH() + { + return lsWgtAvgCostH; + } + + public int[] getMgraParkAreas() + { + return mgraParkArea; + } + + public int[] getNumFreeHours() + { + return numfreehrs; + } + + public int[] getMStallsOth() + { + return mstallsoth; + } + + public int[] getMStallsSam() + { + return mstallssam; + } + + public float[] getMParkCost() + { + return mparkcost; + } + + public int[] getDStallsOth() + { + return dstallsoth; + } + + public int[] getDStallsSam() + { + return dstallssam; + } + + public float[] getDParkCost() + { + return dparkcost; + } + + public int[] getHStallsOth() + { + return hstallsoth; + } + + public int[] getHStallsSam() + { + return hstallssam; + } + + public float[] getHParkCost() + { + return hparkcost; + } + + /** + * @param mgra + * for which table data is desired + * @return high school district for the specified mgra. + */ + public int getMgraHourlyParkingCost(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return (int) mgraTableDataSet.getValueAt(row, MGRA_HPARKCOST_FIELD); + } + + public float getRefeulingStations(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_REFUELING_STATIONS_FIELD_NAME); + } + + public float getRemoteParkingLot(int mgra) + { + int row = mgraDataTableMgraRowMap.get(mgra); + return mgraTableDataSet.getValueAt(row, MGRA_REMOTE_PARKING_LOT_FIELD_NAME); + } + private class Maz2Tap implements Comparable, Serializable + { + public int maz; + public int tap; + public double dist; + public String[] lines; + public boolean servesNewLines = false; + + @Override + public int compareTo(Maz2Tap o) { + if ( this.dist < o.dist ) { + return -1; + } else if (this.dist==o.dist) { + return 0; + } else { + return 1; + } + } + } + public TableDataSet getMgraTableDataSet() { + return mgraTableDataSet; + } + + public static void main(String[] args) + { + ResourceBundle rb = ResourceUtil.getPropertyBundle(new File(args[0])); + MgraDataManager mdm = MgraDataManager.getInstance(ResourceUtil + .changeResourceBundleIntoHashMap(rb)); + mdm.printMgraStats(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/Modes.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/Modes.java new file mode 100644 index 0000000..2204762 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/Modes.java @@ -0,0 +1,115 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; + +/** + * This class is used for specifying modes. + * + * @author Christi Willison + * @version Sep 8, 2008 + *

+ * Created by IntelliJ IDEA. + */ +public final class Modes + implements Serializable +{ + + public enum AutoMode + { + DRIVE_ALONE_TOLL("dat"), DRIVE_ALONE_NONTOLL("dan"), TWO_NONTOLL("2nt"), TWO_TOLL( + "2t"), THREEPLUS_NONTOLL("3+nt"), THREEPLUS_TOLL( + "3+t"); + + private final String name; + + AutoMode(String s) + { + this.name = s; + } + + public AutoMode[] getAutoModes() + { + return AutoMode.values(); + } + + public String toString() + { + return name; + } + } + + public enum TransitMode + { + COMMUTER_RAIL("cr", true), // label and true = premium + LIGHT_RAIL("lr", true), BRT("brt", true), EXPRESS_BUS("eb", true), LOCAL_BUS("lb", false); + + private final String name; + private final boolean premium; + + TransitMode(String name, boolean premium) + { + this.name = name; + this.premium = premium; + } + + public TransitMode[] getTransitModes() + { + return TransitMode.values(); + } + + public boolean isPremiumMode(TransitMode transitMode) + { + return transitMode.premium; + } + + public String toString() + { + return name; + } + + } + + public enum AccessMode + { + WALK("WLK"), PARK_N_RIDE("PNR"), KISS_N_RIDE("KNR"); + private final String name; + + AccessMode(String name) + { + this.name = name; + } + + public AccessMode[] getAccessModes() + { + return AccessMode.values(); + } + + public String toString() + { + return name; + } + + } + + public enum NonMotorizedMode + { + WALK, BIKE + } + + public enum OtherMode + { + SCHOOL_BUS + } + + private Modes() + { + // Not implemented in utility classes + } + + + public static void main(String[] args) + { + System.out.println(AutoMode.DRIVE_ALONE_NONTOLL.toString()); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/NonMotorDMU.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/NonMotorDMU.java new file mode 100644 index 0000000..01a7a4b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/NonMotorDMU.java @@ -0,0 +1,146 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.VariableTable; + +/** + * This class is used for non-motorized DMU attributes. + * + * @author Joel Freedman + * @version May 28,2009 + *

+ */ +public class NonMotorDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(NonMotorDMU.class); + + protected HashMap methodIndexMap; + + private float mgraWalkTime; + private float mgraBikeTime; + + public NonMotorDMU() + { + setupMethodIndexMap(); + } + + /** + * Get MGRA-MGRA walk time. + * + * @return Mgra-mgra walk time in minutes. + */ + public float getMgraWalkTime() + { + return mgraWalkTime; + } + + /** + * Set Mgra-Mgra walk time in minutes. + * + * @param mgraWalkTime + * Mgra walk time in minutes. + */ + public void setMgraWalkTime(float mgraWalkTime) + { + this.mgraWalkTime = mgraWalkTime; + } + + /** + * Get MGRA-MGRA bike time. + * + * @return Mgra-mgra bike time in minutes. + */ + public float getMgraBikeTime() + { + return mgraBikeTime; + } + + /** + * Set Mgra-Mgra bike time in minutes. + * + * @param mgraBikeTime + * Mgra bike time in minutes. + */ + public void setMgraBikeTime(float mgraBikeTime) + { + this.mgraBikeTime = mgraBikeTime; + } + + /** + * Log the DMU values. + * + * @param localLogger + * The logger to use. + */ + public void logValues(Logger localLogger) + { + + localLogger.info(""); + localLogger.info("Non-Motorized DMU Values:"); + localLogger.info(""); + localLogger.info(String.format("MGRA-MGRA Walk Time: %9.4f", mgraWalkTime)); + localLogger.info(String.format("MGRA-MGRA Bike Time: %9.4f", mgraBikeTime)); + + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getMgraBikeTime", 0); + methodIndexMap.put("getMgraWalkTime", 1); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = 0; + + switch (variableIndex) + { + case 0: + returnValue = getMgraBikeTime(); + break; + case 1: + returnValue = getMgraWalkTime(); + break; + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/NonMotorUEC.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/NonMotorUEC.java new file mode 100644 index 0000000..4e80181 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/NonMotorUEC.java @@ -0,0 +1,189 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.Arrays; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.calculator.IndexValues; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.LogitModel; +import com.pb.common.newmodel.UtilityExpressionCalculator; +import com.pb.common.util.Tracer; + +/** + * This class is used for ... + * + * @author Christi Willison + * @version Mar 9, 2009 + *

+ * Created by IntelliJ IDEA. + */ +public class NonMotorUEC + implements Serializable +{ + + private transient Logger logger = Logger.getLogger(NonMotorUEC.class); + private TazDataManager tazManager; + private MgraDataManager mgraManager; + private UtilityExpressionCalculator uec; + private IndexValues index = new IndexValues(); + private int[] availFlag; + private NonMotorDMU dmu; + private LogitModel model; + private ChoiceModelApplication modelApp; + + // seek and trace + private boolean trace; + private int[] traceOtaz; + private int[] traceDtaz; + protected Tracer tracer; + + /** + * Default Constructor. + * + * @param rb + * @param uecFileName + * @param modelSheet + * @param dataSheet + */ + public NonMotorUEC(HashMap rbHashMap, String uecFileName, int modelSheet, + int dataSheet) + { + + dmu = new NonMotorDMU(); + + // use the choice model application to set up the model structure + modelApp = new ChoiceModelApplication(uecFileName, modelSheet, dataSheet, rbHashMap, dmu); + + // but return the logit model itself, so we can use compound utilities + model = modelApp.getRootLogitModel(); + uec = modelApp.getUEC(); + availFlag = new int[uec.getNumberOfAlternatives() + 1]; + + tazManager = TazDataManager.getInstance(); + mgraManager = MgraDataManager.getInstance(); + + trace = Util.getBooleanValueFromPropertyMap(rbHashMap, "Trace"); + traceOtaz = Util.getIntegerArrayFromPropertyMap(rbHashMap, "Trace.otaz"); + traceDtaz = Util.getIntegerArrayFromPropertyMap(rbHashMap, "Trace.dtaz"); + + // set up the tracer object + tracer = Tracer.getTracer(); + tracer.setTrace(trace); + for (int i = 0; i < traceOtaz.length; i++) + { + for (int j = 0; j < traceDtaz.length; j++) + { + tracer.traceZonePair(traceOtaz[i], traceDtaz[j]); + logger.info("Setting trace zone pair in NonMotorUEC Object for i: "+ traceOtaz[i] + " j: " + traceDtaz[j]); + } + } + } + + /** + * Calculate utilities for a given TAZ pair. + * + * @param pTaz + * Production/Origin TAZ. + * @param aTaz + * Attraction/Destination TAZ. + * @return The root utility. + */ + public double calculateUtilitiesForTazPair(int pTaz, int aTaz) + { + + index.setOriginZone(pTaz); + index.setDestZone(aTaz); + + Arrays.fill(availFlag, 1); + dmu.setMgraWalkTime(0); + dmu.setMgraBikeTime(0); + + trace = false; + if (tracer.isTraceOn() && tracer.isTraceZonePair(pTaz, aTaz)) + { + trace = true; + } + + // log DMU values + if (trace) + { + TapDataManager tapManager = TapDataManager.getInstance(); + if (Arrays.binarySearch(tapManager.getTaps(), pTaz) > 0 + && Arrays.binarySearch(tapManager.getTaps(), aTaz) > 0) + uec.logDataValues(logger, pTaz, aTaz, 0); + dmu.logValues(logger); + } + + modelApp.computeUtilities(dmu, index); + double utility = modelApp.getLogsum(); + if (utility == 0) utility = -999; + + // logging + if (trace) + { + uec.logAnswersArray(logger, "NonMotorized UEC"); + uec.logResultsArray(logger, pTaz, aTaz); + modelApp.logLogitCalculations("NonMotorized UEC", "Zone Trace"); + logger.info("Logsum = " + utility); + trace = false; + } + + return utility; + } + + /** + * Calculate utilities for a given TAZ pair. + * + * @param oMgra + * Production/Origin Mgra. + * @param dMgra + * Attraction/Destination Mgra. + * @return The root utility. + */ + public double calculateUtilitiesForMgraPair(int oMgra, int dMgra) + { + + Arrays.fill(availFlag, 1); + + trace = false; + int pTaz = mgraManager.getTaz(oMgra); + int aTaz = mgraManager.getTaz(dMgra); + index.setOriginZone(pTaz); + index.setDestZone(aTaz); + + if (tracer.isTraceOn() && tracer.isTraceZone(pTaz)) + { + trace = true; + } + + dmu.setMgraWalkTime(mgraManager.getMgraToMgraWalkTime(oMgra, dMgra)); + dmu.setMgraBikeTime(mgraManager.getMgraToMgraBikeTime(oMgra, dMgra)); + + // log DMU values + if (trace) + { + logger.info("MGRA-MGRA non-motorized calculations for " + oMgra + " to " + dMgra); + dmu.logValues(logger); + } + + modelApp.computeUtilities(dmu, index); + double utility = modelApp.getLogsum(); + if (utility == 0) utility = -999; + + // logging + if (trace) + { + uec.logAnswersArray(logger, "NonMotorized UEC"); + uec.logResultsArray(logger, pTaz, aTaz); + modelApp.logLogitCalculations("NonMotorized UEC", "Mgra Trace"); + logger.info("Logsum = " + utility); + trace = false; + } + dmu.setMgraWalkTime(0); + dmu.setMgraWalkTime(0); + return utility; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/TapDataManager.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TapDataManager.java new file mode 100644 index 0000000..5f42ed1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TapDataManager.java @@ -0,0 +1,321 @@ +package org.sandag.abm.modechoice; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.HashMap; +import java.util.Iterator; +import java.util.List; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.StringTokenizer; +import java.util.TreeMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.active.sandag.SandagWalkPathAlternativeListGenerationConfiguration; +import org.sandag.abm.active.sandag.SandagWalkPathChoiceLogsumMatrixApplication; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.util.ResourceUtil; + +public final class TapDataManager + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(TapDataManager.class); + private static volatile TapDataManager instance = null; + private static final Object LOCK = new Object(); + + // tapID, [tapNum, lotId, ??, taz][list of values] + private float[][][] tapParkingInfo; + + // an array that stores parking lot use by lot ID. + private int[] lotUse; + + // an array of taps + private int[] taps; + private int maxTap; + + public int getMaxTap() + { + return maxTap; + } + + private TapDataManager(HashMap rbMap) + { + + System.out.println("I'm the TapDataManager"); + readTap(rbMap); + getTapList(rbMap); + intializeLotUse(); + printStats(); + } + + /** + * This method should only be used after the getInstance(HashMap rbMap) method has been called since the rbMap is needed to read + * in all the data and populate the object. This method will return the + * instance that has already been populated. + * + * @return instance + * @throws RuntimeException + */ + public static TapDataManager getInstance() + { + if (instance == null) + { + throw new RuntimeException( + "Must instantiate TapDataManager with the getInstance(rbMap) method first"); + } else + { + return instance; + } + } + + /** + * This method will read in the tapParkingInfo.ptype file and store the info + * in a TreeMap where key equals the iTap and value equals an array of [][3] + * elements. The TreeMap will be passed to the populateTap function which + * will transpose the array of [][3] elements to an array of [4][] elements + * and attaches it to the this.tapParkingInfo[key] + * + * //TODO: Test this and see if there is only a single lot associated // + * TODO with each tap. + * + * The file has 6 columns - tap, lotId, parking type, taz, capacity and mode + * + * @param rb + * - the resource bundle that lists the tap.ptype file and + * scenario.path. + */ + private void readTap(HashMap rbMap) + { + + File tazTdzCorresFile = new File(Util.getStringValueFromPropertyMap(rbMap, "scenario.path") + + Util.getStringValueFromPropertyMap(rbMap, "tap.ptype.file")); + String s; + TreeMap> map = new TreeMap>(); + StringTokenizer st; + try + { + BufferedReader br = new BufferedReader(new FileReader(tazTdzCorresFile)); + while ((s = br.readLine()) != null) + { + st = new StringTokenizer(s, " "); + float[] tapList = new float[6]; + int key = Integer.parseInt(st.nextToken()); // tap number + tapList[0] = Float.parseFloat(st.nextToken()); // lot id + tapList[3] = Float.parseFloat(st.nextToken()); // ptype + tapList[1] = Float.parseFloat(st.nextToken()); // taz + tapList[2] = (Math.max(Float.parseFloat(st.nextToken()), 15)) * 2.5f; // lot capacity + tapList[4] = Float.parseFloat(st.nextToken()); // distance from lot to TAP + tapList[5] = Float.parseFloat(st.nextToken()); /* Transit mode {4: CR, + 5: LRT, + 6: BRT, + 7: BRT, + 8:Limited Express Bus, + 9:Express bus, + 10: local}*/ + + if (map.get(key) == null) + { + List newList = new ArrayList(); + newList.add(tapList); + map.put(key, newList); + } else + { + map.get(key).add(tapList); + } + } + br.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + populateTap(map); + } + + /** + * The function will get a TreeMap having with iTaps as keys and [][4] + * arrays. For each iTap in the TreeMap it will transpose the [][4] array + * associated with it and attach it to the this.tapParkingInfo[key] element. + * + * @param map + * - a TreeMap containing all the records of the + * tapParkingInfo.ptype file + */ + private void populateTap(TreeMap> map) + { + + this.tapParkingInfo = new float[map.lastKey() + 1][6][]; + Iterator iterKeys = map.keySet().iterator(); + while (iterKeys.hasNext()) + { + int key = iterKeys.next(); + int numElem = map.get(key).size(); + for (int i = 0; i < 6; i++) + this.tapParkingInfo[key][i] = new float[numElem]; + for (int i = 0; i < numElem; i++) + { + for (int j = 0; j < 6; j++) + { + this.tapParkingInfo[key][j][i] = map.get(key).get(i)[j]; + } + } + } + } + + // TODO: test this. + public void intializeLotUse() + { + + float maxLotId = 0; + for (int i = 0; i < tapParkingInfo.length; i++) + { + float[] lotIds = tapParkingInfo[i][0]; + if (lotIds != null) + { + for (int j = 0; j < tapParkingInfo[i][0].length; j++) + { + if (maxLotId < tapParkingInfo[i][0][j]) maxLotId = tapParkingInfo[i][0][j]; + + } + } + } + + lotUse = new int[(int) maxLotId + 1]; + } + + /** + * Set the array of tap numbers (taps[]), indexed at 1. + * + * @param rb + * A Resourcebundle with skims.path and tap.skim.file properties. + */ + public void getTapList(HashMap rbMap) + { + ArrayList tapList = new ArrayList(); + + File mgraWlkTapTimeFile = new File(rbMap.get(SandagWalkPathAlternativeListGenerationConfiguration.PROPERTIES_OUTPUT), + rbMap.get(SandagWalkPathChoiceLogsumMatrixApplication.WALK_LOGSUM_SKIM_MGRA_TAP_FILE_PROPERTY)); + Map> mgraWlkTapList = new HashMap<>(); //mgra -> tap -> [board dist,alight dist] + String s; + try ( BufferedReader br = new BufferedReader(new FileReader(mgraWlkTapTimeFile))) + { + // read the first data file line containing column names + s = br.readLine(); + + // read the data records + while ((s = br.readLine()) != null) + { + StringTokenizer st = new StringTokenizer(s, ","); + int mgra = Integer.parseInt(st.nextToken().trim()); + int tap = Integer.parseInt(st.nextToken().trim()); + if (tap > maxTap) maxTap = tap; + if (!tapList.contains(tap)) tapList.add(tap); + } + } catch (IOException e) { + logger.error(e); + throw new RuntimeException(e); + } + + // read taps from park-and-ride file + File tazTdzCorresFile = new File(Util.getStringValueFromPropertyMap(rbMap, "scenario.path") + + Util.getStringValueFromPropertyMap(rbMap, "tap.ptype.file")); + + try (BufferedReader br = new BufferedReader(new FileReader(tazTdzCorresFile))) + { + + while ((s = br.readLine()) != null) + { + StringTokenizer st = new StringTokenizer(s, " "); + int tap = Integer.parseInt(st.nextToken()); // tap number + if (!tapList.contains(tap)) tapList.add(tap); + } + br.close(); + } catch (IOException e) { + logger.error(e); + throw new RuntimeException(e); + } + + Collections.sort(tapList); + // now go thru the array of ArrayLists and convert the lists to arrays + // and + taps = new int[tapList.size() + 1]; + + for (int i = 0; i < tapList.size(); ++i) + taps[i + 1] = tapList.get(i); + + } + + public int getLotUse(int lotId) + { + return lotUse[lotId]; + } + + public void printStats() + { + /* + * logger.info("Tap 561 is in zone: " + tapParkingInfo[561][1][0]); + * logger.info("Tap 298 lot capacity: " + tapParkingInfo[298][2][0]); + */ + } + + public int getTazForTap(int tap) + { + return (int) tapParkingInfo[tap][1][0]; + } + + public static TapDataManager getInstance(HashMap rbMap) + { + if (instance == null) { + synchronized (LOCK) { + if (instance == null) { + instance = new TapDataManager(rbMap); + } + } + } + return instance; + } + + public float[][][] getTapParkingInfo() + { + if (instance != null) + { + return this.tapParkingInfo; + } else + { + throw new RuntimeException(); + } + } + + public float getCarToStationWalkTime(int tap) + { + return 0.0f; + } + + public float getEscalatorTime(int tap) + { + return 0.0f; + } + + public int[] getTaps() + { + return taps; + } + + public static void main(String[] args) + { + ResourceBundle rb = ResourceUtil.getPropertyBundle(new File(args[0])); + + TapDataManager tdm = TapDataManager.getInstance(ResourceUtil + .changeResourceBundleIntoHashMap(rb)); + tdm.printStats(); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/TazDataManager.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TazDataManager.java new file mode 100644 index 0000000..ab697d1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TazDataManager.java @@ -0,0 +1,924 @@ +package org.sandag.abm.modechoice; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.io.Serializable; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; +import java.util.ResourceBundle; +import java.util.StringTokenizer; +import java.util.TreeSet; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.Modes.AccessMode; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +/** + * This class is used for storing the TAZ data for the mode choice model. + * + * @author Christi Willison + * @version Sep 2, 2008 + *

+ * Created by IntelliJ IDEA. + */ +public final class TazDataManager + implements Serializable +{ + + protected transient Logger logger = Logger.getLogger(TazDataManager.class); + private static TazDataManager instance; + public int[] tazs; + protected int[] tazsOneBased; + + // arrays for the MGRA and TAZ fields from the MGRA table data file. + private int[] mgraTableMgras; + private int[] mgraTableTazs; + + // list of TAZs in numerical order + public TreeSet tazSet = new TreeSet(); + public int maxTaz; + + private int nTazsWithMgras; + private int[][] tazMgraArray; + // private int[][] tazXYCoordArray; + private float[] tazDestinationTerminalTime; + private float[] tazOriginTerminalTime; + // private int[] tazSuperDistrict; + // private int[] pmsa; + // private int[] cmsa; + // This might be a poor name for this array. + // Please change if you know better. + private int[] tazAreaType; + // they are being read from same file but might be different - + // [tdz][id,time,dist][tap position] + // in the future. + private float[][][] tazParkNRideTaps; + // They are floats because they store time and distance + private float[][][] tazKissNRideTaps; + + // added from tdz manager + private int[] tazParkingType; + + /** + * Get an array of tazs, indexed sequentially from 0 + * + * @return Taz array indexed from 0 + */ + public int[] getTazs() + { + return tazs; + } + + /** + * Get an array of tazs, indexed sequentially from 1 + * + * @return taz array indexed from 1 + */ + public int[] getTazsOneBased() + { + return tazsOneBased; + } + + private TazDataManager(HashMap rbMap) + { + System.out.println("I'm the TazDataManager"); + + // read the MGRA data file into a TableDataSet and get the MGRA and TAZ + // fields from it for setting TAZ correspondence. + readMgraTableData(rbMap); + setTazMgraCorrespondence(); + readTazTerminalTimeCorrespondence(rbMap); + readPnRTapsInfo(rbMap); + + //printTazStats(); + } + + /** + * This method reads in the taz.tdz file which has 2 columns. The first + * column is the taz and the second column is corresponding tdz. The + * correspondence will be stored in the tdz class. The only data captured + * here is the list of TAZs. + * + * This method will also set the maxTaz value. + * + * @param rb + * the properties file that lists the taz.tdz file and the + * generic.path. + */ + private void readTazs(HashMap rbMap) + { + File tazTdzCorresFile = new File(Util.getStringValueFromPropertyMap(rbMap, "generic.path") + + Util.getStringValueFromPropertyMap(rbMap, "taz.tdz.correspondence.file")); + String s; + int taz; + StringTokenizer st; + try + { + BufferedReader br = new BufferedReader(new FileReader(tazTdzCorresFile)); + while ((s = br.readLine()) != null) + { + st = new StringTokenizer(s, " "); + taz = Integer.parseInt(st.nextToken()); + tazSet.add(taz); + st.nextToken(); + } + br.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + maxTaz = tazSet.last(); + tazs = new int[tazSet.size()]; + tazsOneBased = new int[tazSet.size() + 1]; + int i = 0; + for (Integer tazNumber : tazSet) + { + tazs[i] = tazNumber; + tazsOneBased[i + 1] = tazNumber; + ++i; + } + + } + + /** + * This method will set the TAZ/MGRA correspondence. Two columns from the + * MGRA data table are used. The first column is the MGRA and the second + * column is the TAZ. The goal of this method is to populate the + * tazMgraArray array and the tazs treeset, plus set maxTaz. + * + */ + private void setTazMgraCorrespondence() + { + + HashMap> tazMgraMap = new HashMap>(); + + int mgra; + int taz; + + for (int i = 0; i < mgraTableMgras.length; i++) + { + + mgra = mgraTableMgras[i]; + taz = mgraTableTazs[i]; + if (!tazSet.contains(taz)) tazSet.add(taz); + + maxTaz = Math.max(taz, maxTaz); + + if (!tazMgraMap.containsKey(taz)) + { + ArrayList tazMgraList = new ArrayList(); + tazMgraList.add(mgra); + tazMgraMap.put(taz, tazMgraList); + } else + { + ArrayList tazMgraList = tazMgraMap.get(taz); + tazMgraList.add(mgra); + } + + } + + // now go thru the array of ArrayLists and convert the lists to arrays + // and + // store in the class variable tazMgraArrays. + tazMgraArray = new int[maxTaz + 1][]; + for (Iterator it = tazMgraMap.entrySet().iterator(); it.hasNext();) + { // elements + // in + // the + // array + // of + // arraylists + Map.Entry entry = (Map.Entry) it.next(); + taz = (Integer) entry.getKey(); + ArrayList tazMgraList = (ArrayList) entry.getValue(); + if (tazMgraList != null) + { // if the list isn't null + tazMgraArray[taz] = new int[tazMgraList.size()]; // initialize + // the class + // variable + for (int j = 0; j < tazMgraList.size(); j++) + tazMgraArray[taz][j] = (Integer) tazMgraList.get(j); + nTazsWithMgras++; + } + } + tazs = new int[tazSet.size()]; + + tazsOneBased = new int[tazSet.size() + 1]; + int i = 0; + for (Integer tazNumber : tazSet) + { + tazs[i] = tazNumber; + tazsOneBased[i + 1] = tazNumber; + ++i; + } + } + + /** + * This method will initialize the class variable tazSuperDistrict. The + * taz.district file has 2 columns, the first is the taz and the second is + * the superdistrict + * + * @param rb + * the resource bundle that specifies the taz.district file and + * the generic.path public void + * readTazDistrictCorrespondence(HashMap rbMap) { + * tazSuperDistrict = new int[maxTaz + 1]; File tazTdzCorresFile + * = new File(Util.getStringValueFromPropertyMap(rbMap, + * "generic.path") + Util.getStringValueFromPropertyMap(rbMap, + * "taz.district.correspondence.file")); String s; int taz; int + * sd; StringTokenizer st; try { BufferedReader br = new + * BufferedReader(new FileReader(tazTdzCorresFile)); while ((s = + * br.readLine()) != null) { st = new StringTokenizer(s, " "); + * taz = Integer.parseInt(st.nextToken()); sd = + * Integer.parseInt(st.nextToken()); tazSuperDistrict[taz] = sd; + * } br.close(); } catch (IOException e) { e.printStackTrace(); } + * } + */ + + /** + * This method will read the zone.avrzone file and store the location area + * (0-3) for each taz. + * + * + * @param rb + * - resourceBundle That specifies the zone.avrzone file and the + * generic.path private void + * readZoneAvrZoneCorrespondence(HashMap rbMap) { + * File zoneAvrZoneCorresFile = new + * File(Util.getStringValueFromPropertyMap(rbMap, "generic.path") + * + Util.getStringValueFromPropertyMap(rbMap, + * "taz.avrzone.correspondence.file")); tazAreaType = new + * int[maxTaz + 1]; + * + * // read the file to get the location area (0 - 3) for each TDZ + * String s; int taz; StringTokenizer st; int location; try { + * BufferedReader br = new BufferedReader(new + * FileReader(zoneAvrZoneCorresFile)); while ((s = br.readLine()) + * != null) { st = new StringTokenizer(s, " "); taz = + * Integer.parseInt(st.nextToken()); location = + * Integer.parseInt(st.nextToken()); tazAreaType[taz] = location; + * } br.close(); } catch (IOException e) { e.printStackTrace(); } + * + * } + */ + + /** + * This method reads in the zone.pmsa file which has 2 columns. The first + * column is the taz and the second column is corresponding pmsa. The + * correspondence will be stored in the pmsa list. The only data captured + * here is the list of pmsas. + * + * This method will also set the maxTaz value. + * + * @param rb + * the properties file that lists the taz.tdz file and the + * generic.path private void readZonePMSA(HashMap + * rbMap) { + * + * pmsa = new int[maxTaz + 1]; File zonePmsaFileName = new + * File(Util.getStringValueFromPropertyMap(rbMap, "generic.path") + * + Util.getStringValueFromPropertyMap(rbMap, "taz.pmsa.file")); + * String s; int taz; int tazPmsa; StringTokenizer st; try { + * BufferedReader br = new BufferedReader(new + * FileReader(zonePmsaFileName)); // BufferedReader br = new + * BufferedReader(new // + * FileReader("/Users/michalis/Documents/Fortran2Java/data/zone.pmsa" + * )); while ((s = br.readLine()) != null) { st = new + * StringTokenizer(s, " "); taz = + * Integer.parseInt(st.nextToken()); tazPmsa = + * Integer.parseInt(st.nextToken()); pmsa[taz] = tazPmsa; } + * br.close(); } catch (IOException e) { e.printStackTrace(); } + * + * } + */ + + /** + * This method reads in the zone.cmsa file which has 2 columns. The first + * column is the taz and the second column is corresponding cmsa. The + * correspondence will be stored in the cmsa list. The only data captured + * here is the list of cmsas. + * + * This method will also set the maxTaz value. + * + * @param rb + * the properties file that lists the zone.cmsa file and the + * generic.path + * + * private void readZoneCMSA(HashMap rbMap) { + * + * cmsa = new int[maxTaz + 1]; File zoneCmsaFile = new + * File(Util.getStringValueFromPropertyMap(rbMap, "generic.path") + * + Util.getStringValueFromPropertyMap(rbMap, "taz.cmsa.file")); + * String s; int taz; int tazCmsa; StringTokenizer st; try { + * BufferedReader br = new BufferedReader(new + * FileReader(zoneCmsaFile)); // BufferedReader br = new + * BufferedReader(new // + * FileReader("/Users/michalis/Documents/Fortran2Java/data/zone.cmsa" + * )); while ((s = br.readLine()) != null) { st = new + * StringTokenizer(s, " "); taz = + * Integer.parseInt(st.nextToken()); tazCmsa = + * Integer.parseInt(st.nextToken()); cmsa[taz] = tazCmsa; } + * br.close(); } catch (IOException e) { e.printStackTrace(); } + * + * } + * */ + + /** + * This method will read the zone.term file and store the terminal time for + * each taz. + * + * @param rb + * the properties file that lists the zone.term file and the + * scenario.path + */ + private void readTazTerminalTimeCorrespondence(HashMap rbMap) + { + File tdzTerminalTimeCorresFile = new File(Util.getStringValueFromPropertyMap(rbMap, + "scenario.path") + + Util.getStringValueFromPropertyMap(rbMap, "taz.terminal.time.file")); + + tazDestinationTerminalTime = new float[maxTaz + 1]; + tazOriginTerminalTime = new float[maxTaz + 1]; + + // read the file to get the terminal time for each TDZ + String s; + int taz; + StringTokenizer st; + float terminalTime; + try + { + BufferedReader br = new BufferedReader(new FileReader(tdzTerminalTimeCorresFile)); + while ((s = br.readLine()) != null) + { + st = new StringTokenizer(s, " "); + taz = Integer.parseInt(st.nextToken()); + terminalTime = Float.parseFloat(st.nextToken()); + tazDestinationTerminalTime[taz] = terminalTime; + tazOriginTerminalTime[taz] = terminalTime; + } + br.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + + } + + /** + * This method will read the zone.pterm file and store the production + * terminal time for each tdz. + * + * @param rb + * the properties file that lists the zone.pterm file and the + * scenario.path + * + * + * private void + * readTazProductionTerminalTimeCorrespondence(HashMap rbMap) { File tdzProductionTerminalTimeCorresFile = + * new File(Util.getStringValueFromPropertyMap( rbMap, + * "scenario.path") + Util.getStringValueFromPropertyMap(rbMap, + * "taz.prod.terminal.time.file")); + * + * tazOriginTerminalTime = new float[maxTaz + 1]; + * + * // read the file to get the production terminal time for each + * TDZ String s; int taz; StringTokenizer st; float + * productionTerminalTime; try { BufferedReader br = new + * BufferedReader(new FileReader( + * tdzProductionTerminalTimeCorresFile)); while ((s = + * br.readLine()) != null) { st = new StringTokenizer(s, " "); + * taz = Integer.parseInt(st.nextToken()); productionTerminalTime + * = Float.parseFloat(st.nextToken()); tazOriginTerminalTime[taz] + * = productionTerminalTime; } br.close(); } catch (IOException + * e) { e.printStackTrace(); } + * + * } + */ + + /** + * This method will read the zone.park file and store the parking type for + * each taz. Only types 2 - 5 are given. Rest assumed to be type 1. + * + * @param rb + * the properties file that lists the taz.parkingtype.file and + * the scenario.path private void + * readTAZParkingTypeCorrespondence(HashMap + * rbMap) { File tazParkingTypeCorresFile = new + * File(Util.getStringValueFromPropertyMap(rbMap, + * "scenario.path") + Util.getStringValueFromPropertyMap(rbMap, + * "taz.parkingtype.file")); + * + * tazParkingType = new int[maxTaz + 1]; + * Arrays.fill(tazParkingType, 1); + * + * // read the file to get the parking type (2 - 5) for each TAZ + * String s; int taz; StringTokenizer st; int parkingType; try { + * BufferedReader br = new BufferedReader(new + * FileReader(tazParkingTypeCorresFile)); while ((s = + * br.readLine()) != null) { st = new StringTokenizer(s, " "); + * taz = Integer.parseInt(st.nextToken()); parkingType = + * Integer.parseInt(st.nextToken()); tazParkingType[taz] = + * parkingType; } br.close(); } catch (IOException e) { + * e.printStackTrace(); } + * + * } + */ + + /** + * This method read in the access061.prp file that lists the taz and the # + * of taps that have drive access. Then the taps are listed along with the + * time and the distance to those taps from the taz. + * + * @param rb + * the properties file that lists the taz.driveaccess.taps.file + * and the scenario.path + */ + public void readPnRTapsInfo(HashMap rbMap) + { + File tdzDATapFile = new File(Util.getStringValueFromPropertyMap(rbMap, "scenario.path") + + Util.getStringValueFromPropertyMap(rbMap, "taz.driveaccess.taps.file")); + tazParkNRideTaps = new float[maxTaz + 1][3][]; // tapId, time, distance + tazKissNRideTaps = new float[maxTaz + 1][3][]; // tapId, time, distance + + String s, s1; + StringTokenizer st, st1; + int taz; + int tapId; + float tapTime; + float tapDist; + + //Shove into hash at first, then decompose into float array + HashMap< Integer, HashMap> tazTapMap = new HashMap>(); + + try + { + BufferedReader br = new BufferedReader(new FileReader(tdzDATapFile)); + while ((s = br.readLine()) != null) + { + st = new StringTokenizer(s, ","); + + taz = Integer.parseInt(st.nextToken()); + tapId = Integer.parseInt(st.nextToken()); + tapTime = Float.parseFloat(st.nextToken()); + tapDist = Float.parseFloat(st.nextToken()); + + if(tazTapMap.get(taz) != null){ + + HashMap< Integer, float[] > tapVals = tazTapMap.get(taz); + if(tapVals.get(tapId) != null){ + //something wrong, since there should only be unique taps for a taz + throw new RuntimeException("There should not be any duplicate TAPs for a TAZ"); + }else{ + float[] timeDist = new float[2]; + timeDist[0] = tapTime; + timeDist[1] = tapDist; + tapVals.put(tapId, timeDist); + } + + }else{ + HashMap< Integer, float[] > tapVals = new HashMap(); + float[] timeDist = new float[2]; + timeDist[0] = tapTime; + timeDist[1] = tapDist; + tapVals.put(tapId, timeDist); + tazTapMap.put(taz, tapVals); + } + } + + Iterator it = tazTapMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry pair = (Map.Entry)it.next(); + taz = (int) pair.getKey(); + HashMap< Integer, float[] > tapVals = tazTapMap.get(taz); + int nTaps = tapVals.keySet().size(); + + tazParkNRideTaps[taz][0] = new float[nTaps]; + tazParkNRideTaps[taz][1] = new float[nTaps]; + tazParkNRideTaps[taz][2] = new float[nTaps]; + tazKissNRideTaps[taz][0] = new float[nTaps]; + tazKissNRideTaps[taz][1] = new float[nTaps]; + tazKissNRideTaps[taz][2] = new float[nTaps]; + + Iterator it2 = tapVals.entrySet().iterator(); + int i = 0; + while (it2.hasNext()) { + Map.Entry pair2 = (Map.Entry)it2.next(); + tapId = (int) pair2.getKey(); + float[] vals = (float[]) pair2.getValue(); + tazParkNRideTaps[taz][0][i] = tapId; + tazParkNRideTaps[taz][1][i] = vals[0]; + tazParkNRideTaps[taz][2][i] = vals[1]; + tazKissNRideTaps[taz][0][i] = tapId; + tazKissNRideTaps[taz][1][i] = vals[0]; + tazKissNRideTaps[taz][2][i] = vals[1]; + i++; + } + } + + br.close(); + } catch (IOException e) + { + e.printStackTrace(); + } + + } + + /** + * This method will return the Area Type (Location?) for the TAZ. + * + * + * @param taz + * - TAZ that AreaType is wanted for. + * @return area type that the taz corresponds to + */ + public int getTAZAreaType(int taz) + { + return tazAreaType[taz]; + } + + /** + * Write taz data manager data to logger for debugging. + * + */ + public void printTazStats() + { + + logger.info("Number of TAZs: " + tazSet.size()); + logger.info("Max TAZ: " + maxTaz); + logger.info("Number of TAZs with MGRAs: " + nTazsWithMgras); + } + + /** + * Get a static instance of the Taz Data Manager. One is created if it + * doesn't exist already. + * + * @param rb + * A resourcebundle with properties for the TazDataManager. + * @return A static instance of this class. + */ + public static TazDataManager getInstance(HashMap rbMap) + { + if (instance == null) + { + instance = new TazDataManager(rbMap); + return instance; + } else return instance; + } + + /** + * This method should only be used after the getInstance(HashMap rbMap) method has been called since the rbMap is needed to read + * in all the data and populate the object. This method will return the + * instance that has already been populated. + * + * @return instance + * @throws RuntimeException + */ + public static TazDataManager getInstance() throws RuntimeException + { + if (instance == null) + { + throw new RuntimeException( + "Must instantiate TazDataManager with the getInstance(rbMap) method first"); + } else + { + return instance; + } + } + + /** + * Get the number of TAZs with MGRAs. + * + * @return The number of TAZs with MGRAs. + */ + public int getNTazsWithMgras() + { + if (instance != null) + { + return nTazsWithMgras; + } else + { + throw new RuntimeException(); + } + } + + public int[][] getTazMgraArray() + { + if (instance != null) + { + return tazMgraArray; + } else + { + throw new RuntimeException(); + } + } + + /** + * Return the list of MGRAs within this TAZ. + * + * @param taz + * The TAZ number + * @return An array of MGRAs within the TAZ. + */ + public int[] getMgraArray(int taz) + { + if (instance != null) + { + return tazMgraArray[taz]; + } else + { + throw new RuntimeException(); + } + } + + /* + * public int[][] getTazXYCoordArray() { if (instance != null) { return + * tazXYCoordArray; } else { throw new RuntimeException(); } } + * + * public int[] getTazSuperDistrict() { if (instance != null) { return + * tazSuperDistrict; } else { throw new RuntimeException(); } + * + * } + * + * public int[] getPmsa() { if (instance != null) { return this.pmsa; } else + * { throw new RuntimeException(); } } + * + * public int[] getCmsa() { if (instance != null) { return this.cmsa; } else + * { throw new RuntimeException(); } } + */ + + /** + * This method will return the Parking Type for the TAZ. + * + * @param taz + * - TAZ that Parking Type is wanted for. + * @return Parking Type + */ + public int getTazParkingType(int taz) + { + return tazParkingType[taz]; + } + + /** + * Get the list of Park and Ride Taps for this TAZ. + * + * @param Taz + * @return An array of PNR taps for the TAZ. + */ + public int[] getParkRideTapsForZone(int taz) + { + if (tazParkNRideTaps[taz][0] == null) return null; + + int[] parkTaps = new int[tazParkNRideTaps[taz][0].length]; + for (int i = 0; i < tazParkNRideTaps[taz][0].length; i++) + { + parkTaps[i] = (int) tazParkNRideTaps[taz][0][i]; + } + return parkTaps; + } + + /** + * Get the list of Kiss and Ride Taps for this TAZ. + * + * @param Taz + * @return An array of KNR taps for the TAZ. + */ + public int[] getKissRideTapsForZone(int taz) + { + if (tazKissNRideTaps[taz][0] == null) return null; + int[] kissTaps = new int[tazKissNRideTaps[taz][0].length]; + for (int i = 0; i < tazKissNRideTaps[taz][0].length; i++) + { + kissTaps[i] = (int) tazKissNRideTaps[taz][0][i]; + } + return kissTaps; + } + + public int[] getParkRideOrKissRideTapsForZone(int taz, AccessMode aMode) + { + + switch (aMode) + { + case WALK: + return null; + case PARK_N_RIDE: + return getParkRideTapsForZone(taz); + case KISS_N_RIDE: + return getKissRideTapsForZone(taz); + default: + throw new RuntimeException( + "Error trying to get ParkRideOrKissRideTaps for unknown access mode: " + + aMode); + } + } + + /** + * Get the position of the tap in the taz tap array. + * + * @param taz + * The taz to lookup + * @param tap + * The tap to lookup + * @param aMode + * The access mode + * @return The position of the tap in the taz array. -1 is returned if it is + * an invalid tap for the taz. + */ + public int getTapPosition(int taz, int tap, AccessMode aMode) + { + + int[] taps = getParkRideOrKissRideTapsForZone(taz, aMode); + + if (taps == null) return -1; + + for (int i = 0; i < taps.length; ++i) + if (taps[i] == tap) return i; + + return -1; + + } + + /** + * Get the taz to tap time in minutes. + * + * @param taz + * Origin/Production TAZ + * @param pos + * Position of the TAP in this TAZ + * @param mode + * Park and Ride or Kiss and Ride + * @return The TAZ to TAP time in minutes. + */ + public float getTapTime(int taz, int pos, AccessMode aMode) + { + // only expecting this method for Park and Ride and Kiss and Ride modes. + switch (aMode) + { + case PARK_N_RIDE: + return (tazParkNRideTaps[taz][1][pos]); + case KISS_N_RIDE: + return (tazKissNRideTaps[taz][1][pos]); + default: + throw new RuntimeException( + "Error trying to get ParkRideOrKissRideTaps for invalid access mode: " + + aMode); + } + } + + /** + * Get the taz to tap distance in miles. + * + * @param taz + * Origin/Production TAZ + * @param pos + * Position of the TAP in this TAZ + * @param mode + * Park and Ride or Kiss and Ride + * @return The TAZ to TAP distance in miles. + */ + public float getTapDist(int taz, int pos, AccessMode aMode) + { + // only expecting this method for Park and Ride and Kiss and Ride modes. + switch (aMode) + { + case PARK_N_RIDE: + return (tazParkNRideTaps[taz][2][pos]); + case KISS_N_RIDE: + return (tazKissNRideTaps[taz][2][pos]); + default: + throw new RuntimeException( + "Error trying to get ParkRideOrKissRideTaps for invalid access mode: " + + aMode); + } + } + + /** + * Get the time from the TAZ to the TAP in minutes. + * + * @param taz The origin TAZ + * @param tap The destination TAP + * @param aMode The access model (PNR or KNR) + * @return The time in minutes, or -1 if there isn't an access link from the TAZ to the TAP. + */ + public float getTimeToTapFromTaz(int taz, int tap, AccessMode aMode){ + + int btapPosition = getTapPosition(taz,tap,aMode); + float time; + + if(btapPosition==-1){ + logger.info("Bad tap position for " + (aMode==Modes.AccessMode.PARK_N_RIDE ? "PNR" : "KNR") +" access board tap"); + return -1; + }else{ + time = getTapTime(taz,btapPosition,Modes.AccessMode.PARK_N_RIDE); + } + + return time; + + } + /** + * Get the distance from the TAZ to the TAP in miles. + * + * @param taz The origin TAZ + * @param tap The destination TAP + * @param aMode The access model (PNR or KNR) + * @return The distance in miles, or -1 if there isn't an access link from the TAZ to the TAP. + */ + public float getDistanceToTapFromTaz(int taz, int tap, AccessMode aMode){ + + int btapPosition = getTapPosition(taz,tap,aMode); + float distance; + + if(btapPosition==-1){ + logger.info("Bad tap position for " + (aMode==Modes.AccessMode.PARK_N_RIDE ? "PNR" : "KNR") +" access board tap"); + return -1; + }else{ + distance = getTapDist(taz,btapPosition,Modes.AccessMode.PARK_N_RIDE); + } + + return distance; + + } /** + * Returns the max TAZ value + * + * @return the max TAZ value + */ + public int getMaxTaz() + { + return maxTaz; + } + + private void readMgraTableData(HashMap rbMap) + { + + // get the mgra data table from one of these UECs. + String projectPath = rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String mgraFile = rbMap.get(MgraDataManager.PROPERTIES_MGRA_DATA_FILE); + mgraFile = projectPath + mgraFile; + + TableDataSet mgraTableDataSet = null; + try + { + OLD_CSVFileReader reader = new OLD_CSVFileReader(); + mgraTableDataSet = reader.readFile(new File(mgraFile)); + } catch (IOException e) + { + logger.error("problem reading mgra data table for TazDataManager.", e); + System.exit(1); + } + + // get 0-based arrays from the specified fields in the MGRA table + mgraTableMgras = mgraTableDataSet.getColumnAsInt(MgraDataManager.MGRA_FIELD_NAME); + mgraTableTazs = mgraTableDataSet.getColumnAsInt(MgraDataManager.MGRA_TAZ_FIELD_NAME); + + } + + /** + * Test an instance of the class by instantiating and reporting. + * + * @param args + * [0] The properties file name/path. + */ + public static void main(String[] args) + { + ResourceBundle rb = ResourceUtil.getPropertyBundle(new File(args[0])); + + TazDataManager tdm = TazDataManager.getInstance(ResourceUtil + .changeResourceBundleIntoHashMap(rb)); + + } + + /** + * This method will return the Origin Terminal Time for the TDZ. + * + * @param taz + * - TAZ that Terminal Time is wanted for. + * @return Origin Terminal Time + */ + public float getOriginTazTerminalTime(int taz) + { + return tazOriginTerminalTime[taz]; + } + + /** + * This method will return the Destination Terminal Time for the TDZ. + * + * @param taz + * - TAZ that Terminal Time is wanted for. + * @return Destination Terminal Time + */ + public float getDestinationTazTerminalTime(int taz) + { + return tazDestinationTerminalTime[taz]; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/TransitDriveAccessDMU.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TransitDriveAccessDMU.java new file mode 100644 index 0000000..6e102b6 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TransitDriveAccessDMU.java @@ -0,0 +1,465 @@ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.modechoice.Modes.AccessMode; + +import com.pb.common.calculator.VariableTable; +/** + * This class is used for ... + * + * @author Joel Freedman + * @version Mar 20, 2009 + *

+ * Created by IntelliJ IDEA. + */ +public class TransitDriveAccessDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TransitDriveAccessDMU.class); + + protected HashMap methodIndexMap; + + double driveTimeToTap; + double driveDistToTap; + double driveDistFromTap; + double driveTimeFromTap; + double OrigDestDistance; + double tapToMgraWalkTime; + double mgraToTapWalkTime; + double carToStationWalkTime; + double escalatorTime; + int accessMode; + int period; + int set; + + //default values for generic application + int applicationType = 0; + int personType = 1; + float ivtCoeff; + float costCoeff; + int joint = 0; //added for consistency with MTC + float valueOfTime = 0; //added for consistency with MTC + + + public TransitDriveAccessDMU() + { + setupMethodIndexMap(); + } + + /** + * Set the joint indicator. + * + * @param joint + */ + public void setTourCategoryIsJoint(int joint){ + this.joint = joint; + } + + /** + * Get the joint indicator. + * + * @return joint + */ + public int getTourCategoryIsJoint(){ + return joint; + } + + /** + * Set the value of time. + * + * @param the value of time + */ + public void setValueOfTime(float valueOfTime){ + this.valueOfTime = valueOfTime; + } + + /** + * Get the value of time. + * + * @return value of time. + */ + public float getValueOfTime(){ + return valueOfTime; + } + + + /** + * Get the walk time from the alighting TAP to the destination MGRA. + * + * @return The walk time from the alighting TAP to the destination MGRA. + */ + public double getTapMgraWalkTime() + { + return tapToMgraWalkTime; + } + + /** + * Set the walk time from the alighting TAP to the destination MGRA. + * + * @param walkTime The walk time from the alighting TAP to the destination MGRA. + */ + public void setTapMgraWalkTime(double walkTime) + { + tapToMgraWalkTime = walkTime; + } + + /** + * Get the walk time to the boarding TAP from the origin MGRA. + * + * @return The walk time from the origin MGRA to the boarding TAP. + */ + public double getMgraTapWalkTime() + { + return mgraToTapWalkTime; + } + + /** + * Set the walk time to the boarding TAP from the origin MGRA + * + * @param walkTime The walk time to the boarding TAP from the origin MGRA. + */ + public void setMgraTapWalkTime(double walkTime) + { + mgraToTapWalkTime = walkTime; + } + + /** + * Get the walk time from the lot to the station. + * + * @return The time in minutes. + */ + public double getCarToStationWalkTime() + { + return carToStationWalkTime; + } + + /** + * Set the walk time from the lot to the station. + * + * @param carToStationWalkTime The time in minutes. + */ + public void setCarToStationWalkTime(double carToStationWalkTime) + { + this.carToStationWalkTime = carToStationWalkTime; + } + + /** + * Get the time to get to the platform. + * + * @return The time in minutes. + */ + public double getEscalatorTime() + { + return escalatorTime; + } + + /** + * Set the time to get to the platform. + * + * @param escalatorTime The time in minutes. + */ + public void setEscalatorTime(double escalatorTime) + { + this.escalatorTime = escalatorTime; + } + + /** + * Get the access mode for this DMU. + * + * @return The access mode. + */ + public int getAccessMode() + { + return accessMode; + } + + /** + * Set the access mode for this DMU. + * + * @param accessMode The access mode. + */ + public void setAccessMode(int accessMode) + { + this.accessMode = accessMode; + } + + /** + * Get the drive time from the origin/production TDZ/TAZ to the TAP. + * + * @return The drive time in minutes. + */ + public double getDriveTimeToTap() + { + return driveTimeToTap; + } + + /** + * Set the drive time from the origin/production TDZ/TAZ to the TAP. + * + * @param driveTimeToTap The drive time in minutes. + */ + public void setDriveTimeToTap(double driveTimeToTap) + { + this.driveTimeToTap = driveTimeToTap; + } + + /** + * Get the drive distance from the origin/production TDZ/TAZ to the TAP. + * + * @return The drive distance in miles. + */ + public double getDriveDistToTap() + { + return driveDistToTap; + } + + /** + * Set the drive distance from the origin/production TDZ/TAZ to the TAP. + * + * @param driveDistToTap The drive distance in miles. + */ + public void setDriveDistToTap(double driveDistToTap) + { + this.driveDistToTap = driveDistToTap; + } + + /** + * Get the drive time from the TAP to the destination/attraction TDZ/TAZ. + * + * @return The drive time in minutes. + */ + public double getDriveTimeFromTap() + { + return driveTimeFromTap; + } + + /** + * Set the drive time from the TAP to the destination/attraction TDZ/TAZ. + * + * @param driveTime The drive time in minutes. + */ + public void setDriveTimeFromTap(double driveTime) + { + driveTimeFromTap = driveTime; + } + + /** + * Get the drive distance from the TAP to the destination/attraction TDZ/TAZ. + * + * @return The drive distance in miles. + */ + public double getDriveDistFromTap() + { + return driveDistFromTap; + } + + /** + * Set the drive distance from the TAP to the destination/attraction TDZ/TAZ. + * + * @param driveDist The drive distance in miles. + */ + public void setDriveDistFromTap(double driveDist) + { + driveDistFromTap = driveDist; + } + + public double getOrigDestDistance() { + return OrigDestDistance; + } + + public void setOrigDestDistance(double origDestDistance) { + OrigDestDistance = origDestDistance; + } + + public void setTOD(int period) { + this.period = period; + } + + public int getTOD() { + return period; + } + + public void setSet(int set) { + this.set = set; + } + + public int getSet() { + return set; + } + + + public void setApplicationType(int applicationType) { + this.applicationType = applicationType; + } + + public int getApplicationType() { + return applicationType; + } + + public void setPersonType(int personType) { + this.personType = personType; + } + + public int getPersonType() { + return personType; + } + + public void setIvtCoeff(float ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + public void setCostCoeff(float costCoeff) { + this.costCoeff = costCoeff; + } + + public float getIvtCoeff() { + return ivtCoeff; + } + + public float getCostCoeff() { + return costCoeff; + } + + /** + * Log the DMU values. + * + * @param localLogger The logger to use. + */ + public void logValues(Logger localLogger) + { + + localLogger.info(""); + localLogger.info("Drive-Transit Auto Access DMU Values:"); + localLogger.info(""); + localLogger.info(String.format("Drive Time To Tap: %9.4f", driveTimeToTap)); + localLogger.info(String.format("Drive Dist To Tap: %9.4f", driveDistToTap)); + localLogger.info(String.format("Drive Time From Tap: %9.4f", driveTimeFromTap)); + localLogger.info(String.format("Drive Dist From Tap: %9.4f", driveDistFromTap)); + localLogger.info(String.format("TAP to MGRA walk time: %9.4f", tapToMgraWalkTime)); + localLogger.info(String.format("MGRA to TAP walk time: %9.4f", mgraToTapWalkTime)); + localLogger.info(String.format("Car to station walk time: %9.4f", carToStationWalkTime)); + localLogger.info(String.format("Escalator time: %9.4f", escalatorTime)); + localLogger.info(String.format("Period: %9s", period)); + localLogger.info(String.format("Set: %9s", set)); + localLogger.info(String.format("applicationType: %9s", applicationType)); + localLogger.info(String.format("personType: %9s", personType)); + localLogger.info(String.format("ivtCoeff %9.4f", ivtCoeff)); + localLogger.info(String.format("costCoeff %9.4f", costCoeff)); + localLogger.info(String.format("origDestDistance %9.4f, origDestDistance")); + localLogger.info(String.format("joint : %9s", joint)); + localLogger.info(String.format("value of time : %9.4f", valueOfTime)); + + + AccessMode[] accessModes = AccessMode.values(); + localLogger.info(String.format("Access Mode: %5s", accessModes[accessMode] + .toString())); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getAccessMode", 0); + methodIndexMap.put("getCarToStationWalkTime", 1); + methodIndexMap.put("getDriveDistToTap", 2); + methodIndexMap.put("getDriveTimeToTap", 3); + methodIndexMap.put("getDriveDistFromTap", 4); + methodIndexMap.put("getDriveTimeFromTap", 5); + methodIndexMap.put("getEscalatorTime", 6); + methodIndexMap.put("getTapMgraWalkTime", 7); + methodIndexMap.put("getMgraTapWalkTime", 8); + methodIndexMap.put("getTOD", 9); + methodIndexMap.put("getSet", 10); + + methodIndexMap.put("getApplicationType", 12); + methodIndexMap.put("getTourCategoryIsJoint", 13); + methodIndexMap.put("getPersonType", 14); + methodIndexMap.put("getIvtCoeff", 15); + methodIndexMap.put("getCostCoeff", 16); + methodIndexMap.put("getOrigDestDistance",17); + methodIndexMap.put("getTourCategoryIsJoint", 18); + methodIndexMap.put("getValueOfTime", 19); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getAccessMode(); + case 1: + return getCarToStationWalkTime(); + case 2: + return getDriveDistToTap(); + case 3: + return getDriveTimeToTap(); + case 4: + return getDriveDistFromTap(); + case 5: + return getDriveTimeFromTap(); + case 6: + return getEscalatorTime(); + case 7: + return getTapMgraWalkTime(); + case 8: + return getMgraTapWalkTime(); + case 9: + return getTOD(); + case 10: + return getSet(); + + case 12: + return getApplicationType(); + case 14: + return getPersonType(); + case 15: + return getIvtCoeff(); + case 16: + return getCostCoeff(); + case 17: + return getOrigDestDistance(); + case 18: + return getTourCategoryIsJoint(); + case 19: + return getValueOfTime(); + + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/modechoice/TransitWalkAccessDMU.java b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TransitWalkAccessDMU.java new file mode 100644 index 0000000..781d4d1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/modechoice/TransitWalkAccessDMU.java @@ -0,0 +1,332 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. You + * may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 + * Unless required by applicable law or agreed to in writing, software distributed + * under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR + * CONDITIONS OF ANY KIND, either express or implied. See the License for the + * specific language governing permissions and limitations under the License. + */ +package org.sandag.abm.modechoice; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.VariableTable; + +/** + * WalkDMU is the Decision-Making Unit class for the Walk-transit choice. The class + * contains getter and setter methods for the variables used in the WalkPathUEC. + * + * @author Joel Freedman + * @version 1.0, March, 2009 + * + */ +public class TransitWalkAccessDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(TransitWalkAccessDMU.class); + + protected HashMap methodIndexMap; + + double tapToMgraWalkTime; + double mgraToTapWalkTime; + double escalatorTime; + int period; + int set; + + //default values for generic application + int applicationType = 0; + int personType = 1; //defaults to full-time worker + float ivtCoeff; + float costCoeff; + int accessEgressMode=0; //this is called a walk-access DMU but it is used in the TAP-to-TAP UEC, so it is + //possible that it is being called for a drive-access path! + int joint = 0; //added for consistency with MTC + float valueOfTime = 0; //added for consistency with MTC + public TransitWalkAccessDMU() + { + setupMethodIndexMap(); + } + + + /** + * Set the joint indicator. + * + * @param joint + */ + public void setTourCategoryIsJoint(int joint){ + this.joint = joint; + } + + /** + * Get the joint indicator. + * + * @return joint + */ + public int getTourCategoryIsJoint(){ + return joint; + } + + /** + * Set the value of time. + * + * @param the value of time + */ + public void setValueOfTime(float valueOfTime){ + this.valueOfTime = valueOfTime; + } + + /** + * Get the value of time. + * + * @return value of time. + */ + public float getValueOfTime(){ + return valueOfTime; + } + + + /** + * Set the access/egress mode + * + * @param accessEgressMode + */ + public void setAccessEgressMode(int accessEgressMode){ + this.accessEgressMode = accessEgressMode; + } + + + /** + * Get the access/egress mode + * + * @return accessEgressMode + */ + public int getAccessEgressMode(){ + return accessEgressMode; + } + + + /** + * Get the time from the production/origin MGRA to the boarding TAP. + * + * @return The time from the production/origin MGRA to the boarding TAP. + */ + public double getMgraTapWalkTime() + { + return mgraToTapWalkTime; + } + + /** + * Set the time from the production/origin MGRA to the boarding TAP. + * + * @param walkTime The time from the production/origin MGRA to the boarding TAP. + */ + public void setMgraTapWalkTime(double walkTime) + { + this.mgraToTapWalkTime = walkTime; + } + + /** + * Get the time from the alighting TAP to the attraction/destination MGRA. + * + * @return The time from the alighting TAP to the attraction/destination MGRA. + */ + public double getTapMgraWalkTime() + { + return tapToMgraWalkTime; + } + + /** + * Set the time from the alighting TAP to the attraction/destination MGRA. + * + * @param walkTime The time from the alighting TAP to the attraction/destination + * MGRA. + */ + public void setTapMgraWalkTime(double walkTime) + { + this.tapToMgraWalkTime = walkTime; + } + + /** + * Get the time to get to the platform. + * + * @return The time in minutes. + */ + public double getEscalatorTime() + { + return escalatorTime; + } + + /** + * Set the time to get to the platform. + * + * @param escalatorTime The time in minutes. + */ + public void setEscalatorTime(double escalatorTime) + { + this.escalatorTime = escalatorTime; + } + + public void setTOD(int period) { + this.period = period; + } + + public int getTOD() { + return period; + } + + public void setSet(int set) { + this.set = set; + } + + public int getSet() { + return set; + } + + + public void setApplicationType(int applicationType) { + this.applicationType = applicationType; + } + + public int getApplicationType() { + return applicationType; + } + + + public void setPersonType(int personType) { + this.personType = personType; + } + + public int getPersonType() { + return personType; + } + + public void setIvtCoeff(float ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + public void setCostCoeff(float costCoeff) { + this.costCoeff = costCoeff; + } + + public float getIvtCoeff() { + return ivtCoeff; + } + + public float getCostCoeff() { + return costCoeff; + } + + /** + * Log the DMU values. + * + * @param localLogger The logger to use. + */ + public void logValues(Logger localLogger) + { + + localLogger.info(""); + localLogger.info("Walk DMU Values:"); + localLogger.info(""); + localLogger.info(String.format("MGRA to TAP walk time: %9.4f", mgraToTapWalkTime)); + localLogger.info(String.format("TAP to MGRA walk time: %9.4f", tapToMgraWalkTime)); + localLogger.info(String.format("Escalator time: %9.4f", escalatorTime)); + localLogger.info(String.format("Period: %9s", period)); + localLogger.info(String.format("Set: %9s", set)); + localLogger.info(String.format("applicationType: %9s", applicationType)); + localLogger.info(String.format("personType: %9s", personType)); + localLogger.info(String.format("ivtCoeff : %9.4f", ivtCoeff)); + localLogger.info(String.format("costCoeff : %9.4f", costCoeff)); + localLogger.info(String.format("accessEgressMode : %9s", accessEgressMode)); + localLogger.info(String.format("joint : %9s", joint)); + localLogger.info(String.format("value of time : %9.4f", valueOfTime)); + + + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getEscalatorTime", 0); + methodIndexMap.put("getMgraTapWalkTime", 1); + methodIndexMap.put("getTapMgraWalkTime", 2); + methodIndexMap.put("getTOD", 3); + methodIndexMap.put("getSet", 4); + + methodIndexMap.put("getApplicationType", 6); + methodIndexMap.put("getPersonType", 8); + methodIndexMap.put("getIvtCoeff", 9); + methodIndexMap.put("getCostCoeff", 10); + methodIndexMap.put("getAccessEgressMode", 11); + methodIndexMap.put("getTourCategoryIsJoint", 12); + methodIndexMap.put("getValueOfTime", 13); + + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getEscalatorTime(); + case 1: + return getMgraTapWalkTime(); + case 2: + return getTapMgraWalkTime(); + case 3: + return getTOD(); + case 4: + return getSet(); + case 6: + return getApplicationType(); + case 8: + return getPersonType(); + case 9: + return getIvtCoeff(); + case 10: + return getCostCoeff(); + case 11: + return getAccessEgressMode(); + case 12: + return getTourCategoryIsJoint(); + case 13: + return getValueOfTime(); + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/AbstractCsvExporter.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/AbstractCsvExporter.java new file mode 100644 index 0000000..a757c38 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/AbstractCsvExporter.java @@ -0,0 +1,32 @@ +package org.sandag.abm.reporting; + +import java.io.File; +import java.util.Properties; +import org.apache.log4j.Logger; + +public abstract class AbstractCsvExporter + implements IExporter +{ + private final File file; + private final IMatrixDao matrixDao; + private final String reportFolder = "report.path"; + + protected static final Logger LOGGER = Logger.getLogger(AbstractCsvExporter.class); + + public AbstractCsvExporter(Properties properties, IMatrixDao aMatrixDao, String aBaseFileName) + { + this.file = new File(properties.getProperty(reportFolder), aBaseFileName + ".csv"); + this.matrixDao = aMatrixDao; + } + + public IMatrixDao getMatrixDao() + { + return this.matrixDao; + } + + public File getFile() + { + return this.file; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/CVMExporter.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/CVMExporter.java new file mode 100644 index 0000000..ecc5632 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/CVMExporter.java @@ -0,0 +1,304 @@ +package org.sandag.abm.reporting; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Properties; +import java.util.Set; + +import org.apache.log4j.Logger; + +import com.pb.common.datafile.DataTypes; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; + +public class CVMExporter { + private static final Logger logger = Logger.getLogger(DataExporter.class); + + public final String[] cvmPeriodNames = {"OE","AM","MD","PM","OL"}; + public final String[] periodNames = {"EA","AM","MD","PM","EV"}; + public final String[] cvmClassNames = {"L","M","I","H"}; + public final String[] skimTollClassNames = {"SOV_NT_H","TRK_L","TRK_M","TRK_H"}; + public final String[] skimNonTollClassNames = {"SOV_TR_H","TRK_L","TRK_M","TRK_H"}; + public final String[] nonTollSkims = {"TIME","DIST"}; + public final String[] tollSkims = {"TIME","DIST","TOLLCOST"}; + public final String[] cvmModeNames = {"NT","T"}; + public final String[] modelModeNames = {"GP","TOLL"}; + + public final String[] segmentNames = {"FA","RE","GO","IN","SV","WH","TH"}; + + protected Properties properties; + protected String projectPath; + protected String reportPath; + protected HashMap cvmSkimMap; + protected HashMap periodMap; //lookup cvm period, return model period + protected HashMap tollClassMap; //lookup cvm class, return toll skim class + protected HashMap nonTollClassMap; //lookup cvm class, return non-toll skim class + + protected HashMap modeMap; //lookup cvm mode, return model mode + + private final OMXMatrixDao mtxDao; + protected float autoOperatingCost; + + + public CVMExporter(Properties theProperties, OMXMatrixDao aMtxDao){ + this.properties = theProperties; + this.mtxDao = aMtxDao; + projectPath = properties.getProperty("scenario.path"); + reportPath = properties.getProperty("report.path"); + float fuelCost = new Float(properties.getProperty("aoc.fuel")); + float mainCost = new Float(properties.getProperty("aoc.maintenance")); + autoOperatingCost = (fuelCost + mainCost) * 0.01f; + + } + + private void createPeriodMap(){ + + periodMap = new HashMap(); + for(int i = 0; i(); + tollClassMap = new HashMap(); + for(int i = 0; i(); + for (int i = 0; i < cvmModeNames.length;++i) + modeMap.put(cvmModeNames[i], modelModeNames[i]); + } + + public void export(){ + createPeriodMap(); + createClassMap(); + createModeMap(); + readSkims(); + TableDataSet inputData = readCVMTrips(); + int totalRows = inputData.getRowCount(); + float[] timeCol = new float[totalRows]; + float[] distCol = new float[totalRows]; + float[] aocCol = new float[totalRows]; + float[] tollCol = new float[totalRows]; + + for(int row = 1; row<=totalRows;++row){ + + int otaz = (int) inputData.getValueAt(row, "I"); + int dtaz = (int) inputData.getValueAt(row, "J"); + String cvmPeriod = inputData.getStringValueAt(row,"OriginalTimePeriod"); + String cvmClass = inputData.getStringValueAt(row,"Mode"); + String cvmMode = inputData.getStringValueAt(row,"TripMode"); + + Matrix timeMatrix = null; + Matrix distMatrix = null; + Matrix tollMatrix = null; + + String modelPeriod = periodMap.get(cvmPeriod); + String modelClass = null; + if(cvmMode.equals("NT")){ + modelClass = nonTollClassMap.get(cvmClass); + + }else{ + modelClass = tollClassMap.get(cvmClass); + } + + timeMatrix = cvmSkimMap.get(modelPeriod+"_"+modelClass+"_"+"TIME"); + distMatrix = cvmSkimMap.get(modelPeriod+"_"+modelClass+"_"+"DIST"); + if(cvmSkimMap.containsKey(modelPeriod+"_"+modelClass+"_"+"TOLLCOST")) + tollMatrix = cvmSkimMap.get(modelPeriod+"_"+modelClass+"_"+"TOLLCOST"); + + timeCol[row-1] = timeMatrix.getValueAt(otaz, dtaz); + distCol[row-1] = distMatrix.getValueAt(otaz, dtaz); + aocCol[row-1] = distMatrix.getValueAt(otaz, dtaz) * autoOperatingCost; + if(tollMatrix != null) + tollCol[row-1] = tollMatrix.getValueAt(otaz, dtaz); + + } + + //append the columns + inputData.appendColumn(timeCol, "TIME"); + inputData.appendColumn(distCol, "DIST"); + inputData.appendColumn(aocCol, "AOC"); + inputData.appendColumn(tollCol, "TOLLCOST"); + + //write the data + TableDataSet.writeFile(reportPath+"cvm_trips.csv", inputData); + + } + + /** + * Read data into inputDataTable tabledataset. + * + */ + private TableDataSet readTableDataSet(String inputFile){ + + logger.info("Begin reading the data in file " + inputFile); + TableDataSet inputDataTable = null; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + inputDataTable = csvFile.readFile(new File(inputFile)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + logger.info("End reading the data in file " + inputFile); + + return inputDataTable; + } + + private void readSkims(){ + + cvmSkimMap = new HashMap(); + + for(String period: periodNames){ + + String fileName = "traffic_skims_"+period+".omx"; + + for(String nonTollClass: skimNonTollClassNames){ + + for(String skim:nonTollSkims){ + + String skimName = period+"_"+nonTollClass+"_"+skim; + + Matrix m = mtxDao.getMatrix(fileName, skimName); + cvmSkimMap.put(skimName, m); + + } + } + for(String tollClass: skimTollClassNames){ + for(String skim:tollSkims){ + String skimName = period+"_"+tollClass+"_"+skim; + + Matrix m = mtxDao.getMatrix(fileName, skimName); + cvmSkimMap.put(skimName, m); + + } + } + } + + + + + } + + /** + * Helper method to read in all the CVM files and concatenate into one TableDataSet. + * + * @return the concatenated data + */ + private TableDataSet readCVMTrips(){ + + int tables = 0; + String[] header = null; + int[] columnType = null; + HashMap> floatCols = new HashMap>(); + HashMap> stringCols = new HashMap>(); + + //first read all the data, and store arraylists of data in the two hashmaps + for(String segment: segmentNames){ + + for(String period:cvmPeriodNames){ + + String fileName = projectPath+"output\\Trip_"+segment+"_"+period+".csv"; + TableDataSet inData = readTableDataSet(fileName); + if(tables==0){ + columnType = inData.getColumnType(); + header = inData.getColumnLabels(); + } + ++tables; + for(int i = 0; i< inData.getColumnCount();++i){ + + String colName = header[i]; + if(columnType[i]==DataTypes.NUMBER){ + float[] data = inData.getColumnAsFloat(colName); + ArrayList colArray = null; + if(floatCols.containsKey(colName)) + colArray = floatCols.get(colName); + else + colArray = new ArrayList(); + + for(int j=0;j colArray = null; + if(stringCols.containsKey(colName)) + colArray = stringCols.get(colName); + else + colArray = new ArrayList(); + + for(int j=0;j keySet = floatCols.keySet(); + String[] colNames = new String[keySet.size()]; + float[][] data = null; + int colNumber=0; + for(String colName:keySet){ + colNames[colNumber] = colName; + ArrayList col = floatCols.get(colName); + if(colNumber==0){ + + data = new float[col.size()][colNames.length]; + } + for(int i = 0; i < col.size();++i){ + data[i][colNumber] = col.get(i); + } + ++colNumber; + } + + TableDataSet allTrips = TableDataSet.create(data,colNames); + + //logger.info("Created table data set with "+ allTrips.getColumnCount()+" columns"); + //String outputColNames = ""; + //for(String colName : allTrips.getColumnLabels()) + // outputColNames += (colName + " "); + //logger.info("Columns: "+outputColNames); + + //now append the string columns + keySet = stringCols.keySet(); + colNames = new String[keySet.size()]; + colNumber=0; + for(String colName:keySet){ + colNames[colNumber] = colName; + ArrayList col = stringCols.get(colName); + String[] stringData = new String[col.size()]; + stringData = col.toArray(stringData); + logger.info("Appending string column "+colName+" with "+stringData.length+" elements"); + allTrips.appendColumn(stringData, colName); + } + + //logger.info("Final table data set has "+ allTrips.getColumnCount()+" columns"); + //outputColNames = ""; + //for(String colName : allTrips.getColumnLabels()) + // outputColNames += (colName + " "); + //logger.info("Columns: "+outputColNames); + + return allTrips; + + + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/CVMScaler.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/CVMScaler.java new file mode 100644 index 0000000..d7d595e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/CVMScaler.java @@ -0,0 +1,179 @@ +package org.sandag.abm.reporting; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.List; +import java.util.Properties; + +import org.apache.log4j.Logger; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +public class CVMScaler { + private static final Logger logger= Logger.getLogger(DataExporter.class); + protected Properties properties; + protected String projectPath; + protected String reportPath; + protected String [] lightscalers; + protected String [] mediumscalers; + protected String [] heavyscalers; + protected float lightshare; + protected float mediumshare; + protected float heavyshare; + + public CVMScaler(Properties theProperties){ + this.properties = theProperties; + projectPath = properties.getProperty("scenario.path"); + reportPath = properties.getProperty("report.path"); + String delims = "[,]"; + lightscalers = properties.getProperty("cvm.scale_light").split(delims); + mediumscalers = properties.getProperty("cvm.scale_medium").split(delims); + heavyscalers = properties.getProperty("cvm.scale_heavy").split(delims); + lightshare = new Float(properties.getProperty("cvm.share.light")); + mediumshare = new Float(properties.getProperty("cvm.share.medium")); + heavyshare = new Float(properties.getProperty("cvm.share.heavy")); + } + + public void scale(){ + logger.info("Running CVM scaler ... "); + String fileName = reportPath+"cvm_trips.csv"; + TableDataSet inData = readTableDataSet(fileName); + int totalRows = inData.getRowCount(); + String[] timeCol=new String[totalRows]; + + int tod=lightscalers.length; + float [] lscaler=new float[tod]; + float [] mscaler=new float[tod]; + float [] hscaler=new float[tod]; + + for(int i=0; i0) { + if (colname.equals("Mode")){ + value = value.replaceAll(vehicle, "I"); + }else if (colname.equals("TripTime")){ + value = value.replaceAll(":"+vehicle, ":I"); + } + + if (line_new==null) line_new = value; + else line_new = line_new + "," + value; + } + } + + //write existing lines + scaler = getScaler(scalerArray, str); + value_new = scaler * (1-share); + line = line + "," + Float.toString(value_new); + writer.println(line.trim()); + + //write new lines + if (share>0) { + value_new = scaler * (share); + line_new = line_new + "," + Float.toString(value_new); + writer.println(line_new.trim()); + } + } + + private float getScaler(float [] scalerArray, String str) { + float scaler = 1.0f; + + if(str.contains("_EA")){ + scaler = scalerArray[0]; + }else if(str.contains("_AM")){ + scaler = scalerArray[1]; + }else if(str.contains("_MD")){ + scaler = scalerArray[2]; + }else if(str.contains("_PM")){ + scaler = scalerArray[3]; + }else if(str.contains("_EV")){ + scaler = scalerArray[4]; + }else { + scaler = 1.0f; + } + + return scaler; + + } + + private TableDataSet readTableDataSet(String inputFile){ + + logger.info("Begin reading the data in file " + inputFile); + TableDataSet inputDataTable = null; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + inputDataTable = csvFile.readFile(new File(inputFile)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + logger.info("End reading the data in file " + inputFile); + + return inputDataTable; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/CsvRow.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/CsvRow.java new file mode 100644 index 0000000..fb93a89 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/CsvRow.java @@ -0,0 +1,22 @@ +package org.sandag.abm.reporting; + +public class CsvRow +{ + private final String row; + + public CsvRow(String[] values) + { + StringBuilder sb = new StringBuilder(32); + sb.append(values[0]); + for (int i = 1; i < values.length; i++) + sb.append(',').append(values[i]); + sb.append(System.lineSeparator()); + + row = sb.toString(); + } + + public String getRow() + { + return row; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/CsvWriterThread.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/CsvWriterThread.java new file mode 100644 index 0000000..9ee01e2 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/CsvWriterThread.java @@ -0,0 +1,86 @@ +package org.sandag.abm.reporting; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.nio.ByteBuffer; +import java.nio.channels.FileChannel; +import java.util.concurrent.BlockingQueue; +import org.apache.log4j.Logger; + +public class CsvWriterThread + implements Runnable +{ + private final BlockingQueue queue; + private final File file; + private final String[] header; + + private static final Logger LOGGER = Logger.getLogger(CsvWriterThread.class); + + private int maxBuffer = 1024 * 1024 * 1024; + private static final String ENCODING = "UTF-8"; + + public static final CsvRow POISON_PILL = new CsvRow(new String[] {"ALL_DONE"}); + + public CsvWriterThread(BlockingQueue aRowQueue, File anOutputLocation, String[] aHeader) + { + this.queue = aRowQueue; + this.file = anOutputLocation; + this.header = aHeader; + } + + public int getMaxBuffer() + { + return this.maxBuffer; + } + + public void setMaxBuffer(int aMaxBuffer) + { + this.maxBuffer = aMaxBuffer; + } + + @Override + public void run() + { + FileOutputStream outStream = null; + try + { + outStream = new FileOutputStream(file, false); + FileChannel outChannel = outStream.getChannel(); + ByteBuffer buffer = ByteBuffer.allocateDirect(getMaxBuffer()); + + CsvRow headerRow = new CsvRow(header); + buffer.put(headerRow.getRow().getBytes(ENCODING)); + + CsvRow row = null; + while ((row = queue.take()) != CsvWriterThread.POISON_PILL) + { + byte[] rowBytes = row.getRow().getBytes(ENCODING); + if ((buffer.position() + rowBytes.length) > buffer.capacity()) + { + buffer.flip(); + outChannel.write(buffer); + buffer.clear(); + } + buffer.put(rowBytes); + } + LOGGER.info("End of records found. Clearing Buffer and Writing Remains."); + buffer.flip(); + outChannel.write(buffer); + } catch (IOException | InterruptedException e) + { + LOGGER.fatal(e); + throw new RuntimeException(e); + } finally + { + if (null != outStream) try + { + outStream.close(); + LOGGER.info("CSV Writer Stream Closed."); + } catch (IOException e) + { + LOGGER.error(e); + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/DataExporter.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/DataExporter.java new file mode 100644 index 0000000..30bc37e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/DataExporter.java @@ -0,0 +1,2688 @@ +package org.sandag.abm.reporting; + +import java.io.BufferedReader; +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileInputStream; +import java.io.FileReader; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.rmi.RemoteException; +import java.text.DecimalFormat; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.HashSet; +import java.util.LinkedHashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Properties; +import java.util.Set; +import java.util.TreeSet; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.matrix.OMXMatrixWriter; +import com.pb.common.util.ResourceUtil; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +/** + * The {@code DataExporter} ... + * + * @author crf Started 9/20/12 8:36 AM + */ +public final class DataExporter +{ + private static final Logger LOGGER = Logger.getLogger(DataExporter.class); + + private static final String NUMBER_FORMAT_NAME = "NUMBER"; + private static final String STRING_FORMAT_NAME = "STRING"; + private static final String PROJECT_PATH_PROPERTY_TOKEN = "%project.folder%"; + private static final String TOD_TOKEN = "%TOD%"; + + private final Properties properties; + private final OMXMatrixDao mtxDao; + private final File projectPathFile; + private final int feedbackIterationNumber; + private final Set tables; + private final String[] timePeriods = ModelStructure.MODEL_PERIOD_LABELS; + private final String FUEL_COST_PROPERTY = "aoc.fuel"; + private final String MAINTENANCE_COST_PROPERTY = "aoc.maintenance"; + private static final String WRITE_LOGSUMS_PROPERTY = "Results.WriteLogsums"; + private static final String WRITE_TRANSIT_IVT_PROPERTY = "Report.writeTransitIVT"; + private static final String WRITE_UTILS_PROPERTY = "TourModeChoice.Save.UtilsAndProbs"; + + private float autoOperatingCost; + + private boolean writeCSV = false; + private boolean writeLogsums = false; + private boolean writeUtilities = true; + //private boolean writeTransitIVTs = false; + private MatrixDataServerIf ms; + + + public DataExporter(Properties theProperties, OMXMatrixDao aMtxDao, String projectPath, + int feedbackIterationNumber) + { + this.properties = theProperties; + this.mtxDao = aMtxDao; + + projectPathFile = new File(theProperties.getProperty("Project.Directory")); + this.feedbackIterationNumber = feedbackIterationNumber; + + float fuelCost = new Float(theProperties.getProperty(FUEL_COST_PROPERTY)); + float mainCost = new Float(theProperties.getProperty(MAINTENANCE_COST_PROPERTY)); + writeLogsums = new Boolean(theProperties.getProperty(WRITE_LOGSUMS_PROPERTY)); + writeUtilities = new Boolean(theProperties.getProperty(WRITE_UTILS_PROPERTY)); + //writeTransitIVTs = new Boolean(theProperties.getProperty(WRITE_TRANSIT_IVT_PROPERTY)); + + autoOperatingCost = (fuelCost + mainCost) * 0.01f; + + tables = new LinkedHashSet(); + + } + + private void addTable(String table) + { + tables.add(table); + LOGGER.info("exporting data: " + table); + } + + private String getPath(String path) + { + if (properties.containsKey(path)) return getPathFromProperty(path); + File ff = new File(path); + if (!ff.exists()) ff = new File(projectPathFile, path); + return ff.getAbsolutePath(); + } + + private String getPathFromProperty(String propertyToken) + { + String path = (String) properties.get(propertyToken); + if (!path.startsWith(projectPathFile.getAbsolutePath())) + path = new File(projectPathFile, path).getAbsolutePath(); + return path; + } + + /** + * Takes an input file name, returns the path to the directory + * with that name. + * + * @param The name of the file to create + * @return The path of the file. + */ + private String getOutputPath(String file) + { + return new File(properties.getProperty("report.path"), file).getAbsolutePath(); + } + + private String getData(TableDataSet data, int row, int column, FieldType type) + { + switch (type) + { + case INT: + return "" + Math.round(data.getValueAt(row, column)); + case FLOAT: + return "" + data.getValueAt(row, column); + case STRING: + return data.getStringValueAt(row, column); + case BIT: + return Boolean.parseBoolean(data.getStringValueAt(row, column)) ? "1" : "0"; + default: + throw new IllegalStateException("undefined field type: " + type); + } + } + + private String getPreferredColumnName(String columnName) + { + if (columnName.equalsIgnoreCase("hh_id")) return "HH_ID"; + if (columnName.equalsIgnoreCase("person_id")) return "PERSON_ID"; + if (columnName.toLowerCase().contains("maz")) + return columnName.toLowerCase().replace("maz", "mgra").toUpperCase(); + return columnName.toUpperCase(); + } + + private void exportData(TableDataSet data, String outputFileName, + Map outputMapping, Map outputTypes) + { + int[] outputIndices = new int[outputMapping.size()]; + FieldType[] outputFieldTypes = new FieldType[outputIndices.length]; + String[] header = new String[outputMapping.size()]; + + int counter = 0; + for (String column : outputMapping.keySet()) + { + header[counter] = column; + outputIndices[counter] = data.getColumnPosition(outputMapping.get(column)); + outputFieldTypes[counter++] = outputTypes.get(column); + } + + BlockingQueue queue = new LinkedBlockingQueue(); + Thread writerProcess = null; + try + { + CsvWriterThread writerThread = new CsvWriterThread(queue, new File( + getOutputPath(outputFileName + ".csv")), header); + writerProcess = new Thread(writerThread); + writerProcess.start(); + + for (int i = 1; i <= data.getRowCount(); i++) + { + String[] row = new String[outputMapping.size()]; + row[0] = getData(data, i, outputIndices[0], outputFieldTypes[0]); + + for (int j = 1; j < outputIndices.length; j++) + { + row[j] = getData(data, i, outputIndices[j], outputFieldTypes[j]); + } + queue.add(new CsvRow(row)); + } + } finally + { + queue.add(CsvWriterThread.POISON_PILL); + if (null != writerProcess) + { + try + { + writerProcess.join(); + } catch (InterruptedException e) + { + LOGGER.error(e); + System.exit(-1); + } + } + } + } + + private TableDataSet exportDataGeneric(String outputFileBase, String filePropertyToken, + boolean includeFeedbackIteration, String[] formats, Set floatColumns, + Set stringColumns, Set intColumns, Set bitColumns, + FieldType defaultFieldType, Set primaryKey, + TripStructureDefinition tripStructureDefinition,boolean isCB) + { + return exportDataGeneric(outputFileBase, filePropertyToken, includeFeedbackIteration, + formats, floatColumns, stringColumns, intColumns, bitColumns, defaultFieldType, + primaryKey, tripStructureDefinition, null,isCB); + } + + private TableDataSet exportDataGeneric(String outputFileBase, String filePropertyToken, + boolean includeFeedbackIteration, String[] formats, Set floatColumns, + Set stringColumns, Set intColumns, Set bitColumns, + FieldType defaultFieldType, Set primaryKey, + TripStructureDefinition tripStructureDefinition, JoinData joinData,boolean isCB) + { + return exportDataGeneric(outputFileBase, filePropertyToken, includeFeedbackIteration, + formats, floatColumns, stringColumns, intColumns, bitColumns, defaultFieldType, + primaryKey, new HashMap(), tripStructureDefinition, joinData,isCB); + } + + private TableDataSet exportDataGeneric(String outputFileBase, String filePropertyToken, + boolean includeFeedbackIteration, String[] formats, Set floatColumns, + Set stringColumns, Set intColumns, Set bitColumns, + FieldType defaultFieldType, Set primaryKey, + Map overridingFieldMappings, + TripStructureDefinition tripStructureDefinition,boolean isCB) + { + return exportDataGeneric(outputFileBase, filePropertyToken, includeFeedbackIteration, + formats, floatColumns, stringColumns, intColumns, bitColumns, defaultFieldType, + primaryKey, overridingFieldMappings, tripStructureDefinition, null,isCB); + } + + private TableDataSet exportDataGeneric(String outputFileBase, String filePropertyToken, + boolean includeFeedbackIteration, String[] formats, Set floatColumns, + Set stringColumns, Set intColumns, Set bitColumns, + FieldType defaultFieldType, Set primaryKey, + Map overridingFieldMappings, + TripStructureDefinition tripStructureDefinition, JoinData joinData,boolean isCB) + { + TableDataSet table; + try + { + String f = includeFeedbackIteration ? getPath(filePropertyToken).replace(".csv", + "_" + feedbackIterationNumber + ".csv") : getPath(filePropertyToken); + table = formats == null ? new CSVFileReader().readFile(new File(f)) + : new CSVFileReader().readFileWithFormats(new File(f), formats); + } catch (IOException e) + { + throw new RuntimeException(e); + } + if (joinData != null) joinData.joinDataToTable(table); + exportDataGeneric(table, outputFileBase, floatColumns, stringColumns, intColumns, + bitColumns, defaultFieldType, primaryKey, overridingFieldMappings, + tripStructureDefinition,isCB); + return table; + } + + private class JoinData + { + private final Map> data; + private final Map dataType; + private final String idColumn; + + public JoinData(String idColumn) + { + this.idColumn = idColumn; + data = new LinkedHashMap>(); + dataType = new HashMap(); + } + + public void addJoinData(Map joinData, FieldType type, String columnName) + { + data.put(columnName, joinData); + dataType.put(columnName, type); + } + + public void joinDataToTable(TableDataSet table) + { + int[] ids = table.getColumnAsInt(idColumn); + for (String column : data.keySet()) + table.appendColumn(getData(ids, column), column); + } + + private Object getData(int[] ids, String column) + { + switch (dataType.get(column)) + { + case INT: + { + int[] columnData = new int[ids.length]; + @SuppressWarnings("unchecked") + // this is correct + Map dataMap = (Map) data.get(column); + for (int i = 0; i < ids.length; i++) + columnData[i] = dataMap.get(ids[i]); + return columnData; + } + case FLOAT: + { + float[] columnData = new float[ids.length]; + @SuppressWarnings("unchecked") + // this is correct + Map dataMap = (Map) data.get(column); + for (int i = 0; i < ids.length; i++) + columnData[i] = dataMap.get(ids[i]); + return columnData; + } + case STRING: + { + String[] columnData = new String[ids.length]; + @SuppressWarnings("unchecked") + // this is correct + Map dataMap = (Map) data.get(column); + for (int i = 0; i < ids.length; i++) + columnData[i] = dataMap.get(ids[i]); + return columnData; + } + case BIT: + { + boolean[] columnData = new boolean[ids.length]; + @SuppressWarnings("unchecked") + // this is correct + Map dataMap = (Map) data.get(column); + for (int i = 0; i < ids.length; i++) + columnData[i] = dataMap.get(ids[i]); + return columnData; + } + default: + throw new IllegalStateException("shouldn't be here: " + dataType.get(column)); + } + } + } + + private void exportDataGeneric(TableDataSet table, String outputFileBase, + Set floatColumns, Set stringColumns, Set intColumns, + Set bitColumns, FieldType defaultFieldType, Set primaryKey, + TripStructureDefinition tripStructureDefinition,boolean isCB) + { + exportDataGeneric(table, outputFileBase, floatColumns, stringColumns, intColumns, + bitColumns, defaultFieldType, primaryKey, new HashMap(), + tripStructureDefinition,isCB); + + } + + private void exportDataGeneric(TableDataSet table, String outputFileBase, + Set floatColumns, Set stringColumns, Set intColumns, + Set bitColumns, FieldType defaultFieldType, Set primaryKey, + Map overridingFieldMappings, + TripStructureDefinition tripStructureDefinition,boolean isCB) + { + Map fieldMappings = new LinkedHashMap(); + Map fieldTypes = new HashMap(); + + if (tripStructureDefinition != null) + { + appendTripData(table, tripStructureDefinition,isCB); + floatColumns.add("AUTO_IVT"); + floatColumns.add("AUTO_AOC"); + floatColumns.add("AUTO_STD"); + floatColumns.add("AUTO_TOLL"); + floatColumns.add("TRAN_IVT"); + floatColumns.add("TRAN_WAIT"); + floatColumns.add("TRAN_WALK"); + floatColumns.add("TRAN_FARE"); + floatColumns.add("TRAN_ACCDIST"); + floatColumns.add("TRAN_EGRDIST"); + floatColumns.add("TRAN_AUXTIME"); + floatColumns.add("TRAN_ACCTIME"); + floatColumns.add("TRAN_EGRTIME"); + floatColumns.add("TRAN_TRANSFERS"); + floatColumns.add("WALK_TIME"); + floatColumns.add("BIKE_TIME"); + floatColumns.add("TRIP_DIST"); + stringColumns.add("TRIP_PURPOSE_NAME"); + stringColumns.add("TRIP_MODE_NAME"); + intColumns.add("RECID"); + floatColumns.add("LOC_IVT"); + floatColumns.add("EXP_IVT"); + floatColumns.add("BRT_IVT"); + floatColumns.add("LRT_IVT"); + floatColumns.add("CR_IVT"); + floatColumns.add("TRAN_DIST"); + floatColumns.add("PARK_WALK_TIME"); + floatColumns.add("PARK_WALK_DIST"); + + } + + if (primaryKey.size() == 0) + { + // have to add in a key - call it ID + int[] id = new int[table.getRowCount()]; + for (int i = 0; i < id.length; i++) + id[i] = i + 1; + table.appendColumn(id, "ID"); + + primaryKey.add("ID"); + intColumns.add("ID"); + } + + outer: for (String column : table.getColumnLabels()) + { + String c = overridingFieldMappings.containsKey(column) ? overridingFieldMappings + .get(column) : getPreferredColumnName(column); + fieldMappings.put(c, column); + for (String fc : floatColumns) + { + if (fc.equalsIgnoreCase(column)) + { + fieldTypes.put(c, FieldType.FLOAT); + continue outer; + } + } + for (String sc : stringColumns) + { + if (sc.equalsIgnoreCase(column)) + { + fieldTypes.put(c, FieldType.STRING); + continue outer; + } + } + for (String sc : intColumns) + { + if (sc.equalsIgnoreCase(column)) + { + fieldTypes.put(c, FieldType.INT); + continue outer; + } + } + for (String sc : bitColumns) + { + if (sc.equalsIgnoreCase(column)) + { + fieldTypes.put(c, FieldType.BIT); + continue outer; + } + } + fieldTypes.put(c, defaultFieldType); + } + Set pKey = new LinkedHashSet(); + for (String column : primaryKey) + pKey.add(getPreferredColumnName(column)); + exportData(table, outputFileBase, fieldMappings, fieldTypes); + } + + private PrintWriter getBufferedPrintWriter(String fileName) throws IOException + { + return new PrintWriter(new BufferedWriter(new FileWriter(fileName))); + } + + /** + * Appends trip data to table including skim attributes. + * + * @param table + * @param tripStructureDefinition + */ + private void appendTripData(TableDataSet table, TripStructureDefinition tripStructureDefinition, boolean isCB) + { + // id triptype recid partysize orig_maz dest_maz trip_board_tap + // trip_alight_tap trip_depart_time trip_time trip_distance trip_cost + // trip_purpose_name trip_mode_name vot + int rowCount = table.getRowCount(); + + float[] autoInVehicleTime = new float[rowCount]; + float[] autoOperatingCost = new float[rowCount]; + float[] autoStandardDeviation = new float[rowCount]; + float[] autoTollCost = new float[rowCount]; + float[] transitInVehicleTime = new float[rowCount]; + float[] transitWaitTime = new float[rowCount]; + float[] transitWalkTime = new float[rowCount]; + float[] transitFare = new float[rowCount]; + float[] walkModeTime = new float[rowCount]; + float[] bikeModeTime = new float[rowCount]; + float[] tripDistance = new float[rowCount]; + String[] tripPurpose = new String[rowCount]; + String[] tripMode = new String[rowCount]; + int[] tripId = new int[rowCount]; + int[] tripDepartTime = new int[rowCount]; + int[] tripBoardTaz = new int[rowCount]; + int[] tripAlightTaz = new int[rowCount]; + float[] tripParkingTime = new float[rowCount]; + float[] tripParkingDistance = new float[rowCount]; + + + float[] transitAccessDist = new float[rowCount]; + float[] transitEgressDist = new float[rowCount]; + float[] transitAuxTime = new float[rowCount]; + float[] transitAccTime = new float[rowCount]; + float[] transitEgrTime = new float[rowCount]; + float[] transitTransfers = new float[rowCount]; + + //these are only set if writeTransitIVTs is true + float[] locIVT = new float[rowCount]; + float[] expIVT = new float[rowCount]; + float[] brtIVT = new float[rowCount]; + float[] lrtIVT = new float[rowCount]; + float[] crIVT = new float[rowCount]; + + float[] tranDist = new float[rowCount]; + + SkimBuilder skimBuilder = new SkimBuilder(properties); + boolean hasPurposeColumn = tripStructureDefinition.originPurposeColumn > -1; + for (int i = 0; i < rowCount; i++) + { + int row = i + 1; + + double epsilon = .000001; + boolean inbound = tripStructureDefinition.booleanIndicatorVariables ? table + .getBooleanValueAt(row, tripStructureDefinition.inboundColumn) : Math.abs(table + .getValueAt(row, tripStructureDefinition.inboundColumn) - 1.0) < epsilon; + + int transponderOwnership=0; + if(tripStructureDefinition.transponderOwnershipColumn>0) + transponderOwnership = (int) table.getValueAt(row, tripStructureDefinition.transponderOwnershipColumn); + + SkimBuilder.TripAttributes attributes = skimBuilder.getTripAttributes( + (int) table.getValueAt(row, tripStructureDefinition.originMgraColumn), + (int) table.getValueAt(row, tripStructureDefinition.destMgraColumn), + (int) table.getValueAt(row, tripStructureDefinition.modeColumn), + (int) table.getValueAt(row, tripStructureDefinition.boardTapColumn), + (int) table.getValueAt(row, tripStructureDefinition.alightTapColumn), + (int) table.getValueAt(row, tripStructureDefinition.todColumn), + inbound, + table.getValueAt(row,tripStructureDefinition.valueOfTimeColumn), + (int) table.getValueAt(row, tripStructureDefinition.setColumn),isCB,transponderOwnership); + + autoInVehicleTime[i] = attributes.getAutoInVehicleTime(); + autoOperatingCost[i] = attributes.getAutoOperatingCost(); + autoStandardDeviation[i] = attributes.getAutoStandardDeviationTime(); + autoTollCost[i] = attributes.getAutoTollCost(); + transitInVehicleTime[i] = attributes.getTransitInVehicleTime(); + transitWaitTime[i] = attributes.getTransitWaitTime(); + transitWalkTime[i] = attributes.getTransitWalkTime(); + transitFare[i] = attributes.getTransitFare(); + walkModeTime[i] = attributes.getWalkModeTime(); + bikeModeTime[i] = attributes.getBikeModeTime(); + tripDistance[i] = attributes.getTripDistance(); + transitAccessDist[i] = attributes.getTransitAccessDistance(); + transitEgressDist[i] = attributes.getTransitEgressDistance(); + transitAuxTime[i] = attributes.getTransitAuxiliaryTime(); + transitAccTime[i] = attributes.getTransitAccessTime(); + transitEgrTime[i] = attributes.getTransitEgressTime(); + transitTransfers[i] = attributes.getTransitTransfers(); + + + //get parking walk time + if(tripStructureDefinition.parkingMazColumn>-1) { + int parkingMaz = (int) table.getValueAt(row, tripStructureDefinition.parkingMazColumn); + + if(parkingMaz>0) { + + int destMaz = (int) table.getValueAt(row, tripStructureDefinition.destMgraColumn); + float parkingWalkTime = skimBuilder.getLotWalkTime(parkingMaz,destMaz); + float parkingWalkDistance = skimBuilder.getLotWalkDistance(parkingMaz,destMaz); + tripParkingTime[i]= parkingWalkTime; + tripParkingDistance[i] = parkingWalkDistance; + } + } + + + if (hasPurposeColumn) + { + tripPurpose[i] = table.getStringValueAt(row, + tripStructureDefinition.destinationPurposeColumn); + } else + { + if (!inbound) // going out + tripPurpose[i] = tripStructureDefinition.destinationName; + else tripPurpose[i] = tripStructureDefinition.homeName; + } + tripMode[i] = attributes.getTripModeName(); + tripId[i] = i; + tripDepartTime[i] = attributes.getTripStartTime(); + tripBoardTaz[i] = attributes.getTripBoardTaz(); + tripAlightTaz[i] = attributes.getTripAlightTaz(); + + locIVT[i] = attributes.getLocTime(); + expIVT[i] = attributes.getExpTime(); + brtIVT[i] = attributes.getBrtTime(); + lrtIVT[i] = attributes.getLrtTime(); + crIVT[i] = attributes.getCrTime(); + + tranDist[i] = attributes.getTransitDistance(); + } + table.appendColumn(autoInVehicleTime, "AUTO_IVT"); + table.appendColumn(autoOperatingCost, "AUTO_AOC"); + table.appendColumn(autoStandardDeviation, "AUTO_STD"); + table.appendColumn(autoTollCost, "AUTO_TOLL"); + table.appendColumn(transitInVehicleTime, "TRAN_IVT"); + table.appendColumn(transitWaitTime, "TRAN_WAIT"); + table.appendColumn(transitWalkTime, "TRAN_WALK"); + table.appendColumn(transitFare, "TRAN_FARE"); + table.appendColumn(transitAccessDist, "TRAN_ACCDIST"); + table.appendColumn(transitEgressDist, "TRAN_EGRDIST"); + table.appendColumn(transitAuxTime, "TRAN_AUXTIME"); + table.appendColumn(transitAccTime, "TRAN_ACCTIME"); + table.appendColumn(transitEgrTime, "TRAN_EGRTIME"); + table.appendColumn(transitTransfers, "TRAN_TRANSFERS"); + + table.appendColumn(walkModeTime, "WALK_TIME"); + table.appendColumn(bikeModeTime, "BIKE_TIME"); + table.appendColumn(tripDistance, "TRIP_DIST"); + table.appendColumn(tripPurpose, "TRIP_PURPOSE_NAME"); + table.appendColumn(tripMode, "TRIP_MODE_NAME"); + table.appendColumn(tripId, "RECID"); + table.appendColumn(tripBoardTaz, "TRIP_BOARD_TAZ"); + table.appendColumn(tripAlightTaz, "TRIP_ALIGHT_TAZ"); + + table.appendColumn(locIVT, "LOC_IVT"); + table.appendColumn(expIVT, "EXP_IVT"); + table.appendColumn(brtIVT, "BRT_IVT"); + table.appendColumn(lrtIVT, "LRT_IVT"); + table.appendColumn(crIVT, "CR_IVT"); + + table.appendColumn(tranDist, "TRAN_DIST"); + table.appendColumn(tripParkingTime, "PARK_WALK_TIME"); + table.appendColumn(tripParkingDistance,"PARK_WALK_DIST"); + +// table.appendColumn(valueOfTime, "VALUE_OF_TIME"); + } + + private void exportAccessibilities(String outputFileBase) + { + addTable(outputFileBase); + Set intColumns = new HashSet(Arrays.asList("mgra")); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("mgra")); + exportDataGeneric(outputFileBase, "acc.output.file", false, null, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.FLOAT, primaryKey, null,false); + } + + private void exportMazData(String outputFileBase) + { + addTable(outputFileBase); + Set intColumns = new HashSet(Arrays.asList("mgra", "TAZ", "ZIP09")); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("mgra")); + exportDataGeneric(outputFileBase, "mgra.socec.file", false, null, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.FLOAT, primaryKey, null,false); + } + + private void nullifyFile(String file) + { + String tempFile = file + ".temp"; + File f = new File(file); + if (!f.renameTo(new File(tempFile))) + throw new RuntimeException("Couldn't rename to file: " + f); + BufferedReader reader = null; + PrintWriter writer = null; + try + { + reader = new BufferedReader(new FileReader(tempFile)); + writer = getBufferedPrintWriter(file); + String line; + while ((line = reader.readLine()) != null) + writer.println(line.replace(NULL_VALUE, "")); + } catch (IOException e) + { + throw new RuntimeException(e); + } finally + { + if (reader != null) + { + try + { + reader.close(); + } catch (IOException e) + { + // ignore + } + } + if (writer != null) writer.close(); + } + new File(tempFile).delete(); + } + + public static int NULL_INT_VALUE = -98765; + public static float NULL_FLOAT_VALUE = NULL_INT_VALUE; + public static String NULL_VALUE = "" + NULL_FLOAT_VALUE; + + private void exportTapData(String outputFileBase) + { + addTable(outputFileBase); + Map ptype = readSpaceDelimitedData(getPath("tap.ptype.file"), + Arrays.asList("TAP", "LOTID", "PTYPE", "TAZ", "CAPACITY", "DISTANCE")); + Map pelev = readSpaceDelimitedData( + getPath("tap.ptype.file").replace("ptype", "elev"), Arrays.asList("TAP", "ELEV")); + float[] taps = ptype.get("TAP"); + float[] etaps = pelev.get("TAP"); + ptype.put("ELEV", getPartialData(taps, etaps, pelev.get("ELEV"))); + + TableDataSet finalData = new TableDataSet(); + for (String columnName : ptype.keySet()) + finalData.appendColumn(ptype.get(columnName), columnName); + + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("TAP")); + exportDataGeneric(finalData, outputFileBase, floatColumns, stringColumns, intColumns, + bitColumns, FieldType.INT, primaryKey, null,false); + nullifyFile(getOutputPath(outputFileBase + ".csv")); + } + + private void exportMgraToTapData(String outputFileBase) + { + addTable(outputFileBase); + String walkdistanceFile=PROJECT_PATH_PROPERTY_TOKEN+"\\input\\"+properties.getProperty("active.logsum.matrix.file.walk.mgratap"); + Map mgraToTap = readSpaceDelimitedData(walkdistanceFile, Arrays.asList("MGRA", "TAP", "DISTANCE")); + TableDataSet finalData = new TableDataSet(); + for (String columnName : mgraToTap.keySet()) + finalData.appendColumn(mgraToTap.get(columnName), columnName); + + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("MGRA", "TAP")); + exportDataGeneric(finalData, outputFileBase, floatColumns, stringColumns, intColumns, + bitColumns, FieldType.INT, primaryKey, null,false); + nullifyFile(getOutputPath(outputFileBase + ".csv")); + } + + private void exportMgraToMgraData(String outputFileBase) + { + addTable(outputFileBase); + //wu modified to get the updated walk distance between MGRAs + String walkdistanceFile=PROJECT_PATH_PROPERTY_TOKEN+"\\input\\"+properties.getProperty("active.logsum.matrix.file.walk.mgra"); + Map mgraToMgra = readSpaceDelimitedData(walkdistanceFile, Arrays.asList("ORIG_MGRA", "DEST_MGRA", "DISTANCE")); + Map> actualData = new LinkedHashMap>(); + for (String column : Arrays.asList("TAZ", "ORIG_MGRA", "DEST_MGRA", "DISTANCE")) + actualData.put(column, new LinkedList()); + float[] dcolumn = mgraToMgra.get("DISTANCE"); + float[] origColumn = mgraToMgra.get("ORIG_MGRA"); + float[] destColumn = mgraToMgra.get("DEST_MGRA"); + for (int i = 0; i < dcolumn.length; i++) + { + int count = 0; + if (dcolumn[i] < 0) count = (int) destColumn[i]; + int taz = (int) origColumn[i]; + while (count-- > 0) + { + i++; + actualData.get("TAZ").add(taz); + actualData.get("ORIG_MGRA").add((int) origColumn[i]); + actualData.get("DEST_MGRA").add((int) destColumn[i]); + actualData.get("DISTANCE").add(dcolumn[i]); + } + } + + TableDataSet finalData = new TableDataSet(); + for (String columnName : actualData.keySet()) + { + Object data; + if (columnName.equals("DISTANCE")) + { + float[] dd = new float[actualData.get(columnName).size()]; + int counter = 0; + for (Number n : actualData.get(columnName)) + dd[counter++] = n.floatValue(); + data = dd; + } else + { + int[] dd = new int[actualData.get(columnName).size()]; + int counter = 0; + for (Number n : actualData.get(columnName)) + dd[counter++] = n.intValue(); + data = dd; + } + finalData.appendColumn(data, columnName); + } + + Set intColumns = new HashSet(Arrays.asList("TAZ", "ORIG_MGRA", "DEST_MGRA")); + Set floatColumns = new HashSet(Arrays.asList("DISTANCE")); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("ORIG_MGRA", "DEST_MGRA")); + exportDataGeneric(finalData, outputFileBase, floatColumns, stringColumns, intColumns, + bitColumns, FieldType.INT, primaryKey, null,false); + nullifyFile(getOutputPath(outputFileBase + ".csv")); + } + + private void exportTazToTapData(String outputFileBase) + { + addTable(outputFileBase); + Map tazToTap = readSpaceDelimitedData( + getPath("taz.driveaccess.taps.file"), Arrays.asList("TAZ", "TAP", "TIME", "DISTANCE", "MODE")); + + Map> actualData = new LinkedHashMap>(); + for (String column : Arrays.asList("TAZ", "TAP", "TIME", "DISTANCE", "MODE")) + actualData.put(column, new LinkedList()); + + float[] taz = tazToTap.get("TAZ"); + float[] tap = tazToTap.get("TAP"); + float[] time = tazToTap.get("TIME"); + float[] dist = tazToTap.get("DISTANCE"); + float[] mode = tazToTap.get("MODE"); + + for (int i = 0; i < taz.length; i++) + { + actualData.get("TAZ").add((int) taz[i]); + actualData.get("TAP").add((int) tap[i]); + actualData.get("TIME").add(time[i]); + actualData.get("DISTANCE").add(dist[i]); + actualData.get("MODE").add(mode[i]); + } + + TableDataSet finalData = new TableDataSet(); + for (String columnName : actualData.keySet()) + { + Object data; + if (columnName.equals("DISTANCE") || columnName.equals("TIME")) + { + float[] dd = new float[actualData.get(columnName).size()]; + int counter = 0; + for (Number n : actualData.get(columnName)) + dd[counter++] = n.floatValue(); + data = dd; + } else + { + int[] dd = new int[actualData.get(columnName).size()]; + int counter = 0; + for (Number n : actualData.get(columnName)) + dd[counter++] = n.intValue(); + data = dd; + } + finalData.appendColumn(data, columnName); + } + + Set intColumns = new HashSet(Arrays.asList("TAZ", "TAP")); + Set floatColumns = new HashSet(Arrays.asList("TIME", "DISTANCE")); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("TAZ", "TAP")); + exportDataGeneric(finalData, outputFileBase, floatColumns, stringColumns, intColumns, + bitColumns, FieldType.INT, primaryKey, null,false); + nullifyFile(getOutputPath(outputFileBase + ".csv")); + } + + private float[] toFloatArray(int[] data) + { + float[] f = new float[data.length]; + for (int i = 0; i < f.length; i++) + f[i] = data[i]; + return f; + } + + private float[] getPartialData(float[] fullKey, float[] partialKey, float[] partialData) + { + float[] data = new float[fullKey.length]; + Arrays.fill(data, NULL_FLOAT_VALUE); + int counter = 0; + for (float key : fullKey) + { + for (int i = 0; i < partialKey.length; i++) + { + if (partialKey[i] == key) + { + data[counter] = partialData[i]; + } + } + counter++; + } + return data; + } + + private void exportTazData(String outputFileBase) + { + addTable(outputFileBase); + int[] tazs = getTazList(); + TableDataSet data = new TableDataSet(); + data.appendColumn(tazs, "TAZ"); + Map term = readSpaceDelimitedData(getPath("taz.terminal.time.file"), + Arrays.asList("TAZ", "TERM")); + Map park = readSpaceDelimitedData(getPath("taz.parkingtype.file"), + Arrays.asList("TAZ", "PARK")); + data.appendColumn(getPartialData(toFloatArray(tazs), term.get("TAZ"), term.get("TERM")), + "TERM"); + data.appendColumn(getPartialData(toFloatArray(tazs), park.get("TAZ"), park.get("PARK")), + "PARK"); + + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("TAZ")); + exportDataGeneric(data, outputFileBase, floatColumns, stringColumns, intColumns, + bitColumns, FieldType.INT, primaryKey, null,false); + nullifyFile(getOutputPath(outputFileBase + ".csv")); + } + + private int[] getTazList() + { + Set tazs = new TreeSet(); + TableDataSet mgraData; + try + { + mgraData = new CSVFileReader().readFile(new File(getPath("mgra.socec.file"))); + } catch (IOException e) + { + throw new RuntimeException(e); + } + boolean first = true; + for (int taz : mgraData.getColumnAsInt("taz")) + { + if (first) + { + first = false; + continue; + } + tazs.add(taz); + } + int[] finalTazs = new int[tazs.size()]; + int counter = 0; + for (int taz : tazs) + finalTazs[counter++] = taz; + return finalTazs; + } + + private Map readSpaceDelimitedData(String location, List columnNames) + { + Map> data = new LinkedHashMap>(); + for (String columnName : columnNames) + data.put(columnName, new LinkedList()); + BufferedReader reader = null; + try + { + reader = new BufferedReader(new FileReader(location)); + String line; + while ((line = reader.readLine()) != null) + { + String[] d = line.trim().split(","); + int counter = 0; + for (String columnName : columnNames) + { + if (counter < d.length) + { + data.get(columnName).add(Float.parseFloat(d[counter++])); + } else + { + data.get(columnName).add(NULL_FLOAT_VALUE); // if missing + // entry/entries, + // then put in + // null value + } + } + } + } catch (IOException e) + { + throw new RuntimeException(e); + } finally + { + if (reader != null) + { + try + { + reader.close(); + } catch (IOException e) + { + // ignore + } + } + } + Map d = new LinkedHashMap(); + for (String columnName : columnNames) + { + float[] f = new float[data.get(columnName).size()]; + int counter = 0; + for (Float i : data.get(columnName)) + f[counter++] = i; + d.put(columnName, f); + } + return d; + } + + private void exportHouseholdData(String outputFileBase) + { + addTable(outputFileBase); + ArrayList formatList = new ArrayList(); + + formatList.add(NUMBER_FORMAT_NAME); // hh_id + formatList.add(NUMBER_FORMAT_NAME); // home_mgra + formatList.add(NUMBER_FORMAT_NAME); // income + formatList.add(NUMBER_FORMAT_NAME); // autos + formatList.add(NUMBER_FORMAT_NAME); // HVs + formatList.add(NUMBER_FORMAT_NAME); // AVs + formatList.add(NUMBER_FORMAT_NAME); // transponder + formatList.add(STRING_FORMAT_NAME); // cdap_pattern + formatList.add(NUMBER_FORMAT_NAME); // jtf_choice + + + if(writeLogsums){ + formatList.add(NUMBER_FORMAT_NAME); //aoLogsum + formatList.add(NUMBER_FORMAT_NAME); //transponderLogsum + formatList.add(NUMBER_FORMAT_NAME); //cdapLogsum + formatList.add(NUMBER_FORMAT_NAME); //jtfLogsum + } + + String[] formats = new String[formatList.size()]; + formats = formatList.toArray(formats); + + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(); + + if(writeLogsums){ + floatColumns.add("aoLogsum"); //aoLogsum + floatColumns.add("transponderLogsum"); //transponderLogsum + floatColumns.add("cdapLogsum"); //cdapLogsum + floatColumns.add("jtfLogsum"); //jtfLogsum + } + + Set stringColumns = new HashSet(Arrays.asList("cdap_pattern")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("hh_id")); + exportDataGeneric(outputFileBase, "Results.HouseholdDataFile", true, formats, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, null,false); + } + + private void exportPersonData(String outputFileBase) + { + addTable(outputFileBase); + + ArrayList formatList = new ArrayList(); + + formatList.add(NUMBER_FORMAT_NAME); // hh_id + formatList.add(NUMBER_FORMAT_NAME); // person_id + formatList.add(NUMBER_FORMAT_NAME); // person_num + formatList.add(NUMBER_FORMAT_NAME); // age + formatList.add(STRING_FORMAT_NAME); // gender + formatList.add(STRING_FORMAT_NAME); // type + formatList.add(NUMBER_FORMAT_NAME); // value_of_time (float) + formatList.add(STRING_FORMAT_NAME); // activity_pattern + formatList.add(NUMBER_FORMAT_NAME); // imf_choice + formatList.add(NUMBER_FORMAT_NAME); // inmf_choice + formatList.add(NUMBER_FORMAT_NAME); // fp_choice + formatList.add(NUMBER_FORMAT_NAME); // reimb_pct (float) + formatList.add(NUMBER_FORMAT_NAME); // ie_choice + formatList.add(NUMBER_FORMAT_NAME); // timeFactorWork + formatList.add(NUMBER_FORMAT_NAME); // timeFactorNonWork + + if(writeLogsums){ + formatList.add(NUMBER_FORMAT_NAME); //wfhLogsum + formatList.add(NUMBER_FORMAT_NAME); //wlLogsum + formatList.add(NUMBER_FORMAT_NAME); //slLogsum + formatList.add(NUMBER_FORMAT_NAME); //fpLogsum + formatList.add(NUMBER_FORMAT_NAME); //ieLogsum + formatList.add(NUMBER_FORMAT_NAME); //cdapLogsum + formatList.add(NUMBER_FORMAT_NAME); //imtfLogsum + formatList.add(NUMBER_FORMAT_NAME);//inmtfLogsum + } + + String[] formats = new String[formatList.size()]; + formats = formatList.toArray(formats); + + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("value_of_time", "reimb_pct")); + + if(writeLogsums){ + floatColumns.add("wfhLogsum"); //wfhLogsum + floatColumns.add("wlLogsum"); //wlLogsum + floatColumns.add("slLogsum"); //slLogsum + floatColumns.add("fpLogsum"); //fpLogsum + floatColumns.add("ieLogsum"); //ieLogsum + floatColumns.add("cdapLogsum"); //cdapLogsum + floatColumns.add("imtfLogsum"); //imtfLogsum + floatColumns.add("inmtfLogsum");//inmtfLogsum + } + + Set stringColumns = new HashSet(Arrays.asList("gender", "type", + "activity_pattern")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("person_id")); + exportDataGeneric(outputFileBase, "Results.PersonDataFile", true, formats, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, null,false); + } + + private void exportSyntheticHouseholdData(String outputFileBase) + { + addTable(outputFileBase); + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("HHID")); + exportDataGeneric(outputFileBase, "PopulationSynthesizer.InputToCTRAMP.HouseholdFile", + false, null, floatColumns, stringColumns, intColumns, bitColumns, FieldType.INT, + primaryKey, null,false); + } + + private void exportSyntheticPersonData(String outputFileBase) + { + addTable(outputFileBase); + String[] formats = {NUMBER_FORMAT_NAME, // HHID + NUMBER_FORMAT_NAME, // PERID + NUMBER_FORMAT_NAME, // household_serial_no + NUMBER_FORMAT_NAME, // PNUM + NUMBER_FORMAT_NAME, // AGE + NUMBER_FORMAT_NAME, // SEX + NUMBER_FORMAT_NAME, // MILTARY + NUMBER_FORMAT_NAME, // PEMPLOY + NUMBER_FORMAT_NAME, // PSTUDENT + NUMBER_FORMAT_NAME, // PTYPE + NUMBER_FORMAT_NAME, // EDUC + NUMBER_FORMAT_NAME, // GRADE + NUMBER_FORMAT_NAME, // OCCCEN5 + STRING_FORMAT_NAME, // OCCSOC5 + NUMBER_FORMAT_NAME, // INDCEN + NUMBER_FORMAT_NAME, // WEEKS + NUMBER_FORMAT_NAME, // HOURS + }; + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(Arrays.asList("OCCSOC5")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("PERID")); + exportDataGeneric(outputFileBase, "PopulationSynthesizer.InputToCTRAMP.PersonFile", false, + formats, floatColumns, stringColumns, intColumns, bitColumns, FieldType.INT, + primaryKey, null,false); + } + + private void exportWorkSchoolLocation(String outputFileBase) + { + addTable(outputFileBase); + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("WorkLocationDistance", + "WorkLocationLogsum", "SchoolLocation", "SchoolLocationDistance", + "SchoolLocationLogsum")); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("PERSON_ID")); + Map overridingNames = new HashMap(); + overridingNames.put("PersonID", "PERSON_ID"); + exportDataGeneric(outputFileBase, "Results.UsualWorkAndSchoolLocationChoice", true, null, + floatColumns, stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, + overridingNames, null,false); + } + + private void exportIndivToursData(String outputFileBase) + { + addTable(outputFileBase); + + ArrayList formatList = new ArrayList(); + + formatList.add(NUMBER_FORMAT_NAME); // hh_id + formatList.add(NUMBER_FORMAT_NAME); // person_id + formatList.add(NUMBER_FORMAT_NAME); // person_num + formatList.add(NUMBER_FORMAT_NAME); // person_type + formatList.add(NUMBER_FORMAT_NAME); // tour_id + formatList.add(STRING_FORMAT_NAME); // tour_category + formatList.add(STRING_FORMAT_NAME); // tour_purpose + formatList.add(NUMBER_FORMAT_NAME); // orig_maz + formatList.add(NUMBER_FORMAT_NAME); // dest_maz + formatList.add(NUMBER_FORMAT_NAME); // start_period + formatList.add(NUMBER_FORMAT_NAME); // end_period + formatList.add(NUMBER_FORMAT_NAME); // tour_mode + formatList.add(NUMBER_FORMAT_NAME); // av_avail + formatList.add(NUMBER_FORMAT_NAME); // tour_distance + formatList.add(NUMBER_FORMAT_NAME); // atWork_freq + formatList.add(NUMBER_FORMAT_NAME); // num_ob_stops + formatList.add(NUMBER_FORMAT_NAME); // num_ib_stops + formatList.add(NUMBER_FORMAT_NAME); // valueOfTime + + if(writeUtilities){ + for(int i=1;i<=26;++i) + formatList.add(NUMBER_FORMAT_NAME); // util_i + for(int i=1;i<=26;++i) + formatList.add(NUMBER_FORMAT_NAME); // prob_i + } + + if(writeLogsums){ + formatList.add(NUMBER_FORMAT_NAME); //timeOfDayLogsum + formatList.add(NUMBER_FORMAT_NAME);//tourModeLogsum + formatList.add(NUMBER_FORMAT_NAME);//subtourFreqLogsum + formatList.add(NUMBER_FORMAT_NAME);//tourDestinationLogsum + formatList.add(NUMBER_FORMAT_NAME);//stopFreqLogsum + + for(int i = 1; i<=4;++i) + formatList.add(NUMBER_FORMAT_NAME);//outStopDCLogsum_i + + for(int i = 1; i<=4;++i) + formatList.add(NUMBER_FORMAT_NAME);//inbStopDCLogsum_i + } + + String[] formats = new String[formatList.size()]; + formats = formatList.toArray(formats); + + Set intColumns = new HashSet(Arrays.asList("hh_id", "person_id", + "person_num", "person_type", "tour_id", "orig_mgra", "dest_mgra", "start_period", + "end_period", "tour_mode", "av_avail", "atWork_freq", "num_ob_stops", "num_ib_stops")); + + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + + if(writeUtilities){ + for(int i=1;i<=12;++i) + floatColumns.add("util_"+i); // util_i + for(int i=1;i<=12;++i) + floatColumns.add("prob_"+i); // prob_i + } + if(writeLogsums){ + floatColumns.add("timeOfDayLogsum"); + floatColumns.add("tourModeLogsum"); + floatColumns.add("subtourFreqLogsum"); + floatColumns.add("tourDestinationLogsum"); + floatColumns.add("stopFreqLogsum"); + + for(int i = 1; i<=4;++i) + floatColumns.add("outStopDCLogsum_"+i);//outStopDCLogsum_i + + for(int i = 1; i<=4;++i) + floatColumns.add("inbStopDCLogsum_"+i);//inbStopDCLogsum_i + } + + Set stringColumns = new HashSet(Arrays.asList("tour_category", + "tour_purpose")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("hh_id", "person_id", + "tour_category", "tour_id", "tour_purpose")); + exportDataGeneric(outputFileBase, "Results.IndivTourDataFile", true, formats, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.FLOAT, primaryKey, null,false); + } + + private void exportJointToursData(String outputFileBase) + { + addTable(outputFileBase); + ArrayList formatList = new ArrayList(); + + formatList.add(NUMBER_FORMAT_NAME); // hh_id + formatList.add(NUMBER_FORMAT_NAME); // tour_id + formatList.add(STRING_FORMAT_NAME); // tour_category + formatList.add(STRING_FORMAT_NAME); // tour_purpose + formatList.add(NUMBER_FORMAT_NAME); // tour_composition + formatList.add(STRING_FORMAT_NAME); // tour_participants + formatList.add(NUMBER_FORMAT_NAME); // orig_maz + formatList.add(NUMBER_FORMAT_NAME); // dest_maz + formatList.add(NUMBER_FORMAT_NAME); // start_period + formatList.add(NUMBER_FORMAT_NAME); // end_period + formatList.add(NUMBER_FORMAT_NAME); // tour_mode + formatList.add(NUMBER_FORMAT_NAME); // av_avail + formatList.add(NUMBER_FORMAT_NAME); // tour_distance + formatList.add(NUMBER_FORMAT_NAME); // num_ob_stops + formatList.add(NUMBER_FORMAT_NAME); // num_ib_stops + formatList.add(NUMBER_FORMAT_NAME); // valueOfTime + + if(writeUtilities){ + for(int i=1;i<=26;++i) + formatList.add(NUMBER_FORMAT_NAME); // util_i + for(int i=1;i<=26;++i) + formatList.add(NUMBER_FORMAT_NAME); // prob_i + } + + if(writeLogsums){ + formatList.add(NUMBER_FORMAT_NAME); //timeOfDayLogsum + formatList.add(NUMBER_FORMAT_NAME);//tourModeLogsum + formatList.add(NUMBER_FORMAT_NAME);//subtourFreqLogsum + formatList.add(NUMBER_FORMAT_NAME);//tourDestinationLogsum + formatList.add(NUMBER_FORMAT_NAME);//stopFreqLogsum + + for(int i = 1; i<=4;++i) + formatList.add(NUMBER_FORMAT_NAME);//outStopDCLogsum_i + + for(int i = 1; i<=4;++i) + formatList.add(NUMBER_FORMAT_NAME);//inbStopDCLogsum_i + } + + String[] formats = new String[formatList.size()]; + formats = formatList.toArray(formats); + + Set intColumns = new HashSet(Arrays.asList("hh_id", "tour_id", + "tour_composition", "orig_mgra", "dest_mgra", "start_period", "end_period", + "tour_mode", "av_avail", "num_ob_stops", "num_ib_stops")); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + + if(writeUtilities){ + for(int i=1;i<=12;++i) + floatColumns.add("util_"+i); // util_i + for(int i=1;i<=12;++i) + floatColumns.add("prob_"+i); // prob_i + } + if(writeLogsums){ + floatColumns.add("timeOfDayLogsum"); + floatColumns.add("tourModeLogsum"); + floatColumns.add("subtourFreqLogsum"); + floatColumns.add("tourDestinationLogsum"); + floatColumns.add("stopFreqLogsum"); + + for(int i = 1; i<=4;++i) + floatColumns.add("outStopDCLogsum_"+i);//outStopDCLogsum_i + + for(int i = 1; i<=4;++i) + floatColumns.add("inbStopDCLogsum_"+i);//inbStopDCLogsum_i + } + Set stringColumns = new HashSet(Arrays.asList("tour_category", + "tour_purpose", "tour_participants")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("hh_id", "tour_category", + "tour_id", "tour_purpose")); + exportDataGeneric(outputFileBase, "Results.JointTourDataFile", true, formats, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.FLOAT, primaryKey, null,false); + } + + private void exportIndivTripData(String outputFileBase) + { + addTable(outputFileBase); + ArrayList formatList = new ArrayList(); + + formatList.add(NUMBER_FORMAT_NAME); // 1 hh_id + formatList.add(NUMBER_FORMAT_NAME); // 2 person_id + formatList.add(NUMBER_FORMAT_NAME); // 3 person_num + formatList.add(NUMBER_FORMAT_NAME); // 4 tour_id + formatList.add(NUMBER_FORMAT_NAME); // 5 stop_id + formatList.add(NUMBER_FORMAT_NAME); // 6 inbound + formatList.add(STRING_FORMAT_NAME); // 7 tour_purpose + formatList.add(STRING_FORMAT_NAME); // 8 orig_purpose + formatList.add(STRING_FORMAT_NAME); // 9 dest_purpose + formatList.add(NUMBER_FORMAT_NAME); // 10 orig_maz + formatList.add(NUMBER_FORMAT_NAME); // 11 dest_maz + formatList.add(NUMBER_FORMAT_NAME); // 12 parking_maz + formatList.add(NUMBER_FORMAT_NAME); // 13 stop_period + formatList.add(NUMBER_FORMAT_NAME); // 14 trip_mode + formatList.add(NUMBER_FORMAT_NAME); // 15 av_avail + formatList.add(NUMBER_FORMAT_NAME); // 16 trip_board_tap + formatList.add(NUMBER_FORMAT_NAME); // 17 trip_alight_tap + formatList.add(NUMBER_FORMAT_NAME); // 18 set + formatList.add(NUMBER_FORMAT_NAME); // 19 tour_mode + formatList.add(NUMBER_FORMAT_NAME); // 20 driver_pnum + formatList.add(NUMBER_FORMAT_NAME); // 21 orig_escort_stoptype + formatList.add(NUMBER_FORMAT_NAME); // 22 orig_escortee_pnum + formatList.add(NUMBER_FORMAT_NAME); // 23 dest_escort_stoptype + formatList.add(NUMBER_FORMAT_NAME); // 24 dest_escortee_pnum + formatList.add(NUMBER_FORMAT_NAME); // 25 value of time + formatList.add(NUMBER_FORMAT_NAME); // 26 transponder availability + formatList.add(NUMBER_FORMAT_NAME); // 27 micro_walkMode + formatList.add(NUMBER_FORMAT_NAME); // 28 micro_trnAcc + formatList.add(NUMBER_FORMAT_NAME); // 29 micro_trnEgr + + if(writeLogsums) + formatList.add(NUMBER_FORMAT_NAME);//tripModeLogsum + + String[] formats = new String[formatList.size()]; + formats = formatList.toArray(formats); + + Set intColumns = new HashSet(); + + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + + if(writeLogsums) + floatColumns = new HashSet(Arrays.asList("valueOfTime","tripModeLogsum")); + + Set stringColumns = new HashSet(Arrays.asList("tour_purpose", + "orig_purpose", "dest_purpose")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("hh_id", "person_id", + "tour_id", "tour_purpose", "inbound", "stop_id")); + exportDataGeneric( + outputFileBase, + "Results.IndivTripDataFile", + true, + formats, + floatColumns, + stringColumns, + intColumns, + bitColumns, + FieldType.INT, + primaryKey, + new TripStructureDefinition(10, 11, 8, 9, 13, 14, 16, 17, 12, -1, 29, "INDIV", 6, false, 25, 18,26),false); + } + + private void exportJointTripData(String outputFileBase) + { + addTable(outputFileBase); + ArrayList formatList = new ArrayList(); + + formatList.add(NUMBER_FORMAT_NAME); // 1 hh_id + formatList.add(NUMBER_FORMAT_NAME); // 2 tour_id + formatList.add(NUMBER_FORMAT_NAME); // 3 stop_id + formatList.add(NUMBER_FORMAT_NAME); // 4 inbound + formatList.add(STRING_FORMAT_NAME); // 5 tour_purpose + formatList.add(STRING_FORMAT_NAME); // 6 orig_purpose + formatList.add(STRING_FORMAT_NAME); // 7 dest_purpose + formatList.add(NUMBER_FORMAT_NAME); // 8 orig_maz + formatList.add(NUMBER_FORMAT_NAME); // 9 dest_maz + formatList.add(NUMBER_FORMAT_NAME); // 10 parking_maz + formatList.add(NUMBER_FORMAT_NAME); // 11 stop_period + formatList.add(NUMBER_FORMAT_NAME); // 12 trip_mode + formatList.add(NUMBER_FORMAT_NAME); // 13 av_avail + formatList.add(NUMBER_FORMAT_NAME); // 14 num_participants + formatList.add(NUMBER_FORMAT_NAME); // 15 trip_board_tap + formatList.add(NUMBER_FORMAT_NAME); // 16 trip_alight_tap + formatList.add(NUMBER_FORMAT_NAME); // 17 set + formatList.add(NUMBER_FORMAT_NAME); // 18 tour_mode + formatList.add(NUMBER_FORMAT_NAME); // 19 value of time + formatList.add(NUMBER_FORMAT_NAME); // 20 transponder availability + formatList.add(NUMBER_FORMAT_NAME); // 21 micro_walkMode + formatList.add(NUMBER_FORMAT_NAME); // 22 micro_trnAcc + formatList.add(NUMBER_FORMAT_NAME); // 23 micro_trnEgr + + if(writeLogsums) + formatList.add(NUMBER_FORMAT_NAME);//tripModeLogsum + + String[] formats = new String[formatList.size()]; + formats = formatList.toArray(formats); + + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + + if(writeLogsums) + floatColumns = new HashSet(Arrays.asList("valueOfTime","tripModeLogsum")); + + Set stringColumns = new HashSet(Arrays.asList("tour_purpose", + "orig_purpose", "dest_purpose")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("hh_id", "tour_id", + "tour_purpose", "inbound", "stop_id")); + exportDataGeneric(outputFileBase, "Results.JointTripDataFile", true, formats, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, + new TripStructureDefinition(8, 9, 6, 7, 11, 12, 15, 16, 10, 14, 23, "JOINT", 4, false, 19, 17,20),false); + } + + private void exportAirportTripsSAN(String outputFileBase) + { + + //id,direction,purpose,size,income,nights,departTime,originMGRA,destinationMGRA,originTAZ,destinationTAZ,tripMode,av_avail,arrivalMode,boardingTAP,alightingTAP,set,valueOfTime\n"); + + addTable(outputFileBase); + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("id")); + Map overridingNames = new HashMap(); + // overridingNames.put("id","PARTYID"); + exportDataGeneric(outputFileBase, "airport.SAN.output.file", false, null, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, overridingNames, + new TripStructureDefinition(8, 9, 7, 12, 15, 16, -1, 4, 18, "AIRPORT", "HOME", + "AIRPORT", 2, false, 18, 17,-1),false); + } + + private void exportAirportTripsCBX(String outputFileBase) + { + + //id,direction,purpose,size,income,nights,departTime,originMGRA,destinationMGRA,originTAZ,destinationTAZ,tripMode,av_avail,arrivalMode,boardingTAP,alightingTAP,set,valueOfTime\n"); + addTable(outputFileBase); + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("id")); + Map overridingNames = new HashMap(); + // overridingNames.put("id","PARTYID"); + exportDataGeneric(outputFileBase, "airport.CBX.output.file", false, null, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, overridingNames, + new TripStructureDefinition(8, 9, 7, 12, 15, 16, -1, 4, 18, "AIRPORT", "HOME", + "AIRPORT", 2, false, 18, 17,-1),false); + } + + private void exportCrossBorderTourData(String outputFileBase) + { + addTable(outputFileBase); + String[] formats = {NUMBER_FORMAT_NAME, // id + NUMBER_FORMAT_NAME, // purpose + STRING_FORMAT_NAME, // sentri + NUMBER_FORMAT_NAME, // poe + NUMBER_FORMAT_NAME, // departTime + NUMBER_FORMAT_NAME, // arriveTime + NUMBER_FORMAT_NAME, // originMGRA + NUMBER_FORMAT_NAME, // destinationMGRA + NUMBER_FORMAT_NAME, // origTaz + NUMBER_FORMAT_NAME, // destTaz + NUMBER_FORMAT_NAME, // tourMode + NUMBER_FORMAT_NAME, // av_avail + NUMBER_FORMAT_NAME, // workTimeFactor + NUMBER_FORMAT_NAME, // nonWorkTimeFactor + NUMBER_FORMAT_NAME // valueOfTime + }; + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(Arrays.asList("sentri")); + Set primaryKey = new LinkedHashSet(Arrays.asList("TOURID")); + Map overridingNames = new HashMap(); + overridingNames.put("id", "TOURID"); + exportDataGeneric(outputFileBase, "crossBorder.tour.output.file", false, formats, + floatColumns, stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, + overridingNames, null,true); + } + + private void exportCrossBorderTripData(String outputFileBase) + { + addTable(outputFileBase); + String[] formats = { + NUMBER_FORMAT_NAME, // 1 tourID + NUMBER_FORMAT_NAME, // 2 tripID + NUMBER_FORMAT_NAME, // 3 originPurp + NUMBER_FORMAT_NAME, // 4 destPurp + NUMBER_FORMAT_NAME, // 5 originMGRA + NUMBER_FORMAT_NAME, // 6 destinationMGRA + NUMBER_FORMAT_NAME, // 7 originTAZ + NUMBER_FORMAT_NAME, // 8 destinationTAZ + STRING_FORMAT_NAME, // 9 inbound + STRING_FORMAT_NAME, // 10 originIsTourDestination + STRING_FORMAT_NAME, // 11 destinationIsTourDestination + NUMBER_FORMAT_NAME, // 12 period + NUMBER_FORMAT_NAME, // 13 tripMode + NUMBER_FORMAT_NAME, // 14 av_avail + NUMBER_FORMAT_NAME, // 15 boardingTap + NUMBER_FORMAT_NAME, // 16 alightingTap + NUMBER_FORMAT_NAME, // 17 set + NUMBER_FORMAT_NAME, // 18 workTimeFactor + NUMBER_FORMAT_NAME, // 19 nonWorkTimeFactor + NUMBER_FORMAT_NAME // 20 valueOfTime + }; + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("workTimeFactor","nonWorkTimeFactor","valueOfTime")); + Set stringColumns = new HashSet(Arrays.asList("inbound", + "originIsTourDestination", "destinationIsTourDestination")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("tourID", "tripID")); + Map overridingNames = new HashMap(); + overridingNames.put("id", "TOURID"); + exportDataGeneric(outputFileBase, "crossBorder.trip.output.file", false, formats, + floatColumns, stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, + overridingNames, new TripStructureDefinition(5, 6, 3, 4, 12, 13, 15, 16, -1, -1, 20, + "CB", 9, true, 20, 17,-1),true); + } + + private void exportVisitorData(String outputTourFileBase, String outputTripFileBase) + { + TableDataSet tourData = exportVisitorTourData(outputTourFileBase); + String tourIdField = "id"; + String partySizeField = "partySize"; + Map tourIdToPartySize = new HashMap(); + int[] ids = tourData.getColumnAsInt(tourIdField); + int[] partySize = tourData.getColumnAsInt(partySizeField); + for (int i = 0; i < ids.length; i++) + tourIdToPartySize.put(ids[i], partySize[i]); + exportVisitorTripData(outputTripFileBase, tourIdToPartySize); + } + + private TableDataSet exportVisitorTourData(String outputFileBase) + { + addTable(outputFileBase); + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("id", "segment")); + Map overridingNames = new HashMap(); + // overridingNames.put("id","PARTYID"); + return exportDataGeneric(outputFileBase, "visitor.tour.output.file", false, null, + floatColumns, stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, + overridingNames, null,false); + } + + private void exportVisitorTripData(String outputFileBase, Map tourIdToPartyMap) + { + addTable(outputFileBase); + String[] formats = { + NUMBER_FORMAT_NAME, // 1 tourID + NUMBER_FORMAT_NAME, // 2 tripID + NUMBER_FORMAT_NAME, // 3 originPurp + NUMBER_FORMAT_NAME, // 4 destPurp + NUMBER_FORMAT_NAME, // 5 originMGRA + NUMBER_FORMAT_NAME, // 6 destinationMGRA + STRING_FORMAT_NAME, // 7 inbound + STRING_FORMAT_NAME, // 8 originIsTourDestination + STRING_FORMAT_NAME, // 9 destinationIsTourDestination + NUMBER_FORMAT_NAME, // 10 period + NUMBER_FORMAT_NAME, // 11 tripMode + NUMBER_FORMAT_NAME, // 12 avAvailable + NUMBER_FORMAT_NAME, // 13 boardingTap + NUMBER_FORMAT_NAME, // 14 alightingTap + NUMBER_FORMAT_NAME, // 15 set + NUMBER_FORMAT_NAME, // 16 valueOfTime + NUMBER_FORMAT_NAME, // 17 partySize (added) + NUMBER_FORMAT_NAME, // 18 micro_walkMode + NUMBER_FORMAT_NAME, // 19 micro_trnAcc + NUMBER_FORMAT_NAME // 20 micro_trnEgr + + }; + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + Set stringColumns = new HashSet(Arrays.asList("inbound", + "originIsTourDestination", "destinationIsTourDestination")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("tourID", "tripId")); + primaryKey = new LinkedHashSet(Arrays.asList("RECID")); // todo: temporary until bugfix + //JoinData joinData = new JoinData("tourID"); + //joinData.addJoinData(tourIdToPartyMap, FieldType.INT, "partySize"); + exportDataGeneric( + outputFileBase, + "visitor.trip.output.file", + false, + formats, + floatColumns, + stringColumns, + intColumns, + bitColumns, + FieldType.INT, + primaryKey, + new TripStructureDefinition(5, 6, 3, 4, 10, 11, 13, 14, -1, 17, 20, "VISITOR", 7, true, 16,15,-1),false); + //, joinData); + } + + private void exportInternalExternalTripData(String outputFileBase) + { + addTable(outputFileBase); + String[] formats = { + NUMBER_FORMAT_NAME, // 1 hh_id + NUMBER_FORMAT_NAME, // 2 pnum + NUMBER_FORMAT_NAME, // 3 person_id + NUMBER_FORMAT_NAME, // 4 tour_id + NUMBER_FORMAT_NAME, // 5 originMGRA + NUMBER_FORMAT_NAME, // 6 destinationMGRA + NUMBER_FORMAT_NAME, // 7 originTAZ + NUMBER_FORMAT_NAME, // 8 destinationTAZ + STRING_FORMAT_NAME, // 9 inbound + STRING_FORMAT_NAME, // 10 originIsTourDestination + STRING_FORMAT_NAME, // 11 destinationIsTourDestination + NUMBER_FORMAT_NAME, // 12 period + NUMBER_FORMAT_NAME, // 13 tripMode + NUMBER_FORMAT_NAME, // 14 av_avail + NUMBER_FORMAT_NAME, // 15 boardingTap + NUMBER_FORMAT_NAME, // 16 alightingTap + NUMBER_FORMAT_NAME, // 17 set + NUMBER_FORMAT_NAME // 18 value of time + }; + Set intColumns = new HashSet(); + Set floatColumns = new HashSet(Arrays.asList("valueOfTime")); + Set stringColumns = new HashSet(Arrays.asList("inbound", + "originIsTourDestination", "destinationIsTourDestination")); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(); + exportDataGeneric(outputFileBase, "internalExternal.trip.output.file", false, formats, + floatColumns, stringColumns, intColumns, bitColumns, FieldType.INT, primaryKey, + new TripStructureDefinition(5, 6, 12, 13, 15, 16, -1, -1, 18, "IE", "HOME", "EXTERNAL", + 9, true,18,17,-1),false); + } + + private Set getExternalZones() + { + Set externalZones = new LinkedHashSet(); + for (String zone : ((String) properties.get("external.tazs")).trim().split(",")) + externalZones.add(Integer.parseInt(zone.trim())); + return externalZones; + } + + /** + * Export commercial tNCVehicle data. + * + * @param outputFileBase + * @throws IOException + */ + private void exportCommVehData(String outputFileBase) throws IOException + { + addTable(outputFileBase); + Set internalZones = new LinkedHashSet(); + DecimalFormat formatter = new DecimalFormat("#.######"); + + BufferedWriter writer = null; + try + { + writer = new BufferedWriter(new FileWriter(new File(getOutputPath(outputFileBase + + ".csv"))), 1024 * 1024 * 1024); + + CsvRow headerRow = new CsvRow(new String[] {"ORIG_TAZ", "DEST_TAZ", "TOD", + "TRIPS_COMMVEH"}); + writer.write(headerRow.getRow()); + + for (String period : timePeriods) + { + Matrix matrixData = mtxDao.getMatrix("commVehTODTrips", period + " Trips"); + + // This doesn't make sense + if (internalZones.isEmpty()) for (int zone : matrixData.getExternalColumnNumbers()) + internalZones.add(zone); + + for (int i : internalZones) + { + for (int j : internalZones) + { + float value = matrixData.getValueAt(i, j); + if (value > .00001) + { + String[] rowValue = new String[4]; + rowValue[0] = String.valueOf(i); + rowValue[1] = String.valueOf(j); + rowValue[2] = period; + rowValue[3] = formatter.format(value); + CsvRow dataRow = new CsvRow(rowValue); + writer.write(dataRow.getRow()); + } + } + } + } + } finally + { + if (writer != null) writer.close(); + } + } + + /** + * Export commercial tNCVehicle data to OMX Format. + * + * @param outputFileBase + * @throws IOException + */ + private void exportCommVehDataToOmx(String outputFileBase) throws IOException + { + String[] modes = {"Toll","NonToll"}; + + addTable(outputFileBase); + for (String period : timePeriods){ + + Matrix[] matrices = new Matrix[modes.length]; + int counter = 0; + for(String mode : modes){ + + matrices[counter] = mtxDao.getMatrix("commVehTODTrips", period + " " + mode); + ++counter; + } + File outMatrixFile = new File(getOutputPath("commVeh_" + period + ".omx")); + MatrixWriter matrixWriter = MatrixWriter.createWriter(MatrixType.OMX,outMatrixFile); + matrixWriter.writeMatrices(modes,matrices); + } + + } + private void exportExternalInternalTripData(String outputFileBase) + { + addTable(outputFileBase); + Set internalZones = new LinkedHashSet(); + Set externalZones = getExternalZones(); + List cores = Arrays.asList("DAN", "S2N", "S3N", "DAT", "S2T", "S3T"); + Map purposeMap = new HashMap(); + purposeMap.put("WORK", "Wrk"); + purposeMap.put("NONWORK", "Non"); + + Matrix[] matrixData = new Matrix[cores.size()]; + + PrintWriter writer = null; + try + { + writer = getBufferedPrintWriter(getOutputPath(outputFileBase + ".csv")); + + StringBuilder sb = new StringBuilder(); + sb.append("ORIG_TAZ,DEST_TAZ,TOD,PURPOSE"); + for (String core : cores) + sb.append(",").append("TRIPS_").append(core); + writer.println(sb.toString()); + + for (String period : timePeriods) + { + for (String purpose : purposeMap.keySet()) + { + int counter = 0; + for (String core : cores) + matrixData[counter++] = mtxDao.getMatrix("usSd" + purposeMap.get(purpose) + + "_" + period, core); + + if (internalZones.size() == 0) + { // only need to form internal zones once + for (int zone : matrixData[0].getExternalColumnNumbers()) + internalZones.add(zone); + internalZones.removeAll(externalZones); + } + + for (int i : internalZones) + { + for (int e : externalZones) + { + StringBuilder sbie = new StringBuilder(); + StringBuilder sbei = new StringBuilder(); + sbie.append(i).append(",").append(e).append(",").append(period) + .append(",").append(purpose); + sbei.append(e).append(",").append(i).append(",").append(period) + .append(",").append(purpose); + float ie = 0; + float ei = 0; + + for (Matrix matrix : matrixData) + { + float vie = matrix.getValueAt(i, e); + float vei = matrix.getValueAt(e, i); + ie += vie; + ei += vei; + sbie.append(",").append(vie); + sbei.append(",").append(vei); + } + if (ie > 0) writer.println(sbie.toString()); + if (ei > 0) writer.println(sbei.toString()); + } + } + } + } + + } catch (IOException e) + { + throw new RuntimeException(e); + } finally + { + if (writer != null) writer.close(); + } + } + + /** + * Export the external-internal trips to OMX format. Collapse out purposes. + * @param outputFileBase + */ + private void exportExternalInternalTripDataToOMX(String outputFileBase) + { + addTable(outputFileBase); + String[] cores = {"DAN", "S2N", "S3N", "DAT", "S2T", "S3T"}; + String[] purposes = {"Wrk","Non"}; + + Matrix[] outMatrixData = new Matrix[cores.length]; + + for (String period : timePeriods) + { + for(int p = 0; p externalZones = getExternalZones(); + + BufferedWriter writer = null; + MatrixWriter matrixWriter = null; + try + { + if(writeCSV){ + writer = new BufferedWriter(new FileWriter(new File(getOutputPath(outputFileBase + + ".csv"))), 1024 * 1024 * 1024); + + CsvRow headerRow = new CsvRow(new String[] {"ORIG_TAZ", "DEST_TAZ", "TRIPS_EE"}); + writer.write(headerRow.getRow()); + }else{ + matrixWriter = MatrixWriter.createWriter(MatrixType.OMX, new File(getOutputPath(outputFileBase + ".omx"))); + } + + Matrix m = mtxDao.getMatrix("externalExternalTrips", "Trips"); + + if(writeCSV){ + for (int o : externalZones) + { + for (int d : externalZones) + { + String[] values = new String[3]; + values[0] = String.valueOf(o); + values[1] = String.valueOf(d); + values[2] = String.valueOf(m.getValueAt(o, d)); + CsvRow dataRow = new CsvRow(values); + writer.write(dataRow.getRow()); + } + } + }else{ + matrixWriter.writeMatrix(m); + } + } finally + { + if (writer != null) writer.close(); + } + + } + + /** + * A private helper class to organize skims + * + * @author joel.freedman + * + */ + private class AutoSkimSet{ + + String fileName; + String[] skimNames; + + AutoSkimSet(String fileName, String[] skimNames){ + this.fileName = fileName; + this.skimNames = skimNames; + } + } + + /** + * Return a map containing a number of elements where key is the name of the skim file and + * value is the name of a matrix core in the skim file. The map includes length and time for + * "free" path skims and length, time and toll for toll skims. + * + * @return The map. + */ + private HashMap getVehicleSkimFileCoreNameMapping() + { + HashMap map = new HashMap(); + + String[] votBins = {"L","M","H"}; + + for(int i = 1; i< votBins.length;++i){ + + // DA Non-Toll + AutoSkimSet SOVGP = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_SOVGP"+votBins[i]+"_DIST", + TOD_TOKEN+"_SOVGP"+votBins[i]+"_TIME", + TOD_TOKEN+"_SOVGP"+votBins[i]+"_REL"}); + map.put("SOVGP"+votBins[i], SOVGP); + + // DA Toll + AutoSkimSet SOVTOLL = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_SOVTOLL"+votBins[i]+"_DIST", + TOD_TOKEN+"_SOVTOLL"+votBins[i]+"_TIME", + TOD_TOKEN+"_SOVTOLL"+votBins[i]+"_TOLLCOST", + TOD_TOKEN+"_SOVTOLL"+votBins[i]+"_REL"}); + map.put("SOTOLL"+votBins[i], SOVTOLL); + + // S2 Non-Toll + AutoSkimSet HOV2HOV = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_HOV2HOV"+votBins[i]+"_DIST", + TOD_TOKEN+"_HOV2HOV"+votBins[i]+"_TIME", + TOD_TOKEN+"_HOV2HOV"+votBins[i]+"_REL"}); + map.put("HOV2HOV"+votBins[i], HOV2HOV); + + // S2 Toll + AutoSkimSet HOV2TOLL = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_HOV2TOLL"+votBins[i]+"_DIST", + TOD_TOKEN+"_HOV2TOLL"+votBins[i]+"_TIME", + TOD_TOKEN+"_HOV2TOLL"+votBins[i]+"_TOLLCOST", + TOD_TOKEN+"_HOV2TOLL"+votBins[i]+"_REL"}); + map.put("HOV2TOLL"+votBins[i], HOV2TOLL); + + // S3+ Non-Toll + AutoSkimSet HOV3HOV = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_HOV3HOV"+votBins[i]+"_DIST", + TOD_TOKEN+"_HOV3HOV"+votBins[i]+"_TIME", + TOD_TOKEN+"_HOV3HOV"+votBins[i]+"_REL"}); + map.put("HOV3HOV"+votBins[i], HOV3HOV); + + // S3+ Toll + AutoSkimSet HOV3TOLL = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_HOV3TOLL"+votBins[i]+"_DIST", + TOD_TOKEN+"_HOV3TOLL"+votBins[i]+"_TIME", + TOD_TOKEN+"_HOV3TOLL"+votBins[i]+"_TOLLCOST", + TOD_TOKEN+"_HOV3TOLL"+votBins[i]+"_REL"}); + map.put("HOV3TOLL"+votBins[i], HOV3TOLL); + + } + + // Light Truck GP + AutoSkimSet TRKLGP = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_TRKLGP_DIST", + TOD_TOKEN+"_TRKLGP_TIME"}); + map.put("TRKLGP", TRKLGP); + + // Light Truck Toll + AutoSkimSet TRKLTOLL = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_TRKLTOLL_DIST", + TOD_TOKEN+"_TRKLTOLL_TIME", + TOD_TOKEN+"_TRKLTOLL_TOLLCOST"}); + map.put("TRKLTOLL", TRKLTOLL); + + + // Medium Truck GP + AutoSkimSet TRKMGP = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_TRKMGP_DIST", + TOD_TOKEN+"_TRKMGP_TIME"}); + map.put("TRKMGP", TRKMGP); + + // Medium Truck Toll + AutoSkimSet TRKMTOLL = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_TRKMTOLL_DIST", + TOD_TOKEN+"_TRKMTOLL_TIME", + TOD_TOKEN+"_TRKMTOLL_TOLLCOST"}); + map.put("TRKMTOLL", TRKMTOLL); + + // Heavy Truck GP + AutoSkimSet TRKHGP = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_TRKHGP_DIST", + TOD_TOKEN+"_TRKHGP_TIME"}); + map.put("TRKHGP", TRKHGP); + + // Heavy Truck Toll + AutoSkimSet TRKHTOLL = new AutoSkimSet("traffic_skims_" + TOD_TOKEN, new String[] { + TOD_TOKEN+"_TRKHTOLL_DIST", + TOD_TOKEN+"_TRKHTOLL_TIME", + TOD_TOKEN+"_TRKHTOLL_TOLLCOST"}); + map.put("TRKHTOLL", TRKHTOLL); + + + return map; + } + + /** + * Export auto skims to the directory using both csv and omx formats. The CSV file will be + * written if writeCSV is true. Otherwise OMX files will be written. The OMX files will also + * contain an auto operating cost matrix. + * + * @param outputFileBase The name of output csv file to write to the reports directory. + */ + private void exportAutoSkims(String outputFileBase) + { + addTable(outputFileBase); + String[] includedTimePeriods = getTimePeriodsForSkims(); + Set internalZones = new LinkedHashSet(); + String path = properties.getProperty("report.path"); + + BlockingQueue queue = new LinkedBlockingQueue(); + try + { + + Map vehicleSkimCores = getVehicleSkimFileCoreNameMapping(); + + boolean first = true; + + ArrayList modeNames = new ArrayList(); + + for (String period : includedTimePeriods) + { + Map lengthMatrix = new LinkedHashMap(); + Map timeMatrix = new LinkedHashMap(); + Map tollMatrix = new LinkedHashMap(); + Map stdMatrix = new LinkedHashMap(); + + + //iterate through the auto modes + for (String key : vehicleSkimCores.keySet()) + { + // String name = vehicleSkimFiles.get(key); + AutoSkimSet skimSet = vehicleSkimCores.get(key); + String skimFileName = skimSet.fileName; + String[] inputMatrixNames = skimSet.skimNames; + + // the first skim is always distance. Remove it to get the name of the mode. + modeNames.add(key+"_"+TOD_TOKEN); //store all the modes + + int stdMatrixNumber=-1; + int tollMatrixNumber=-1; + + //need to replace the TOD token with the period name for matrices to output to OMX + String[] outCores = new String[inputMatrixNames.length+1]; + for(int i =0; i < (outCores.length-1);++i){ + outCores[i] = inputMatrixNames[i].replace(TOD_TOKEN, period); + if(inputMatrixNames[i].contains("REL")) + stdMatrixNumber=i; + if(inputMatrixNames[i].contains("TOLLCOST")) + tollMatrixNumber=i; + } + + skimFileName = skimFileName.replace(TOD_TOKEN,period); + Matrix length = mtxDao.getMatrix(skimFileName+".omx", inputMatrixNames[0].replace(TOD_TOKEN, period)); + Matrix time = mtxDao.getMatrix(skimFileName+".omx", inputMatrixNames[1].replace(TOD_TOKEN, period)); + Matrix aoc = length.multiply(autoOperatingCost); + + String aocName = outCores[0].replace("_DIST", "_AOC"); + outCores[outCores.length-1] = aocName; + + String outputFileName = path+key+"_"+period+".omx"; + + MatrixWriter matrixWriter = MatrixWriter.createWriter(MatrixType.OMX, new File(outputFileName)); + + Matrix[] matrices = new Matrix[inputMatrixNames.length+1]; + matrices[0] = length; + matrices[1] = time; + + lengthMatrix.put(inputMatrixNames[0],length); + timeMatrix.put(inputMatrixNames[1], time); + + + int matrixNumber=2; + if(stdMatrixNumber>-1){ + Matrix std = mtxDao.getMatrix(skimFileName+".omx", inputMatrixNames[stdMatrixNumber].replace(TOD_TOKEN, period)); + matrices[matrixNumber]= std; + stdMatrix.put(inputMatrixNames[matrixNumber], std); + ++matrixNumber; + } + if(tollMatrixNumber>-1){ + Matrix cost = mtxDao.getMatrix(skimFileName+".omx", inputMatrixNames[tollMatrixNumber].replace(TOD_TOKEN, period)); + matrices[matrixNumber]= cost; + + ++matrixNumber; + } + + matrices[matrixNumber] = aoc; + + LOGGER.info("Writing "+outCores.length+" skims to file "+outputFileName); + matrixWriter.writeMatrices(outCores, matrices); + + if(writeCSV){ + if (internalZones.size() == 0) + { + boolean f = true; + for (int zone : lengthMatrix.get(inputMatrixNames[0]).getExternalColumnNumbers()) + { + if (f) + { + f = false; + continue; + } + internalZones.add(zone); + } + } + + // put data into arrays for faster access + Matrix[] orderedData = new Matrix[lengthMatrix.size() + timeMatrix.size() + + stdMatrix.size() + tollMatrix.size()]; + int counter = 0; + for (String mode : modeNames) + { + orderedData[counter++] = lengthMatrix.get(mode); + orderedData[counter++] = timeMatrix.get(mode); + orderedData[counter++] = stdMatrix.get(mode); + if (tollMatrix.containsKey(mode)) + orderedData[counter++] = tollMatrix.get(mode); + } + + if (first) + { + List header = new ArrayList(); + header.add("ORIG_TAZ"); + header.add("DEST_TAZ"); + header.add("TOD"); + + for (String modeName : modeNames) + { + header.add("DIST_" + modeName); + header.add("TIME_" + modeName); + header.add("STD_TIME_" + modeName); + if (tollMatrix.containsKey(modeName)) + { + header.add("COST_" + modeName); + } + } + + CsvWriterThread writerThread = new CsvWriterThread(queue, new File( + getOutputPath(outputFileBase + ".csv")), + header.toArray(new String[header.size()])); + new Thread(writerThread).start(); + first = false; + } + + int rowSize = 3 + orderedData.length; + + for (int i : internalZones) + { + for (int j : internalZones) + { + String[] values = new String[rowSize]; + values[0] = String.valueOf(i); + values[1] = String.valueOf(j); + values[2] = period; + int position = 3; + for (Matrix matrix : orderedData) + values[position++] = DoubleFormatUtil.formatDouble( + matrix.getValueAt(i, j), 4, 4); + queue.add(new CsvRow(values)); + } + } + } + } + } + } finally + { + queue.add(CsvWriterThread.POISON_PILL); + } + } + + private Map getTransitSkimFileNameMapping() + { + Map map = new LinkedHashMap(); + // map.put("implocl_" + TOD_TOKEN + "o", "LOCAL_TRANSIT"); + map.put("impprem_" + TOD_TOKEN + "o", "PREMIUM_TRANSIT"); + return map; + } + + private String getTransitSkimFileFareCoreName() + { + return "Fare"; + } + + private Map getTransitSkimFileInVehicleTimeCoreNameMapping() + { // distance,time,cost + Map map = new LinkedHashMap(); + map.put("impprem_" + TOD_TOKEN + "o", new String[] {"IVT:CR", "IVT:LR", "IVT:BRT", + "IVT:EXP", "IVT:LB"}); + return map; + } + + private String[] getTimePeriodsForSkims() + { + return IExporter.TOD_TOKENS; + } + + /** + * This method reads the transit skims and exports them to OMX format. It will also write + * csv file of skim values if the writeCSVSkims attribute is set to true. + * + * @param outputFileBase + */ + private void exportTransitSkims(String outputFileBase) + { + addTable(outputFileBase); + String[] includedTimePeriods = getTimePeriodsForSkims(); + + Set internalZones = new LinkedHashSet(); + + BlockingQueue queue = new LinkedBlockingQueue(); + try + { + Map transitSkimFiles = getTransitSkimFileNameMapping(); + Map transitSkimTimeCores = getTransitSkimFileInVehicleTimeCoreNameMapping(); + String fareCore = getTransitSkimFileFareCoreName(); + String initialWaitCore = "Initial Wait Time"; + String transferTimeCore = "Transfer Wait Time"; + String walkTimeCore = "Walk Time"; + Set modeNames = new LinkedHashSet(); + for (String n : transitSkimFiles.keySet()) + modeNames.add(transitSkimFiles.get(n)); + boolean first = true; + int numOfColumns = 3 + 5 * modeNames.size(); + for (String period : includedTimePeriods) + { + Map timeMatrix = new LinkedHashMap(); + Map fareMatrix = new LinkedHashMap(); + Map initialMatrix = new LinkedHashMap(); + Map transferMatrix = new LinkedHashMap(); + Map walkTimeMatrix = new LinkedHashMap(); + + for (String key : transitSkimFiles.keySet()) + { + String name = transitSkimFiles.get(key); + String[] timeCores = transitSkimTimeCores.get(key); + String file = key.replace(TOD_TOKEN, period); + Matrix[] timeMatrices = new Matrix[timeCores.length]; + for (int i = 0; i < timeCores.length; i++) + timeMatrices[i] = mtxDao.getMatrix(file, + timeCores[i].replace(TOD_TOKEN, period)); + timeMatrix.put(name, timeMatrices); + fareMatrix.put(name, + mtxDao.getMatrix(file, fareCore.replace(TOD_TOKEN, period))); + initialMatrix.put(name, mtxDao.getMatrix(file, initialWaitCore)); + transferMatrix.put(name, mtxDao.getMatrix(file, transferTimeCore)); + walkTimeMatrix.put(name, mtxDao.getMatrix(file, walkTimeCore)); + if (internalZones.size() == 0) + { + boolean f = true; + for (int zone : fareMatrix.get(name).getExternalColumnNumbers()) + { + if (f) + { + f = false; + continue; + } + internalZones.add(zone); + } + } + } + + // put data into arrays for faster access + Matrix[][] orderedTimeData = new Matrix[timeMatrix.size()][]; + Matrix[] fareData = new Matrix[orderedTimeData.length]; + Matrix[] initialWaitData = new Matrix[orderedTimeData.length]; + Matrix[] transferTimeData = new Matrix[orderedTimeData.length]; + Matrix[] walkTimeData = new Matrix[orderedTimeData.length]; + + int counter = 0; + for (String mode : modeNames) + { + orderedTimeData[counter] = timeMatrix.get(mode); + fareData[counter] = fareMatrix.get(mode); + initialWaitData[counter] = initialMatrix.get(mode); + transferTimeData[counter] = transferMatrix.get(mode); + walkTimeData[counter++] = walkTimeMatrix.get(mode); + } + + if (first) + { + String[] header = new String[numOfColumns]; + + header[0] = "ORIG_TAP"; + header[1] = "DEST_TAP"; + header[2] = "TOD"; + int column = 3; + + for (String modeName : modeNames) + { + header[column++] = "TIME_INIT_WAIT_" + modeName; + header[column++] = "TIME_IVT_TIME_" + modeName; + header[column++] = "TIME_WALK_TIME_" + modeName; + header[column++] = "TIME_TRANSFER_TIME_" + modeName; + header[column++] = "FARE_" + modeName; + } + + CsvWriterThread writerThread = new CsvWriterThread(queue, new File( + getOutputPath(outputFileBase + ".csv")), header); + new Thread(writerThread).start(); + + first = false; + } + + for (int i : internalZones) + { + for (int j : internalZones) + { + String[] values = new String[numOfColumns]; + values[0] = String.valueOf(i); + values[1] = String.valueOf(j); + values[2] = period; + + int column = 3; + float runningTotal = 0.0f; + + for (int m = 0; m < orderedTimeData.length; m++) + { + float time = 0.0f; + float initTime = initialWaitData[m].getValueAt(i, j); + for (Matrix tm : orderedTimeData[m]) + time += tm.getValueAt(i, j); + float walkTime = walkTimeData[m].getValueAt(i, j); + float transferTime = transferTimeData[m].getValueAt(i, j); + float fare = fareData[m].getValueAt(i, j); + runningTotal += fare + time; + values[column++] = DoubleFormatUtil.formatDouble(initTime, 4, 4); + values[column++] = DoubleFormatUtil.formatDouble(time, 4, 4); + values[column++] = DoubleFormatUtil.formatDouble(walkTime, 4, 4); + values[column++] = DoubleFormatUtil.formatDouble(transferTime, 4, 4); + values[column++] = DoubleFormatUtil.formatDouble(fare, 2, 2); + } + if (runningTotal > 0.0f) queue.add(new CsvRow(values)); + } + } + } + + } finally + { + queue.add(CsvWriterThread.POISON_PILL); + } + } + + private void exportDefinitions(String outputFileBase) + { + addTable(outputFileBase); + Map tripPurposes = new LinkedHashMap(); + Map modes = new LinkedHashMap(); + Map ejCategories = new LinkedHashMap(); + + PrintWriter writer = null; + try + { + writer = getBufferedPrintWriter(getOutputPath(outputFileBase + ".csv")); + writer.println("type,code,description"); + writer.println("nothing,placeholder,this describes nothing"); + for (String tripPurpose : tripPurposes.keySet()) + writer.println("trip_purpose," + tripPurpose + "," + tripPurposes.get(tripPurpose)); + for (String mode : modes.keySet()) + writer.println("mode," + mode + "," + modes.get(mode)); + for (String ejCategory : ejCategories.keySet()) + writer.println("ej_category," + ejCategory + "," + ejCategories.get(ejCategory)); + } catch (IOException e) + { + throw new RuntimeException(e); + } finally + { + if (writer != null) writer.close(); + } + } + + private void exportPnrVehicleData(String outputFileBase) + { + addTable(outputFileBase); + Set intColumns = new HashSet(Arrays.asList("TAP")); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("TAP")); + exportDataGeneric(outputFileBase, "Results.PNRFile", false, null, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.FLOAT, primaryKey, null,false); + } + + private void exportCbdVehicleData(String outputFileBase) + { + addTable(outputFileBase); + Set intColumns = new HashSet(Arrays.asList("MGRA")); + Set floatColumns = new HashSet(); + Set stringColumns = new HashSet(); + Set bitColumns = new HashSet(); + Set primaryKey = new LinkedHashSet(Arrays.asList("MGRA")); + exportDataGeneric(outputFileBase, "Results.CBDFile", false, null, floatColumns, + stringColumns, intColumns, bitColumns, FieldType.FLOAT, primaryKey, null,false); + } + + private static enum FieldType + { + INT, FLOAT, STRING, BIT + } + + private final class TripStructureDefinition + { + private final int originMgraColumn; + private final int destMgraColumn; + private final int originPurposeColumn; + private final int destinationPurposeColumn; + private final int todColumn; + private final int modeColumn; + private final int boardTapColumn; + private final int alightTapColumn; + + private final int parkingMazColumn; + + private final String homeName; + private final String destinationName; + private final int inboundColumn; + private final boolean booleanIndicatorVariables; + private final int valueOfTimeColumn; + private final int setColumn; + private final int transponderOwnershipColumn; + + private TripStructureDefinition(int originMgraColumn, int destMgraColumn, + int originPurposeColumn, int destinationPurposeColumn, int todColumn, + int modeColumn, int boardTapColumn, int alightTapColumn, int parkingMazColumn, int partySizeColumn, + int tripTimeColumn, int outVehicleTimeColumn, int tripDistanceColumn, + int tripCostColumn, int tripPurposeNameColumn, int tripModeNameColumn, + int recIdColumn, int boardTazColumn, int alightTazColumn, String tripType, + String homeName, String destinationName, int inboundColumn, + boolean booleanIndicatorVariables, int valueOfTimeColumn, int setColumn, int transponderOwnershipColumn) + { + this.originMgraColumn = originMgraColumn; + this.destMgraColumn = destMgraColumn; + this.originPurposeColumn = originPurposeColumn; + this.destinationPurposeColumn = destinationPurposeColumn; + this.todColumn = todColumn; + this.modeColumn = modeColumn; + this.boardTapColumn = boardTapColumn; + this.alightTapColumn = alightTapColumn; + this.parkingMazColumn = parkingMazColumn; + this.homeName = homeName; + this.destinationName = destinationName; + this.inboundColumn = inboundColumn; + + this.booleanIndicatorVariables = booleanIndicatorVariables; + this.valueOfTimeColumn = valueOfTimeColumn; + this.setColumn = setColumn; + this.transponderOwnershipColumn = transponderOwnershipColumn; + } + + private TripStructureDefinition(int originMgraColumn, int destMgraColumn, + int originPurposeColumn, int destinationPurposeColumn, int todColumn, + int modeColumn, int boardTapColumn, int alightTapColumn, int parkingMazColumn, int partySizeColumn, + int columnCount, String tripType, int inboundColumn, + boolean booleanIndicatorVariables, int valueOfTimeColumn, int setColumn, int transponderOwnershipColumn) + { + this(originMgraColumn, destMgraColumn, originPurposeColumn, destinationPurposeColumn, + todColumn, modeColumn, boardTapColumn, alightTapColumn, parkingMazColumn, partySizeColumn, + columnCount + 1, columnCount + 2, columnCount + 3, columnCount + 4, + columnCount + 5, columnCount + 6, columnCount + 7, columnCount + 8, + columnCount + 9, tripType, "", "", inboundColumn, booleanIndicatorVariables, valueOfTimeColumn,setColumn,transponderOwnershipColumn); + } + + private TripStructureDefinition(int originMgraColumn, int destMgraColumn, int todColumn, + int modeColumn, int boardTapColumn, int alightTapColumn, int parkingMazColumn, int partySizeColumn, + int columnCount, String tripType, String homeName, String destinationName, + int inboundColumn, boolean booleanIndicatorVariables, int valueOfTimeColumn, int setColumn, int transponderOwnershipColumn) + { + this(originMgraColumn, destMgraColumn, -1, -1, todColumn, modeColumn, boardTapColumn, + alightTapColumn, parkingMazColumn, partySizeColumn, columnCount + 1, columnCount + 2, + columnCount + 3, columnCount + 4, columnCount + 5, columnCount + 6, + columnCount + 7, columnCount + 8, columnCount + 9, tripType, homeName, + destinationName, inboundColumn, booleanIndicatorVariables, valueOfTimeColumn,setColumn,transponderOwnershipColumn); + } + } + + public static void main(String... args) throws Exception + { + String propertiesFile = null; + propertiesFile = args[0]; + + Properties properties = new Properties(); + properties.load(new FileInputStream("conf/sandag_abm.properties")); + HashMap pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + + int feedbackIteration = Integer.valueOf(properties.getProperty("Report.iteration").trim()); + + List definedTables = new ArrayList(); + for (String table : properties.getProperty("Report.tables").trim().split(",")) + definedTables.add(table.trim().toLowerCase()); + + String path = ClassLoader.getSystemResource("").getPath(); + path = path.substring(1, path.length() - 2); + String appPath = path.substring(0, path.lastIndexOf("/")); + + for (Object key : properties.keySet()) + { + String value = (String) properties.get(key); + properties.setProperty((String) key, + value.replace(PROJECT_PATH_PROPERTY_TOKEN, appPath)); + } + + OMXMatrixDao mtxDao = new OMXMatrixDao(properties); + + DataExporter dataExporter = new DataExporter(properties, mtxDao, appPath, feedbackIteration); + dataExporter.startMatrixServer(pMap); + + if (definedTables.contains("accessibilities")) + dataExporter.exportAccessibilities("accessibilities"); + if (definedTables.contains("mgra")) dataExporter.exportMazData("mgra"); + if (definedTables.contains("taz")) dataExporter.exportTazData("taz"); + if (definedTables.contains("tap")) dataExporter.exportTapData("tap"); + if (definedTables.contains("mgratotap")) dataExporter.exportMgraToTapData("mgratotap"); + if (definedTables.contains("mgratomgra")) dataExporter.exportMgraToMgraData("mgratomgra"); + if (definedTables.contains("taztotap")) dataExporter.exportTazToTapData("taztotap"); + if (definedTables.contains("hhdata")) dataExporter.exportHouseholdData("hhdata"); + if (definedTables.contains("persondata")) dataExporter.exportPersonData("persondata"); + if (definedTables.contains("wslocation")) + dataExporter.exportWorkSchoolLocation("wslocation"); + if (definedTables.contains("synhh")) dataExporter.exportSyntheticHouseholdData("synhh"); + if (definedTables.contains("synperson")) + dataExporter.exportSyntheticPersonData("synperson"); + if (definedTables.contains("indivtours")) dataExporter.exportIndivToursData("indivtours"); + if (definedTables.contains("jointtours")) dataExporter.exportJointToursData("jointtours"); + if (definedTables.contains("indivtrips")) dataExporter.exportIndivTripData("indivtrips"); + if (definedTables.contains("jointtrips")) dataExporter.exportJointTripData("jointtrips"); + if (definedTables.contains("airporttripssan")) + dataExporter.exportAirportTripsSAN("airporttripssan"); + if (definedTables.contains("airporttripscbx")) + dataExporter.exportAirportTripsCBX("airporttripscbx"); + if (definedTables.contains("cbtours")) dataExporter.exportCrossBorderTourData("cbtours"); + if (definedTables.contains("cbtrips")) dataExporter.exportCrossBorderTripData("cbtrips"); + if (definedTables.contains("visitortours") && definedTables.contains("visitortrips")) + dataExporter.exportVisitorData("visitortours", "visitortrips"); + if (definedTables.contains("ietrip")) + dataExporter.exportInternalExternalTripData("ietrip"); + if (definedTables.contains("commtrip")){ + CVMExporter cvmExporter = new CVMExporter(properties,mtxDao); + cvmExporter.export(); + CVMScaler cvmScaler = new CVMScaler(properties); + cvmScaler.scale(); + } + + + if (definedTables.contains("trucktrip")) + { + if(dataExporter.writeCSV){ + IExporter truckExporter = new TruckCsvExporter(properties, mtxDao, "trucktrip"); + truckExporter.export(); + }else{ + IExporter truckExporter = new TruckOmxExporter(properties, mtxDao, "trucktrip"); + truckExporter.export(); + } + } + if (definedTables.contains("eetrip")) + dataExporter.exportExternalExternalTripData("eetrip"); + + if (definedTables.contains("eitrip")) + if(dataExporter.writeCSV) + dataExporter.exportExternalInternalTripData("eitrip"); + else + dataExporter.exportExternalInternalTripDataToOMX("eitrip"); + + if (definedTables.contains("tazskim")) dataExporter.exportAutoSkims("tazskim"); + if (definedTables.contains("tapskim")) dataExporter.exportTransitSkims("tapskim"); + if (definedTables.contains("definition")) dataExporter.exportDefinitions("definition"); + if (definedTables.contains("pnrvehicles")) + dataExporter.exportPnrVehicleData("pnrvehicles"); + if (definedTables.contains("cbdvehicles")) + dataExporter.exportCbdVehicleData("cbdvehicles"); + } + + private void startMatrixServer(HashMap properties) { + String serverAddress = (String) properties.get("RunModel.MatrixServerAddress"); + int serverPort = new Integer((String) properties.get("RunModel.MatrixServerPort")); + LOGGER.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try{ + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) { + LOGGER.error("could not connect to matrix server"); + LOGGER.info("Running Data Exporter with internal matrix class"); + // throw new RuntimeException(e); + + } + + } + + /** + * Startup a connection to the matrix manager. + * + * @param serverAddress + * @param serverPort + * @param mt + * @return + */ + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + try + { + // create the concrete data server object + matrixServer.start32BitMatrixIoServer(mt); + } catch (RuntimeException e) + { + matrixServer.stop32BitMatrixIoServer(); + LOGGER.error( + "RuntimeException caught making remote method call to start 32 bit mitrix in remote MatrixDataServer.", + e); + } + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + LOGGER.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + matrixServer.stop32BitMatrixIoServer(); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + LOGGER.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + matrixServer.stop32BitMatrixIoServer(); + throw new RuntimeException(); + } + + return matrixServer; + + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/DoubleFormatUtil.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/DoubleFormatUtil.java new file mode 100644 index 0000000..19f2c7d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/DoubleFormatUtil.java @@ -0,0 +1,484 @@ +package org.sandag.abm.reporting; +/* + * Licensed to the Apache Software Foundation (ASF) under one or more + * contributor license agreements. See the NOTICE file distributed with this + * work for additional information regarding copyright ownership. The ASF + * licenses this file to You under the Apache License, Version 2.0 (the + * "License"); you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT + * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the + * License for the specific language governing permissions and limitations under + * the License. + */ + +/* $Id$ */ + +/** + * This class implements fast, thread-safe format of a double value with a given + * number of decimal digits. + *

+ * The contract for the format methods is this one: if the source is greater + * than or equal to 1 (in absolute value), use the decimals parameter to define + * the number of decimal digits; else, use the precision parameter to define the + * number of decimal digits. + *

+ * A few examples (consider decimals being 4 and precision being 8): + *

    + *
  • 0.0 should be rendered as "0" + *
  • 0.1 should be rendered as "0.1" + *
  • 1234.1 should be rendered as "1234.1" + *
  • 1234.1234567 should be rendered as "1234.1235" (note the trailing 5! + * Rounding!) + *
  • 1234.00001 should be rendered as "1234" + *
  • 0.00001 should be rendered as "0.00001" (here you see the effect of the + * "precision" parameter) + *
  • 0.00000001 should be rendered as "0.00000001" + *
  • 0.000000001 should be rendered as "0" + *
+ * + * Originally authored by Julien Aymé. + */ +public final class DoubleFormatUtil +{ + + private DoubleFormatUtil() + { + } + + public static String formatDouble(double source, int decimals, int precision) + { + StringBuffer target = new StringBuffer(); + int scale = (Math.abs(source) >= 1.0) ? decimals : precision; + if (tooManyDigitsUsed(source, scale) || tooCloseToRound(source, scale)) + { + formatDoublePrecise(source, decimals, precision, target); + } else + { + formatDoubleFast(source, decimals, precision, target); + } + + return target.toString(); + } + + /** + * Rounds the given source value at the given precision and writes the + * rounded value into the given target + * + * @param source + * the source value to round + * @param decimals + * the decimals to round at (use if abs(source) ≥ 1.0) + * @param precision + * the precision to round at (use if abs(source) < 1.0) + * @param target + * the buffer to write to + */ + public static void formatDouble(double source, int decimals, int precision, StringBuffer target) + { + int scale = (Math.abs(source) >= 1.0) ? decimals : precision; + if (tooManyDigitsUsed(source, scale) || tooCloseToRound(source, scale)) + { + formatDoublePrecise(source, decimals, precision, target); + } else + { + formatDoubleFast(source, decimals, precision, target); + } + } + + /** + * Rounds the given source value at the given precision and writes the + * rounded value into the given target + *

+ * This method internally uses the String representation of the source + * value, in order to avoid any double precision computation error. + * + * @param source + * the source value to round + * @param decimals + * the decimals to round at (use if abs(source) ≥ 1.0) + * @param precision + * the precision to round at (use if abs(source) < 1.0) + * @param target + * the buffer to write to + */ + public static void formatDoublePrecise(double source, int decimals, int precision, + StringBuffer target) + { + if (isRoundedToZero(source, decimals, precision)) + { + // Will always be rounded to 0 + target.append('0'); + return; + } else if (Double.isNaN(source) || Double.isInfinite(source)) + { + // Cannot be formated + target.append(Double.toString(source)); + return; + } + + boolean negative = source < 0.0; + if (negative) + { + source = -source; + // Done once and for all + target.append('-'); + } + int scale = (source >= 1.0) ? decimals : precision; + + // The only way to format precisely the double is to use the String + // representation of the double, and then to do mathematical integer + // operation on it. + String s = Double.toString(source); + if (source >= 1e-3 && source < 1e7) + { + // Plain representation of double: "intPart.decimalPart" + int dot = s.indexOf('.'); + String decS = s.substring(dot + 1); + int decLength = decS.length(); + if (scale >= decLength) + { + if ("0".equals(decS)) + { + // source is a mathematical integer + target.append(s.substring(0, dot)); + } else + { + target.append(s); + // Remove trailing zeroes + for (int l = target.length() - 1; l >= 0 && target.charAt(l) == '0'; l--) + { + target.setLength(l); + } + } + return; + } else if (scale + 1 < decLength) + { + // ignore unnecessary digits + decLength = scale + 1; + decS = decS.substring(0, decLength); + } + long intP = Long.parseLong(s.substring(0, dot)); + long decP = Long.parseLong(decS); + format(target, scale, intP, decP); + } else + { + // Scientific representation of double: "x.xxxxxEyyy" + int dot = s.indexOf('.'); + assert dot >= 0; + int exp = s.indexOf('E'); + assert exp >= 0; + int exposant = Integer.parseInt(s.substring(exp + 1)); + String intS = s.substring(0, dot); + String decS = s.substring(dot + 1, exp); + int decLength = decS.length(); + if (exposant >= 0) + { + int digits = decLength - exposant; + if (digits <= 0) + { + // no decimal part, + // no rounding involved + target.append(intS); + target.append(decS); + for (int i = -digits; i > 0; i--) + { + target.append('0'); + } + } else if (digits <= scale) + { + // decimal part precision is lower than scale, + // no rounding involved + target.append(intS); + target.append(decS.substring(0, exposant)); + target.append('.'); + target.append(decS.substring(exposant)); + } else + { + // decimalDigits > scale, + // Rounding involved + long intP = Long.parseLong(intS) * tenPow(exposant) + + Long.parseLong(decS.substring(0, exposant)); + long decP = Long.parseLong(decS.substring(exposant, exposant + scale + 1)); + format(target, scale, intP, decP); + } + } else + { + // Only a decimal part is supplied + exposant = -exposant; + int digits = scale - exposant + 1; + if (digits < 0) + { + target.append('0'); + } else if (digits == 0) + { + long decP = Long.parseLong(intS); + format(target, scale, 0L, decP); + } else if (decLength < digits) + { + long decP = Long.parseLong(intS) * tenPow(decLength + 1) + Long.parseLong(decS) + * 10; + format(target, exposant + decLength, 0L, decP); + } else + { + long subDecP = Long.parseLong(decS.substring(0, digits)); + long decP = Long.parseLong(intS) * tenPow(digits) + subDecP; + format(target, scale, 0L, decP); + } + } + } + } + + /** + * Returns true if the given source value will be rounded to zero + * + * @param source + * the source value to round + * @param decimals + * the decimals to round at (use if abs(source) ≥ 1.0) + * @param precision + * the precision to round at (use if abs(source) < 1.0) + * @return true if the source value will be rounded to zero + */ + private static boolean isRoundedToZero(double source, int decimals, int precision) + { + // Use 4.999999999999999 instead of 5 since in some cases, 5.0 / 1eN > + // 5e-N (e.g. for N = 37, 42, 45, 66, ...) + return source == 0.0 + || Math.abs(source) < 4.999999999999999 / tenPowDouble(Math + .max(decimals, precision) + 1); + } + + /** + * Most used power of ten (to avoid the cost of Math.pow(10, n) + */ + private static final long[] POWERS_OF_TEN_LONG = new long[19]; + private static final double[] POWERS_OF_TEN_DOUBLE = new double[30]; + static + { + POWERS_OF_TEN_LONG[0] = 1L; + for (int i = 1; i < POWERS_OF_TEN_LONG.length; i++) + { + POWERS_OF_TEN_LONG[i] = POWERS_OF_TEN_LONG[i - 1] * 10L; + } + for (int i = 0; i < POWERS_OF_TEN_DOUBLE.length; i++) + { + POWERS_OF_TEN_DOUBLE[i] = Double.parseDouble("1e" + i); + } + } + + /** + * Returns ten to the power of n + * + * @param n + * the nth power of ten to get + * @return ten to the power of n + */ + public static long tenPow(int n) + { + assert n >= 0; + return n < POWERS_OF_TEN_LONG.length ? POWERS_OF_TEN_LONG[n] : (long) Math.pow(10, n); + } + + private static double tenPowDouble(int n) + { + assert n >= 0; + return n < POWERS_OF_TEN_DOUBLE.length ? POWERS_OF_TEN_DOUBLE[n] : Math.pow(10, n); + } + + /** + * Helper method to do the custom rounding used within formatDoublePrecise + * + * @param target + * the buffer to write to + * @param scale + * the expected rounding scale + * @param intP + * the source integer part + * @param decP + * the source decimal part, truncated to scale + 1 digit + */ + private static void format(StringBuffer target, int scale, long intP, long decP) + { + if (decP != 0L) + { + // decP is the decimal part of source, truncated to scale + 1 digit. + // Custom rounding: add 5 + decP += 5L; + decP /= 10L; + if (decP >= tenPowDouble(scale)) + { + intP++; + decP -= tenPow(scale); + } + if (decP != 0L) + { + // Remove trailing zeroes + while (decP % 10L == 0L) + { + decP = decP / 10L; + scale--; + } + } + } + target.append(intP); + if (decP != 0L) + { + target.append('.'); + // Use tenPow instead of tenPowDouble for scale below 18, + // since the casting of decP to double may cause some imprecisions: + // E.g. for decP = 9999999999999999L and scale = 17, + // decP < tenPow(16) while (double) decP == tenPowDouble(16) + while (scale > 0 + && (scale > 18 ? decP < tenPowDouble(--scale) : decP < tenPow(--scale))) + { + // Insert leading zeroes + target.append('0'); + } + target.append(decP); + } + } + + /** + * Rounds the given source value at the given precision and writes the + * rounded value into the given target + *

+ * This method internally uses double precision computation and rounding, so + * the result may not be accurate (see formatDouble method for conditions). + * + * @param source + * the source value to round + * @param decimals + * the decimals to round at (use if abs(source) ≥ 1.0) + * @param precision + * the precision to round at (use if abs(source) < 1.0) + * @param target + * the buffer to write to + */ + public static void formatDoubleFast(double source, int decimals, int precision, + StringBuffer target) + { + if (isRoundedToZero(source, decimals, precision)) + { + // Will always be rounded to 0 + target.append('0'); + return; + } else if (Double.isNaN(source) || Double.isInfinite(source)) + { + // Cannot be formated + target.append(Double.toString(source)); + return; + } + + boolean isPositive = source >= 0.0; + source = Math.abs(source); + int scale = (source >= 1.0) ? decimals : precision; + + long intPart = (long) Math.floor(source); + double tenScale = tenPowDouble(scale); + double fracUnroundedPart = (source - intPart) * tenScale; + long fracPart = Math.round(fracUnroundedPart); + if (fracPart >= tenScale) + { + intPart++; + fracPart = Math.round(fracPart - tenScale); + } + if (fracPart != 0L) + { + // Remove trailing zeroes + while (fracPart % 10L == 0L) + { + fracPart = fracPart / 10L; + scale--; + } + } + + if (intPart != 0L || fracPart != 0L) + { + // non-zero value + if (!isPositive) + { + // negative value, insert sign + target.append('-'); + } + // append integer part + target.append(intPart); + if (fracPart != 0L) + { + // append fractional part + target.append('.'); + // insert leading zeroes + while (scale > 0 && fracPart < tenPowDouble(--scale)) + { + target.append('0'); + } + target.append(fracPart); + } + } else + { + target.append('0'); + } + } + + /** + * Returns the exponent of the given value + * + * @param value + * the value to get the exponent from + * @return the value's exponent + */ + public static int getExponant(double value) + { + // See Double.doubleToRawLongBits javadoc or IEEE-754 spec + // to have this algorithm + long exp = Double.doubleToRawLongBits(value) & 0x7ff0000000000000L; + exp = exp >> 52; + return (int) (exp - 1023L); + } + + /** + * Returns true if the rounding is considered to use too many digits of the + * double for a fast rounding + * + * @param source + * the source to round + * @param scale + * the scale to round at + * @return true if the rounding will potentially use too many digits + */ + private static boolean tooManyDigitsUsed(double source, int scale) + { + // if scale >= 308, 10^308 ~= Infinity + double decExp = Math.log10(source); + return scale >= 308 || decExp + scale >= 14.5; + } + + /** + * Returns true if the given source is considered to be too close of a + * rounding value for the given scale. + * + * @param source + * the source to round + * @param scale + * the scale to round at + * @return true if the source will be potentially rounded at the scale + */ + private static boolean tooCloseToRound(double source, int scale) + { + source = Math.abs(source); + long intPart = (long) Math.floor(source); + double fracPart = (source - intPart) * tenPowDouble(scale); + double decExp = Math.log10(source); + double range = decExp + scale >= 12 ? .1 : .001; + double distanceToRound1 = Math.abs(fracPart - Math.floor(fracPart)); + double distanceToRound2 = Math.abs(fracPart - Math.floor(fracPart) - 0.5); + return distanceToRound1 <= range || distanceToRound2 <= range; + // .001 range: Totally arbitrary range, + // I never had a failure in 10e7 random tests with this value + // May be JVM dependent or architecture dependent + } +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/IExporter.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/IExporter.java new file mode 100644 index 0000000..ef96f80 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/IExporter.java @@ -0,0 +1,11 @@ +package org.sandag.abm.reporting; + +import java.io.IOException; + +public interface IExporter +{ + static final String[] TOD_TOKENS = {"EA", "AM", "MD", "PM", "EV"}; + static final String TOD_TOKEN = "${TOD_TOKEN}"; + + void export() throws IOException; +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/IMatrixDao.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/IMatrixDao.java new file mode 100644 index 0000000..12567c9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/IMatrixDao.java @@ -0,0 +1,8 @@ +package org.sandag.abm.reporting; + +import com.pb.common.matrix.Matrix; + +public interface IMatrixDao +{ + Matrix getMatrix(String matrixName, String coreName); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/OMXMatrixDao.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/OMXMatrixDao.java new file mode 100644 index 0000000..2ba5261 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/OMXMatrixDao.java @@ -0,0 +1,36 @@ +package org.sandag.abm.reporting; + +import java.io.File; +import java.util.HashMap; +import java.util.Properties; + +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; +import com.pb.common.matrix.MatrixType; + +public class OMXMatrixDao + implements IMatrixDao +{ + private final String outputFolderToken = "skims.path"; + private final String matrixLocation; + + public OMXMatrixDao(Properties properties) + { + matrixLocation = properties.getProperty(outputFolderToken); + } + + public OMXMatrixDao(HashMap properties) + { + matrixLocation = (String)properties.get(outputFolderToken); + } + + + public Matrix getMatrix(String matrixName, String coreName) + { + String matrixPath = matrixLocation + File.separator + matrixName; + + MatrixReader mr = MatrixReader.createReader(MatrixType.OMX, new File(matrixPath)); + + return mr.readMatrix(coreName); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/SkimBuilder.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/SkimBuilder.java new file mode 100644 index 0000000..ff3e8df --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/SkimBuilder.java @@ -0,0 +1,721 @@ +package org.sandag.abm.reporting; + +import java.util.HashMap; +import java.util.Map; +import java.util.Properties; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.accessibilities.BestTransitPathCalculator; +import org.sandag.abm.accessibilities.DriveTransitWalkSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitDriveSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitWalkSkimsCalculator; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +/** + * The {@code SkimBuilder} ... + * + * @author crf Started 10/17/12 9:12 AM + */ +public class SkimBuilder +{ + private static final Logger logger = Logger.getLogger(SkimBuilder.class); + + private static final int WALK_TIME_INDEX = 0; + private static final int BIKE_TIME_INDEX = 0; + + private static final int DA_NT_TIME_INDEX = 0; + private static final int DA_NT_FF_TIME_INDEX = 1; + private static final int DA_NT_DIST_INDEX = 2; + private static final int DA_NT_TOLL_INDEX = 3; + private static final int DA_NT_TOLLDIST_INDEX = 4; + private static final int DA_NT_STD_INDEX = 5; + private static final int DA_TR_TIME_INDEX = 6; + private static final int DA_TR_FF_TIME_INDEX = 7; + private static final int DA_TR_DIST_INDEX = 8; + private static final int DA_TR_TOLL_INDEX = 9; + private static final int DA_TR_TOLLDIST_INDEX = 10; + private static final int DA_TR_STD_INDEX = 11; + private static final int SR2_TIME_INDEX = 12; + private static final int SR2_FF_TIME_INDEX = 13; + private static final int SR2_DIST_INDEX = 14; + private static final int SR2_HOVDIST_INDEX = 15; + private static final int SR2_TOLL_INDEX = 16; + private static final int SR2_TOLLDIST_INDEX = 17; + private static final int SR2_STD_INDEX = 18; + private static final int SR3_TIME_INDEX = 19; + private static final int SR3_FF_TIME_INDEX = 20; + private static final int SR3_DIST_INDEX = 21; + private static final int SR3_HOVDIST_INDEX = 22; + private static final int SR3_TOLL_INDEX = 23; + private static final int SR3_TOLLDIST_INDEX = 24; + private static final int SR3_STD_INDEX = 25; + + + + private static final int TRANSIT_SET_ACCESS_TIME_INDEX = 0; + private static final int TRANSIT_SET_EGRESS_TIME_INDEX = 1; + private static final int TRANSIT_SET_AUX_WALK_TIME_INDEX = 2; + private static final int TRANSIT_SET_LOCAL_BUS_TIME_INDEX = 3; + private static final int TRANSIT_SET_EXPRESS_BUS_TIME_INDEX = 4; + private static final int TRANSIT_SET_BRT_TIME_INDEX = 5; + private static final int TRANSIT_SET_LRT_TIME_INDEX = 6; + private static final int TRANSIT_SET_CR_TIME_INDEX = 7; + private static final int TRANSIT_SET_FIRST_WAIT_TIME_INDEX = 8; + private static final int TRANSIT_SET_TRANSFER_WAIT_TIME_INDEX = 9; + private static final int TRANSIT_SET_FARE_INDEX = 10; + private static final int TRANSIT_SET_MAIN_MODE_INDEX = 11; + private static final int TRANSIT_SET_XFERS_INDEX = 12; + private static final int TRANSIT_SET_DIST_INDEX = 13; + + private static final double FEET_IN_MILE = 5280.0; + + private final TapDataManager tapManager; + private final TazDataManager tazManager; + private final MgraDataManager mgraManager; + private final AutoTazSkimsCalculator tazDistanceCalculator; + private final AutoAndNonMotorizedSkimsCalculator autoNonMotSkims; + private final WalkTransitWalkSkimsCalculator wtw; + private final WalkTransitDriveSkimsCalculator wtd; + private final DriveTransitWalkSkimsCalculator dtw; + + private final String FUEL_COST_PROPERTY = "aoc.fuel"; + private final String MAINTENANCE_COST_PROPERTY = "aoc.maintenance"; + private float autoOperatingCost; + + + public SkimBuilder(Properties properties) + { + + HashMap rbMap = new HashMap( + (Map) (Map) properties); + tapManager = TapDataManager.getInstance(rbMap); + tazManager = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + autoNonMotSkims = new AutoAndNonMotorizedSkimsCalculator(rbMap); + autoNonMotSkims.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + BestTransitPathCalculator bestPathUEC = new BestTransitPathCalculator(rbMap); + wtw = new WalkTransitWalkSkimsCalculator(rbMap); + wtw.setup(rbMap, logger, bestPathUEC); + wtd = new WalkTransitDriveSkimsCalculator(rbMap); + wtd.setup(rbMap, logger, bestPathUEC); + dtw = new DriveTransitWalkSkimsCalculator(rbMap); + dtw.setup(rbMap, logger, bestPathUEC); + + float fuelCost = new Float(properties.getProperty(FUEL_COST_PROPERTY)); + float mainCost = new Float(properties.getProperty(MAINTENANCE_COST_PROPERTY)); + autoOperatingCost = (fuelCost + mainCost) * 0.01f; + + } + + // todo: hard coding these next two lookups because it is convenient, but + // probably should move to a lookup file + private final String[] modeNameLookup = { + "UNKNOWN", // ids start at one + "DRIVEALONE", "SHARED2", "SHARED3", "WALK", "BIKE", "WALK_SET", "PNR_SET", + "KNR_TRN", "TNC_TRN", "TAXI", "TNC_SINGLE", "TNC_SHARED","SCHBUS"}; + + private final TripModeChoice[] modeChoiceLookup = {TripModeChoice.UNKNOWN, + TripModeChoice.DRIVE_ALONE, TripModeChoice.SR2,TripModeChoice.SR3, + TripModeChoice.WALK, TripModeChoice.BIKE, TripModeChoice.WALK_SET, + TripModeChoice.PNR_SET, TripModeChoice.KNR_SET, TripModeChoice.KNR_SET, + TripModeChoice.SR2, + TripModeChoice.SR2, TripModeChoice.SR2, TripModeChoice.SR2 }; + + private int getTod(int tripTimePeriod) + { + return ModelStructure.getSkimPeriodIndex(tripTimePeriod); + } + + private int getStartTime(int tripTimePeriod) + { + return (tripTimePeriod - 1) * 30 + 270; // starts at 4:30 and goes half + // hour intervals after that + } + + public TripAttributes getTripAttributes(int origin, int destination, int tripModeIndex, + int boardTap, int alightTap, int tripTimePeriod, boolean inbound, float valueOfTime, int set, boolean isCB, int transponderOwnership) + { + int tod = getTod(tripTimePeriod); + TripModeChoice tripMode = modeChoiceLookup[tripModeIndex < 0 ? 0 : tripModeIndex]; + + TripAttributes attributes = getTripAttributes(tripMode, origin, destination, boardTap, + alightTap, tod, inbound, valueOfTime, set,isCB,transponderOwnership); + attributes.setTripModeName(modeNameLookup[tripModeIndex < 0 ? 0 : tripModeIndex]); + attributes.setTripStartTime(getStartTime(tripTimePeriod)); + return attributes; + } + + private TripAttributes getTripAttributesUnknown() + { + return new TripAttributes(0,0,0,0,0,0,0,0,0,0,0,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + } + + private final float DEFAULT_BIKE_SPEED = 12; + private final float DEFAULT_WALK_SPEED = 3; + private int omeMgra=7123; + + private TripAttributes getTripAttributes(TripModeChoice modeChoice, int origin, + int destination, int boardTap, int alightTap, int tod, boolean inbound, float vot, int set,boolean isCB, int transponderOwnership) + { + int timeIndex = -1; + int distIndex = -1; + int costIndex = -1; + int stdIndex = -1; + int otaz=-1; + int dtaz=-1; + + double [] autoSkims; + + switch (modeChoice) + { + case UNKNOWN: + return getTripAttributesUnknown(); + case DRIVE_ALONE: + { + if(transponderOwnership>0) { + timeIndex = DA_TR_TIME_INDEX; + distIndex = DA_TR_DIST_INDEX; + costIndex = DA_TR_TOLL_INDEX; + stdIndex = DA_TR_STD_INDEX; + }else { + timeIndex = DA_NT_TIME_INDEX; + distIndex = DA_NT_DIST_INDEX; + costIndex = DA_NT_TOLL_INDEX; + stdIndex = DA_NT_STD_INDEX; + + } + if(isCB && (origin==omeMgra||destination==omeMgra)) { + int[] tazPair=setTazOD(origin, destination); + otaz=tazPair[0]; + dtaz=tazPair[1]; + autoSkims = autoNonMotSkims.getAutoSkimsByTAZ(otaz, dtaz, tod, vot,false, + logger); + }else { + autoSkims = autoNonMotSkims.getAutoSkims(origin, destination, tod, vot,false, + logger); + } + return new TripAttributes(autoSkims[timeIndex], autoSkims[distIndex], autoSkims[distIndex]*autoOperatingCost, autoSkims[stdIndex], autoSkims[costIndex]); + } + + case SR2: // wu added + { + timeIndex = SR2_TIME_INDEX; + distIndex = SR2_DIST_INDEX; + costIndex = SR2_TOLL_INDEX; + stdIndex = SR2_STD_INDEX; + if(isCB && (origin==omeMgra||destination==omeMgra)) { + int[] tazPair=setTazOD(origin, destination); + otaz=tazPair[0]; + dtaz=tazPair[1]; + autoSkims = autoNonMotSkims.getAutoSkimsByTAZ(otaz, dtaz, tod, vot,false, + logger); + }else { + autoSkims = autoNonMotSkims.getAutoSkims(origin, destination, tod, vot,false, + logger); + } + + return new TripAttributes(autoSkims[timeIndex], autoSkims[distIndex], autoSkims[distIndex]*autoOperatingCost, autoSkims[stdIndex], autoSkims[costIndex]); + } + case SR3: + { + timeIndex = SR3_TIME_INDEX; + distIndex = SR3_DIST_INDEX; + costIndex = SR3_TOLL_INDEX; + stdIndex = SR3_STD_INDEX; + if(isCB && (origin==omeMgra||destination==omeMgra)) { + int[] tazPair=setTazOD(origin, destination); + otaz=tazPair[0]; + dtaz=tazPair[1]; + autoSkims = autoNonMotSkims.getAutoSkimsByTAZ(otaz, dtaz, tod, vot,false, + logger); + }else { + autoSkims = autoNonMotSkims.getAutoSkims(origin, destination, tod, vot,false, + logger); + } + return new TripAttributes(autoSkims[timeIndex], autoSkims[distIndex], autoSkims[distIndex]*autoOperatingCost, autoSkims[stdIndex], autoSkims[costIndex]); + } + case WALK: + { + // first, look in mgra manager, otherwise default to auto skims + double distance = mgraManager.getMgraToMgraWalkDistFrom(origin, destination) / FEET_IN_MILE; + double time =0; + if (distance > 0) + { + time = mgraManager.getMgraToMgraWalkTime(origin, destination); + }else{ + distance = autoNonMotSkims.getAutoSkims(origin, destination, tod, vot,false, logger)[DA_NT_DIST_INDEX]; + time = distance * 60 / DEFAULT_WALK_SPEED; + } + return new TripAttributes(0, 0, 0, 0, 0, 0, 0, 0, time, 0, distance, -1, -1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0); + } + case BIKE: + { + double time = mgraManager.getMgraToMgraBikeTime(origin, destination); + double distance = 0; + if (time > 0) + { + distance = time * DEFAULT_BIKE_SPEED / 60; + + }else{ + distance = autoNonMotSkims.getAutoSkims(origin, destination, tod, vot,false, + logger)[DA_NT_DIST_INDEX]; + time = distance * 60 / DEFAULT_BIKE_SPEED; + } + return new TripAttributes(0, 0, 0, 0, 0, 0, 0, 0, 0, time, distance, -1, -1, 0,0,0,0,0,0,0,0,0,0,0,0,0,0); + } + case WALK_SET : + case PNR_SET : + case KNR_SET : { + boolean isDrive = modeChoice.isDrive; + double walkTime = 0.0; + double driveTime = 0.0; + + double[] skims; + int boardTaz = -1; + int alightTaz = -1; + double boardAccessTime = 0.0; + double alightEgressTime = 0.0; + double accessDistance = 0.0; + double egressDistance = 0.0; + int originTaz = mgraManager.getTaz(origin); + int destTaz = mgraManager.getTaz(destination); + if (isDrive) { + if (!inbound) { //outbound: drive to transit stop at origin, then transit to destination + boardAccessTime = tazManager.getTimeToTapFromTaz(originTaz,boardTap,( modeChoice==TripModeChoice.PNR_SET ? Modes.AccessMode.PARK_N_RIDE : Modes.AccessMode.KISS_N_RIDE)); + accessDistance = tazManager.getDistanceToTapFromTaz(originTaz,boardTap,( modeChoice==TripModeChoice.PNR_SET ? Modes.AccessMode.PARK_N_RIDE : Modes.AccessMode.KISS_N_RIDE)); + alightEgressTime = mgraManager.getWalkTimeFromMgraToTap(destination,alightTap); + egressDistance = mgraManager.getWalkDistanceFromMgraToTap(destination,alightTap); + + if (boardAccessTime ==-1) { + logger.info("Error: TAP not accessible from origin TAZ by "+ (modeChoice==TripModeChoice.PNR_SET ? "PNR" : "KNR" )+" access"); + logger.info("mc: " + modeChoice); + logger.info("origin MAZ: " + origin); + logger.info("origin TAZ" + originTaz); + logger.info("dest MAZ: " + destination); + logger.info("board tap: " + boardTap); + logger.info("alight tap: " + alightTap); + logger.info("tod: " + tod); + logger.info("inbound: " + inbound); + logger.info("set: " + set); + } + + if (alightEgressTime == -1){ + logger.info("Error: TAP not accessible from destination MAZ by walk access"); + logger.info("mc: " + modeChoice); + logger.info("origin MAZ: " + origin); + logger.info("origin TAZ" + originTaz); + logger.info("dest MAZ: " + destination); + logger.info("board tap: " + boardTap); + logger.info("alight tap: " + alightTap); + logger.info("tod: " + tod); + logger.info("inbound: " + inbound); + logger.info("set: " + set); + + } + skims = dtw.getDriveTransitWalkSkims(set,boardAccessTime,alightEgressTime,boardTap,alightTap,tod,false); + walkTime = alightEgressTime; + driveTime= boardAccessTime; + + } else { //inbound: transit from origin to destination, then drive + boardAccessTime = mgraManager.getWalkTimeFromMgraToTap(origin,boardTap); + accessDistance = mgraManager.getWalkDistanceFromMgraToTap(origin,boardTap); + alightEgressTime = tazManager.getTimeToTapFromTaz(destTaz,alightTap,( modeChoice==TripModeChoice.PNR_SET ? Modes.AccessMode.PARK_N_RIDE : Modes.AccessMode.KISS_N_RIDE)); + egressDistance = tazManager.getDistanceToTapFromTaz(destTaz,alightTap,( modeChoice==TripModeChoice.PNR_SET ? Modes.AccessMode.PARK_N_RIDE : Modes.AccessMode.KISS_N_RIDE)); + if (boardAccessTime ==-1) { + logger.info("Error: TAP not accessible from origin MAZ by walk access"); + logger.info("mc: " + modeChoice); + logger.info("origin MAZ: " + origin); + logger.info("origin TAZ" + originTaz); + logger.info("dest MAZ: " + destination); + logger.info("board tap: " + boardTap); + logger.info("alight tap: " + alightTap); + logger.info("tod: " + tod); + logger.info("inbound: " + inbound); + logger.info("set: " + set); + } + + if (alightEgressTime == -1){ + logger.info("Error: TAP not accessible from destination TAZ by "+ (modeChoice==TripModeChoice.PNR_SET ? "PNR" : "KNR" )+" access"); + logger.info("mc: " + modeChoice); + logger.info("origin MAZ: " + origin); + logger.info("origin TAZ" + originTaz); + logger.info("dest MAZ: " + destination); + logger.info("board tap: " + boardTap); + logger.info("alight tap: " + alightTap); + logger.info("tod: " + tod); + logger.info("inbound: " + inbound); + logger.info("set: " + set); + + } + skims = wtd.getWalkTransitDriveSkims(set,boardAccessTime,alightEgressTime,boardTap,alightTap,tod,false); + walkTime = boardAccessTime ; + driveTime= alightEgressTime; + } + } else { + int bt = mgraManager.getTapPosition(origin,boardTap); + int at = mgraManager.getTapPosition(destination,alightTap); + if (bt < 0 || at < 0) { + logger.info("bad tap position: " + bt + " " + at); + logger.info("mc: " + modeChoice); + logger.info("origin: " + origin); + logger.info("dest: " + destination); + logger.info("board tap: " + boardTap); + logger.info("alight tap: " + alightTap); + logger.info("tod: " + tod); + logger.info("inbound: " + inbound); + logger.info("set: " + set); + logger.info("board tap position: " + bt); + logger.info("alight tap position: " + at); + } else { + boardAccessTime = mgraManager.getMgraToTapWalkTime(origin,bt); + accessDistance = mgraManager.getWalkDistanceFromMgraToTap(origin,boardTap); + alightEgressTime = mgraManager.getMgraToTapWalkTime(destination,at); + egressDistance = mgraManager.getWalkDistanceFromMgraToTap(destination,alightTap); + } + walkTime = boardAccessTime + alightEgressTime; + skims = wtw.getWalkTransitWalkSkims(set,boardAccessTime,alightEgressTime,boardTap,alightTap,tod,false); + } + + double transitInVehicleTime = 0.0; + + transitInVehicleTime += skims[TRANSIT_SET_CR_TIME_INDEX]; + transitInVehicleTime += skims[TRANSIT_SET_LRT_TIME_INDEX]; + transitInVehicleTime += skims[TRANSIT_SET_BRT_TIME_INDEX]; + transitInVehicleTime += skims[TRANSIT_SET_EXPRESS_BUS_TIME_INDEX]; + transitInVehicleTime += skims[TRANSIT_SET_LOCAL_BUS_TIME_INDEX]; + + double crTime = skims[TRANSIT_SET_CR_TIME_INDEX]; + double lrtTime = skims[TRANSIT_SET_LRT_TIME_INDEX]; + double brtTime = skims[TRANSIT_SET_BRT_TIME_INDEX]; + double expTime = skims[TRANSIT_SET_EXPRESS_BUS_TIME_INDEX]; + double locTime = skims[TRANSIT_SET_LOCAL_BUS_TIME_INDEX]; + + //wsu 9/17/18, walkTime already set + //walkTime += skims[TRANSIT_SET_ACCESS_TIME_INDEX]; + //walkTime += skims[TRANSIT_SET_EGRESS_TIME_INDEX ]; + walkTime += skims[TRANSIT_SET_AUX_WALK_TIME_INDEX]; + + double auxiliaryTime = skims[TRANSIT_SET_AUX_WALK_TIME_INDEX]; + + double waitTime = 0.0; + waitTime += skims[TRANSIT_SET_FIRST_WAIT_TIME_INDEX]; + waitTime += skims[TRANSIT_SET_TRANSFER_WAIT_TIME_INDEX]; + + double transfers = skims[TRANSIT_SET_XFERS_INDEX]; + + double transitFare = 0.0; + transitFare += skims[TRANSIT_SET_FARE_INDEX]; + + double transitDist = skims[TRANSIT_SET_DIST_INDEX]; + /* + int modeIndex = 0; + for(modeIndex = TRANSIT_SET_LOCAL_BUS_TIME_INDEX; modeIndex <= TRANSIT_SET_CR_TIME_INDEX; modeIndex++){ + if(skims[modeIndex] > 0) + break; + } + */ + double dist = autoNonMotSkims.getAutoSkims(origin,destination,tod,vot,false,logger)[DA_NT_DIST_INDEX]; //todo: is this correct enough? + return new TripAttributes(driveTime, driveTime/60*35*autoOperatingCost, 0, 0, transitInVehicleTime, + waitTime, walkTime, transitFare, 0, 0, dist, boardTaz, alightTaz, vot, set, + accessDistance,egressDistance,auxiliaryTime,boardAccessTime,alightEgressTime,transfers,locTime,expTime,brtTime,lrtTime,crTime,transitDist); + } + default: + throw new IllegalStateException("Should not be here: " + modeChoice); + } + } + + private int[] setTazOD(int omgra, int dmgra) { + int [] result=new int[2]; + //int omeMgra=7123; + result [0]=mgraManager.getTaz(omgra); + result [1]=mgraManager.getTaz(dmgra); + if (omgra==omeMgra) result[0]=3; + if (dmgra==omeMgra) result[1]=3; + return result; + } + + public static enum TripModeChoice + { + UNKNOWN(false), + DRIVE_ALONE(true), + SR2(true), + SR3(true), + WALK(false), + BIKE(false), + WALK_SET(false), + PNR_SET(true), + KNR_SET(true); + + private final boolean isDrive; + + private TripModeChoice(boolean drive) + { + isDrive = drive; + } + + } + + public static class TripAttributes + { + private final float autoInVehicleTime; + private final float autoOperatingCost; + private final float autoStandardDeviationTime; + private final float autoTollCost; + private final float transitInVehicleTime; + private final float transitWaitTime; + private final float transitWalkTime; + private final float transitFare; + private final float walkModeTime; + private final float bikeModeTime; + private final float tripDistance; + private final int tripBoardTaz; + private final int tripAlightTaz; + private final int set; + private final float valueOfTime; + private final float transitAccessDistance; + private final float transitEgressDistance; + private final float transitAuxiliaryTime; + private final float transitAccessTime; + private final float transitEgressTime; + private final float transitTransfers; + private final float locTime; + private final float expTime; + private final float brtTime; + private final float lrtTime; + private final float crTime; + private final float transitDistance; + + private String tripModeName; + + public int getTripStartTime() + { + return tripStartTime; + } + + public void setTripStartTime(int tripStartTime) + { + this.tripStartTime = tripStartTime; + } + + private int tripStartTime; + + public TripAttributes(double autoInVehicleTime, double autoOperatingCost, double autoStandardDeviationTime, double autoTollCost, double transitInVehicleTime, + double transitWaitTime, double transitWalkTime, double transitFare, double walkModeTime, double bikeModeTime, double tripDistance, + int tripBoardTaz, int tripAlightTaz, float valueOfTime, int set, double accessDistance, + double egressDistance, double auxiliaryTime, double accessTime,double egressTime, double transfers, double locTime, double expTime, double brtTime, double lrtTime, double crTime, double trnDist) + { + this.autoInVehicleTime = (float) autoInVehicleTime; + this.autoOperatingCost = (float) autoOperatingCost; + this.autoStandardDeviationTime = (float) autoStandardDeviationTime; + this.autoTollCost = (float) autoTollCost; + this.transitInVehicleTime = (float) transitInVehicleTime; + this.transitWaitTime = (float) transitWaitTime; + this.transitWalkTime = (float) transitWalkTime; + this.transitFare = (float) transitFare; + this.walkModeTime = (float) walkModeTime; + this.bikeModeTime = (float) bikeModeTime; + this.tripDistance = (float) tripDistance; + this.tripBoardTaz = tripBoardTaz; + this.tripAlightTaz = tripAlightTaz; + this.set = set; + this.valueOfTime = valueOfTime; + this.transitAccessDistance = (float) accessDistance; + this.transitEgressDistance = (float) egressDistance; + this.transitAuxiliaryTime = (float) auxiliaryTime; + this.transitAccessTime = (float) accessTime; + this.transitEgressTime = (float) egressTime; + this.transitTransfers = (float) transfers; + this.locTime = (float) locTime; + this.expTime = (float) expTime; + this.brtTime = (float) brtTime; + this.lrtTime = (float) lrtTime; + this.crTime = (float) crTime; + this.transitDistance = (float) trnDist; + + } + + + /** + * A method to set create trip attributes for a non-toll auto choice. + * + * @param autoInVehicleTime + * @param tripDistance + * @param autoOperatingCost + */ + public TripAttributes(double autoInVehicleTime, double tripDistance, double autoOperatingCost, double stdDevTime) + { + this(autoInVehicleTime, autoOperatingCost, stdDevTime, 0,0,0,0,0,0,0,tripDistance,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + } + + /** + * A method to create trip attributes for a toll auto choice. + * + * @param autoInVehicleTime + * @param tripDistance + * @param autoOperatingCost + * @param tollCost + */ + public TripAttributes(double autoInVehicleTime, double tripDistance, double autoOperatingCost, double stdDevTime, double tollCost) + { + this(autoInVehicleTime, autoOperatingCost, stdDevTime, tollCost,0,0,0,0,0,0,tripDistance,-1,-1,0,0,0,0,0,0,0,0,0,0,0,0,0,0); + } + + + + public void setTripModeName(String tripModeName) + { + this.tripModeName = tripModeName; + } + + public float getAutoInVehicleTime() { + return autoInVehicleTime; + } + + public float getAutoOperatingCost() { + return autoOperatingCost; + } + + public float getAutoStandardDeviationTime() { + return autoStandardDeviationTime; + } + + public float getAutoTollCost() { + return autoTollCost; + } + + public float getTransitInVehicleTime() { + return transitInVehicleTime; + } + + public float getTransitWaitTime() { + return transitWaitTime; + } + + public float getTransitFare() { + return transitFare; + } + + public float getTransitWalkTime() { + return transitWalkTime; + } + + public float getWalkModeTime() { + return walkModeTime; + } + + public float getBikeModeTime() { + return bikeModeTime; + } + + public float getTripDistance() { + return tripDistance; + } + + public String getTripModeName() + { + return tripModeName; + } + + public int getTripBoardTaz() + { + return tripBoardTaz; + } + + public int getTripAlightTaz() + { + return tripAlightTaz; + } + + public float getValueOfTime() { + return valueOfTime; + } + + public int getSet() { + return set; + } + + public float getTransitAccessDistance() { + return transitAccessDistance; + } + + public float getTransitEgressDistance() { + return transitEgressDistance; + } + + public float getTransitAuxiliaryTime() { + return transitAuxiliaryTime; + } + + public float getTransitAccessTime() { + return transitAccessTime; + } + + public float getTransitEgressTime() { + return transitEgressTime; + } + + public float getTransitTransfers() { + return transitTransfers; + } + + public float getLocTime() { + return locTime; + } + + public float getExpTime() { + return expTime; + } + + public float getBrtTime() { + return brtTime; + } + + public float getLrtTime() { + return lrtTime; + } + + public float getCrTime() { + return crTime; + } + + public float getTransitDistance(){ + return transitDistance; + } + } + + public float getLotWalkTime(int parkingLotMaz, int destinationMaz) { + + // first, look in mgra manager, otherwise default to auto skims + double distance = mgraManager.getMgraToMgraWalkDistFrom(parkingLotMaz, destinationMaz) / FEET_IN_MILE; + if (distance <= 0) { + distance = autoNonMotSkims.getAutoSkims(parkingLotMaz, destinationMaz, SandagModelStructure.EA_SKIM_PERIOD_INDEX +1, (float)15.0,false, logger)[DA_NT_DIST_INDEX]; + } + + return (float) (distance * 60 / DEFAULT_WALK_SPEED); + } + + + public float getLotWalkDistance(int parkingLotMaz, int destinationMaz) { + + // first, look in mgra manager, otherwise default to auto skims + double distance = mgraManager.getMgraToMgraWalkDistFrom(parkingLotMaz, destinationMaz) / FEET_IN_MILE; + if (distance <= 0) { + distance = autoNonMotSkims.getAutoSkims(parkingLotMaz, destinationMaz, SandagModelStructure.EA_SKIM_PERIOD_INDEX +1, (float)15.0,false, logger)[DA_NT_DIST_INDEX]; + } + + return (float) distance; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/TranscadMatrixDao.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/TranscadMatrixDao.java new file mode 100644 index 0000000..f5aafc2 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/TranscadMatrixDao.java @@ -0,0 +1,28 @@ +package org.sandag.abm.reporting; + +import java.io.File; +import java.util.Properties; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; +import com.pb.common.matrix.MatrixType; + +public class TranscadMatrixDao + implements IMatrixDao +{ + private final String outputFolderToken = "skims.path"; + private final String matrixLocation; + + public TranscadMatrixDao(Properties properties) + { + matrixLocation = properties.getProperty(outputFolderToken); + } + + public Matrix getMatrix(String matrixName, String coreName) + { + String matrixPath = matrixLocation + File.separator + matrixName + ".mtx"; + + MatrixReader mr = MatrixReader.createReader(MatrixType.TRANSCAD, new File(matrixPath)); + + return mr.readMatrix(coreName); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/TransitTimeReporter.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/TransitTimeReporter.java new file mode 100644 index 0000000..bb5628f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/TransitTimeReporter.java @@ -0,0 +1,449 @@ +package org.sandag.abm.reporting; + +import java.io.BufferedWriter; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.accessibilities.BestTransitPathCalculator; +import org.sandag.abm.accessibilities.DriveTransitWalkSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitDriveSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitWalkSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.Modes; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.util.ResourceUtil; + +public class TransitTimeReporter { + private static final Logger logger = Logger.getLogger(TransitTimeReporter.class); + private BestTransitPathCalculator bestPathCalculator; + protected WalkTransitWalkSkimsCalculator wtw; + protected WalkTransitDriveSkimsCalculator wtd; + protected DriveTransitWalkSkimsCalculator dtw; + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + private MatrixDataServerRmi ms; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + AutoTazSkimsCalculator tazDistanceCalculator; + + //skim locations in WalkTransitWalkSkims UEC + private static final int WLK_WALKACCESSTIME = 0; + private static final int WLK_WALKEGRESSTIME = 1; + private static final int WLK_AUXWALKTIME = 2; + private static final int WLK_LOCALBUSIVT = 3; + private static final int WLK_EXPRESSBUSIVT = 4; + private static final int WLK_BRTIVT = 5; + private static final int WLK_LRTIVT = 6; + private static final int WLK_CRIVT = 7; + private static final int WLK_T1IVT = 8; + private static final int WLK_FIRSTWAITTIME = 9; + private static final int WLK_TRWAITTIME = 10; + private static final int WLK_FARE = 11; + private static final int WLK_TOTALIVT = 12; + private static final int WLK_XFERS = 13; + private static final int WLK_DIST = 14; + + //skim locations in DriveTransitWalkSkims UEC + private static final int DRV_DRIVEACCESSTIME = 0; + private static final int DRV_WALKEGRESSTIME = 1; + private static final int DRV_AUXWALKTIME = 2; + private static final int DRV_LOCALBUSIVT = 3; + private static final int DRV_EXPRESSBUSIVT = 4; + private static final int DRV_BRTIVT = 5; + private static final int DRV_LRTIVT = 6; + private static final int DRV_CRIVT = 7; + private static final int DRV_T1IVT = 8; + private static final int DRV_FIRSTWAITTIME = 9; + private static final int DRV_TRWAITTIME = 10; + private static final int DRV_FARE = 11; + private static final int DRV_TOTALIVT = 12; + private static final int DRV_XFERS = 13; + private static final int DRV_DIST = 14; + + String period; //should be "AM" or "MD" + float threshold; //tested at 30 minutes + boolean inbound = false; + + private PrintWriter walkAccessWriter; + private PrintWriter driveAccessWriter; + private String outWalkFile; + private String outDriveFile; + private boolean createDriveFile=false; + + public TransitTimeReporter(HashMap propertyMap, float threshold, String period,String outWalkFileName,String outDriveFileName){ + + startMatrixServer(propertyMap); + + this.threshold = threshold; + this.period = period; + this.outWalkFile = outWalkFileName; + this.outDriveFile= outDriveFileName; + if(outDriveFile!=null) { + this.outDriveFile = outDriveFileName; + createDriveFile=true; + } + + initialize(propertyMap); + } + + /** + * Initialize best path builders. + * + * @param propertyMap A property map with relevant properties. + */ + public void initialize(HashMap propertyMap){ + + String path=System.getProperty("user.dir"); + outWalkFile=path+"\\output\\"+outWalkFile; + if(createDriveFile) { + outDriveFile=path+"\\output\\"+outDriveFile; + } + + logger.info("Initializing Transit Time Reporter"); + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + bestPathCalculator = new BestTransitPathCalculator(propertyMap); + + tazDistanceCalculator = new AutoTazSkimsCalculator(propertyMap); + tazDistanceCalculator.computeTazDistanceArrays(); + + wtw = new WalkTransitWalkSkimsCalculator(propertyMap); + wtw.setup(propertyMap, logger, bestPathCalculator); + wtd = new WalkTransitDriveSkimsCalculator(propertyMap); + wtd.setup(propertyMap, logger, bestPathCalculator); + dtw = new DriveTransitWalkSkimsCalculator(propertyMap); + dtw.setup(propertyMap, logger, bestPathCalculator); + + walkAccessWriter = createOutputFile(outWalkFile); + if(createDriveFile) { + driveAccessWriter = createOutputFile(outDriveFile); + } + } + + /** + * Create the output file. + */ + private PrintWriter createOutputFile(String fileName){ + + logger.info("Creating file " + fileName); + PrintWriter writer; + try + { + writer = new PrintWriter(new BufferedWriter(new FileWriter(fileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + fileName + " for writing\n"); + throw new RuntimeException(); + } + + return writer; + + } + + private ArrayList getWalkTransitTimeComponents(HashMap propertyMap){ + String timeElements = (String) propertyMap.get("transitShed.walkTransitTimeComponents"); + String delims = "[,]"; + String[] elements = timeElements.split(delims); + ArrayList components=new ArrayList(); + for (int i=0; i getDriveTransitTimeComponents(HashMap propertyMap){ + String timeElements = (String) propertyMap.get("transitShed.driveTransitTimeComponents"); + String delims = "[,]"; + String[] elements = timeElements.split(delims); + ArrayList components=new ArrayList(); + for (int i=0; i pMap){ + + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + double boardAccessTime; + double alightAccessTime; + + int skimPeriod = -1; + + if(period.compareTo("EA")==0){ + skimPeriod=ModelStructure.EA_SKIM_PERIOD_INDEX; + inbound = false; + }else if(period.compareTo("AM")==0){ + skimPeriod=ModelStructure.AM_SKIM_PERIOD_INDEX; + inbound = false; + }else if(period.compareTo("MD")==0){ + skimPeriod=ModelStructure.MD_SKIM_PERIOD_INDEX; + inbound = false; + }else if(period.compareTo("PM")==0){ + skimPeriod=ModelStructure.PM_SKIM_PERIOD_INDEX; + inbound = true; + }else if(period.compareTo("EV")==0){ + skimPeriod=ModelStructure.EV_SKIM_PERIOD_INDEX; + inbound = true; + }else{ + logger.fatal("Skim period "+period+" not recognized"); + throw new RuntimeException(); + } + + //iterate through mazs and calculate time + ArrayList mazs = mgraManager.getMgras(); + + //origins + for(int originMaz: mazs ){ + + if((originMaz<=100) || ((originMaz % 100) == 0)) + logger.info("Processing origin mgra "+originMaz); + + int originTaz = mgraManager.getTaz(originMaz); + + //for saving results + String outWalkString = null; + String outDriveString = null; + + //destinations + for(int destinationMaz:mazs){ + + int destinationTaz = mgraManager.getTaz(destinationMaz); + + float odDistance = (float) tazDistanceCalculator.getTazToTazDistance(skimPeriod, originTaz, destinationTaz); + + //walk calculations + double[][] bestWalkTaps = bestPathCalculator.getBestTapPairs(walkDmu, driveDmu, bestPathCalculator.WTW, originMaz, destinationMaz, skimPeriod, false, logger, odDistance); + double[] bestWalkUtilities = bestPathCalculator.getBestUtilities(); + + //only look at best utility path; continue if MGRA isn't available by walk. + if(bestWalkUtilities[0]>-500){ + + //Best walk TAP pair + int boardTap = (int) bestWalkTaps[0][0]; + int alightTap = (int) bestWalkTaps[0][1]; + int set = (int) bestWalkTaps[0][2]; + + // get walk skims + boardAccessTime = mgraManager.getWalkTimeFromMgraToTap(originMaz,boardTap); + alightAccessTime = mgraManager.getWalkTimeFromMgraToTap(destinationMaz,alightTap); + double[] walkSkims = wtw.getWalkTransitWalkSkims(set, boardAccessTime, alightAccessTime, boardTap, alightTap, skimPeriod, false); + + //calculate total time + double totalTime=0; + ArrayList wtelements=getWalkTransitTimeComponents(pMap); + for (int i=0; i-500){ + + //best drive TAP pair + int boardTap = (int) bestDriveTaps[0][0]; + int alightTap = (int) bestDriveTaps[0][1]; + int set = (int) bestDriveTaps[0][2]; + + //skims for best drive pair + double[] driveSkims = null; + if(inbound==false){ + boardAccessTime = tazManager.getTimeToTapFromTaz(originTaz,boardTap,( Modes.AccessMode.PARK_N_RIDE )); + alightAccessTime = mgraManager.getWalkTimeFromMgraToTap(destinationMaz,alightTap); + driveSkims = dtw.getDriveTransitWalkSkims(set, boardAccessTime, alightAccessTime, boardTap, alightTap, skimPeriod, false); + }else{ + boardAccessTime = mgraManager.getWalkTimeFromMgraToTap(originMaz,boardTap); + alightAccessTime = tazManager.getTimeToTapFromTaz(destinationTaz,alightTap,( Modes.AccessMode.PARK_N_RIDE )); + driveSkims = wtd.getWalkTransitDriveSkims(set, boardAccessTime, alightAccessTime, boardTap, alightTap, skimPeriod, false); + + } + //total drive-transit time + //calculate total time + double totalTime=0; + ArrayList dtelements=getDriveTransitTimeComponents(pMap); + for (int i=0; i properties) { + String serverAddress = (String) properties.get("RunModel.MatrixServerAddress"); + int serverPort = new Integer((String) properties.get("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try{ + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + MatrixDataServerIf ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) { + logger.error("could not connect to matrix server", e); + throw new RuntimeException(e); + + } + + } + + /** + * Main run method + * @param args + */ + public static void main(String[] args) { + + String propertiesFile = null; + float threshold = 0; + String period = null; + String outWalkFileName = null; + String outDriveFileName = null; + String delims = "[.]"; + + HashMap pMap; + + logger.info(String.format("Report MAZs within transit time threshold. Using CT-RAMP version ", + CtrampApplication.VERSION)); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else { + propertiesFile = args[0]; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-threshold")) + { + threshold = Float.valueOf(args[i + 1]); + } + + if (args[i].equalsIgnoreCase("-period")) + { + period = args[i + 1]; + } + + if (args[i].equalsIgnoreCase("-outWalkFileName")) + { + String[] elements = args[i + 1].split(delims); + outWalkFileName = elements[0]+"_"+period+".csv"; + } + if (args[i].equalsIgnoreCase("-outDriveFileName")) + { + String[] elements = args[i + 1].split(delims); + outDriveFileName = elements[0]+"_"+period+".csv"; + } + } + } + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + TransitTimeReporter transitTimeReporter = new TransitTimeReporter(pMap, threshold, period,outWalkFileName,outDriveFileName); + + + transitTimeReporter.run(pMap); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckCsvExporter.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckCsvExporter.java new file mode 100644 index 0000000..ebd5cf2 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckCsvExporter.java @@ -0,0 +1,58 @@ +package org.sandag.abm.reporting; + +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +public class TruckCsvExporter + extends AbstractCsvExporter +{ + private static final String MATRIX_BASE_NAME = "dailyDistributionMatricesTruck" + TOD_TOKEN; + private static final String[] CORE_NAMES = {"lhdn", "lhdt", "mhdn", "mhdt", "hhdn", + "hhdt" }; + private static final String[] COLUMN_HEADERS = {"ORIG", "DEST", "TOD", "CLASS", "TRIPS"}; + + public TruckCsvExporter(Properties properties, IMatrixDao aMatrixServerWrapper, + String aBaseFileName) + { + super(properties, aMatrixServerWrapper, aBaseFileName); + } + + @Override + public void export() throws IOException + { + BlockingQueue queue = new LinkedBlockingQueue(); + + Thread[] threads = new Thread[TOD_TOKENS.length]; + + LOGGER.info("Initializing Truck Writer Thread. Output Location: " + + getFile().getAbsoluteFile()); + CsvWriterThread writerThread = new CsvWriterThread(queue, getFile(), COLUMN_HEADERS); + new Thread(writerThread).start(); + + for (int i = 0; i < TOD_TOKENS.length; i++) + { + String matrixName = MATRIX_BASE_NAME.replace(TOD_TOKEN, TOD_TOKENS[i]); + LOGGER.info("Initializing Truck Reader Thread. Matrix: " + matrixName); + TruckCsvPublisherThread publisherThread = new TruckCsvPublisherThread(queue, + getMatrixDao(), matrixName, TOD_TOKENS[i], CORE_NAMES); + threads[i] = new Thread(publisherThread); + threads[i].start(); + } + + for (Thread thread : threads) + { + try + { + thread.join(); + } catch (InterruptedException e) + { + e.printStackTrace(System.err); + } + } + + LOGGER.info("Initializing Truck Reader Threads Complete. Issuing Poison Pill to Writer."); + queue.add(CsvWriterThread.POISON_PILL); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckCsvPublisherThread.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckCsvPublisherThread.java new file mode 100644 index 0000000..2120d6e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckCsvPublisherThread.java @@ -0,0 +1,67 @@ +package org.sandag.abm.reporting; + +import java.text.DecimalFormat; +import java.util.concurrent.BlockingQueue; +import org.apache.log4j.Logger; +import com.pb.common.matrix.Matrix; + +public class TruckCsvPublisherThread + implements Runnable +{ + private static final Logger LOGGER = Logger.getLogger(TruckCsvPublisherThread.class); + + private BlockingQueue queue; + private IMatrixDao mtxDao; + private String matrixName; + private String tod; + private String[] cores; + + private final double sizeThreshold = 0.00001; + + private static final DecimalFormat FORMATTER = new DecimalFormat("#.######"); + + public TruckCsvPublisherThread(BlockingQueue aQueue, + IMatrixDao aMtxDao, String aMatrixName, String aTod, String[] theCores) + { + this.queue = aQueue; + this.mtxDao = aMtxDao; + this.matrixName = aMatrixName; + this.tod = aTod; + this.cores = theCores; + } + + @Override + public void run() + { + for (String core : cores) + { + Matrix matrix = mtxDao.getMatrix(matrixName, core); + try + { + addRowsToQueue(core, matrix); + } catch (InterruptedException e) + { + LOGGER.fatal(e); + throw new RuntimeException(e); + } + } + + } + + public void addRowsToQueue(String core, Matrix matrix) throws InterruptedException + { + for (int origin : matrix.getExternalNumbers()) + { + for (int dest : matrix.getExternalColumnNumbers()) + { + float trips = matrix.getValueAt(origin, dest); + if (trips > sizeThreshold) + { + CsvRow row = new CsvRow(new String[] {String.valueOf(origin), + String.valueOf(dest), tod, core, FORMATTER.format(trips)}); + queue.put(row); + } + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckOmxExporter.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckOmxExporter.java new file mode 100644 index 0000000..a7272ef --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/TruckOmxExporter.java @@ -0,0 +1,56 @@ +package org.sandag.abm.reporting; + +import java.io.File; +import java.io.IOException; +import java.util.Properties; +import java.util.concurrent.BlockingQueue; +import java.util.concurrent.LinkedBlockingQueue; + +import org.apache.log4j.Logger; + +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; + +public class TruckOmxExporter implements IExporter +{ + private static final String MATRIX_BASE_NAME = "DailyDistributionMatricesTruck" + TOD_TOKEN; + private static final String[] CORE_NAMES = {"lhdn", "lhdt", "mhdn", "mhdt", "hhdn", + "hhdt" }; + + private IMatrixDao matrixDao; + private String reportFolder = "report.path"; + private Properties properties; + + protected static final Logger LOGGER = Logger.getLogger(AbstractCsvExporter.class); + + + public TruckOmxExporter(Properties properties, IMatrixDao aMatrixServerWrapper, + String aBaseFileName) + { + this.matrixDao = aMatrixServerWrapper; + this.properties = properties; + } + + @Override + public void export() throws IOException + { + + for (int i = 0; i < TOD_TOKENS.length; i++) + { + String matrixName = MATRIX_BASE_NAME.replace(TOD_TOKEN, TOD_TOKENS[i]); + + File outMatrixFile = new File(properties.getProperty(reportFolder), matrixName+".omx"); + + MatrixWriter matrixWriter = MatrixWriter.createWriter(MatrixType.OMX, outMatrixFile); + Matrix[] inMatrix = new Matrix[CORE_NAMES.length]; + + for(int j = 0; j < CORE_NAMES.length; ++j) + inMatrix[j] = matrixDao.getMatrix(matrixName, CORE_NAMES[j]); + + + matrixWriter.writeMatrices(CORE_NAMES, inMatrix); + + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/AquavisDataBuilder.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/AquavisDataBuilder.java new file mode 100644 index 0000000..e8ec218 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/AquavisDataBuilder.java @@ -0,0 +1,47 @@ +package org.sandag.abm.reporting.emfac2011; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.pb.sawdust.util.property.PropertyDeluxe; + +/** + * The {@code SandagAquavisInputBuilder} ... + * + * @author Wu.Sun@sandag.org 1/21/2014 + */ +public class AquavisDataBuilder { + private static final Logger LOGGER = LoggerFactory + .getLogger(AquavisDataBuilder.class); + private final PropertyDeluxe properties; + private Emfac2011SqlUtil sqlUtil = null; + + public AquavisDataBuilder(PropertyDeluxe properties, + Emfac2011SqlUtil sqlUtil) { + this.sqlUtil = sqlUtil; + this.properties = properties; + } + + public void createAquavisInputs() { + String scenarioId = properties + .getString(Emfac2011Properties.SCENARIO_ID); + String scenarioToken = properties + .getString(Emfac2011Properties.AQUAVIS_TEMPLATE_SCENARIOID_TOKEN_PROPERTY); + + LOGGER.info("Step 1.1: Creating intrazonal Aquavis table..."); + sqlUtil.detemplifyAndRunScript( + properties + .getPath(Emfac2011Properties.CREATE_AQUAVIS_INTRAZONAL_TEMPLATE_PROPERTY), + scenarioId, scenarioToken); + LOGGER.info("Step 1.2: Creating network Aquavis table..."); + sqlUtil.detemplifyAndRunScript( + properties + .getPath(Emfac2011Properties.CREATE_AQUAVIS_NETWORK_TEMPLATE_PROPERTY), + scenarioId, scenarioToken); + LOGGER.info("Step 1.3: Creating trips Aquavis table..."); + sqlUtil.detemplifyAndRunScript( + properties + .getPath(Emfac2011Properties.CREATE_AQUAVIS_TRIPS_TEMPLATE_PROPERTY), + scenarioId, scenarioToken); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011AquavisIntrazonal.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011AquavisIntrazonal.java new file mode 100644 index 0000000..81fb2b9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011AquavisIntrazonal.java @@ -0,0 +1,45 @@ +package org.sandag.abm.reporting.emfac2011; +/** + * + * @author Wu.Sun@sandag.org + * + */ +public class Emfac2011AquavisIntrazonal { + protected int zone; + protected double distance; + protected double speed; + protected String region; + protected String aType; + public int getZone() { + return zone; + } + public void setZone(int zone) { + this.zone = zone; + } + public double getDistance() { + return distance; + } + public void setDistance(double distance) { + this.distance = distance; + } + public double getSpeed() { + return speed; + } + public void setSpeed(double speed) { + this.speed = speed; + } + public String getRegion() { + return region; + } + public void setRegion(String region) { + this.region = region; + } + public String getaType() { + return aType; + } + public void setaType(String aType) { + this.aType = aType; + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Data.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Data.java new file mode 100644 index 0000000..76a6fd4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Data.java @@ -0,0 +1,302 @@ +package org.sandag.abm.reporting.emfac2011; + +import java.util.ArrayList; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.pb.sawdust.tabledata.DataRow; +import com.pb.sawdust.tabledata.DataTable; +import com.pb.sawdust.tabledata.TableIndex; +import com.pb.sawdust.tabledata.basic.BasicTableIndex; +import com.pb.sawdust.tabledata.basic.RowDataTable; +import com.pb.sawdust.tabledata.metadata.DataType; +import com.pb.sawdust.tabledata.metadata.TableSchema; +import com.pb.sawdust.util.property.PropertyDeluxe; + +/** + * The {@code AbstractEmfac2011Data} class is used to provide data used to + * modify the EMFAC2011 SG input file. It essentially reads in the generic + * AquaVis data (which represents the travel demand model results) and refactors + * it into a data table that is used (by {@link Emfac2011InputFileCreator}) to + * create an adjusted EMFAC2011 input file. + * + * @author crf Started 2/8/12 9:13 AM + * Modified by Wu.Sun@sandag.org 1/21/2014 + */ +public abstract class Emfac2011Data { + private static final Logger LOGGER = LoggerFactory + .getLogger(Emfac2011Data.class); + private final PropertyDeluxe properties; + private Emfac2011SqlUtil sqlUtil = null; + + /** + * Get a mapping from the tNCVehicle types listed in a model's AquaVis results + * to their corresponding EMFAC2011 tNCVehicle types. The returned map should + * have the (exact) names listed in the AquaVis results as keys, and the set + * of EMFAC2011 tNCVehicle types that the represent the AquaVis type. A single + * EMFAC2011 may be used in the mappings of multiple AquaVis types (there is + * no functional mapping requirement), and only mutable EMFAC2011 tNCVehicle + * types may be used in the mapping (see + * {@link com.pb.aquavis.emfac2011.Emfac2011VehicleType#getMutableVehicleTypes()} + * . Also, all aquavis tNCVehicle types must be represented in the map + * (even if it is an empty mapping). + * + * @return a map representing the relationship between the AquaVis and + * EMFAC2011 tNCVehicle types. + */ + protected abstract Map> getAquavisVehicleTypeToEmfacTypeMapping(); + + public Emfac2011Data(PropertyDeluxe properties, Emfac2011SqlUtil sqlUtil) { + this.sqlUtil = sqlUtil; + this.properties = properties; + } + + public DataTable processAquavisData(Emfac2011Properties properties) { + + String scenario = properties.getString(Emfac2011Properties.SCENARIO_ID); + ArrayList> network = queryNetwork(sqlUtil, scenario); + ArrayList> trips = queryTrips(sqlUtil, scenario); + ArrayList> intrazonal = queryIntrazonal(sqlUtil, + scenario); + + Map> areas = new HashMap<>( + properties + .> getMap(Emfac2011Properties.AREAS_PROPERTY)); + Map districtsToSubareas = new HashMap<>(); + for (String subarea : areas.keySet()) + for (String district : areas.get(subarea)) + districtsToSubareas.put(district, subarea); + + DataTable outputTable = buildEmfacDataTableShell(areas); + TableIndex index = new BasicTableIndex<>(outputTable, + Emfac2011Definitions.EMFAC_2011_DATA_SPEED_FIELD, + Emfac2011Definitions.EMFAC_2011_DATA_SUB_AREA_FIELD, + Emfac2011Definitions.EMFAC_2011_DATA_VEHICLE_TYPE_FIELD); + index.buildIndex(); + + // need to spread out speed fractions - by auto class + Map> aquavisVehicleTypeToEmfacTypeMapping = getAquavisVehicleTypeToEmfacTypeMapping(); + Map> vehicleFractions = buildVehicleFractioning(aquavisVehicleTypeToEmfacTypeMapping); + + LOGGER.info("Step 2.1: Aggregating aquavis network VMT data"); + for (ArrayList row : network) { + double len = new Double(row.get(3)).doubleValue(); + String vehicleType = row.get(6); + double speed = new Double(row.get(7)).doubleValue(); + double vol = new Double(row.get(8)).doubleValue(); + String district = row.get(9); + + if (districtsToSubareas.containsKey(district)) { + String subarea = districtsToSubareas.get(district); + for (Emfac2011VehicleType emfacVehicle : aquavisVehicleTypeToEmfacTypeMapping + .get(vehicleType)) { + double fraction = vehicleFractions.get(emfacVehicle).get( + vehicleType); + for (int r : index.getRowNumbers(Emfac2011SpeedCategory + .getSpeedCategory(speed).getName(), subarea, + emfacVehicle.getName())) + outputTable + .setCellValue( + r, + Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD, + (Double) outputTable + .getCellValue( + r, + Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD) + + fraction * vol * len); + } + } + } + + // need to collect intrazonal vmt and add it to network vmt - by auto + // class + LOGGER.info("Step 2.2: Aggregating aquavis intrazonal VMT data"); + HashMap intrazonalMap = convertIntrazonal(intrazonal); + for (ArrayList row : trips) { + int zone = new Integer(row.get(1)).intValue(); + String vClass = row.get(5); + int vol = new Integer(row.get(6)).intValue(); + String district = (String) intrazonalMap.get(zone).getRegion(); + if (districtsToSubareas.containsKey(district)) { + String subarea = districtsToSubareas.get(district); + double speed = intrazonalMap.get(zone).getSpeed(); + double vmt = intrazonalMap.get(zone).getDistance() * vol; + for (Emfac2011VehicleType emfacVehicle : aquavisVehicleTypeToEmfacTypeMapping + .get(vClass)) { + double fraction = vehicleFractions.get(emfacVehicle).get( + vClass); + for (int r : index.getRowNumbers(Emfac2011SpeedCategory + .getSpeedCategory(speed).getName(), subarea, + emfacVehicle.getName())) + outputTable + .setCellValue( + r, + Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD, + (Double) outputTable + .getCellValue( + r, + Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD) + + fraction * vmt); + } + } + } + + LOGGER.info("Step 2.3: Building speed fractions"); + // build fractions + index = new BasicTableIndex<>(outputTable, + Emfac2011Definitions.EMFAC_2011_DATA_SUB_AREA_FIELD, + Emfac2011Definitions.EMFAC_2011_DATA_VEHICLE_TYPE_FIELD); + index.buildIndex(); + for (Emfac2011VehicleType emfacVehicle : Emfac2011VehicleType + .getMutableVehicleTypes()) { + for (String subarea : areas.keySet()) { + double sum = 0.0; + int count = 0; + for (DataRow row : outputTable.getIndexedRows(index, subarea, + emfacVehicle.getName())) { + sum += row + .getCellAsDouble(Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD); + count++; + } + for (int r : index.getRowNumbers(subarea, + emfacVehicle.getName())) + outputTable + .setCellValue( + r, + Emfac2011Definitions.EMFAC_2011_DATA_SPEED_FRACTION_FIELD, + sum == 0.0 ? 1.0 / count + : (Double) outputTable + .getCellValue( + r, + Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD) + / sum); + } + } + + return outputTable; + } + + private DataTable buildEmfacDataTableShell(Map> areas) { + LOGGER.debug("Building EMFAC data table shell"); + TableSchema schema = new TableSchema("Emfac Data"); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_DATA_SPEED_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_DATA_SUB_AREA_FIELD, + DataType.STRING); + schema.addColumn( + Emfac2011Definitions.EMFAC_2011_DATA_VEHICLE_TYPE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD, + DataType.DOUBLE); + schema.addColumn( + Emfac2011Definitions.EMFAC_2011_DATA_SPEED_FRACTION_FIELD, + DataType.DOUBLE); + DataTable outputTable = new RowDataTable(schema); + + // first, add rows for everything + for (Emfac2011VehicleType vehicle : Emfac2011VehicleType + .getMutableVehicleTypes()) + for (String subArea : areas.keySet()) + for (Emfac2011SpeedCategory speed : Emfac2011SpeedCategory + .values()) + outputTable.addRow(speed.getName(), subArea, + vehicle.getName(), 0.0, -1.0); // -1 + // is + // for + // error + // checking + // - + // 0 + // might + // pass + // through + return outputTable; // unnoticed + } + + private Map> buildVehicleFractioning( + Map> aquavisVehicleTypeToEmfacTypeMapping) { + // returns a map which says for every emfac tNCVehicle type, what aquavis + // tNCVehicle types should have their vmt added + // to it, and by what fraction + + Map> vehicleFractionMap = new EnumMap<>( + Emfac2011VehicleType.class); + for (Emfac2011VehicleType type : Emfac2011VehicleType + .getMutableVehicleTypes()) + vehicleFractionMap.put(type, new HashMap()); + for (String aquavisVehicleType : aquavisVehicleTypeToEmfacTypeMapping + .keySet()) { + double fraction = 1.0 / aquavisVehicleTypeToEmfacTypeMapping.get( + aquavisVehicleType).size(); + for (Emfac2011VehicleType type : aquavisVehicleTypeToEmfacTypeMapping + .get(aquavisVehicleType)) { + if (!vehicleFractionMap.containsKey(type)) + throw new IllegalStateException( + "Emfac tNCVehicle type is not mutable (" + + type + + ") and should not be component for aquavis type " + + aquavisVehicleType); + vehicleFractionMap.get(type).put(aquavisVehicleType, fraction); + } + } + return vehicleFractionMap; + } + + private HashMap convertIntrazonal( + ArrayList> intrazonal) { + HashMap result = new HashMap(); + for (ArrayList row : intrazonal) { + Emfac2011AquavisIntrazonal rec = new Emfac2011AquavisIntrazonal(); + int zone = new Integer(row.get(1)).intValue(); + rec.setZone(zone); + rec.setDistance(new Double(row.get(2))); + rec.setSpeed(new Double(row.get(3))); + rec.setRegion(row.get(4)); + rec.setaType(row.get(5)); + result.put(zone, rec); + } + return result; + } + + private ArrayList> queryNetwork(Emfac2011SqlUtil sqlUtil, + String schema) { + ArrayList> result = sqlUtil + .queryAquavisTables( + properties + .getPath(Emfac2011Properties.QUERY_AQUAVIS_NETWORK_TEMPLATE_PROPERTY), + schema, + properties + .getString(Emfac2011Properties.AQUAVIS_TEMPLATE_SCENARIOID_TOKEN_PROPERTY)); + return result; + } + + private ArrayList> queryTrips(Emfac2011SqlUtil sqlUtil, + String schema) { + ArrayList> result = sqlUtil + .queryAquavisTables( + properties + .getPath(Emfac2011Properties.QUERY_AQUAVIS_TRIPS_TEMPLATE_PROPERTY), + schema, + properties + .getString(Emfac2011Properties.AQUAVIS_TEMPLATE_SCENARIOID_TOKEN_PROPERTY)); + return result; + } + + private ArrayList> queryIntrazonal( + Emfac2011SqlUtil sqlUtil, String schema) { + ArrayList> result = sqlUtil + .queryAquavisTables( + properties + .getPath(Emfac2011Properties.QUERY_AQUAVIS_INTRAZONAL_TEMPLATE_PROPERTY), + schema, + properties + .getString(Emfac2011Properties.AQUAVIS_TEMPLATE_SCENARIOID_TOKEN_PROPERTY)); + return result; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Definitions.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Definitions.java new file mode 100644 index 0000000..bdc94b2 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Definitions.java @@ -0,0 +1,86 @@ +package org.sandag.abm.reporting.emfac2011; + +/** + * + * @author Wu.Sun@sandag.org 1/20/2014 + * + */ + +public class Emfac2011Definitions { + + //Aquavis table content defintions + public static final String AQUAVIS_NETWORK_FROM_NODE_FIELD = "from_node"; + public static final String AQUAVIS_NETWORK_TO_NODE_FIELD = "to_node"; + public static final String AQUAVIS_NETWORK_LENGTH_FIELD = "length"; + public static final String AQUAVIS_NETWORK_LINK_CLASS_FIELD = "link_class"; + public static final String AQUAVIS_NETWORK_TIME_PERIOD_FIELD = "time_period"; + public static final String AQUAVIS_NETWORK_VEHICLE_CLASS_FIELD = "vehicle_class"; + public static final String AQUAVIS_NETWORK_SPEED_FIELD = "assigned_speed"; + public static final String AQUAVIS_NETWORK_VOLUME_FIELD = "volume"; + public static final String AQUAVIS_NETWORK_REGION_FIELD = "region"; + + public static final String AQUAVIS_INTRAZONAL_ZONE_FIELD = "zone"; + public static final String AQUAVIS_INTRAZONAL_LENGTH_FIELD = "distance"; + public static final String AQUAVIS_INTRAZONAL_SPEED_FIELD = "speed"; + public static final String AQUAVIS_INTRAZONAL_REGION_FIELD = "region"; + public static final String AQUAVIS_INTRAZONAL_AREA_TYPE_FIELD = "area_type"; + + public static final String AQUAVIS_TRIPS_ORIGIN_ZONE_FIELD = "origin_zone"; + public static final String AQUAVIS_TRIPS_DESTINATION_ZONE_FIELD = "destination_zone"; + public static final String AQUAVIS_TRIPS_HOUR_FIELD = "hour"; + public static final String AQUAVIS_TRIPS_TIME_PERIOD_FIELD = "time_period"; + public static final String AQUAVIS_TRIPS_VEHICLE_CLASS_FIELD = "vehicle_class"; + public static final String AQUAVIS_TRIPS_TRIPS_FIELD = "trips"; + + public static final String VEHICLE_CODE_MAPPING_EMFAC2011_VEHICLE_NAME_COLUMN = "EMFAC2011_MODE"; + + // Emfac2011 Data Table Definitions + public static final String EMFAC_2011_DATA_SUB_AREA_FIELD = "subarea"; + public static final String EMFAC_2011_DATA_SPEED_FIELD = "speed"; + public static final String EMFAC_2011_DATA_VEHICLE_TYPE_FIELD = "vehicle_type"; + public static final String EMFAC_2011_DATA_VMT_FIELD = "vmt"; + public static final String EMFAC_2011_DATA_SPEED_FRACTION_FIELD = "fraction"; + + // Emfac2011 Excel Input Sheets definitions + public static final String EMFAC_2011_SCENARIO_TABLE_NAME = "Regional_Scenarios"; + public static final String EMFAC_2011_SCENARIO_TABLE_GROUP_FIELD = "Group"; + public static final String EMFAC_2011_SCENARIO_TABLE_AREA_TYPE_FIELD = "Area Type"; + public static final String EMFAC_2011_SCENARIO_TABLE_AREA_FIELD = "Area"; + public static final String EMFAC_2011_SCENARIO_TABLE_YEAR_FIELD = "CalYr"; + public static final String EMFAC_2011_SCENARIO_TABLE_SEASON_FIELD = "Season"; + + public static final String EMFAC_2011_VMT_TABLE_NAME = "Scenario_Base_Inputs"; + public static final String EMFAC_2011_VMT_TABLE_GROUP_FIELD = "Group"; + public static final String EMFAC_2011_VMT_TABLE_AREA_FIELD = "Area"; + public static final String EMFAC_2011_VMT_TABLE_SCENARIO_FIELD = "Scenario"; + public static final String EMFAC_2011_VMT_TABLE_SUB_AREA_FIELD = "Sub-Area"; + public static final String EMFAC_2011_VMT_TABLE_YEAR_FIELD = "CalYr"; + public static final String EMFAC_2011_VMT_TABLE_SEASON_FIELD = "Season"; + public static final String EMFAC_2011_VMT_TABLE_TITLE_FIELD = "Title"; + public static final String EMFAC_2011_VMT_TABLE_VMT_PROFILE_FIELD = "VMT Profile"; + public static final String EMFAC_2011_VMT_TABLE_VMT_BY_VEH_FIELD = "VMT by TNCVehicle Category"; + public static final String EMFAC_2011_VMT_TABLE_SPEED_PROFILE_FIELD = "Speed Profile"; + public static final String EMFAC_2011_VMT_TABLE_VMT_FIELD = "New Total VMT"; + + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_NAME = "Scenario_VMT_by_VehCat"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_GROUP_FIELD = "Group"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_AREA_FIELD = "Area"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_SCENARIO_FIELD = "Scenario"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_SUB_AREA_FIELD = "Sub-Area"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_YEAR_FIELD = "CalYr"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_SEASON_FIELD = "Season"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_TITLE_FIELD = "Title"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_VEHICLE_FIELD = "Veh & Tech"; + public static final String EMFAC_2011_VEHICLE_VMT_TABLE_VMT_FIELD = "New VMT"; + + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_NAME = "Scenario_Speed_Profiles"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_GROUP_FIELD = "Group"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_AREA_FIELD = "Area"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_SCENARIO_FIELD = "Scenario"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_SUB_AREA_FIELD = "Sub-Area"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_YEAR_FIELD = "CalYr"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_SEASON_FIELD = "Season"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_TITLE_FIELD = "Title"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_VEHICLE_FIELD = "Veh & Tech"; + public static final String EMFAC_2011_SPEED_FRACTION_TABLE_2007_VEHICLE_FIELD = "EMFAC2007 Veh & Tech"; +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011InputFileCreator.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011InputFileCreator.java new file mode 100644 index 0000000..85a5cef --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011InputFileCreator.java @@ -0,0 +1,577 @@ +package org.sandag.abm.reporting.emfac2011; + +import static com.pb.sawdust.util.Range.range; +import java.io.IOException; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.Arrays; +import java.util.EnumMap; +import java.util.HashMap; +import java.util.LinkedHashMap; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import com.pb.sawdust.excel.tabledata.read.ExcelTableReader; +import com.pb.sawdust.excel.tabledata.write.ExcelTableWriter; +import com.pb.sawdust.tabledata.DataRow; +import com.pb.sawdust.tabledata.DataTable; +import com.pb.sawdust.tabledata.TableIndex; +import com.pb.sawdust.tabledata.basic.BasicTableIndex; +import com.pb.sawdust.tabledata.basic.RowDataTable; +import com.pb.sawdust.tabledata.metadata.DataType; +import com.pb.sawdust.tabledata.metadata.TableSchema; +import com.pb.sawdust.tabledata.write.TableWriter; +import com.pb.sawdust.util.ProcessUtil; +import com.pb.sawdust.util.exceptions.RuntimeIOException; + +/** + * The {@code InputTemplateCreator} class is used to build an adjusted input + * file used for running the EMFAC2011 SG model. + * + * + * @author crf Started 2/7/12 1:48 PM Modified by Wu.Sun@sandag.org 1/21/2014 + */ +public class Emfac2011InputFileCreator +{ + private static final Logger LOGGER = LoggerFactory.getLogger(Emfac2011Data.class); + + private static final String[] SEASONS = {"ANNUAL", "SUMMER", "WINTER"}; + + /** + * Create an input file that can be used with the EMFAC2011 SG model. The + * constructed input file will use the default EMFAC2011 + * parameters/specifications, with adjustments based on a travel demand + * model's results. + * + * @param properties + * The properties specific to the model run. + * + * @param emfacModelData + * A data table (obtained from + * {@link Emfac2011Data#processAquavisData(Emfac2011Properties)} + * )) holding the results of the travel demand model. + * + * @return an EMFAC2011 SG input file, adjusted using {@code emfacModelData} + * . + */ + public Path createInputFile(Emfac2011Properties properties, DataTable emfacModelData) + { + String areaType = properties.getString(Emfac2011Properties.AREA_TYPE_PROPERTY); + String region = properties.getString(Emfac2011Properties.REGION_NAME_PROPERTY); + // Set areas = new + // HashSet<>(properties.getList(Emfac2011Properties.AREAS_PROPERTY)); + // Map> areas = new + // HashMap<>(properties.>getMap(Emfac2011Properties.AREAS_PROPERTY)); + Set areas = new HashMap<>( + properties.>getMap(Emfac2011Properties.AREAS_PROPERTY)) + .keySet(); + int oriYear = properties.getInt(Emfac2011Properties.YEAR_PROPERTY); + int year = Math.min(oriYear, 2035); + String inventoryDir = Paths.get( + properties.getString(Emfac2011Properties.EMFAC2011_INSTALLATION_DIR_PROPERTY), + "Application Files/Inventory Files").toString(); + String outputDir = properties.getString(Emfac2011Properties.OUTPUT_DIR_PROPERTY); + String converterProgram = properties + .getString(Emfac2011Properties.XLS_CONVERTER_PROGRAM_PROPERTY); + boolean preserveEmfacVehicleFractions = properties + .getBoolean(Emfac2011Properties.PRESERVE_EMFAC_VEHICLE_FRACTIONS_PROPERTY); + boolean modelVmtIncludesNonMutableVehicleTypes = properties + .getBoolean(Emfac2011Properties.MODEL_VMT_INCLUDES_NON_MUTABLES_PROPERTY); + return createInputFile(areaType, region, areas, year, oriYear, emfacModelData, + preserveEmfacVehicleFractions, modelVmtIncludesNonMutableVehicleTypes, + inventoryDir, outputDir, converterProgram); + } + + private String formInventoryFileName(String area, String season, int year) + { + return "EMFAC2011-SG Inventory - " + area + " - " + year + " (" + season + ").xls"; + } + + private void convertFile(String inventoryFile, String outputInventoryFile, + String converterProgram) + { + ProcessUtil.runProcess(Arrays.asList(converterProgram, inventoryFile, outputInventoryFile)); + } + + private DataTable readInventoryTable(String inventoryFile) + { + return new RowDataTable(ExcelTableReader.excelTableReader(inventoryFile)); + } + + private Path createInputFile(String areaType, String region, Set areas, int year, + int oriYear, DataTable emfacModelData, boolean preserveEmfacVehicleFractions, + boolean modelVmtIncludesNonMutableVehicleTypes, String inventoryDir, String outputDir, + String converterProgram) + { + Path outputFile = Paths.get(outputDir, formOutputFileName(region, oriYear)); + try + { + Files.deleteIfExists(outputFile); + } catch (IOException e) + { + throw new RuntimeIOException(e); + } + + TableWriter writer = new ExcelTableWriter(outputFile.toFile()); + LOGGER.debug("Initializing input excel file: " + outputFile); + writer.writeTable(formScenarioTable(areaType, region, year, SEASONS)); + + DataTable masterVmtTable = initVmtTable(); + DataTable masterVehicleVmtTable = initVehicleVmtTable(); + DataTable masterVmtSpeedTable = initVmtSpeedTable(); + + for (int i=0;i inputTables = new LinkedHashMap<>(); + for (String area : areas) + { + String inventoryFile = Paths.get(inventoryDir, + formInventoryFileName(area, SEASONS[i], year)).toString(); + Path outputInventoryFile = Paths.get(outputDir, + formInventoryFileName(area, SEASONS[i], year)); + convertFile(inventoryFile, outputInventoryFile.toString(), converterProgram); + inputTables.put(area, readInventoryTable(outputInventoryFile.toString())); + try + { + Files.delete(outputInventoryFile); + } catch (IOException e) + { + throw new RuntimeIOException(e); + } + } + + LOGGER.debug("Building vmt table"); + DataTable vmtTable = extractVmtTables(inputTables, i+1, region, year, SEASONS[i]); + LOGGER.debug("Building vmt by tNCVehicle type table"); + DataTable vehicleVmtTable = extractVmtVehicleTables(inputTables, i+1, region, year, SEASONS[i]); + LOGGER.debug("Building speed fraction table"); + DataTable vmtSpeedTable = extractVmtSpeedTables(inputTables, i+1, region, year, SEASONS[i]); + LOGGER.debug("Shifting tables using model data"); + shiftVmtTables(vmtTable, vehicleVmtTable, areas, emfacModelData, + preserveEmfacVehicleFractions, modelVmtIncludesNonMutableVehicleTypes); + shiftSpeedFractionTable(vmtSpeedTable, emfacModelData); + LOGGER.debug("Writing tables"); + + appendDataTable(masterVmtTable, vmtTable); + appendDataTable(masterVehicleVmtTable, vehicleVmtTable); + appendDataTable(masterVmtSpeedTable, vmtSpeedTable); + } + + writer.writeTable(masterVmtTable); + writer.writeTable(masterVehicleVmtTable); + writer.writeTable(masterVmtSpeedTable); + return outputFile; + } + + private void appendDataTable(DataTable master, DataTable fragment) + { + for(DataRow row : fragment) + { + master.addRow(row); + } + } + + private String formOutputFileName(String region, int year) + { + return "EMFAC2011-" + region + "-" + year + ".xls"; + } + + private DataTable formScenarioTable(String areaType, String area, int year, String[] seasons) + { + TableSchema schema = new TableSchema(Emfac2011Definitions.EMFAC_2011_SCENARIO_TABLE_NAME); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SCENARIO_TABLE_GROUP_FIELD, DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SCENARIO_TABLE_AREA_TYPE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SCENARIO_TABLE_AREA_FIELD, DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SCENARIO_TABLE_YEAR_FIELD, DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SCENARIO_TABLE_SEASON_FIELD, + DataType.STRING); + + DataTable table = new RowDataTable(schema); + + for (int i = 0; i < seasons.length; i++) + { + List row = new LinkedList<>(); + row.add(i+1); + row.add(areaType); + row.add(area); + row.add(year); + row.add(seasons[i]); + table.addRow(row.toArray(new Object[row.size()])); + } + return table; + } + + private DataTable initVmtTable() + { + TableSchema schema = new TableSchema(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_NAME); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_GROUP_FIELD, DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_AREA_FIELD, DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_SCENARIO_FIELD, DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_SUB_AREA_FIELD, DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_YEAR_FIELD, DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_SEASON_FIELD, DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_TITLE_FIELD, DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_VMT_PROFILE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_VMT_BY_VEH_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_SPEED_PROFILE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_VMT_FIELD, DataType.DOUBLE); + return new RowDataTable(schema); + } + + private DataTable initVehicleVmtTable() + { + TableSchema schema = new TableSchema(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_NAME); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_GROUP_FIELD, + DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_AREA_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_SCENARIO_FIELD, + DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_SUB_AREA_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_YEAR_FIELD, DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_SEASON_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_TITLE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VEHICLE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VMT_FIELD, + DataType.DOUBLE); + return new RowDataTable(schema); + } + + private DataTable initVmtSpeedTable() + { + TableSchema schema = new TableSchema( + Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_NAME); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_GROUP_FIELD, + DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_AREA_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_SCENARIO_FIELD, + DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_SUB_AREA_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_YEAR_FIELD, + DataType.INT); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_SEASON_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_TITLE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_VEHICLE_FIELD, + DataType.STRING); + schema.addColumn(Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_2007_VEHICLE_FIELD, + DataType.STRING); + for (Emfac2011SpeedCategory category : Emfac2011SpeedCategory.values()) + schema.addColumn(category.getName(), DataType.DOUBLE); + return new RowDataTable(schema); + } + + private DataTable extractVmtTables(Map inputTables, int group, String area, int year, + String season) + { + DataTable vmtTable = initVmtTable(); + + int counter = 1; + for (String subArea : inputTables.keySet()) + { + List row = new LinkedList<>(); + row.add(group); + row.add(area); + row.add(counter); + row.add(subArea); + row.add(year); + row.add(season); + row.add(String.format("Group #1 (%s), Scenario #%d - %s %d %s", area, counter++, + subArea, year, season)); + row.add("User"); + row.add("User"); + row.add("User"); + + double totalVmt = 0.0; + for (DataRow r : inputTables.get(subArea)) + if (r.getCellAsString("Tech").equals("TOT")) totalVmt += r.getCellAsDouble("VMT"); + row.add(totalVmt); + vmtTable.addRow(row.toArray(new Object[row.size()])); + } + return vmtTable; + } + + private DataTable extractVmtVehicleTables(Map inputTables, int group, String area, + int year, String season) + { + DataTable vehicleVmtTable = initVehicleVmtTable(); + + int counter = 1; + for (String subArea : inputTables.keySet()) + { + for (DataRow r : inputTables.get(subArea)) + { + String tech = r.getCellAsString("Tech"); + if (tech.equals("DSL") || tech.equals("GAS")) + { + List row = new LinkedList<>(); + row.add(group); + row.add(area); + row.add(counter); + row.add(subArea); + row.add(year); + row.add(season); + row.add(String.format("Group #1 (%s), Scenario #%d - %s %d %s", area, counter, + subArea, year, season)); + row.add(r.getCellAsString("Veh & Tech")); + row.add(r.getCellAsDouble("VMT")); + vehicleVmtTable.addRow(row.toArray(new Object[row.size()])); + } + } + counter++; + } + return vehicleVmtTable; + } + + private DataTable extractVmtSpeedTables(Map inputTables, int group, String area, + int year, String season) + { + DataTable vmtSpeedTable = initVmtSpeedTable(); + + int counter = 1; + for (String subArea : inputTables.keySet()) + { + // loop over everything once to get sums and types, and then second + // time to generate fractions + Map techTotals = new LinkedHashMap<>(); + for (DataRow r : inputTables.get(subArea)) + { + String tech = r.getCellAsString("Tech"); + if (tech.startsWith("Spd") && !tech.endsWith("TOT")) + { + String vehNTech = r.getCellAsString("Veh & Tech").toLowerCase(); + if (!techTotals.containsKey(vehNTech)) techTotals.put(vehNTech, 0.0); + techTotals.put(vehNTech, techTotals.get(vehNTech) + r.getCellAsDouble("VMT")); + } + } + Map techRows = new HashMap<>(); + // loop over each type and add in the rows + for (Emfac2011VehicleType type : Emfac2011VehicleType.values()) + { + List row = new LinkedList<>(); + row.add(group); + row.add(area); + row.add(counter); + row.add(subArea); + row.add(year); + row.add(season); + row.add(String.format("Group #1 (%s), Scenario #%d - %s %d %s", area, counter, + subArea, year, season)); + row.add(type.getName()); + row.add(type.getEmfac2007Name()); + for (int i : range(5, 71, 5)) + row.add(0.0); + vmtSpeedTable.addRow(row.toArray(new Object[row.size()])); + techRows.put(type.getName().toLowerCase(), vmtSpeedTable.getRowCount() - 1); + } + // now reloop over table to get fractions + for (DataRow r : inputTables.get(subArea)) + { + String tech = r.getCellAsString("Tech"); + if (tech.startsWith("Spd") && !tech.endsWith("TOT")) + { + String vehNTech = r.getCellAsString("Veh & Tech").toLowerCase(); + double fraction = techTotals.get(vehNTech) == 0.0 ? 0.0 : r + .getCellAsDouble("VMT") / techTotals.get(vehNTech); + vmtSpeedTable.setCellValue(techRows.get(vehNTech), + Integer.parseInt(tech.substring(3, 5)) + "MPH", fraction); + } + } + counter++; + } + // ensure that we sum up to one + counter = 0; + for (DataRow r : vmtSpeedTable) + { + double sum = 1.0; + Emfac2011SpeedCategory[] speeds = Emfac2011SpeedCategory.values(); + for (int i : range(speeds.length - 1)) + sum -= r.getCellAsDouble(speeds[i].getName()); + vmtSpeedTable.setCellValue(counter++, Emfac2011SpeedCategory.SPEED_65_70plus.getName(), + sum); + } + return vmtSpeedTable; + } + + // private void shiftSpeedFractionTable(DataTable speedVmtTable, DataTable + // modelData) { + private void shiftSpeedFractionTable(DataTable speedVmtTable, DataTable modelData) + { + TableIndex index = new BasicTableIndex<>(speedVmtTable, + Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_SUB_AREA_FIELD, + Emfac2011Definitions.EMFAC_2011_SPEED_FRACTION_TABLE_VEHICLE_FIELD); + index.buildIndex(); + + for (DataRow row : modelData) + { + String subArea = row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_DATA_SUB_AREA_FIELD); + String vehicleType = row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_DATA_VEHICLE_TYPE_FIELD); + String category = Emfac2011SpeedCategory.getTypeForName( + row.getCellAsString(Emfac2011Definitions.EMFAC_2011_DATA_SPEED_FIELD)) + .getName(); + speedVmtTable.setCellValue(index.getRowNumbers(subArea, vehicleType).iterator().next(), + category, + row.getCellAsDouble(Emfac2011Definitions.EMFAC_2011_DATA_SPEED_FRACTION_FIELD)); + } + } + + private void shiftVmtTables(DataTable vmtTable, DataTable vehicleVmtTable, Set areas, + DataTable modelData, boolean preserveEmfacVehicleFractions, + boolean modelVmtIncludesNonMutableVehicleTypes) + { + Map> modelVmtByAreaAndVehicleType = new HashMap<>(); + Map> emfacMutableVmtByAreaAndVehicleType = new HashMap<>(); + Map> emfacImmutableVmtByAreaAndVehicleType = new HashMap<>(); + + Set mutableVehicleTypes = Emfac2011VehicleType + .getMutableVehicleTypes(); + + for (String subarea : areas) + { + Map m1 = new EnumMap<>(Emfac2011VehicleType.class); + Map m2 = new EnumMap<>(Emfac2011VehicleType.class); + Map m3 = new EnumMap<>(Emfac2011VehicleType.class); + for (Emfac2011VehicleType vehicleType : Emfac2011VehicleType.values()) + { + if (mutableVehicleTypes.contains(vehicleType)) + { + m1.put(vehicleType, 0.0); + m2.put(vehicleType, 0.0); + } else + { + if (modelVmtIncludesNonMutableVehicleTypes) m1.put(vehicleType, 0.0); + m3.put(vehicleType, 0.0); + } + } + modelVmtByAreaAndVehicleType.put(subarea, m1); + emfacMutableVmtByAreaAndVehicleType.put(subarea, m2); + emfacImmutableVmtByAreaAndVehicleType.put(subarea, m3); + } + + for (DataRow row : vehicleVmtTable) + { + String subArea = row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_SUB_AREA_FIELD); + Emfac2011VehicleType vehicleType = Emfac2011VehicleType + .getVehicleType(row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VEHICLE_FIELD)); + double vmt = row + .getCellAsDouble(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VMT_FIELD); + if (mutableVehicleTypes.contains(vehicleType)) emfacMutableVmtByAreaAndVehicleType.get( + subArea).put(vehicleType, + emfacMutableVmtByAreaAndVehicleType.get(subArea).get(vehicleType) + vmt); + else emfacImmutableVmtByAreaAndVehicleType.get(subArea).put(vehicleType, + emfacImmutableVmtByAreaAndVehicleType.get(subArea).get(vehicleType) + vmt); + } + + for (DataRow row : modelData) + { + String subArea = row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_DATA_SUB_AREA_FIELD); + Emfac2011VehicleType vehicleType = Emfac2011VehicleType.getVehicleType(row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_DATA_VEHICLE_TYPE_FIELD)); + double vmt = row.getCellAsDouble(Emfac2011Definitions.EMFAC_2011_DATA_VMT_FIELD); + modelVmtByAreaAndVehicleType.get(subArea).put(vehicleType, + modelVmtByAreaAndVehicleType.get(subArea).get(vehicleType) + vmt); + } + + if (preserveEmfacVehicleFractions) + { + // need to reshift data + for (String subarea : modelVmtByAreaAndVehicleType.keySet()) + { + double totalVmt = 0.0; + Map modelVmt = modelVmtByAreaAndVehicleType + .get(subarea); + for (Emfac2011VehicleType vehicleType : modelVmt.keySet()) + totalVmt += modelVmt.get(vehicleType); + double totalEmfacVmt = 0.0; + Map emfacMutableVmt = emfacMutableVmtByAreaAndVehicleType + .get(subarea); + Map emfacImutableVmt = emfacImmutableVmtByAreaAndVehicleType + .get(subarea); + for (Emfac2011VehicleType vehicleType : emfacMutableVmt.keySet()) + totalEmfacVmt += emfacMutableVmt.get(vehicleType); + if (modelVmtIncludesNonMutableVehicleTypes) + for (Emfac2011VehicleType vehicleType : emfacImutableVmt.keySet()) + totalEmfacVmt += emfacImutableVmt.get(vehicleType); + for (Emfac2011VehicleType vehicleType : modelVmt.keySet()) + { + if (emfacMutableVmt.containsKey(vehicleType)) modelVmt.put(vehicleType, + totalVmt * emfacMutableVmt.get(vehicleType) / totalEmfacVmt); + else modelVmt.put(vehicleType, totalVmt * emfacImutableVmt.get(vehicleType) + / totalEmfacVmt); + } + } + } + + // shift overall vmt + vmtTable.setPrimaryKey(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_SUB_AREA_FIELD); + for (DataRow row : vmtTable) + { + String subArea = row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_SUB_AREA_FIELD); + double originalVmt = row + .getCellAsDouble(Emfac2011Definitions.EMFAC_2011_VMT_TABLE_VMT_FIELD); + Map modelVmt = modelVmtByAreaAndVehicleType.get(subArea); + Map emfacMutableVmt = emfacMutableVmtByAreaAndVehicleType + .get(subArea); + Map emfacImutableVmt = emfacImmutableVmtByAreaAndVehicleType + .get(subArea); + for (Emfac2011VehicleType vehicleType : modelVmt.keySet()) + { + originalVmt += modelVmt.get(vehicleType); // add corrected vmt + originalVmt -= emfacMutableVmt.containsKey(vehicleType) ? emfacMutableVmt + .get(vehicleType) : emfacImutableVmt.get(vehicleType); // subtract + // old + // vmt + } + vmtTable.setCellValueByKey(subArea, + Emfac2011Definitions.EMFAC_2011_VMT_TABLE_VMT_FIELD, originalVmt); + } + + // replace tNCVehicle vmts + TableIndex index = new BasicTableIndex<>(vehicleVmtTable, + Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_SUB_AREA_FIELD, + Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VEHICLE_FIELD); + index.buildIndex(); + for (DataRow row : vehicleVmtTable) + { + String subArea = row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_SUB_AREA_FIELD); + Map modelVmt = modelVmtByAreaAndVehicleType.get(subArea); + Map emfacMutableVmt = emfacMutableVmtByAreaAndVehicleType + .get(subArea); + Emfac2011VehicleType vehicleType = Emfac2011VehicleType + .getVehicleType(row + .getCellAsString(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VEHICLE_FIELD)); + if (modelVmt.containsKey(vehicleType)) + { + double vmt = row + .getCellAsDouble(Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VMT_FIELD); + if (modelVmtIncludesNonMutableVehicleTypes) vmt = modelVmt.get(vehicleType); + else vmt += modelVmt.get(vehicleType) - emfacMutableVmt.get(vehicleType); + vehicleVmtTable.setCellValue(index.getRowNumbers(subArea, vehicleType.getName()) + .iterator().next(), + Emfac2011Definitions.EMFAC_2011_VEHICLE_VMT_TABLE_VMT_FIELD, vmt); + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Properties.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Properties.java new file mode 100644 index 0000000..b3a2031 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Properties.java @@ -0,0 +1,101 @@ +package org.sandag.abm.reporting.emfac2011; + +import com.pb.sawdust.util.property.PropertyDeluxe; + +/** + * The {@code Emfac2011Properties} holds the properties used by the various + * classes in this package. The property keys listed in this class (as + * {@code public static final} constants) must all be present in the + * instantiated properties object, or it will throw an error during + * construction. Additionally, {@link #AREAS_PROPERTY} must be typed correctly + * as a map from a string to a list holding strings (see its documentation for + * more information). + * + * @author crf Started 2/9/12 8:40 AM + * Modified by Wu.Sun@sanag.org 1/28/2014 + */ +public class Emfac2011Properties + extends PropertyDeluxe +{ + //database properties + public static final String REPORTS_DATABASE_IPADDRESS_PROPERTY = "reports.database.ipaddress"; + public static final String REPORTS_DATABASE_PORT_PROPERTY = "reports.database.port"; + public static final String REPORTS_DATABASE_NAME_PROPERTY = "reports.database.name"; + public static final String REPORTS_DATABASE_USERNAME_PROPERTY = "reports.database.username"; + public static final String REPORTS_DATABASE_PASSWORD_PROPERTY = "reports.database.password"; + public static final String REPORTS_DATABASE_INSTANCE_PROPERTY = "reports.database.instance"; + + //San Diego Emfac2011 properties + public static final String AREA_TYPE_PROPERTY = "emfac.2011.area.type"; + public static final String REGION_NAME_PROPERTY = "emfac.2011.region.name"; + public static final String AREAS_PROPERTY = "emfac.2011.area"; + public static final String SEASON_PROPERTY = "emfac.2011.season"; + public static final String YEAR_PROPERTY = "emfac.2011.year"; + public static final String EMFAC2011_INSTALLATION_DIR_PROPERTY = "emfac.2011.installation.dir"; + public static final String OUTPUT_DIR_PROPERTY = "emfac.2011.output.dir"; + public static final String AQUAVIS_INTRAZONAL_FILE_PROPERTY = "emfac.2011.aquavis.intrazonal"; + + // Aquavis table creation templates + public static final String CREATE_AQUAVIS_NETWORK_TEMPLATE_PROPERTY = "aquavis.network.sql.template"; + public static final String CREATE_AQUAVIS_TRIPS_TEMPLATE_PROPERTY = "aquavis.trips.sql.template"; + public static final String CREATE_AQUAVIS_INTRAZONAL_TEMPLATE_PROPERTY = "aquavis.intrazonal.sql.template"; + + // Aquavis table query templates + public static final String QUERY_AQUAVIS_NETWORK_TEMPLATE_PROPERTY = "aquavis.network.query.template"; + public static final String QUERY_AQUAVIS_TRIPS_TEMPLATE_PROPERTY = "aquavis.trips.query.template"; + public static final String QUERY_AQUAVIS_INTRAZONAL_TEMPLATE_PROPERTY = "aquavis.intrazonal.query.template"; + + // inputs, outputs, and tokens + public static final String AQUAVIS_TEMPLATE_SCENARIOID_TOKEN_PROPERTY= "aquavis.template.scenarioId.token"; + public static final String SCENARIO_ID = "scenario.id"; + public static final String VEHICLE_CODE_MAPPING_FILE_PROPERTY = "emfac.2011.to.sandag.vehicle.code.mapping.file"; + + // switch if EMFAC is executed + public static final String EXECUTE_EMFAC="execute.emfac"; + + /** + * The property key for the boolean indicating if the (default) EMFAC + * tNCVehicle fractions should be preserved in the EMFAC input file (value is + * {@code true}), or if the model tNCVehicle fractions should be used (value is + * {@code false}). + */ + public static final String PRESERVE_EMFAC_VEHICLE_FRACTIONS_PROPERTY = "emfac.2011.preserve.emfac.vehicle.fractions"; + /** + * The property key for the boolean indicating whether or not the model + * (travel demand, not EMFAC) VMT includes totals for non-mutable tNCVehicle + * types. If it does, then the VMT will be scaled before adjusting the EMFAC + * input file. + */ + public static final String MODEL_VMT_INCLUDES_NON_MUTABLES_PROPERTY = "emfac.2011.model.vmt.includes.non.mutable.vehicles"; + + /** + * The property key for the location of the xls converter program. This + * program converts the malformed EMFAC2011 reference files to a (strictly) + * valid format, which can then be used by the rest of the model. + */ + public static final String XLS_CONVERTER_PROGRAM_PROPERTY = "emfac.2011.xls.converter.program"; + + /** + * The property key for the location (full path) of the AquaVis output + * intrazonal file. + */ + + /** + * Constructor specifying the resources used to build the properties. + * + * @param firstResource + * The first properties resource. + * + * @param additionalResources + * Any additional properties resources. + * + * @throws IllegalArgumentException + * if any of the required properties is missing, or if they are + * typed incorrectly. + */ + public Emfac2011Properties(String firstResource) + { + super(firstResource); + System.out.println("first property="+firstResource); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Runner.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Runner.java new file mode 100644 index 0000000..4622be2 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011Runner.java @@ -0,0 +1,216 @@ +package org.sandag.abm.reporting.emfac2011; + +import java.io.IOException; +import java.nio.file.FileSystems; +import java.nio.file.FileVisitOption; +import java.nio.file.FileVisitResult; +import java.nio.file.FileVisitor; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.PathMatcher; +import java.nio.file.Paths; +import java.nio.file.SimpleFileVisitor; +import java.nio.file.attribute.BasicFileAttributes; +import java.util.Arrays; +import java.util.Collections; +import java.util.EnumMap; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.LinkedHashSet; +import java.util.LinkedList; +import java.util.List; +import java.util.Map; +import java.util.Set; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.pb.sawdust.tabledata.DataRow; +import com.pb.sawdust.tabledata.DataTable; +import com.pb.sawdust.tabledata.basic.RowDataTable; +import com.pb.sawdust.tabledata.read.CsvTableReader; +import com.pb.sawdust.util.ProcessUtil; +import com.pb.sawdust.util.exceptions.RuntimeIOException; + +/** + * The {@code Emfac2011Runner} class is used to generate an EMFAC2011 SG input + * file adjusted for travel demand model results, and then run (via the end + * user) the EMFAC2011 SG model using those inputs. + * + * @author crf Started 2/9/12 9:17 AM + * Modified by Wu.Sun@sandag.org 1/24/2014 + */ +public class Emfac2011Runner { + private static final Logger LOGGER = LoggerFactory + .getLogger(Emfac2011Runner.class); + private final Emfac2011Properties properties; + private Emfac2011SqlUtil sqlUtil;; + + /** + * Constructor specifying the resources used to build the properties used + * for the EMFAC2011 SG run. + * + * @param propertyResource + * The first properties resource. + * + * @param additionalResources + * Any additional properties resources. + */ + public Emfac2011Runner(String propertyResource) { + properties = new Emfac2011Properties(propertyResource); + sqlUtil = new Emfac2011SqlUtil(properties); + } + + public void runEmfac2011() { + LOGGER.info("***************Running Emfac2011 for SANDAG***********************"); + LOGGER.info("Step 0: Setting up mutable tNCVehicle types"); + // have to call this first because it sets the mutable types, which are, + // used throughout the EMFAC2011 process + Path path = Paths + .get(properties.getString(Emfac2011Properties.VEHICLE_CODE_MAPPING_FILE_PROPERTY)); + + final Map> aquavisVehicleTypeToEmfacMapping = buildAquavisVehicleTypeToEmfacMapping(path); + + runEmfac2011(new Emfac2011Data(properties, sqlUtil) { + @Override + protected Map> getAquavisVehicleTypeToEmfacTypeMapping() { + return aquavisVehicleTypeToEmfacMapping; + } + }); + } + + /** + * Run the EMFAC2011 model. This method will process the model results (via + * AquaVis outputs), create an adjusted EMFAC2011 input file, and initiate + * the EMFAC2011 SG model. Because of the way it is set up, the user must + * actually set up and run the EMFAC2011 SG model, but this method will + * create a dialog window which will walk the user through the steps + * required to do that. + * + * @param emfac2011Data + * The {@code Emfac2011Data} instance corresponding to the model + * results/run. + */ + public void runEmfac2011(Emfac2011Data emfac2011Data) { + LOGGER.info("Step 1: Building Aquavis inputs from scenario: " + + properties.getString(Emfac2011Properties.SCENARIO_ID)); + AquavisDataBuilder builder = new AquavisDataBuilder(properties, sqlUtil); + builder.createAquavisInputs(); + LOGGER.info("Step 2: Processing aquavis data"); + DataTable data = emfac2011Data.processAquavisData(properties); + LOGGER.info("Step 3: Creating EMFAC2011 input file"); + Emfac2011InputFileCreator inputFileCreator = new Emfac2011InputFileCreator(); + Path inputfile = inputFileCreator.createInputFile(properties, data); + if((properties.getString(Emfac2011Properties.EXECUTE_EMFAC)).equalsIgnoreCase("true")){ + LOGGER.info("Step 4: Initiating EMFAC2011"); + RunEmfacDialog.createAndShowGUI(inputfile, this); + }else{ + LOGGER.info("Sipped--Step 4: Initiating EMFAC2011"); + } + LOGGER.info("EMFAC2011 run finished"); + } + + private Map> buildAquavisVehicleTypeToEmfacMapping( + Path vehicleCodeMappingFile) { + Map> mapping = new EnumMap<>( + SandagAutoModes.class); + for (SandagAutoModes type : SandagAutoModes.values()) + mapping.put(type, EnumSet.noneOf(Emfac2011VehicleType.class)); + + // file has one column = + // VEHICLE_CODE_MAPPING_EMFAC2011_VEHICLE_NAME_COLUMN + // the rest have names which, when made uppercase, should match + // VehicleType enum + DataTable vehicleCodeMapping = new RowDataTable(new CsvTableReader( + vehicleCodeMappingFile.toString())); + vehicleCodeMapping.setDataCoersion(true); + Set vehicleCodeColumns = new LinkedHashSet<>(); + for (String column : vehicleCodeMapping.getColumnLabels()) { + try { + SandagAutoModes.valueOf(column.toUpperCase()); + vehicleCodeColumns.add(column); + } catch (IllegalArgumentException e) { + // absorb - not a valid type column + } + } + Set mutableVehicleType = EnumSet + .noneOf(Emfac2011VehicleType.class); + for (DataRow row : vehicleCodeMapping) { + Emfac2011VehicleType emfac2011VehicleType = Emfac2011VehicleType + .getVehicleType(row + .getCellAsString(Emfac2011Definitions.VEHICLE_CODE_MAPPING_EMFAC2011_VEHICLE_NAME_COLUMN)); + // now dynamically setting mutable tNCVehicle types, so we need to not + // rely on the defaults + // if (!emfac2011VehicleType.isMutableType()) + // continue; //skip any non-mutable types, as they can't be used + for (String column : vehicleCodeColumns) { + if (row.getCellAsBoolean(column)) { + mutableVehicleType.add(emfac2011VehicleType); // if a + // mapping + // exists, + // then the + // EMFAC + // tNCVehicle + // type is + // assumed + // to + // be + // mutable + mapping.get(SandagAutoModes.valueOf(column.toUpperCase())) + .add(emfac2011VehicleType); + } + } + } + Emfac2011VehicleType.setMutableTypes(mutableVehicleType); + Map> finalMapping = new HashMap<>(); + for (SandagAutoModes type : mapping.keySet()) + finalMapping.put(type.name(), mapping.get(type)); + return finalMapping; + } + + void runEmfac2011Program() { + final Path emfacInstallationDir = Paths + .get(properties + .getString(Emfac2011Properties.EMFAC2011_INSTALLATION_DIR_PROPERTY)); + final PathMatcher matcher = FileSystems.getDefault().getPathMatcher( + "glob:*.lnk"); + final List link = new LinkedList<>(); + FileVisitor visitor = new SimpleFileVisitor() { + + @Override + public FileVisitResult visitFile(Path file, + BasicFileAttributes attrs) throws IOException { + Path name = file.getFileName(); + if (name != null && matcher.matches(name)) { + link.add(file); + return FileVisitResult.TERMINATE; + } + return FileVisitResult.CONTINUE; + } + }; + + try { + Files.walkFileTree(emfacInstallationDir, + Collections. emptySet(), 1, visitor); + } catch (IOException e) { + throw new RuntimeIOException(e); + } + + if (link.size() == 0) + throw new IllegalStateException( + "Cannot find Emfac2011 shortcut in " + emfacInstallationDir); + ProcessUtil.runProcess(Arrays.asList("cmd", "/c", link.get(0) + .toString())); + } + + public static void main(String... args) { + double startTime = System.currentTimeMillis(); + // do work + new Emfac2011Runner(args[0]).runEmfac2011(); + // time stamp + LOGGER.info("Emfac2011 completed in: " + + (float) (((System.currentTimeMillis() - startTime) / 1000.0) / 60.0) + + " minutes."); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011SpeedCategory.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011SpeedCategory.java new file mode 100644 index 0000000..1d76b98 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011SpeedCategory.java @@ -0,0 +1,73 @@ +package org.sandag.abm.reporting.emfac2011; + +/** + * The {@code EmfacSpeedClass} enum represents the speed categories used in the + * EMFAC2011 model. + * + * @author crf Started 2/9/12 5:58 AM + */ +public enum Emfac2011SpeedCategory +{ + SPEED_0_5(5, "5MPH"), SPEED_5_10(10, "10MPH"), SPEED_10_15(15, "15MPH"), SPEED_15_20(20, + "20MPH"), SPEED_20_25(25, "25MPH"), SPEED_25_30(30, "30MPH"), SPEED_30_35(35, "35MPH"), SPEED_35_40( + 40, "40MPH"), SPEED_40_45(45, "45MPH"), SPEED_45_50(50, "50MPH"), SPEED_50_55(55, + "55MPH"), SPEED_55_60(60, "60MPH"), SPEED_60_65(65, "65MPH"), SPEED_65_70plus(1000, + "70MPH"); // big upper bound + + private final String name; + private final double upperBound; + + private Emfac2011SpeedCategory(double upperBound, String name) + { + this.upperBound = upperBound; + this.name = name; + } + + /** + * Get the EMFAC name for this speed category. + * + * @return this speed category's name. + */ + public String getName() + { + return name; + } + + /** + * Get the {@code SpeedCategory} for a given speed. + * + * @param speed + * The speed in question. + * + * @return the {@code SpeedCategory} for the given speed. + * + * @throws IllegalArgumentException + * if {@code speed} < 0. + */ + public static Emfac2011SpeedCategory getSpeedCategory(double speed) + { + if (speed < 0) + throw new IllegalArgumentException("Negative speeds are not allowed: " + speed); + for (Emfac2011SpeedCategory sc : values()) + if (speed <= sc.upperBound) return sc; + throw new IllegalStateException("Couldn't find speed category for " + speed); + } + + /** + * Get the {@code SpeedCategory} corresponding to an EMFAC name. + * + * @param name + * The EMFAC speed category name. + * + * @return the {@code SpeedCategory} corresponding to {@code name}. + * + * @throws IllegalArgumentException + * if {@code name} is not a valid EMFAC speed category name. + */ + public static Emfac2011SpeedCategory getTypeForName(String name) + { + for (Emfac2011SpeedCategory type : values()) + if (type.name.equals(name)) return type; + throw new IllegalArgumentException("Type for name not found: " + name); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011SqlUtil.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011SqlUtil.java new file mode 100644 index 0000000..56a719e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011SqlUtil.java @@ -0,0 +1,145 @@ +package org.sandag.abm.reporting.emfac2011; + +import java.io.FileReader; +import java.io.IOException; +import java.nio.file.Path; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; + +import nl.tudelft.simulation.logger.Logger; + +import com.pb.sawdust.util.exceptions.RuntimeIOException; +import com.pb.sawdust.util.exceptions.RuntimeWrappingException; +import com.pb.sawdust.util.property.PropertyDeluxe; + +/** + * @author crf Started 2/9/12 9:17 AM + * Modified by Wu.Sun@sandag.org 1/21/2014 + */ + +public class Emfac2011SqlUtil { + + private final String connectionUrl; + + public Emfac2011SqlUtil(PropertyDeluxe properties) { + connectionUrl = formConnectionUrl( + properties + .getString(Emfac2011Properties.REPORTS_DATABASE_IPADDRESS_PROPERTY), + properties + .getInt(Emfac2011Properties.REPORTS_DATABASE_PORT_PROPERTY), + properties + .getString(Emfac2011Properties.REPORTS_DATABASE_NAME_PROPERTY), + properties + .hasKey(Emfac2011Properties.REPORTS_DATABASE_USERNAME_PROPERTY) ? properties + .getString(Emfac2011Properties.REPORTS_DATABASE_USERNAME_PROPERTY) + : null, + properties + .hasKey(Emfac2011Properties.REPORTS_DATABASE_PASSWORD_PROPERTY) ? properties + .getString(Emfac2011Properties.REPORTS_DATABASE_PASSWORD_PROPERTY) + : null, + properties + .hasKey(Emfac2011Properties.REPORTS_DATABASE_INSTANCE_PROPERTY) ? properties + .getString(Emfac2011Properties.REPORTS_DATABASE_INSTANCE_PROPERTY) + : null); + } + + public void detemplifyAndRunScript(Path script, String scenarioId, + String scenarioIdToken) { + String s = readFile(script).replace(scenarioIdToken, scenarioId); + try (Connection connection = getConnection(); + Statement statement = connection.createStatement()) { + connection.setAutoCommit(false); + statement.execute(s); + connection.commit(); + } catch (SQLException e) { + throw new RuntimeWrappingException(e); + } + } + + public ArrayList> queryAquavisTables(Path script, + String scenarioId, String scenarioIdToken) { + ArrayList> table = null; + String s = readFile(script).replace(scenarioIdToken, scenarioId); + try (Connection connection = getConnection(); + Statement statement = connection.createStatement()) { + System.out.println("query="+s); + table = extract(statement.executeQuery(s)); + connection.close(); + } catch (SQLException e) { + throw new RuntimeWrappingException(e); + } + return table; + } + + private ArrayList> extract(ResultSet resultSet) + throws SQLException { + ArrayList> table; + int columnCount = resultSet.getMetaData().getColumnCount(); + + if (resultSet.getType() == ResultSet.TYPE_FORWARD_ONLY) + table = new ArrayList>(); + else { + resultSet.last(); + table = new ArrayList>(resultSet.getRow()); + resultSet.beforeFirst(); + } + + for (ArrayList row; resultSet.next(); table.add(row)) { + row = new ArrayList(columnCount); + + for (int c = 1; c <= columnCount; ++c) + row.add(resultSet.getString(c).intern()); + } + return table; + } + + private String readFile(Path file) { + try (FileReader reader = new FileReader(file.toFile())) { + StringBuilder sb = new StringBuilder(); + char[] buffer = new char[8192]; + int readCount; + while ((readCount = reader.read(buffer, 0, buffer.length)) > 0) + sb.append(buffer, 0, readCount); + return sb.toString(); + } catch (IOException e) { + throw new RuntimeIOException(e); + } + } + + private String formConnectionUrl(String ipAddress, int port, + String databaseName, String username, String password, + String instance) { + String url = "jdbc:jtds:sqlserver://" + ipAddress + ":" + port + "/" + + databaseName; + if (username != null) + url += ";user=" + username + ";" + password; // not + // super + // secure, + // btu + // ok + // for + // now + // - + // probably + // will + // use + // SSO + // normally + if (instance != null) + url += ";instance=" + instance; + return url; + } + + private Connection getConnection() throws SQLException { + try { + Class.forName("net.sourceforge.jtds.jdbc.Driver"); + } catch (ClassNotFoundException e) { + throw new RuntimeWrappingException(e); + } + return DriverManager.getConnection(connectionUrl); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011VehicleType.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011VehicleType.java new file mode 100644 index 0000000..0ec7a68 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/Emfac2011VehicleType.java @@ -0,0 +1,146 @@ +package org.sandag.abm.reporting.emfac2011; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; + +/** + * The {@code EmfacVehicleType} enum represents the EMFAC2011 tNCVehicle types. + * + * @author crf Started 2/8/12 8:54 AM + */ +public enum Emfac2011VehicleType +{ + OTHER_BUSES_DSL("All Other Buses - DSL", "OBUS - DSL", false), LDA_DSL("LDA - DSL", + "LDA - DSL", true), LDA_GAS("LDA - GAS", "LDA - GAS", true), LDT1_DSL("LDT1 - DSL", + "LDT1 - DSL", true), LDT1_GAS("LDT1 - GAS", "LDT1 - GAS", true), LDT2_DSL("LDT2 - DSL", + "LDT2 - DSL", true), LDT2_GAS("LDT2 - GAS", "LDT2 - GAS", true), LHD1_DSL("LHD1 - DSL", + "LHDT1 - DSL", true), LHE1_GAS("LHD1 - GAS", "LHDT1 - GAS", true), LHD2_DSL( + "LHD2 - DSL", "LHDT2 - DSL", true), LHD2_GAS("LHD2 - GAS", "LHDT2 - GAS", true), MCY_GAS( + "MCY - GAS", "MCY - GAS", true), MDV_DSL("MDV - DSL", "MDV - DSL", true), MDV_GAS( + "MDV - GAS", "MDV - GAS", true), MH_DSL("MH - DSL", "MH - DSL", false), MH_GAS( + "MH - GAS", "MH - GAS", false), MOTOR_COACH_DSL("Motor Coach - DSL", "OBUS - DSL", + false), OBUS_GAS("OBUS - GAS", "OBUS - GAS", false), PTO_DSL("PTO - DSL", "HHDT - DSL", + false), SBUS_DSL("SBUS - DSL", "SBUS - DSL", false), SBUS_GAS("SBUS - GAS", + "SBUS - GAS", false), T6_AG_DSL("T6 Ag - DSL", "MHDT - DSL", false), T6_CAIRP_HEAVY_DSL( + "T6 CAIRP heavy - DSL", "MHDT - DSL", false), T6_CAIRP_SMALL_DSL( + "T6 CAIRP small - DSL", "MHDT - DSL", false), T6_INSTATE_CONSTRUCTION_HEAVY_DSL( + "T6 instate construction heavy - DSL", "MHDT - DSL", false), T6_INSTATE_CONSTRUCTION_SMALL_DSL( + "T6 instate construction small - DSL", "MHDT - DSL", false), T6_INSTATE_HEAVY_DSL( + "T6 instate heavy - DSL", "MHDT - DSL", false), T6_INSTATE_SMALL_DSL( + "T6 instate small - DSL", "MHDT - DSL", false), T6_OOS_HEAVY_DSL("T6 OOS heavy - DSL", + "MHDT - DSL", false), T6_OOS_SMALL_DSL("T6 OOS small - DSL", "MHDT - DSL", false), T6_PUBLIC_DSL( + "T6 public - DSL", "MHDT - DSL", false), T6_UTILITY_DSL("T6 utility - DSL", + "MHDT - DSL", false), T6TS_GAS("T6TS - GAS", "MHDT - GAS", false), T7_AG_DSL( + "T7 Ag - DSL", "HHDT - DSL", false), T7_CAIRP_DSL("T7 CAIRP - DSL", "HHDT - DSL", false), T7_CAIRP_CONSTRUCTION_DSL( + "T7 CAIRP construction - DSL", "HHDT - DSL", false), T7_NNOOS_DSL("T7 NNOOS - DSL", + "HHDT - DSL", false), T7_NOOS_DSL("T7 NOOS - DSL", "HHDT - DSL", false), T7_OTHER_PORT_DSL( + "T7 other port - DSL", "HHDT - DSL", false), T7_POAK_DSL("T7 POAK - DSL", "HHDT - DSL", + false), T7_POLA_DSL("T7 POLA - DSL", "HHDT - DSL", false), T7_PUBLIC_DSL( + "T7 public - DSL", "HHDT - DSL", false), T7_SINGLE_DSL("T7 Single - DSL", "HHDT - DSL", + false), T7_SINGLE_CONSTRUCTION_DSL("T7 single construction - DSL", "HHDT - DSL", false), T7_SWCV_DSL( + "T7 SWCV - DSL", "HHDT - DSL", false), T7_TRACTOR_DSL("T7 tractor - DSL", "HHDT - DSL", + false), T7_TRACTOR_CONSTRUCTION_DSL("T7 tractor construction - DSL", "HHDT - DSL", + false), T7_UTILITY_DSL("T7 utility - DSL", "HHDT - DSL", false), T7IS_GAS("T7IS - GAS", + "HHDT - GAS", false), UBUS_DSL("UBUS - DSL", "UBUS - DSL", false), UBUS_GAS( + "UBUS - GAS", "UBUS - GAS", false); + + private final String name; + private final String emfac2007Name; + private final boolean isMutableType; + + private Emfac2011VehicleType(String name, String emfac2007Name, boolean isMutableType) + { + this.name = name; + this.emfac2007Name = emfac2007Name; + this.isMutableType = isMutableType; + } + + /** + * Get the name of the tNCVehicle type. This is the name used by the EMFAC2011 + * model. + * + * @return the name of the tNCVehicle type. + */ + public String getName() + { + return name; + } + + /** + * Get this tNCVehicle type's equivalent EMFAC2007 tNCVehicle type name. + * + * @return the EMFAC2007 tNCVehicle type corresponding to this tNCVehicle type. + */ + public String getEmfac2007Name() + { + return emfac2007Name; + } + + /** + * Determine if this tNCVehicle type is mutable. If a tNCVehicle type is mutable, + * then its EMFAC2011 SG inputs may be adjusted to account for travel demand + * model results. + * + * @return {@code true} if this tNCVehicle type is mutable, {@code false} if + * not. + */ + public boolean isMutableType() + { + return mutableTypes.contains(this); + } + + private static Set mutableTypes; + + static + { + Set set = EnumSet.noneOf(Emfac2011VehicleType.class); + for (Emfac2011VehicleType type : Emfac2011VehicleType.values()) + if (type.isMutableType) set.add(type); + setMutableTypes(set); + } + + /** + * Set the mutable tNCVehicle types. This need only be called if the default + * mutable types are unsatisfactory for the particular application; however, + * if it needs to be called, then it should be before any of the + * EMFAC2011/Aquavis processing commences. + * + * @param mutableTypes + * The set of mutable tNCVehicle types for processing. + */ + public static void setMutableTypes(Set mutableTypes) + { + Emfac2011VehicleType.mutableTypes = Collections.unmodifiableSet(mutableTypes); + } + + /** + * Get the tNCVehicle type corresponding to the given (EMFAC2011) name. + * + * @param name + * The tNCVehicle type name used in the EMFAC2011 tNCVehicle type. + * + * @return the tNCVehicle type corresponding to {@code name}. + * + * @throws IllegalArgumentException + * if {@code name} does not correspond to any tNCVehicle type. + */ + public static Emfac2011VehicleType getVehicleType(String name) + { + for (Emfac2011VehicleType type : values()) + if (type.getName().equals(name)) return type; + throw new IllegalArgumentException("No EMFAC tNCVehicle type corresponding to: " + name); + } + + /** + * Get the set of EMFAC2011 tNCVehicle types which are mutable. If a tNCVehicle + * type is mutable, then its EMFAC2011 SG inputs may be adjusted to account + * for travel demand model results. + * + * @return a set holding the mutable EMFAC2011 tNCVehicle types. + */ + public static Set getMutableVehicleTypes() + { + return mutableTypes; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/RunEmfacDialog.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/RunEmfacDialog.java new file mode 100644 index 0000000..a19b83d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/RunEmfacDialog.java @@ -0,0 +1,174 @@ +package org.sandag.abm.reporting.emfac2011; + +import java.awt.GridBagConstraints; +import java.awt.GridBagLayout; +import java.awt.event.ActionEvent; +import java.awt.event.ActionListener; +import java.awt.event.WindowAdapter; +import java.awt.event.WindowEvent; +import java.nio.file.Path; +import javax.swing.JButton; +import javax.swing.JFrame; +import javax.swing.JLayeredPane; +import javax.swing.JPanel; +import javax.swing.JScrollPane; +import javax.swing.JTextArea; +import com.pb.sawdust.util.exceptions.RuntimeInterruptedException; + +/** + * The {@code HelpDialog} ... + * + * @author crf Started 2/9/12 3:57 PM + */ +class RunEmfacDialog + extends JPanel + implements ActionListener +{ + private static final long serialVersionUID = -3645537208340049132L; + private final JButton button; + private final JLayeredPane pane; + private final Emfac2011Runner emfac2011Runner; + + public RunEmfacDialog(Path outputPath, Emfac2011Runner emfac2011Runner) + { + super(new GridBagLayout()); + + StringBuilder sb = new StringBuilder(); + sb.append("\n ") + .append("Almost there! Press the button to start EMFAC2011, then follow these directions.") + .append("\n\n"); + sb.append(" ") + .append("EMFAC2011 should have booted up. If not, check that the installation directory is defined correctly in the properties file.") + .append("\n\n"); + sb.append(" ").append("The following steps will take you through running the program.") + .append("\n\n"); + sb.append(" ") + .append("1) In the \"Regional Scenarios\" box, hit the \"Load Regional Scenarios (External Files)\" button.") + .append("\n\n"); + sb.append(" ").append("2) Browse to and select: ").append(outputPath).append("\n\n"); + sb.append(" ") + .append("3) The EMFAC2011-SG-Scenario Builder window should appear. Press the \"Save and Continue\" button.") + .append("\n\n"); + sb.append(" ").append("4) A message box will appear. Click \"Yes\"").append("\n\n"); + sb.append(" ") + .append("5) In the EMFAC2011-SG model window, hit the \"Verify Speed Data Quality\" button.") + .append("\n\n"); + sb.append(" ") + .append("6) If there are no errors, hit the \"Continue\" button in the \"Verify Speed Inputs\" window.") + .append("\n\n"); + sb.append(" ") + .append("7) In the EMFAC2011-SG model window, hit the \"Save Scenarios\" button.") + .append("\n\n"); + sb.append(" ") + .append("8) Select the same file that we loaded in step (2). Say \"Yes\" to the question about replacing the file.") + .append("\n\n"); + sb.append(" ").append("9) EMFAC2011 will tell you it saved the input file. Click \"OK\"") + .append("\n\n"); + sb.append(" ") + .append("10) In the EMFAC2011-SG model window, hit the \"Execute Model\" button.") + .append("\n\n"); + sb.append(" ") + .append("11) In the EMFAC2011-SG-Model Execution Options window do the following") + .append("\n"); + sb.append(" ") + .append("\ta) In the \"Input Parameters\" box, the \"Export Default Input Parameters\" check box should NOT be checked.") + .append("\n"); + sb.append(" ") + .append("\tb) In the \"Model Outputs\" box, choose \"XLS\" as the output format, and check the \"Create Additional Summary Outputs\" \n\t checkbox. Leave the \"Create Separate Output Files for Each Regional Scenario\" checkbox unchecked.") + .append("\n"); + sb.append(" ").append("\tc) Hit the \"Start\" button.").append("\n\n"); + sb.append(" ") + .append("12) The EMFAC2011 model should run, and then pop up a dialog box saying it finished. Click \"OK\"") + .append("\n\n"); + sb.append(" ").append("13) Click the \"Exit EMFAC2011-SG\" button.").append("\n\n"); + sb.append(" ").append("14) All done! Close this window when you are finished."); + + JTextArea textArea = new JTextArea(40, 80); + textArea.setEditable(false); + textArea.setText(sb.toString()); + textArea.setCaretPosition(0); + textArea.setLineWrap(true); + textArea.setWrapStyleWord(true); + JScrollPane scrollPane = new JScrollPane(textArea); + GridBagConstraints c = new GridBagConstraints(); + c.gridwidth = GridBagConstraints.REMAINDER; + c.fill = GridBagConstraints.HORIZONTAL; + c.fill = GridBagConstraints.BOTH; + c.weightx = 1.0; + c.weighty = 1.0; + + pane = new JLayeredPane(); + scrollPane.setSize(850, 675); + button = new JButton("Start EMFAC2011"); + button.addActionListener(this); + button.setLocation(500, 15); + button.setSize(150, 20); + pane.add(button, 0, -1); + pane.add(scrollPane); + add(pane); + add(pane, c); + + this.emfac2011Runner = emfac2011Runner; + } + + public static void createAndShowGUI(Path inputFile, Emfac2011Runner emfac2011Runner) + { + final Object lock = new Object(); + final JFrame frame = new JFrame("Run EMFAC2011"); + frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); + frame.add(new RunEmfacDialog(inputFile, emfac2011Runner)); + frame.setSize(800, 700); + frame.setVisible(true); + + Thread thread = new Thread() + { + @Override + public void run() + { + synchronized (lock) + { + while (frame.isVisible()) + { + try + { + lock.wait(); + } catch (InterruptedException e) + { + throw new RuntimeInterruptedException(e); + } + } + } + } + }; + thread.start(); + + frame.addWindowListener(new WindowAdapter() + { + @Override + public void windowClosing(WindowEvent arg0) + { + synchronized (lock) + { + frame.setVisible(false); + lock.notify(); + } + } + }); + try + { + thread.join(); + } catch (InterruptedException e) + { + throw new RuntimeInterruptedException(e); + } + + } + + @Override + public void actionPerformed(ActionEvent e) + { + pane.remove(button); + pane.repaint(); + emfac2011Runner.runEmfac2011Program(); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/SandagAutoModes.java b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/SandagAutoModes.java new file mode 100644 index 0000000..4cdb52a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/reporting/emfac2011/SandagAutoModes.java @@ -0,0 +1,11 @@ +package org.sandag.abm.reporting.emfac2011; + +/** + * The {@code VehicleType} ... + * + * @author crf Started 12/7/12 3:28 PM + */ +public enum SandagAutoModes +{ + SOV_GP, SOV_PAY, SR2_GP, SR2_HOV, SR2_PAY, SR3_GP, SR3_HOV, SR3_PAY, LHDN, MHDN, HHDN, LHDT, MHDT, HHDT, UBUS +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventDmuFactory.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventDmuFactory.java new file mode 100644 index 0000000..2eb422a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventDmuFactory.java @@ -0,0 +1,42 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.specialevent; + +import java.io.Serializable; +import org.sandag.abm.application.SandagModelStructure; + +/** + * ArcCtrampDmuFactory is a class that creates Visitor Model DMU objects + * + * @author Joel Freedman + */ +public class SpecialEventDmuFactory + implements SpecialEventDmuFactoryIf, Serializable +{ + + private SandagModelStructure sandagModelStructure; + + public SpecialEventDmuFactory(SandagModelStructure modelStructure) + { + this.sandagModelStructure = modelStructure; + } + + public SpecialEventTripModeChoiceDMU getSpecialEventTripModeChoiceDMU() + { + return new SpecialEventTripModeChoiceDMU(sandagModelStructure, null); + } + + public SpecialEventOriginChoiceDMU getSpecialEventOriginChoiceDMU() + { + return new SpecialEventOriginChoiceDMU(sandagModelStructure); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventDmuFactoryIf.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventDmuFactoryIf.java new file mode 100644 index 0000000..33e5633 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventDmuFactoryIf.java @@ -0,0 +1,13 @@ +package org.sandag.abm.specialevent; + +/** + * A DMU factory interface + */ +public interface SpecialEventDmuFactoryIf +{ + + SpecialEventTripModeChoiceDMU getSpecialEventTripModeChoiceDMU(); + + SpecialEventOriginChoiceDMU getSpecialEventOriginChoiceDMU(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventModel.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventModel.java new file mode 100644 index 0000000..ddc0782 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventModel.java @@ -0,0 +1,347 @@ +package org.sandag.abm.specialevent; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +/** + * Trips for special events. + * + * This programs models trips to special events using the Event Model framework. + * The Event Model framework generates and distributes trips. These trips are + * put through a mode choice model. User benefits are optionally calculated and + * written to a SUMMIT formatted file. + * + */ +public final class SpecialEventModel +{ + + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + + private MatrixDataServerRmi ms; + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + private HashMap rbMap; + private McLogsumsCalculator logsumsCalculator; + private AutoTazSkimsCalculator tazDistanceCalculator; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private boolean seek; + private int traceId; + + private TableDataSet eventData; + private double sampleRate = 1; + + /** + * Default Constructor. + */ + private SpecialEventModel(HashMap rbMap) + { + this.rbMap = rbMap; + mgraManager = MgraDataManager.getInstance(rbMap); + tazManager = TazDataManager.getInstance(rbMap); + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + + // read the event data + String eventFile = Util.getStringValueFromPropertyMap(rbMap, "specialEvent.event.file"); + eventFile = directory + eventFile; + eventData = readFile(eventFile); + + seek = new Boolean(Util.getStringValueFromPropertyMap(rbMap, "specialEvent.seek")); + traceId = new Integer(Util.getStringValueFromPropertyMap(rbMap, "specialEvent.trace")); + + } + + /** + * Read the file and return the TableDataSet. + * + * @param fileName + * @return data + */ + private TableDataSet readFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet data; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + data = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + return data; + } + + /** + * @return the sampleRate + */ + public double getSampleRate() + { + return sampleRate; + } + + /** + * @param sampleRate + * the sampleRate to set + */ + public void setSampleRate(double sampleRate) + { + this.sampleRate = sampleRate; + } + + /** + * Run the Event Model. + * + * The Event Model is run for each mgra specified in the events.file + */ + public void runModel() + { + + SandagModelStructure modelStructure = new SandagModelStructure(); + + SpecialEventDmuFactoryIf dmuFactory = new SpecialEventDmuFactory(modelStructure); + + SpecialEventTourManager tourManager = new SpecialEventTourManager(rbMap, eventData); + + tourManager.generateTours(); + SpecialEventTour[] tours = tourManager.getTours(); + + tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + logsumsCalculator = new McLogsumsCalculator(); + logsumsCalculator.setupSkimCalculators(rbMap); + logsumsCalculator.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + SpecialEventOriginChoiceModel originChoiceModel = new SpecialEventOriginChoiceModel(rbMap, + dmuFactory, eventData); + originChoiceModel.calculateSizeTerms(dmuFactory); + originChoiceModel.calculateTazProbabilities(dmuFactory); + + SpecialEventTripModeChoiceModel tripModeChoiceModel = new SpecialEventTripModeChoiceModel( + rbMap, modelStructure, dmuFactory, logsumsCalculator, eventData); + + // Run models for array of tours + for (int i = 0; i < tours.length; ++i) + { + + SpecialEventTour tour = tours[i]; + + // Wu added for sampling tours + double rand = tour.getRandom(); + if (rand > sampleRate) continue; + + if (i < 10 || i % 1000 == 0) logger.info("Processing tour " + (i + 1)); + + if (seek && tour.getID() != traceId) continue; + + if (tour.getID() == traceId) tour.setDebugChoiceModels(true); + originChoiceModel.chooseOrigin(tour); + // generate trips and choose mode for them + SpecialEventTrip[] trips = new SpecialEventTrip[2]; + int tripNumber = 0; + + // generate an outbound trip from the tour origin to the destination + // and choose a mode + trips[tripNumber] = new SpecialEventTrip(tour, true); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + + // generate an inbound trip from the tour destination to the origin + // and choose a mode + trips[tripNumber] = new SpecialEventTrip(tour, false); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + + // set the trips in the tour object + tour.setTrips(trips); + + } + + tourManager.writeOutputFile(rbMap); + + logger.info("Special Event Model successfully completed!"); + + } + + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * Run Special Events Model. + * + * The Special Events Model generates, distributes, and chooses modes for + * attendees of sporting events and similar activities. + */ + public static void main(String[] args) + { + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running Special Event Model")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + SpecialEventModel specialEventModel = new SpecialEventModel(pMap); + + //Wu added for sampling special event tours based on sample rate + float sampleRate = 1.0f; + int iteration = 1; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + logger.info("Special Event Model:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + specialEventModel.setSampleRate(sampleRate); + + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = specialEventModel.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + specialEventModel.ms = matrixServer; + } else + { + specialEventModel.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + specialEventModel.ms.testRemote("SpecialEventModel"); + + // these methods need to be called to set the matrix data + // manager in the matrix data server + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(specialEventModel.ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + specialEventModel.runModel(); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventOriginChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventOriginChoiceDMU.java new file mode 100644 index 0000000..0f418bc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventOriginChoiceDMU.java @@ -0,0 +1,205 @@ +package org.sandag.abm.specialevent; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class SpecialEventOriginChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger("specialEventModel"); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected float tourDepartPeriod; + protected float tourArrivePeriod; + protected int purpose; + protected double[][] sizeTerms; // by + // purpose, + // alternative + // (taz + // or + // sampled + // mgras) + + protected double nmWalkTimeOut; + protected double nmWalkTimeIn; + protected double nmBikeTimeOut; + protected double nmBikeTimeIn; + protected double lsWgtAvgCostM; + protected double lsWgtAvgCostD; + protected double lsWgtAvgCostH; + + public SpecialEventOriginChoiceDMU(SandagModelStructure modelStructure) + { + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + /** + * @return the sizeTerm. The size term is the size of the origin taz. + */ + public double getSizeTerm(int alt) + { + return sizeTerms[purpose][alt]; + } + + /** + * @param sizeTerms + * the sizeTerms to set. The size term is the array of origin taz + * sizes. + */ + public void setSizeTerms(double[][] sizeTerms) + { + this.sizeTerms = sizeTerms; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the purpose + */ + public int getPurpose() + { + return purpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(int purpose) + { + this.purpose = purpose; + } + + public float getTimeOutbound() + { + return tourDepartPeriod; + } + + public float getTimeInbound() + { + return tourArrivePeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(float tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(float tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTimeOutbound", 0); + methodIndexMap.put("getTimeInbound", 1); + methodIndexMap.put("getSizeTerm", 2); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getTimeOutbound(); + break; + case 1: + returnValue = getTimeInbound(); + break; + case 2: + returnValue = getSizeTerm(arrayIndex); + break; + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventOriginChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventOriginChoiceModel.java new file mode 100644 index 0000000..690775a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventOriginChoiceModel.java @@ -0,0 +1,384 @@ +package org.sandag.abm.specialevent; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class SpecialEventOriginChoiceModel +{ + + private double[][] mgraSizeTerms; // by + // purpose, + // MGRA + private double[][] tazSizeTerms; // by + // purpose, + // TAZ + private double[][][] mgraProbabilities; // by + // purpose, + // tazNumber, + // mgra + // index + // (sequential, + // 0-based) + private Matrix[] tazProbabilities; // by + // purpose, + // origin + // TAZ, + // destination + // TAZ + + private TableDataSet alternativeData; // the + // alternatives, + // with + // a + // dest + // field + // indicating + // tazNumber + + private transient Logger logger = Logger.getLogger("specialEventModel"); + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private ChoiceModelApplication destModel; + private UtilityExpressionCalculator sizeTermUEC; + private HashMap rbMap; + private HashMap purposeMap; // string + // is + // purpose, + // int + // is + // alternative + // for + // size + // terms + + /** + * Constructor + * + * @param propertyMap + * Resource properties file map. + * @param dmuFactory + * Factory object for creation of airport model DMUs + */ + public SpecialEventOriginChoiceModel(HashMap rbMap, + SpecialEventDmuFactoryIf dmuFactory, TableDataSet eventData) + { + + this.rbMap = rbMap; + + tazManager = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String destUecFileName = Util.getStringValueFromPropertyMap(rbMap, + "specialEvent.dc.uec.file"); + destUecFileName = uecFileDirectory + destUecFileName; + + int dataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "specialEvent.dc.data.page")); + int sizePage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "specialEvent.dc.size.page")); + int modelPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "specialEvent.dc.model.page")); + + // read the model pages from the property file, create one choice model + // for each + // get page from property file + + SpecialEventOriginChoiceDMU dcDmu = dmuFactory.getSpecialEventOriginChoiceDMU(); + + // create a ChoiceModelApplication object for the filename, model page + // and data page. + destModel = new ChoiceModelApplication(destUecFileName, modelPage, dataPage, rbMap, + (VariableTable) dcDmu); + + // get the alternative data from the first segment + UtilityExpressionCalculator uec = destModel.getUEC(); + alternativeData = uec.getAlternativeData(); + + // create a UEC to solve size terms for each MGRA + SpecialEventOriginChoiceDMU dmu = dmuFactory.getSpecialEventOriginChoiceDMU(); + sizeTermUEC = new UtilityExpressionCalculator(new File(destUecFileName), sizePage, + dataPage, rbMap, dmu); + + } + + /** + * Calculate size terms + */ + public void calculateSizeTerms(SpecialEventDmuFactoryIf dmuFactory) + { + + logger.info("Calculating Special Event Origin Choice Model Size Terms"); + + ArrayList mgras = mgraManager.getMgras(); + int[] mgraTaz = mgraManager.getMgraTaz(); + int maxMgra = mgraManager.getMaxMgra(); + int maxTaz = tazManager.getMaxTaz(); + int purposes = sizeTermUEC.getNumberOfAlternatives(); + + // set up the map of string purpose to integer purpose + String[] altNames = sizeTermUEC.getAlternativeNames(); + purposeMap = new HashMap(); + for (int i = 0; i < altNames.length; ++i) + { + purposeMap.put(altNames[i], i); + } + + mgraSizeTerms = new double[purposes][maxMgra + 1]; + tazSizeTerms = new double[purposes][maxTaz + 1]; + IndexValues iv = new IndexValues(); + SpecialEventOriginChoiceDMU aDmu = dmuFactory.getSpecialEventOriginChoiceDMU(); + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + int taz = mgraTaz[mgra]; + iv.setZoneIndex(mgra); + double[] utilities = sizeTermUEC.solve(iv, aDmu, null); + + // store the size terms + for (int purpose = 0; purpose < purposes; ++purpose) + { + + mgraSizeTerms[purpose][mgra] = utilities[purpose]; + tazSizeTerms[purpose][taz] += utilities[purpose]; + } + + } + + // now calculate probability of selecting each MGRA within each TAZ for + // SOA + mgraProbabilities = new double[purposes][maxTaz + 1][]; + int[] tazs = tazManager.getTazs(); + + for (int purpose = 0; purpose < purposes; ++purpose) + { + for (int taz = 0; taz < tazs.length; ++taz) + { + int tazNumber = tazs[taz]; + int[] mgraArray = tazManager.getMgraArray(tazNumber); + + // initialize the vector of mgras for this purpose-taz + mgraProbabilities[purpose][tazNumber] = new double[mgraArray.length]; + + // now calculate the cumulative probability distribution + double lastProb = 0.0; + for (int mgra = 0; mgra < mgraArray.length; ++mgra) + { + + int mgraNumber = mgraArray[mgra]; + if (tazSizeTerms[purpose][tazNumber] > 0.0) + mgraProbabilities[purpose][tazNumber][mgra] = lastProb + + mgraSizeTerms[purpose][mgraNumber] + / tazSizeTerms[purpose][tazNumber]; + lastProb = mgraProbabilities[purpose][tazNumber][mgra]; + } + if (tazSizeTerms[purpose][tazNumber] > 0.0 && Math.abs(lastProb - 1.0) > 0.000001) + logger.info("Error: purpose " + purpose + " taz " + tazNumber + + " cum prob adds up to " + lastProb); + } + + } + + // calculate logged size terms for mgra and taz vectors to be used in + // dmu + for (int purpose = 0; purpose < purposes; ++purpose) + { + for (int taz = 0; taz < tazSizeTerms[purpose].length; ++taz) + if (tazSizeTerms[purpose][taz] > 0.0) + tazSizeTerms[purpose][taz] = Math.log(tazSizeTerms[purpose][taz] + 1.0); + + for (int mgra = 0; mgra < mgraSizeTerms[purpose].length; ++mgra) + if (mgraSizeTerms[purpose][mgra] > 0.0) + mgraSizeTerms[purpose][mgra] = Math.log(mgraSizeTerms[purpose][mgra] + 1.0); + + } + logger.info("Finished Calculating Special Event Tour Origin Choice Model Size Terms"); + } + + /** + * Calculate taz probabilities. This method initializes and calculates the + * tazProbabilities array. + */ + public void calculateTazProbabilities(SpecialEventDmuFactoryIf dmuFactory) + { + + if (tazSizeTerms == null) + { + logger.error("Error: attemping to execute SpecialEventTourOriginChoiceModel.calculateTazProbabilities() before calling calculateMgraProbabilities()"); + throw new RuntimeException(); + } + + logger.info("Calculating Special Event Model TAZ Probabilities Arrays"); + + // initialize taz probabilities array + int purposes = tazSizeTerms.length; + + // initialize the arrays + tazProbabilities = new Matrix[purposes]; + + // iterate through the alternatives in the alternatives file and set the + // size term for each alternative + UtilityExpressionCalculator modelUEC = destModel.getUEC(); + TableDataSet altData = modelUEC.getAlternativeData(); + + SpecialEventOriginChoiceDMU dcDmu = dmuFactory.getSpecialEventOriginChoiceDMU(); + dcDmu.setSizeTerms(tazSizeTerms); + + // iterate through purposes + for (int purpose = 0; purpose < purposes; ++purpose) + { + + tazProbabilities[purpose] = new Matrix("Prob_Matrix", "Probability Matrix", + altData.getRowCount() + 1, altData.getRowCount() + 1); + int[] tazs = altData.getColumnAsInt("dest"); + tazProbabilities[purpose].setExternalNumbersZeroBased(tazs); + + // iterate through destination zones, solve the UEC for all origins + // and store the results in the matrix + for (int taz = 0; taz < tazs.length; ++taz) + { + + int destinationTaz = (int) tazs[taz]; + + // set origin taz in dmu (destination set in UEC by alternative) + dcDmu.setDmuIndexValues(0, 0, 0, destinationTaz, false); + + dcDmu.setPurpose(purpose); + + // Calculate utilities & probabilities + destModel.computeUtilities(dcDmu, dcDmu.getDmuIndexValues()); + + // Store probabilities (by purpose) + double[] probabilities = destModel.getCumulativeProbabilities(); + + for (int i = 0; i < probabilities.length; ++i) + { + + double cumProb = probabilities[i]; + int originTaz = (int) altData.getValueAt(i + 1, "dest"); + tazProbabilities[purpose] + .setValueAt(originTaz, destinationTaz, (float) cumProb); + } + } + } + logger.info("Finished Calculating Special Event Model TAZ Probabilities Arrays"); + } + + /** + * Choose an MGRA + * + * @param eventType + * Event type corresponding to size term + * @param destinationMgra + * MGRA of destination + * @param random + * Random number + * @return The chosen MGRA number + */ + public int chooseMGRA(String eventType, int destinationMgra, double random, boolean debug) + { + + int destinationTaz = mgraManager.getTaz(destinationMgra); + int purpose = purposeMap.get(eventType); + + if (debug) + { + logger.info("Random number " + random); + logger.info("Purpose " + purpose); + logger.info("Destination TAZ " + destinationTaz); + + } + + // first find a TAZ and station + Matrix tazCumProb = tazProbabilities[purpose]; + double altProb = 0; + double cumProb = 0; + int originTaz = -1; + for (int i = 0; i < tazCumProb.getColumnCount(); ++i) + { + originTaz = (int) tazCumProb.getExternalColumnNumber(i); + if (tazCumProb.getValueAt(originTaz, destinationTaz) > random) + { // the + // probabilities + // are + // stored + // column-wise + if (i != 0) + { + cumProb = tazCumProb.getValueAt(originTaz, + tazCumProb.getExternalColumnNumber(i - 1)); + altProb = tazCumProb.getValueAt(originTaz, destinationTaz) + - tazCumProb.getValueAt(originTaz, + tazCumProb.getExternalColumnNumber(i - 1)); + } else + { + altProb = tazCumProb.getValueAt(originTaz, destinationTaz); + } + break; + } + } + + // get the taz number of the alternative, and an array of mgras in that + // taz + int[] mgraArray = tazManager.getMgraArray(originTaz); + + // now find an MGRA in the taz corresponding to the random number drawn: + // note that the indexing needs to be offset by the cumulative + // probability of the chosen taz and the + // mgra probabilities need to be scaled by the alternatives probability + int mgraNumber = 0; + + if (debug) + { + logger.info("Chosen origin TAZ " + originTaz); + } + + double[] mgraCumProb = mgraProbabilities[purpose][originTaz]; + for (int i = 0; i < mgraCumProb.length; ++i) + { + cumProb += mgraCumProb[i] * altProb; + if (cumProb > random) + { + mgraNumber = mgraArray[i]; + } + } + if (debug) logger.info("Chose origin MGRA " + mgraNumber); + // return the chosen MGRA number + return mgraNumber; + } + + /** + * Choose origin MGRAs for a special event tour. + * + * @param tour + * A Special Event tour + */ + public void chooseOrigin(SpecialEventTour tour) + { + + String eventType = tour.getEventType(); + double random = tour.getRandom(); + int destinationMgra = tour.getDestinationMGRA(); + int mgra = chooseMGRA(eventType, destinationMgra, random, tour.getDebugChoiceModels()); + tour.setOriginMGRA(mgra); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTour.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTour.java new file mode 100644 index 0000000..ba05b9b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTour.java @@ -0,0 +1,291 @@ +package org.sandag.abm.specialevent; + +import java.io.Serializable; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Household; +import com.pb.common.math.MersenneTwister; + +public class SpecialEventTour + implements Serializable +{ + + private MersenneTwister random; + private int ID; + + private byte eventNumber; + private String eventType; + // following variables determined via simulation + private int income; + private int partySize; + + private SpecialEventTrip[] trips; + + private int departTime; + private int arriveTime; + + private boolean debugChoiceModels; + + // following variables chosen via choice models + private int originMGRA; + private int destinationMGRA; + private byte tourMode; + + private float valueOfTime; + + /** + * Public constructor. + * + * @param seed + * A seed for the random number generator. + */ + public SpecialEventTour(long seed) + { + + random = new MersenneTwister(seed); + } + + /** + * @return the iD + */ + public int getID() + { + return ID; + } + + /** + * @param iD + * the iD to set + */ + public void setID(int iD) + { + ID = iD; + } + + /** + * @return the eventNumber + */ + public byte getEventNumber() + { + return eventNumber; + } + + /** + * @param eventNumber + * the eventNumber to set + */ + public void setEventNumber(byte eventNumber) + { + this.eventNumber = eventNumber; + } + + /** + * @return the departTime + */ + public int getDepartTime() + { + return departTime; + } + + /** + * @param departTime + * the departTime to set + */ + public void setDepartTime(int departTime) + { + this.departTime = departTime; + } + + public SpecialEventTrip[] getTrips() + { + return trips; + } + + /** + * @return the eventType + */ + public String getEventType() + { + return eventType; + } + + /** + * @param eventType + * the eventType to set + */ + public void setEventType(String eventType) + { + this.eventType = eventType; + } + + /** + * @return the income + */ + public int getIncome() + { + return income; + } + + /** + * @param income + * the income to set + */ + public void setIncome(int income) + { + this.income = income; + } + + /** + * @return the partySize + */ + public int getPartySize() + { + return partySize; + } + + /** + * @param partySize + * the partySize to set + */ + public void setPartySize(int partySize) + { + this.partySize = partySize; + } + + public void setTrips(SpecialEventTrip[] trips) + { + this.trips = trips; + } + + /** + * @return the originMGRA + */ + public int getOriginMGRA() + { + return originMGRA; + } + + /** + * @param originMGRA + * the originMGRA to set + */ + public void setOriginMGRA(int originMGRA) + { + this.originMGRA = originMGRA; + } + + /** + * @return the tour mode + */ + public byte getTourMode() + { + return tourMode; + } + + /** + * @param mode + * the tour mode to set + */ + public void setTourMode(byte mode) + { + this.tourMode = mode; + } + + /** + * Get a random number from the parties random class. + * + * @return A random number. + */ + public double getRandom() + { + return random.nextDouble(); + } + + /** + * @return the debugChoiceModels + */ + public boolean getDebugChoiceModels() + { + return debugChoiceModels; + } + + /** + * @param debugChoiceModels + * the debugChoiceModels to set + */ + public void setDebugChoiceModels(boolean debugChoiceModels) + { + this.debugChoiceModels = debugChoiceModels; + } + + + + /** + * Get the number of outbound stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberOutboundStops() + { + return 0; + + } + + /** + * Get the number of return stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberInboundStops() + { + return 0; + + } + + /** + * @return the destinationMGRA + */ + public int getDestinationMGRA() + { + return destinationMGRA; + } + + /** + * @param destinationMGRA + * the destinationMGRA to set + */ + public void setDestinationMGRA(int destinationMGRA) + { + this.destinationMGRA = destinationMGRA; + } + + public void setArriveTime(int arriveTime) + { + this.arriveTime = arriveTime; + } + + public int getArriveTime() + { + return arriveTime; + } + + public float getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(float valueOfTime) { + this.valueOfTime = valueOfTime; + } + + public void logTourObject(Logger logger, int totalChars) + { + + Household.logHelper(logger, "tourId: ", ID, totalChars); + Household.logHelper(logger, "Event type: ", eventType, totalChars); + Household.logHelper(logger, "tourOrigMgra: ", originMGRA, totalChars); + Household.logHelper(logger, "tourDestMgra: ", destinationMGRA, totalChars); + Household.logHelper(logger, "tourDepartPeriod: ", departTime, totalChars); + Household.logHelper(logger, "tourArrivePeriod: ", arriveTime, totalChars); + Household.logHelper(logger, "tourMode: ", tourMode, totalChars); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTourManager.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTourManager.java new file mode 100644 index 0000000..9e38021 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTourManager.java @@ -0,0 +1,342 @@ +package org.sandag.abm.specialevent; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; + +public class SpecialEventTourManager +{ + + private TableDataSet eventData; + private TableDataSet incomeData; + private TableDataSet partySizeData; + private HashMap rbMap; + private static Logger logger = Logger.getLogger("specialEventModel"); + + private SpecialEventTour[] tours; + private MersenneTwister randomGenerator; + private SandagModelStructure sandagStructure; + private boolean saveUtilsAndProbs; + + /** + * Default Constructor. + */ + public SpecialEventTourManager(HashMap rbMap, TableDataSet eventData) + { + this.rbMap = rbMap; + randomGenerator = new MersenneTwister(10001); + saveUtilsAndProbs = Util.getBooleanValueFromPropertyMap(rbMap, + "specialEvent.saveUtilsAndProbs"); + this.eventData = eventData; + sandagStructure = new SandagModelStructure(); + + } + + /** + * Generate special event tours. + */ + public void generateTours() + { + + // read the party size data + String partySizeFile = Util.getStringValueFromPropertyMap(rbMap, + "specialEvent.partySize.file"); + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + partySizeFile = directory + partySizeFile; + partySizeData = readFile(partySizeFile); + + // read the income data + String incomeFile = Util.getStringValueFromPropertyMap(rbMap, "specialEvent.income.file"); + incomeFile = directory + incomeFile; + incomeData = readFile(incomeFile); + + ArrayList eventTourList = new ArrayList(); + + int eventTours = 0; + for (int i = 1; i <= eventData.getRowCount(); ++i) + { + + int eventMgra = (int) eventData.getValueAt(i, "MGRA"); + int attendance = (int) eventData.getValueAt(i, "Attendance"); + String eventType = eventData.getStringValueAt(i, "EventType"); + int startPeriod = (int) eventData.getValueAt(i, "StartPeriod"); + int endPeriod = (int) eventData.getValueAt(i, "EndPeriod"); + + // generate tours for the event + for (int j = 0; j < attendance; ++j) + { + + ++eventTours; + + long randomSeed = getRandomSeed(eventTours); + SpecialEventTour tour = new SpecialEventTour(randomSeed); + tour.setID(eventTours); + tour.setEventNumber((byte) i); + tour.setDestinationMGRA(eventMgra); + tour.setDepartTime(startPeriod); + tour.setArriveTime(endPeriod); + tour.setEventType(eventType); + + // choose income and party size for the tour + int income = chooseIncome(randomGenerator.nextDouble(), eventType); + int partySize = choosePartySize(randomGenerator.nextDouble(), eventType); + + tour.setIncome(income); + tour.setPartySize(partySize); + + eventTourList.add(tour); + } + } + + // convert the ArrayList to an array + tours = new SpecialEventTour[eventTourList.size()]; + for (int i = 0; i < tours.length; ++i) + tours[i] = eventTourList.get(i); + + } + + /** + * Simulate income from the income data table. + * + * @param random + * a uniformly-distributed random number. + * @param eventType + * a string identifying the type of event, which should be a + * column in the income data table + * @return income chosen + */ + public int chooseIncome(double random, String eventType) + { + + int income = -1; + double cumProb = 0; + for (int i = 1; i <= incomeData.getRowCount(); ++i) + { + cumProb += incomeData.getValueAt(i, eventType); + if (random < cumProb) + { + income = (int) incomeData.getValueAt(i, "Income"); + break; + } + } + return income; + } + + /** + * Simulate party size from the party size data table. + * + * @param random + * a uniformly-distributed random number. + * @param eventType + * a string identifying the type of event, which should be a + * column in the party size data table + * @return party size chosen + */ + public int choosePartySize(double random, String eventType) + { + + int partySize = -1; + double cumProb = 0; + for (int i = 1; i <= partySizeData.getRowCount(); ++i) + { + cumProb += partySizeData.getValueAt(i, eventType); + if (random < cumProb) + { + partySize = (int) partySizeData.getValueAt(i, "PartySize"); + break; + } + } + return partySize; + } + + /** + * Read the file and return the TableDataSet. + * + * @param fileName + * @return data + */ + private TableDataSet readFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet data; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + data = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + return data; + } + + /** + * Create a text file and write all records to the file. + * + */ + public void writeOutputFile(HashMap rbMap) + { + + // Open file and print header + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String tourFileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "specialEvent.tour.output.file"); + String tripFileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "specialEvent.trip.output.file"); + + logger.info("Writing special event tours to file " + tourFileName); + logger.info("Writing special event trips to file " + tripFileName); + + PrintWriter tourWriter = null; + try + { + tourWriter = new PrintWriter(new BufferedWriter(new FileWriter(tourFileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + tourFileName + " for writing\n"); + throw new RuntimeException(); + } + String tourHeaderString = new String( + "id,eventNumber,eventType,income,partySize,departTime,arriveTime,originMGRA,destinationMGRA,tourMode,valueOfTime\n"); + tourWriter.print(tourHeaderString); + + PrintWriter tripWriter = null; + try + { + tripWriter = new PrintWriter(new BufferedWriter(new FileWriter(tripFileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + tripFileName + " for writing\n"); + throw new RuntimeException(); + } + String tripHeaderString = new String( + "tourID,tripID,originMGRA,destinationMGRA,inbound,originIsTourDestination,destinationIsTourDestination,period,tripMode,boardingTap,alightingTap,set,valueOfTime"); + + // Iterate through the array, printing records to the file + for (int i = 0; i < tours.length; ++i) + { + + SpecialEventTour tour = tours[i]; + + SpecialEventTrip[] trips = tours[i].getTrips(); + + if (trips == null) continue; + + writeTour(tour, tourWriter); + + // if this is the first record, and we are saving utils and probs, + // append a line to the trip file header + if (i == 0) + { + + if (saveUtilsAndProbs) + { + float[] utils = trips[0].getModeUtilities(); + String header = ""; + for (int j = 0; j < utils.length; ++j) + header += ",util_" + j; + for (int j = 0; j < utils.length; ++j) + header += ",prob_" + j; + tripWriter.print(tripHeaderString + header + "\n"); + } else tripWriter.print(tripHeaderString + "\n"); + } + for (int j = 0; j < trips.length; ++j) + { + writeTrip(tour, trips[j], j + 1, tripWriter); + } + } + + tourWriter.close(); + tripWriter.close(); + + } + + /** + * Write the tour to the PrintWriter + * + * @param tour + * @param writer + */ + private void writeTour(SpecialEventTour tour, PrintWriter writer) + { + String record = new String(tour.getID() + "," + tour.getEventNumber() + "," + + tour.getEventType() + "," + tour.getIncome() + "," + tour.getPartySize() + "," + + tour.getDepartTime() + "," + tour.getArriveTime() + "," + tour.getOriginMGRA() + + "," + tour.getDestinationMGRA() + "," + tour.getTourMode() + "," + + String.format("%9.2f",tour.getValueOfTime()) + "\n"); + writer.print(record); + + } + + /** + * Write the trip to the PrintWriter + * + * @param tour + * @param trip + * @param tripNumber + * @param writer + */ + private void writeTrip(SpecialEventTour tour, SpecialEventTrip trip, int tripNumber, + PrintWriter writer) + { + + String record = new String(tour.getID() + "," + tripNumber + "," + trip.getOriginMgra() + + "," + trip.getDestinationMgra() + "," + trip.isInbound() + "," + + trip.isOriginIsTourDestination() + "," + trip.isDestinationIsTourDestination() + + "," + trip.getPeriod() + "," + trip.getTripMode() + "," + + trip.getBoardTap() + "," + trip.getAlightTap() +"," + trip.getSet()+ "," + + String.format("%9.2f",tour.getValueOfTime())); + + + if (saveUtilsAndProbs) + { + + String utilRecord = new String(); + float[] utils = trip.getModeUtilities(); + for (int i = 0; i < utils.length; ++i) + utilRecord += ("," + String.format("%9.5f", utils[i])); + float[] probs = trip.getModeProbabilities(); + for (int i = 0; i < probs.length; ++i) + utilRecord += ("," + String.format("%9.5f", probs[i])); + record = record + utilRecord; + } + writer.print(record + "\n"); + } + /** + * get special event tours. + * + * @return + */ + public SpecialEventTour[] getTours() + { + return tours; + } + + /** + * Calculate and return a random number seed for the tour. + * + * @param eventID + * @return + */ + public long getRandomSeed(int eventID) + { + + long seed = (eventID * 10 + 100001); + return seed; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTrip.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTrip.java new file mode 100644 index 0000000..cc34fa1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTrip.java @@ -0,0 +1,292 @@ +package org.sandag.abm.specialevent; + +public class SpecialEventTrip +{ + + private int originMgra; + private int destinationMgra; + private int tripMode; + private byte period; + private boolean inbound; + private boolean firstTrip; + private boolean lastTrip; + private boolean originIsTourDestination; + private boolean destinationIsTourDestination; + + private float[] modeProbabilities; + private float[] modeUtilities; + + private int boardTap; + private int alightTap; + private int set = -1; + + /** + * Default constructor; nothing initialized. + */ + public SpecialEventTrip() + { + + } + + /** + * Create a cross border trip from a tour leg (no stops). + * + * @param tour + * The tour. + * @param outbound + * Outbound direction + */ + public SpecialEventTrip(SpecialEventTour tour, boolean outbound) + { + + initializeFromTour(tour, outbound); + + } + + /** + * Initilize from the tour. + * + * @param tour + * The tour. + * @param outbound + * Outbound direction. + */ + public void initializeFromTour(SpecialEventTour tour, boolean outbound) + { + // Note: mode is unknown + if (outbound) + { + this.originMgra = tour.getOriginMGRA(); + this.destinationMgra = tour.getDestinationMGRA(); + this.period = (byte) tour.getDepartTime(); + this.inbound = false; + this.firstTrip = true; + this.lastTrip = false; + this.originIsTourDestination = false; + this.destinationIsTourDestination = true; + } else + { + this.originMgra = tour.getDestinationMGRA(); + this.destinationMgra = tour.getOriginMGRA(); + this.period = (byte) tour.getArriveTime(); + this.inbound = true; + this.firstTrip = false; + this.lastTrip = true; + this.originIsTourDestination = true; + this.destinationIsTourDestination = false; + } + + } + + /** + * @return the period + */ + public byte getPeriod() + { + return period; + } + + /** + * @param period + * the period to set + */ + public void setPeriod(byte period) + { + this.period = period; + } + + /** + * @return the originMgra + */ + public int getOriginMgra() + { + return originMgra; + } + + /** + * @param originMgra + * the originMgra to set + */ + public void setOriginMgra(int originMgra) + { + this.originMgra = originMgra; + } + + /** + * @return the destinationMgra + */ + public int getDestinationMgra() + { + return destinationMgra; + } + + /** + * @param destinationMgra + * the destinationMgra to set + */ + public void setDestinationMgra(int destinationMgra) + { + this.destinationMgra = destinationMgra; + } + + /** + * @return the tripMode + */ + public int getTripMode() + { + return tripMode; + } + + /** + * @param tripMode + * the tripMode to set + */ + public void setTripMode(int tripMode) + { + this.tripMode = tripMode; + } + + /** + * @return the inbound + */ + public boolean isInbound() + { + return inbound; + } + + /** + * @param inbound + * the inbound to set + */ + public void setInbound(boolean inbound) + { + this.inbound = inbound; + } + + /** + * @return the firstTrip + */ + public boolean isFirstTrip() + { + return firstTrip; + } + + /** + * @param firstTrip + * the firstTrip to set + */ + public void setFirstTrip(boolean firstTrip) + { + this.firstTrip = firstTrip; + } + + /** + * @return the lastTrip + */ + public boolean isLastTrip() + { + return lastTrip; + } + + /** + * @param lastTrip + * the lastTrip to set + */ + public void setLastTrip(boolean lastTrip) + { + this.lastTrip = lastTrip; + } + + /** + * @return the originIsTourDestination + */ + public boolean isOriginIsTourDestination() + { + return originIsTourDestination; + } + + /** + * @param originIsTourDestination + * the originIsTourDestination to set + */ + public void setOriginIsTourDestination(boolean originIsTourDestination) + { + this.originIsTourDestination = originIsTourDestination; + } + + /** + * @return the destinationIsTourDestination + */ + public boolean isDestinationIsTourDestination() + { + return destinationIsTourDestination; + } + + /** + * @param destinationIsTourDestination + * the destinationIsTourDestination to set + */ + public void setDestinationIsTourDestination(boolean destinationIsTourDestination) + { + this.destinationIsTourDestination = destinationIsTourDestination; + } + + /** + * @return the modeProbabilities + */ + public float[] getModeProbabilities() + { + return modeProbabilities; + } + + /** + * @param modeProbabilities + * the modeProbabilities to set + */ + public void setModeProbabilities(float[] modeProbabilities) + { + this.modeProbabilities = modeProbabilities; + } + + /** + * @return the modeUtilities + */ + public float[] getModeUtilities() + { + return modeUtilities; + } + + /** + * @param modeUtilities + * the modeUtilities to set + */ + public void setModeUtilities(float[] modeUtilities) + { + this.modeUtilities = modeUtilities; + } + + public int getBoardTap() { + return boardTap; + } + + public void setBoardTap(int boardTap) { + this.boardTap = boardTap; + } + + public int getAlightTap() { + return alightTap; + } + + public void setAlightTap(int alightTap) { + this.alightTap = alightTap; + } + + public int getSet() { + return set; + } + + public void setSet(int set) { + this.set = set; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripModeChoiceDMU.java new file mode 100644 index 0000000..2ac573b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripModeChoiceDMU.java @@ -0,0 +1,451 @@ +package org.sandag.abm.specialevent; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class SpecialEventTripModeChoiceDMU + implements Serializable, VariableTable +{ + protected transient Logger logger = Logger.getLogger(SpecialEventTripModeChoiceDMU.class); + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected int tourDepartPeriod; + protected int tourArrivePeriod; + protected int tripPeriod; + protected int tripOrigIsTourDest; + protected int tripDestIsTourDest; + protected float parkingCost; + protected float parkingTime; + protected int income; + protected int partySize; + + protected double nmWalkTime; + protected double nmBikeTime; + + protected double ivtCoeff; + protected double costCoeff; + + protected double walkTransitLogsum; + protected double pnrTransitLogsum; + protected double knrTransitLogsum; + + protected int outboundHalfTourDirection; + + public SpecialEventTripModeChoiceDMU(SandagModelStructure modelStructure, Logger aLogger) + { + if (aLogger == null) + { + aLogger = Logger.getLogger("specialEventModel"); + } + logger = aLogger; + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the tripPeriod + */ + public int getTripPeriod() + { + return tripPeriod; + } + + /** + * @param tripPeriod + * the tripPeriod to set + */ + public void setTripPeriod(int tripPeriod) + { + this.tripPeriod = tripPeriod; + } + + /** + * @return the tripOrigIsTourDest + */ + public int getTripOrigIsTourDest() + { + return tripOrigIsTourDest; + } + + /** + * @param tripOrigIsTourDest + * the tripOrigIsTourDest to set + */ + public void setTripOrigIsTourDest(int tripOrigIsTourDest) + { + this.tripOrigIsTourDest = tripOrigIsTourDest; + } + + /** + * @return the tripDestIsTourDest + */ + public int getTripDestIsTourDest() + { + return tripDestIsTourDest; + } + + /** + * @param tripDestIsTourDest + * the tripDestIsTourDest to set + */ + public void setTripDestIsTourDest(int tripDestIsTourDest) + { + this.tripDestIsTourDest = tripDestIsTourDest; + } + + /** + * @return the outboundHalfTourDirection + */ + public int getOutboundHalfTourDirection() + { + return outboundHalfTourDirection; + } + + /** + * @param outboundHalfTourDirection + * the outboundHalfTourDirection to set + */ + public void setOutboundHalfTourDirection(int outboundHalfTourDirection) + { + this.outboundHalfTourDirection = outboundHalfTourDirection; + } + + /** + * @return the tourDepartPeriod + */ + public int getTourDepartPeriod() + { + return tourDepartPeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(int tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(int tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + /** + * @return the tourArrivePeriod + */ + public int getTourArrivePeriod() + { + return tourArrivePeriod; + } + + public double getNm_walkTime() + { + return nmWalkTime; + } + + public void setNonMotorizedWalkTime(double nmWalkTime) + { + this.nmWalkTime = nmWalkTime; + } + + public void setNonMotorizedBikeTime(double nmBikeTime) + { + this.nmBikeTime = nmBikeTime; + } + + public double getNm_bikeTime() + { + return nmBikeTime; + } + + /** + * @return the parkingCost + */ + public float getParkingCost() + { + return parkingCost; + } + + /** + * @param parkingCost + * the parkingCost to set + */ + public void setParkingCost(float parkingCost) + { + this.parkingCost = parkingCost; + } + + /** + * @return the parkingTime + */ + public float getParkingTime() + { + return parkingTime; + } + + /** + * @param parkingTime + * the parkingTime to set + */ + public void setParkingTime(float parkingTime) + { + this.parkingTime = parkingTime; + } + + /** + * @return the income + */ + public int getIncome() + { + return income; + } + + /** + * @param income + * the income to set + */ + public void setIncome(int income) + { + this.income = income; + } + + /** + * @return the partySize + */ + public int getPartySize() + { + return partySize; + } + + /** + * @param partySize + * the partySize to set + */ + public void setPartySize(int partySize) + { + this.partySize = partySize; + } + + public double getNmWalkTime() { + return nmWalkTime; + } + + public void setNmWalkTime(double nmWalkTime) { + this.nmWalkTime = nmWalkTime; + } + + public double getNmBikeTime() { + return nmBikeTime; + } + + public void setNmBikeTime(double nmBikeTime) { + this.nmBikeTime = nmBikeTime; + } + + public double getIvtCoeff() { + return ivtCoeff; + } + + public void setIvtCoeff(double ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + public double getCostCoeff() { + return costCoeff; + } + + public void setCostCoeff(double costCoeff) { + this.costCoeff = costCoeff; + } + + public double getWalkTransitLogsum() { + return walkTransitLogsum; + } + + public void setWalkTransitLogsum(double walkTransitLogsum) { + this.walkTransitLogsum = walkTransitLogsum; + } + + public double getPnrTransitLogsum() { + return pnrTransitLogsum; + } + + public void setPnrTransitLogsum(double pnrTransitLogsum) { + this.pnrTransitLogsum = pnrTransitLogsum; + } + + public double getKnrTransitLogsum() { + return knrTransitLogsum; + } + + public void setKnrTransitLogsum(double knrTransitLogsum) { + this.knrTransitLogsum = knrTransitLogsum; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTourDepartPeriod", 0); + methodIndexMap.put("getTourArrivePeriod", 1); + methodIndexMap.put("getTripPeriod", 2); + methodIndexMap.put("getParkingCost", 3); + methodIndexMap.put("getParkingTime", 4); + methodIndexMap.put("getTripOrigIsTourDest", 5); + methodIndexMap.put("getTripDestIsTourDest", 6); + methodIndexMap.put("getIncome", 7); + methodIndexMap.put("getPartySize", 8); + + methodIndexMap.put("getIvtCoeff", 60); + methodIndexMap.put("getCostCoeff", 61); + + methodIndexMap.put("getWalkSetLogSum", 62); + methodIndexMap.put("getPnrSetLogSum", 63); + methodIndexMap.put("getKnrSetLogSum", 64); + + methodIndexMap.put("getNm_walkTime", 90); + methodIndexMap.put("getNm_bikeTime", 91); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getTourDepartPeriod(); + break; + case 1: + returnValue = getTourArrivePeriod(); + break; + case 2: + returnValue = getTripPeriod(); + break; + case 3: + returnValue = getParkingCost(); + break; + case 4: + returnValue = getParkingTime(); + break; + case 5: + returnValue = getTripOrigIsTourDest(); + break; + case 6: + returnValue = getTripDestIsTourDest(); + break; + case 7: + returnValue = getIncome(); + break; + case 8: + returnValue = getPartySize(); + break; + case 60: + returnValue = getIvtCoeff(); + break; + case 61: + returnValue = getCostCoeff(); + break; + case 62: + returnValue = getWalkTransitLogsum(); + break; + case 63: + returnValue = getPnrTransitLogsum(); + break; + case 64: + returnValue = getKnrTransitLogsum(); + break; + case 90: + returnValue = getNm_walkTime(); + break; + case 91: + returnValue = getNm_bikeTime(); + break; + default: + logger.error( "method number = " + variableIndex + " not found" ); + throw new RuntimeException( "method number = " + variableIndex + " not found" ); + } + return returnValue; + + + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripModeChoiceModel.java new file mode 100644 index 0000000..8680d17 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripModeChoiceModel.java @@ -0,0 +1,284 @@ +package org.sandag.abm.specialevent; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.TripModeChoiceDMU; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class SpecialEventTripModeChoiceModel +{ + + private transient Logger logger = Logger.getLogger("specialEventModel"); + + private AutoAndNonMotorizedSkimsCalculator anm; + private McLogsumsCalculator logsumHelper; + private ModelStructure modelStructure; + private TazDataManager tazs; + private MgraDataManager mgraManager; + + private SpecialEventTripModeChoiceDMU dmu; + private ChoiceModelApplication tripModeChoiceModel; + private boolean saveUtilsAndProbs; + double logsum = 0; + TableDataSet eventData; + private TripModeChoiceDMU mcDmuObject; + + private static final String PROPERTIES_UEC_DATA_SHEET = "specialEvent.trip.mc.data.page"; + private static final String PROPERTIES_UEC_MODEL_SHEET = "specialEvent.trip.mc.model.page"; + private static final String PROPERTIES_UEC_FILE = "specialEvent.trip.mc.uec.file"; + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public SpecialEventTripModeChoiceModel(HashMap propertyMap, + ModelStructure myModelStructure, SpecialEventDmuFactoryIf dmuFactory, + McLogsumsCalculator myLogsumHelper, TableDataSet eventData) + { + tazs = TazDataManager.getInstance(propertyMap); + mgraManager = MgraDataManager.getInstance(propertyMap); + + modelStructure = myModelStructure; + logsumHelper = myLogsumHelper; + this.eventData = eventData; + + SandagModelStructure modelStructure = new SandagModelStructure(); + mcDmuObject = new TripModeChoiceDMU(modelStructure, logger); + + setupTripModeChoiceModel(propertyMap, dmuFactory); + saveUtilsAndProbs = Util.getBooleanValueFromPropertyMap(propertyMap, + "specialEvent.saveUtilsAndProbs"); + + } + + /** + * Read the UEC file and set up the trip mode choice model. + * + * @param propertyMap + * @param dmuFactory + */ + private void setupTripModeChoiceModel(HashMap propertyMap, + SpecialEventDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up Special Event trip mode choice model.")); + + dmu = dmuFactory.getSpecialEventTripModeChoiceDMU(); + + int dataPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_DATA_SHEET)); + int modelPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_MODEL_SHEET)); + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String tripModeUecFile = propertyMap.get(PROPERTIES_UEC_FILE); + tripModeUecFile = uecPath + tripModeUecFile; + logger.info(tripModeUecFile); + + tripModeChoiceModel = new ChoiceModelApplication(tripModeUecFile, modelPage, dataPage, + propertyMap, (VariableTable) dmu); + logger.info(String.format("Finished setting up Special Event trip mode choice model.")); + } + + /** + * Calculate utilities and return logsum for the tour and stop. + * + * @param tour + * @param trip + */ + public double computeUtilities(SpecialEventTour tour, SpecialEventTrip trip) + { + + setDmuAttributes(tour, trip); + + tripModeChoiceModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + if (tour.getDebugChoiceModels()) + { + tour.logTourObject(logger, 100); + tripModeChoiceModel.logUECResults(logger, "Special Event trip mode choice model"); + + } + + logsum = tripModeChoiceModel.getLogsum(); + + if (tour.getDebugChoiceModels()) logger.info("Returning logsum " + logsum); + + return logsum; + + } + + /** + * Choose a mode and store in the trip object. + * + * @param tour + * SpecialEventTour + * @param trip + * SpecialEventTrip + * + */ + public void chooseMode(SpecialEventTour tour, SpecialEventTrip trip) + { + + computeUtilities(tour, trip); + + double rand = tour.getRandom(); + int mode = tripModeChoiceModel.getChoiceResult(rand); + + trip.setTripMode(mode); + + //value of time; lookup vot, votS2, or votS3 from the UEC depending on chosen mode + UtilityExpressionCalculator uec = tripModeChoiceModel.getUEC(); + + float vot = 0.0f; + + if(modelStructure.getTourModeIsS2(mode)){ + int votIndex = uec.lookupVariableIndex("votS2"); + vot = (float) uec.getValueForIndex(votIndex); + }else if (modelStructure.getTourModeIsS3(mode)){ + int votIndex = uec.lookupVariableIndex("votS3"); + vot = (float) uec.getValueForIndex(votIndex); + }else{ + int votIndex = uec.lookupVariableIndex("vot"); + vot = (float) uec.getValueForIndex(votIndex); + } + tour.setValueOfTime(vot); + + if(mode>=9){ + double[][] bestTapPairs = null; + + if (mode == 9){ + bestTapPairs = logsumHelper.getBestWtwTripTaps(); + } + else if (mode==10||mode==11){ + if (!trip.isInbound()) + bestTapPairs = logsumHelper.getBestDtwTripTaps(); + else + bestTapPairs = logsumHelper.getBestWtdTripTaps(); + } + double rn = tour.getRandom(); + int pathIndex = logsumHelper.chooseTripPath(rn, bestTapPairs, tour.getDebugChoiceModels(), logger); + int boardTap = (int) bestTapPairs[pathIndex][0]; + int alightTap = (int) bestTapPairs[pathIndex][1]; + int set = (int) bestTapPairs[pathIndex][2]; + trip.setBoardTap(boardTap); + trip.setAlightTap(alightTap); + trip.setSet(set); + } + + + if (tour.getDebugChoiceModels()) + { + logger.info("Chose mode " + mode + " with random number " + rand); + } + + if (saveUtilsAndProbs) + { + double[] probs = tripModeChoiceModel.getProbabilities(); + float[] localProbs = new float[probs.length]; + for (int i = 0; i < probs.length; ++i) + localProbs[i] = (float) probs[i]; + + double[] utils = tripModeChoiceModel.getUtilities(); + float[] localUtils = new float[utils.length]; + for (int i = 0; i < utils.length; ++i) + localUtils[i] = (float) utils[i]; + + trip.setModeUtilities(localUtils); + trip.setModeProbabilities(localProbs); + } + + } + + /** + * Set DMU attributes. + * + * @param tour + * @param trip + */ + public void setDmuAttributes(SpecialEventTour tour, SpecialEventTrip trip) + { + + int tourDestinationMgra = tour.getDestinationMGRA(); + int tripOriginMgra = trip.getOriginMgra(); + int tripDestinationMgra = trip.getDestinationMgra(); + + int tripOriginTaz = mgraManager.getTaz(tripOriginMgra); + int tripDestinationTaz = mgraManager.getTaz(tripDestinationMgra); + + dmu.setDmuIndexValues(tripOriginTaz, tripDestinationTaz, tripOriginTaz, tripDestinationTaz, + tour.getDebugChoiceModels()); + + dmu.setTourDepartPeriod(tour.getDepartTime()); + dmu.setTourArrivePeriod(tour.getArriveTime()); + dmu.setTripPeriod(trip.getPeriod()); + dmu.setIncome(tour.getIncome()); + dmu.setPartySize(tour.getPartySize()); + if (trip.isInbound()) dmu.setOutboundHalfTourDirection(0); + else dmu.setOutboundHalfTourDirection(1); + + // set trip mc dmu values for transit logsum (gets replaced below by uec values) + double c_ivt = -0.03; + double c_cost = - 0.0033; + + // Solve trip mode level utilities + mcDmuObject.setIvtCoeff(c_ivt); + mcDmuObject.setCostCoeff(c_cost); + double walkTransitLogsum = -999.0; + double driveTransitLogsum = -999.0; + + logsumHelper.setNmTripMcDmuAttributes(mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + dmu.setNonMotorizedWalkTime(mcDmuObject.getNm_walkTime()); + dmu.setNonMotorizedBikeTime(mcDmuObject.getNm_bikeTime()); + + logsumHelper.setWtwTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(),tour.getDebugChoiceModels()); + walkTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTW); + + dmu.setWalkTransitLogsum(walkTransitLogsum); + if (!trip.isInbound()) + { + logsumHelper.setDtwTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.DTW); + } else + { + logsumHelper.setWtdTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTD); + } + + dmu.setPnrTransitLogsum(driveTransitLogsum); + dmu.setKnrTransitLogsum(driveTransitLogsum); + + int eventNumber = tour.getEventNumber(); + + float parkingCost = eventData.getValueAt(eventNumber, "ParkingCost"); + float parkingTime = eventData.getValueAt(eventNumber, "ParkingTime"); + + dmu.setParkingCost(parkingCost); + dmu.setParkingTime(parkingTime); + + if (trip.isOriginIsTourDestination()) dmu.setTripOrigIsTourDest(1); + else dmu.setTripOrigIsTourDest(0); + + if (trip.isDestinationIsTourDestination()) dmu.setTripDestIsTourDest(1); + else dmu.setTripDestIsTourDest(0); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripTables.java b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripTables.java new file mode 100644 index 0000000..f3edf5a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/specialevent/SpecialEventTripTables.java @@ -0,0 +1,595 @@ +package org.sandag.abm.specialevent; +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.util.ResourceUtil; + +public class SpecialEventTripTables { + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + public static final int MATRIX_DATA_SERVER_PORT = 1171; + + private TableDataSet tripData; + + // Some parameters + private int[] modeIndex; // an index array,dimensioned by number of total modes, returns 0=auto modes, 1=non-motor, 2=transit, 3=other + private int[] matrixIndex; // an index array, dimensioned by number of modes, returns the element of the matrix array to store value + // array modes: AUTO, NON-MOTORIZED, TRANSIT, OTHER + private int autoModes = 0; + private int tranModes = 0; + private int nmotModes = 0; + private int othrModes = 0; + + // one file per time period + private int numberOfPeriods; + + private HashMap rbMap; + + // matrices are indexed by modes + private Matrix[][] matrix; + + private ResourceBundle rb; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private TapDataManager tapManager; + private SandagModelStructure modelStructure; + + private MatrixDataServerRmi ms; + private float sampleRate; + private static int iteration=1; + public int numSkimSets; + + public SpecialEventTripTables(HashMap rbMap) + { + + this.rbMap = rbMap; + tazManager = TazDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + modelStructure = new SandagModelStructure(); + + // Time period limits + numberOfPeriods = modelStructure.getNumberModelPeriods(); + + numSkimSets = Util.getIntegerValueFromPropertyMap(rbMap,"utility.bestTransitPath.skim.sets"); + + // number of modes + modeIndex = new int[modelStructure.MAXIMUM_TOUR_MODE_ALT_INDEX + 1]; + matrixIndex = new int[modeIndex.length]; + + // set the mode arrays + for (int i = 1; i < modeIndex.length; ++i) + { + if (modelStructure.getTourModeIsSovOrHov(i)) + { + modeIndex[i] = 0; + matrixIndex[i] = autoModes; + ++autoModes; + } else if (modelStructure.getTourModeIsNonMotorized(i)) + { + modeIndex[i] = 1; + matrixIndex[i] = nmotModes; + ++nmotModes; + } else if (modelStructure.getTourModeIsWalkTransit(i) + || modelStructure.getTourModeIsDriveTransit(i)) + { + modeIndex[i] = 2; + matrixIndex[i] = tranModes; + ++tranModes; + } else + { + modeIndex[i] = 3; + matrixIndex[i] = othrModes; + ++othrModes; + } + } + + logger.info("autoModes="+autoModes+" nmotModes="+nmotModes+" tranModes="+tranModes+" othrModes="+othrModes); + } + + /** + * Initialize all the matrices for the given time period. + * + * @param periodName + * The name of the time period. + */ + public void initializeMatrices(String periodName) + { + + /* + * This won't work because external stations aren't listed in the MGRA + * file int[] tazIndex = tazManager.getTazsOneBased(); int tazs = + * tazIndex.length-1; + */ + // Instead, use maximum taz number + int maxTaz = tazManager.getMaxTaz(); + int[] tazIndex = new int[maxTaz + 1]; + + // assume zone numbers are sequential + for (int i = 1; i < tazIndex.length; ++i) + tazIndex[i] = i; + + // get the tap index + int[] tapIndex = tapManager.getTaps(); + int taps = tapIndex.length - 1; + + // Initialize matrices; one for each mode group (auto, non-mot, tran, + // other) + // All matrices will be dimensioned by TAZs except for transit, which is + // dimensioned by TAPs + int numberOfModes = 4; + matrix = new Matrix[numberOfModes][]; + for (int i = 0; i < numberOfModes; ++i) + { + + String modeName; + + if (i == 0) + { + matrix[i] = new Matrix[autoModes]; + for (int j = 0; j < autoModes; ++j) + { + modeName = modelStructure.getModeName(j + 1); + matrix[i][j] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j].setExternalNumbers(tazIndex); + } + } else if (i == 1) + { + matrix[i] = new Matrix[nmotModes]; + for (int j = 0; j < nmotModes; ++j) + { + modeName = modelStructure.getModeName(j + 1 + autoModes); + matrix[i][j] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j].setExternalNumbers(tazIndex); + } + } else if (i == 2) + { + matrix[i] = new Matrix[tranModes*numSkimSets]; + for (int k = 0; k < tranModes; ++k) + { + for(int l=0;l pMap; + String propertiesFile = null; + + logger.info(String.format( + "SANDAG Special Event Model Trip Table Generation Program using CT-RAMP version %s", + CtrampApplication.VERSION)); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + float sampleRate = 1.0f; + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + logger.info("Special Event Model Trip Table:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + SpecialEventTripTables tripTables = new SpecialEventTripTables(pMap); + tripTables.setSampleRate(sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = tripTables.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + tripTables.ms = matrixServer; + } else + { + tripTables.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + tripTables.ms.testRemote("SpecialEventTripTables"); + + // mdm = MatrixDataManager.getInstance(); + // mdm.setMatrixDataServerObject(ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + tripTables.createTripTables(mt); + + } + + /** + * @return the sampleRate + */ + public double getSampleRate() + { + return sampleRate; + } + + /** + * @param sampleRate + * the sampleRate to set + */ + public void setSampleRate(float sampleRate) + { + this.sampleRate = sampleRate; + } + +} + + diff --git a/sandag_abm/src/main/java/org/sandag/abm/survey/OutputTapPairs.java b/sandag_abm/src/main/java/org/sandag/abm/survey/OutputTapPairs.java new file mode 100644 index 0000000..912a87c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/survey/OutputTapPairs.java @@ -0,0 +1,363 @@ +package org.sandag.abm.survey; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.rmi.RemoteException; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.accessibilities.BestTransitPathCalculator; +import org.sandag.abm.accessibilities.DriveTransitWalkSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitDriveSkimsCalculator; +import org.sandag.abm.accessibilities.WalkTransitWalkSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; +import org.sandag.abm.modechoice.TransitDriveAccessDMU; +import org.sandag.abm.modechoice.TransitWalkAccessDMU; +import org.sandag.abm.modechoice.Modes; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +/** + * This class reads and processes on-board transit survey data. It writes out + * all TAP-pairs given the origin/destination MAZ, the time period, and the + * access/egress mode sequence for the observation. + * + * @author joel.freedman + * + */ +public class OutputTapPairs { + private static final Logger logger = Logger.getLogger(OutputTapPairs.class); + private BestTransitPathCalculator bestPathCalculator; + protected WalkTransitWalkSkimsCalculator wtw; + protected WalkTransitDriveSkimsCalculator wtd; + protected DriveTransitWalkSkimsCalculator dtw; + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + private MatrixDataServerRmi ms; + private String inputFile; + private String outputFile; + private TableDataSet inputDataTable; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private HashMap sequentialMaz; + + AutoTazSkimsCalculator tazDistanceCalculator; + + protected PrintWriter writer; + + + public OutputTapPairs(HashMap propertyMap, String inputFile, String outputFile){ + this.inputFile = inputFile; + this.outputFile = outputFile; + + startMatrixServer(propertyMap); + initialize(propertyMap); + } + + + /** + * Initialize best path builders. + * + * @param propertyMap A property map with relevant properties. + */ + public void initialize(HashMap propertyMap){ + + logger.info("Initializing OutputTapPairs"); + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + bestPathCalculator = new BestTransitPathCalculator(propertyMap); + + tazDistanceCalculator = new AutoTazSkimsCalculator(propertyMap); + tazDistanceCalculator.computeTazDistanceArrays(); + + wtw = new WalkTransitWalkSkimsCalculator(propertyMap); + wtw.setup(propertyMap, logger, bestPathCalculator); + wtd = new WalkTransitDriveSkimsCalculator(propertyMap); + wtd.setup(propertyMap, logger, bestPathCalculator); + dtw = new DriveTransitWalkSkimsCalculator(propertyMap); + dtw.setup(propertyMap, logger, bestPathCalculator); + + readData(); + createOutputFile(); + + } + + /** + * Read data into inputDataTable tabledataset. + * + */ + private void readData(){ + + logger.info("Begin reading the data in file " + inputFile); + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + inputDataTable = csvFile.readFile(new File(inputFile)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + logger.info("End reading the data in file " + inputFile); + } + + /** + * Create the output file and write a header record. + */ + private void createOutputFile(){ + + logger.info("Creating file " + outputFile); + + try + { + writer = new PrintWriter(new BufferedWriter(new FileWriter(outputFile))); + } catch (IOException e) + { + logger.fatal("Could not open file " + outputFile + " for writing\n"); + throw new RuntimeException(); + } + String headerString = new String( + "rownames,npath,access_mode_recode,period,set,boardTap,alightTap,bestUtility,accessTime,egressTime,auxWalkTime," + + "localBusIvt,expressBusIvt,brtIvt,lrtIvt,crIvt,firstWaitTime,trfWaitTime,fare,totalIVT,xfers\n"); + + + writer.print(headerString); + + } + + + /** + * Iterate through input data and process\write taps. + */ + private void run(){ + + TransitWalkAccessDMU walkDmu = new TransitWalkAccessDMU(); + TransitDriveAccessDMU driveDmu = new TransitDriveAccessDMU(); + double[][] bestTaps = null; + double[] skims = null; + double boardAccessTime; + double alightAccessTime; + //iterate through data and calculate + for(int row = 1; row<=inputDataTable.getRowCount();++row ){ + + if((row<=100) || ((row % 100) == 0)) + logger.info("Processing input record "+row); + + String label=inputDataTable.getStringValueAt(row, "id"); + int originMaz = (int) inputDataTable.getValueAt(row, "orig_maz"); + int destinationMaz = (int) inputDataTable.getValueAt(row, "dest_maz"); + int period = (int) inputDataTable.getValueAt(row, "period")-1; //Input is 1=EA, 2=AM, 3=MD, 4=PM, 5=EV + int accessMode = (int) inputDataTable.getValueAt(row, "accessEgress"); // 1 walk, 2 PNR, 3 KNR\bike + int inbound = (int) inputDataTable.getValueAt(row, "inbound"); // 1 if inbound, else 0 + + int accessEgressMode = -1; + + if(accessMode ==1) + accessEgressMode=bestPathCalculator.WTW; + else if ((accessMode == 2||accessMode==3) && inbound==0) + accessEgressMode = bestPathCalculator.DTW; + else if ((accessMode == 2||accessMode==3) && inbound==1) + accessEgressMode = bestPathCalculator.WTD; + + if(originMaz==0||destinationMaz==0||accessEgressMode==-1) + continue; + + + int originTaz = mgraManager.getTaz(originMaz); + int destinationTaz = mgraManager.getTaz(destinationMaz); + + float odDistance = (float) tazDistanceCalculator.getTazToTazDistance(ModelStructure.AM_SKIM_PERIOD_INDEX, originTaz, destinationTaz); + bestTaps = bestPathCalculator.getBestTapPairs(walkDmu, driveDmu, accessEgressMode, originMaz, destinationMaz, period, false, logger, odDistance); + double[] bestUtilities = bestPathCalculator.getBestUtilities(); + + //iterate through n-best paths + for (int i = 0; i < bestTaps.length; i++) + { + if(bestUtilities[i]<-500) + continue; + + writer.print(label); + + //write transit TAP pairs and utility + int boardTap = (int) bestTaps[i][0]; + int alightTap = (int) bestTaps[i][1]; + int set = (int) bestTaps[i][2]; + + writer.format(",%d,%d,%d,%d,%d,%d,%9.4f",i,accessMode,period,set,boardTap,alightTap,bestUtilities[i]); + + // System.out.println(label+String.format(",%d,%d,%d,%d,%d,%d,%9.4f",i,accessEgressMode,period,set,boardTap,alightTap,bestUtilities[i])); + //write skims + if(accessEgressMode==bestPathCalculator.WTW){ + boardAccessTime = mgraManager.getWalkTimeFromMgraToTap(originMaz,boardTap); + alightAccessTime = mgraManager.getWalkTimeFromMgraToTap(destinationMaz,alightTap); + skims = wtw.getWalkTransitWalkSkims(set, boardAccessTime, alightAccessTime, boardTap, alightTap, period, false); + }else if (accessEgressMode==bestPathCalculator.DTW){ + boardAccessTime = tazManager.getTimeToTapFromTaz(originTaz,boardTap,( accessMode==2? Modes.AccessMode.PARK_N_RIDE : Modes.AccessMode.KISS_N_RIDE)); + alightAccessTime = mgraManager.getWalkTimeFromMgraToTap(destinationMaz,alightTap); + skims = dtw.getDriveTransitWalkSkims(set, boardAccessTime, alightAccessTime, boardTap, alightTap, period, false); + }else if(accessEgressMode==bestPathCalculator.WTD){ + boardAccessTime = mgraManager.getWalkTimeFromMgraToTap(originMaz,boardTap); + alightAccessTime = tazManager.getTimeToTapFromTaz(destinationTaz,alightTap,( accessMode==2? Modes.AccessMode.PARK_N_RIDE : Modes.AccessMode.KISS_N_RIDE)); + skims = wtd.getWalkTransitDriveSkims(set, boardAccessTime, alightAccessTime, boardTap, alightTap, period, false); + } + + for(int j=0; j < skims.length; ++j) + writer.format(",%9.2f",skims[j]); + + writer.format("\n"); + + } + writer.flush(); + } + + + } + + /** + * Startup a connection to the matrix manager. + * + * @param serverAddress + * @param serverPort + * @param mt + * @return + */ + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + try + { + // create the concrete data server object + matrixServer.start32BitMatrixIoServer(mt); + } catch (RuntimeException e) + { + matrixServer.stop32BitMatrixIoServer(); + logger.error( + "RuntimeException caught making remote method call to start 32 bit mitrix in remote MatrixDataServer.", + e); + } + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + matrixServer.stop32BitMatrixIoServer(); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + matrixServer.stop32BitMatrixIoServer(); + throw new RuntimeException(); + } + + return matrixServer; + + } + + + /** + * Main run method + * @param args + */ + public static void main(String[] args) { + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("Best Tap Pairs Program using CT-RAMP version ", + CtrampApplication.VERSION)); + + logger.info(String.format("Outputting TAP pairs and utilities for on-board survey data")); + + + String inputFile = null; + String outputFile = null; + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else { + propertiesFile = args[0]; + + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-inputFile")) + { + inputFile = args[i + 1]; + } + if (args[i].equalsIgnoreCase("-outputFile")) + { + outputFile = args[i + 1]; + } + } + } + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + OutputTapPairs outputTapPairs = new OutputTapPairs(pMap, inputFile, outputFile); + + + outputTapPairs.run(); + + + + + } + private void startMatrixServer(HashMap properties) { + String serverAddress = (String) properties.get("RunModel.MatrixServerAddress"); + int serverPort = new Integer((String) properties.get("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try{ + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + MatrixDataServerIf ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) { + logger.error("could not connect to matrix server", e); + throw new RuntimeException(e); + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/utilities/CreateLogsums.java b/sandag_abm/src/main/java/org/sandag/abm/utilities/CreateLogsums.java new file mode 100644 index 0000000..ae898e5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/utilities/CreateLogsums.java @@ -0,0 +1,410 @@ +package org.sandag.abm.utilities; + +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.jppf.client.JPPFClient; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagHouseholdDataManager; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.HouseholdChoiceModelRunner; +import org.sandag.abm.ctramp.HouseholdDataManager; +import org.sandag.abm.ctramp.HouseholdDataManagerIf; +import org.sandag.abm.ctramp.HouseholdDataManagerRmi; +import org.sandag.abm.ctramp.HouseholdDataWriter; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.UsualWorkSchoolLocationChoiceModel; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.util.ResourceUtil; + +public class CreateLogsums { + + + private BuildAccessibilities aggAcc; + private JPPFClient jppfClient; + private static Logger logger = Logger.getLogger(CreateLogsums.class); + private HouseholdDataManagerIf householdDataManager; + private HashMap propertyMap; + private ResourceBundle resourceBundle; + // are used if no command line arguments are specified. + private int globalIterationNumber = 0; + private float iterationSampleRate = 0f; + private int sampleSeed = 0; + private SandagModelStructure modelStructure; + private SandagCtrampDmuFactory dmuFactory; + private MatrixDataServerIf ms; + private ModelOutputReader modelOutputReader; + + + /** + * Constructor. + * + * @param propertiesFile + * @param globalIterationNumber + * @param globalSampleRate + * @param sampleSeed + */ + public CreateLogsums(String propertiesFile, int globalIterationNumber, float globalSampleRate, int sampleSeed){ + + this.resourceBundle = ResourceBundle.getBundle(propertiesFile); + propertyMap = ResourceUtil.getResourceBundleAsHashMap ( propertiesFile); + this.globalIterationNumber = globalIterationNumber; + this.iterationSampleRate = globalSampleRate; + this.sampleSeed = sampleSeed; + + } + + /** + * Initialize data members + */ + public void initialize(){ + + startMatrixServer(propertyMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + householdDataManager = getHouseholdDataManager(); + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager after getting household manager"); + + // create a factory object to pass to various model components from which + // they can create DMU objects + dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + modelOutputReader = new ModelOutputReader(propertyMap,modelStructure, globalIterationNumber); + } + + + /** + * Run all components. + * + */ + public void run(){ + + initialize(); + readModelOutputsAndCreateTours(); + createWorkLogsums(); + createNonWorkLogsums(); + + HouseholdDataWriter dataWriter = new HouseholdDataWriter( propertyMap, modelStructure, globalIterationNumber ); + dataWriter.writeDataToFiles(householdDataManager); + + } + + /** + * Read the model outputs and create tours. + */ + public void readModelOutputsAndCreateTours(){ + + modelOutputReader.readHouseholdDataOutput(); + modelOutputReader.readPersonDataOutput(); + modelOutputReader.readTourDataOutput(); + + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager before reading model output"); + + Household[] households = householdDataManager.getHhArray(); + for(Household household : households){ + + modelOutputReader.setHouseholdAndPersonAttributes(household); + + if(modelOutputReader.hasJointTourFile()) + modelOutputReader.createJointTours(household); + + if(modelOutputReader.hasIndividualTourFile()) + modelOutputReader.createIndividualTours(household); + } + householdDataManager.setHhArray(households); + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager after reading model output"); + + } + + + + /** + * Calculate and write work destination choice logsums for the synthetic population. + * + * @param propertyMap + */ + public void createWorkLogsums(){ + + jppfClient = new JPPFClient(); + + if (aggAcc == null) + { + logger.info("creating Accessibilities Object for UWSL."); + aggAcc = BuildAccessibilities.getInstance(); + aggAcc.setupBuildAccessibilities(propertyMap,false); +// aggAcc.setJPPFClient(jppfClient); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateConstants(); + + boolean readAccessibilities = ResourceUtil.getBooleanProperty(resourceBundle, "acc.read.input.file"); + if (readAccessibilities) + { + String projectDirectory = Util.getStringValueFromPropertyMap(propertyMap,"Project.Directory"); + String accFileName = Paths.get(projectDirectory,Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file")).toString(); + + aggAcc.readAccessibilityTableFromFile(accFileName); + + } else + { + + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + } + } + + // new the usual school and location choice model object + UsualWorkSchoolLocationChoiceModel usualWorkSchoolLocationChoiceModel = new UsualWorkSchoolLocationChoiceModel( + resourceBundle, "none", jppfClient, modelStructure, ms, dmuFactory, aggAcc); + + // calculate and get the array of worker size terms table - MGRAs by + // occupations + aggAcc.createWorkSegmentNameIndices(); + aggAcc.calculateWorkerSizeTerms(); + double[][] workerSizeTerms = aggAcc.getWorkerSizeTerms(); + + // run the model + logger.info("Starting usual work location choice for logsum calculations."); + usualWorkSchoolLocationChoiceModel.runWorkLocationChoiceModel(householdDataManager, workerSizeTerms); + logger.info("Finished with usual work location choice for logsum calculations."); + + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager after running school and work location choice"); + + } + + public void createNonWorkLogsums(){ + + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager before running non-work logsums"); + + HouseholdChoiceModelRunner runner = new HouseholdChoiceModelRunner( propertyMap, jppfClient, "False", householdDataManager, ms, modelStructure, dmuFactory ); + runner.runHouseholdChoiceModels(); + + } + + + + /** + * Create the household data manager. Based on the code in MTCTM2TourBasedModel.runTourBasedModel() + * @return The household data manager interface. + */ + public HouseholdDataManagerIf getHouseholdDataManager( ){ + + + boolean localHandlers = false; + + String testString; + + HouseholdDataManagerIf householdDataManager; + String hhHandlerAddress = ""; + int hhServerPort = 0; + try + { + // get household server address. if none is specified a local server in + // the current process will be started. + hhHandlerAddress = resourceBundle.getString("RunModel.HouseholdServerAddress"); + try + { + // get household server port. + hhServerPort = Integer.parseInt(resourceBundle.getString("RunModel.HouseholdServerPort")); + localHandlers = false; + } catch (MissingResourceException e) + { + // if no household data server address entry is found, the object + // will be created in the local process + localHandlers = true; + } + } catch (MissingResourceException e) + { + localHandlers = true; + } + + + try + { + + if (localHandlers) + { + + // create a new local instance of the household array manager + householdDataManager = new SandagHouseholdDataManager(); + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population + // files and apply its tables to objects mapping method. + String inputHouseholdFileName = resourceBundle.getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = resourceBundle.getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(iterationSampleRate, sampleSeed); + householdDataManager.setupHouseholdDataManager(modelStructure, inputHouseholdFileName, inputPersonFileName); + + } else + { + + householdDataManager = new HouseholdDataManagerRmi(hhHandlerAddress, hhServerPort, + SandagHouseholdDataManager.HH_DATA_SERVER_NAME); + testString = householdDataManager.testRemote(); + logger.info("HouseholdDataManager test: " + testString); + + householdDataManager.setPropertyFileValues(propertyMap); + } + + //always starting from scratch (RunModel.RestartWithHhServer=none) + householdDataManager.setDebugHhIdsFromHashmap(); + + String inputHouseholdFileName = resourceBundle + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = resourceBundle + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(iterationSampleRate, sampleSeed); + householdDataManager.setupHouseholdDataManager(modelStructure, inputHouseholdFileName, inputPersonFileName); + + }catch (Exception e) + { + + logger.error(String + .format("Exception caught setting up household data manager."), e); + throw new RuntimeException(); + + } + + return householdDataManager; + } + + + /** + * Start a new matrix server connection. + * + * @param properties + */ + private void startMatrixServer(HashMap properties) { + String serverAddress = (String) properties.get("RunModel.MatrixServerAddress"); + int serverPort = new Integer((String) properties.get("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try{ + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) { + logger.error("could not connect to matrix server", e); + throw new RuntimeException(e); + + } + + } + + + public JPPFClient getJppfClient() { + return jppfClient; + } + + public void setJppfClient(JPPFClient jppfClient) { + this.jppfClient = jppfClient; + } + + public static void main(String[] args) { + + long startTime = System.currentTimeMillis(); + int globalIterationNumber = -1; + float iterationSampleRate = -1.0f; + int sampleSeed = -1; + + ResourceBundle rb = null; + + logger.info( String.format( "Generating Logsums from MTC Tour Based Model using CT-RAMP version %s, 22feb2011 build %s", CtrampApplication.VERSION, 2 ) ); + + if ( args.length == 0 ) { + logger.error( String.format( "no properties file base name (without .properties extension) was specified as an argument." ) ); + return; + } + else { + rb = ResourceBundle.getBundle( args[0] ); + + // optional arguments + for (int i=1; i < args.length; i++) { + + if (args[i].equalsIgnoreCase("-iteration")) { + globalIterationNumber = Integer.parseInt( args[i+1] ); + logger.info( String.format( "-iteration %d.", globalIterationNumber ) ); + } + + if (args[i].equalsIgnoreCase("-sampleRate")) { + iterationSampleRate = Float.parseFloat( args[i+1] ); + logger.info( String.format( "-sampleRate %.4f.", iterationSampleRate ) ); + } + + if (args[i].equalsIgnoreCase("-sampleSeed")) { + sampleSeed = Integer.parseInt( args[i+1] ); + logger.info( String.format( "-sampleSeed %d.", sampleSeed ) ); + } + + } + + if ( globalIterationNumber < 0 ) { + globalIterationNumber = 1; + logger.info( String.format( "no -iteration flag, default value %d used.", globalIterationNumber ) ); + } + + if ( iterationSampleRate < 0 ) { + iterationSampleRate = 1; + logger.info( String.format( "no -sampleRate flag, default value %.4f used.", iterationSampleRate ) ); + } + + if ( sampleSeed < 0 ) { + sampleSeed = 0; + logger.info( String.format( "no -sampleSeed flag, default value %d used.", sampleSeed ) ); + } + + } + + + String baseName; + if ( args[0].endsWith(".properties") ) { + int index = args[0].indexOf(".properties"); + baseName = args[0].substring(0, index); + } + else { + baseName = args[0]; + } + + + // create an instance of this class for main() to use. + CreateLogsums mainObject = new CreateLogsums( args[0], globalIterationNumber, iterationSampleRate, sampleSeed ); + + // Create logsums + try { + + logger.info ("Creating logsums."); + mainObject.run(); + + } + catch ( RuntimeException e ) { + logger.error ( "RuntimeException caught in com.pb.mtctm2.abm.reports.CreateLogsums.main() -- exiting.", e ); + System.exit(2); + } + + + logger.info (""); + logger.info (""); + logger.info ("CreateLogsums finished in " + ((System.currentTimeMillis() - startTime) / 60000.0) + " minutes."); + + System.exit(0); + + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/utilities/ErrorLogging.java b/sandag_abm/src/main/java/org/sandag/abm/utilities/ErrorLogging.java new file mode 100644 index 0000000..92ee34d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/utilities/ErrorLogging.java @@ -0,0 +1,41 @@ +package org.sandag.abm.utilities; + +import java.util.HashMap; +/** + * ErrorLogging definitions + * + * @author wsu + * @mail Wu.Sun@sandag.org + * @version 13.3.0 + * @since 2016-06-20 + * + */ +public class ErrorLogging { + public static final String AtTapNotInTransitNetwork = "A TAP in AT network is not in TRANSIT network!"; + public static final String TransitTapNotInAt = "A TAP in TRANSIT network is not in AT network!"; + public static final String InconsistentTapPostions = "Positions of a TAP are different in AT and TRANSIT networks!"; + public static final String NoAtTaps = "No valid TAPs in AT network!"; + public static final String NoTransitTaps = "No valid TAPs in TRANSIT network!"; + protected HashMap atErrorIndexMap; + + public ErrorLogging() + { + + atErrorIndexMap = new HashMap(); + createAtErrorIndexMap(); + } + private void createAtErrorIndexMap() + { + atErrorIndexMap.put("AT1", AtTapNotInTransitNetwork); + atErrorIndexMap.put("AT2", TransitTapNotInAt ); + atErrorIndexMap.put("AT3", InconsistentTapPostions); + atErrorIndexMap.put("AT4", NoAtTaps); + atErrorIndexMap.put("AT5", NoTransitTaps); + } + + public String getAtError(String index) + { + return atErrorIndexMap.get(index); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/utilities/ModelOutputReader.java b/sandag_abm/src/main/java/org/sandag/abm/utilities/ModelOutputReader.java new file mode 100644 index 0000000..23ef9fa --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/utilities/ModelOutputReader.java @@ -0,0 +1,836 @@ +package org.sandag.abm.utilities; + +import java.io.File; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.ModelStructure; +import org.sandag.abm.ctramp.Person; +import org.sandag.abm.ctramp.Tour; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +public class ModelOutputReader { + + private transient Logger logger = Logger.getLogger(ModelOutputReader.class); + + private static final String PROPERTIES_HOUSEHOLD_DATA_FILE = "Accessibilities.HouseholdDataFile"; + private static final String PROPERTIES_PERSON_DATA_FILE = "Accessibilities.PersonDataFile"; + private static final String PROPERTIES_INDIV_TOUR_DATA_FILE = "Accessibilities.IndivTourDataFile"; + private static final String PROPERTIES_JOINT_TOUR_DATA_FILE = "Accessibilities.JointTourDataFile"; + private static final String PROPERTIES_INDIV_TRIP_DATA_FILE = "Accessibilities.IndivTripDataFile"; + private static final String PROPERTIES_JOINT_TRIP_DATA_FILE = "Accessibilities.JointTripDataFile"; + private ModelStructure modelStructure; + private int iteration; + private HashMap rbMap; + private HashMap householdFileAttributesMap; + private HashMap personFileAttributesMap; + private HashMap> individualTourAttributesMap; //by person_id + private HashMap> jointTourAttributesMap; //by hh_id + + private boolean readIndividualTourFile = false; + private boolean readJointTourFile = false; + + /** + * Default constructor. + * @param rbMap Hashmap of properties + * @param modelStructure Model structure object + * @param iteration Iteration number used for file names + */ + public ModelOutputReader(HashMap rbMap, ModelStructure modelStructure, + int iteration) + { + logger.info("Writing data structures to files."); + this.modelStructure = modelStructure; + this.iteration = iteration; + this.rbMap = rbMap; + } + + + /** + * Read household data and store records in householdFileAttributesMap + */ + public void readHouseholdDataOutput(){ + + String baseDir = rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String hhFile = rbMap.get(PROPERTIES_HOUSEHOLD_DATA_FILE); + + TableDataSet householdData = readTableData(baseDir+hhFile); + + householdFileAttributesMap = new HashMap(); + + //hh_id,home_mgra,income,HVs,AVs,transponder,cdap_pattern,out_escort_choice,inb_escort_choice,jtf_choice + for(int row = 1; row<=householdData.getRowCount();++row){ + + long hhid = (long) householdData.getValueAt(row,"hh_id"); + int home_mgra = (int)householdData.getValueAt(row,"home_mgra"); + int income = (int) householdData.getValueAt(row,"income"); + int automated_vehicles = (int) householdData.getValueAt(row,"AVs"); + int human_vehicles = (int) householdData.getValueAt(row,"HVs"); + int autos = automated_vehicles + human_vehicles; + int transponder = (int) householdData.getValueAt(row,"transponder"); + String cdap_pattern = householdData.getStringValueAt(row,"cdap_pattern"); + int jtf_choice = (int) householdData.getValueAt(row,"jtf_choice"); + int out_escort_choice = (int) householdData.getValueAt(row,"out_escort_choice"); + int inb_escort_choice = (int) householdData.getValueAt(row,"inb_escort_choice"); + + + // float sampleRate = householdData.getValueAt(row,"sampleRate"); + HouseholdFileAttributes hhAttributes = new HouseholdFileAttributes(hhid, + home_mgra, income, autos, automated_vehicles, human_vehicles,transponder,cdap_pattern, + jtf_choice,out_escort_choice,inb_escort_choice); + + householdFileAttributesMap.put(hhid, hhAttributes); + + } + } + + + /** + * Read the data from the Results.PersonDataFile. + * Data is stored in HashMap personFileAttributesMap + * so that it can be retrieved quickly for a household object. + * + */ + public void readPersonDataOutput(){ + + //read person data + String baseDir = rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String personFile = baseDir + rbMap.get(PROPERTIES_PERSON_DATA_FILE); + TableDataSet personData = readTableData(personFile); + + personFileAttributesMap = new HashMap(); + //hh_id,person_id,person_num,age,gender,type,value_of_time,activity_pattern,imf_choice,inmf_choice, + // fp_choice,reimb_pct,tele_choice,ie_choice,timeFactorWork,timeFactorNonWork + + for(int row = 1; row<=personData.getRowCount();++row){ + + //get the values for this person + long hhid = (long) personData.getValueAt(row, "hh_id"); + long person_id = (long) personData.getValueAt(row,"person_id"); + long personNumber = (long) personData.getValueAt(row,"person_num"); + int age = (int) personData.getValueAt(row,"age"); + + String genderString = personData.getStringValueAt(row,"gender"); + int gender = (genderString.compareTo("m")==0 ? 1 : 2); + + float valueOfTime = personData.getValueAt(row,"value_of_time"); + String activityPattern = personData.getStringValueAt(row,"activity_pattern"); + String type = personData.getStringValueAt(row,"type"); + int personType = getPersonType(type); + + // int occup = (int) personData.getValueAt(row,"occp"); + + + int imfChoice = (int) personData.getValueAt(row, "imf_choice"); + int inmfChoice = (int) personData.getValueAt(row, "inmf_choice"); + int fp_choice = (int) personData.getValueAt(row,"fp_choice"); + float reimb_pct = personData.getValueAt(row,"reimb_pct"); + int tele_choice = (int) personData.getValueAt(row,"tele_choice"); + int ie_choice = (int) personData.getValueAt(row,"ie_choice"); + float timeFactorWork = personData.getValueAt(row,"timeFactorWork"); + float timeFactorNonWork = personData.getValueAt(row,"timeFactorNonWork"); + + //float sampleRate = personData.getValueAt(row,"sampleRate"); + + PersonFileAttributes personFileAttributes = new PersonFileAttributes(hhid,person_id,personNumber,age,gender,valueOfTime, + activityPattern,personType, imfChoice,inmfChoice,fp_choice,reimb_pct,tele_choice, + ie_choice, timeFactorWork, timeFactorNonWork); + + personFileAttributesMap.put(person_id,personFileAttributes); + + } + + } + + /** + * Read both tour files. + * + */ + public void readTourDataOutput(){ + + String baseDir = rbMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + + if(rbMap.containsKey(PROPERTIES_INDIV_TOUR_DATA_FILE)){ + String indivTourFile = rbMap.get(PROPERTIES_INDIV_TOUR_DATA_FILE); + if(indivTourFile != null){ + if(indivTourFile.length()>0){ + individualTourAttributesMap = readTourData(baseDir+indivTourFile, false, individualTourAttributesMap); + readIndividualTourFile = true; + } + } + } + if(rbMap.containsKey(PROPERTIES_JOINT_TOUR_DATA_FILE)){ + String jointTourFile = rbMap.get(PROPERTIES_JOINT_TOUR_DATA_FILE); + if(jointTourFile != null){ + if(jointTourFile.length()>0){ + jointTourAttributesMap = readTourData(baseDir+jointTourFile, true, jointTourAttributesMap); + readJointTourFile = true; + } + } + } + if(readIndividualTourFile==false){ + logger.info("No individual tour file to read in MtcModelOutputReader class"); + } + if(readJointTourFile==false){ + logger.info("No joint tour file to read in MtcModelOutputReader class"); + } + } + + + /** + * Read the data from the Results.IndivTourDataFile or Results.JointTourDataFile. + * Data is stored in HashMap passed into method as an argument. Method handles + * both individual and joint data. Joint tour data is indexed by hh_id + * so that it can be retrieved quickly for a household object. Individual tour data is + * indexed by person_id. + * + */ + public HashMap> readTourData(String filename, boolean isJoint, HashMap> tourFileAttributesMap ){ + + TableDataSet tourData = readTableData(filename); + + tourFileAttributesMap = new HashMap>(); + //hh_id,person_id,person_num,person_type,tour_id,tour_category,tour_purpose, + //orig_mgra,dest_mgra,start_period,end_period,tour_mode,av_avail,tour_distance,atwork_freq, + //num_ob_stops,num_ib_stops,valueOfTime,escort_type_out,escort_type_in,driver_num_out,driver_num_in + + for(int row = 1; row<=tourData.getRowCount();++row){ + + long hh_id = (long) tourData.getValueAt(row,"hh_id"); + long person_id = 0; + int person_num=0; + int person_type=0; + int escort_type_out=0; + int escort_type_in=0; + int driver_num_out=0; + int driver_num_in=0; + if(!isJoint){ + person_id = (long) tourData.getValueAt(row,"person_id");; + person_num = (int) tourData.getValueAt(row,"person_num"); + person_type = (int) tourData.getValueAt(row,"person_type"); + escort_type_out = (int) tourData.getValueAt(row,"escort_type_out"); + escort_type_in = (int) tourData.getValueAt(row,"escort_type_in"); + driver_num_out = (int) tourData.getValueAt(row,"driver_num_out"); + driver_num_in = (int) tourData.getValueAt(row,"driver_num_in"); + } + int tour_id = (int) tourData.getValueAt(row,"tour_id"); + String tour_category = tourData.getStringValueAt(row,"tour_category"); + String tour_purpose = tourData.getStringValueAt(row,"tour_purpose"); + + int tour_composition = 0; + String tour_participants = null; + if(isJoint){ + tour_composition = (int) tourData.getValueAt(row,"tour_composition"); + tour_participants = tourData.getStringValueAt(row,"tour_participants"); + } + + int orig_mgra = (int) tourData.getValueAt(row,"orig_mgra"); + int dest_mgra = (int) tourData.getValueAt(row,"dest_mgra"); + int start_period = (int) tourData.getValueAt(row,"start_period"); + int end_period = (int) tourData.getValueAt(row,"end_period"); + int tour_mode = (int) tourData.getValueAt(row,"tour_mode"); + int av_avail = (int) tourData.getValueAt(row,"av_avail"); + float tour_distance = tourData.getValueAt(row,"tour_distance"); + // float tour_time = tourData.getValueAt(row,"tour_time"); + int atWork_freq = (int) tourData.getValueAt(row,"atWork_freq"); + int num_ob_stops = (int) tourData.getValueAt(row,"num_ob_stops"); + int num_ib_stops = (int) tourData.getValueAt(row,"num_ib_stops"); + float valueOfTime = tourData.getValueAt(row, "valueOfTime"); + /* + int out_btap = (int) tourData.getValueAt(row,"out_btap"); + int out_atap = (int) tourData.getValueAt(row,"out_atap"); + int in_btap = (int) tourData.getValueAt(row,"in_btap"); + int in_atap = (int) tourData.getValueAt(row,"in_atap"); + int out_set = (int) tourData.getValueAt(row,"out_set"); + int in_set = (int) tourData.getValueAt(row,"in_set"); +// float sampleRate = tourData.getValueAt(row,"sampleRate"); +// int avAvailable = (int) tourData.getValueAt(row,"avAvailable"); + */ float[] util = new float[modelStructure.getMaxTourModeIndex()]; + float[] prob = new float[modelStructure.getMaxTourModeIndex()]; + + TourFileAttributes tourFileAttributes = new TourFileAttributes(hh_id, person_id, person_num, person_type, + tour_id, tour_category, tour_purpose, orig_mgra,dest_mgra, + start_period, end_period, tour_mode, av_avail, tour_distance, + atWork_freq, num_ob_stops, num_ib_stops, valueOfTime, + escort_type_out,escort_type_in,driver_num_out,driver_num_in, + tour_composition, tour_participants,util,prob); + + //if individual tour, map key is person_id, else it is hh_id + long key = -1; + if(!isJoint) + key = person_id; + else + key = hh_id; + + //if the not the first tour for this person or hh, add the tour to the existing + //arraylist; else create a new arraylist and add the tour attributes to it, + //then add the arraylist to the map + if(tourFileAttributesMap.containsKey(key)){ + ArrayList tourArray = tourFileAttributesMap.get(key); + tourArray.add(tourFileAttributes); + }else{ + ArrayList tourArray = new ArrayList(); + tourArray.add(tourFileAttributes); + tourFileAttributesMap.put(key, tourArray); + } + + } + + return tourFileAttributesMap; + } + + /** + * Create individual tour objects for all persons in the household object based + * on the data read in the individual tour file. + * + * @param household + */ + public void createIndividualTours(Household household){ + + HashMap purposeIndexMap = modelStructure.getPrimaryPurposeNameIndexMap(); + Person[] persons = household.getPersons(); + for(int pnum=1;pnum tourAttributesArray = individualTourAttributesMap.get(personId); + + //store tours by type + ArrayList workTours = new ArrayList(); + ArrayList universityTours = new ArrayList(); + ArrayList schoolTours = new ArrayList(); + ArrayList atWorkSubtours = new ArrayList(); + ArrayList nonMandTours = new ArrayList(); + + for(int i=0;i0){ + p.createWorkTours(workTours.size(), 0, ModelStructure.WORK_PRIMARY_PURPOSE_NAME, + ModelStructure.WORK_PRIMARY_PURPOSE_INDEX); + ArrayList workTourArrayList = p.getListOfWorkTours(); + for(int i=0;i0){ + p.createSchoolTours(schoolTours.size(), 0, ModelStructure.SCHOOL_PRIMARY_PURPOSE_NAME, + ModelStructure.SCHOOL_PRIMARY_PURPOSE_INDEX); + ArrayList schoolTourArrayList = p.getListOfSchoolTours(); + for(int i=0;i0){ + p.createSchoolTours(universityTours.size(), 0, ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_NAME, + ModelStructure.UNIVERSITY_PRIMARY_PURPOSE_INDEX); + ArrayList universityTourArrayList = p.getListOfSchoolTours(); + for(int i=0;i nonMandTourArrayList = p.getListOfIndividualNonMandatoryTours(); + for(int i =0; i purposeIndexMap = modelStructure.getPrimaryPurposeNameIndexMap(); + + //joint tours + long hhid = household.getHhId(); + if(jointTourAttributesMap.containsKey(hhid)){ + ArrayList tourArray = jointTourAttributesMap.get(hhid); + int numberOfJointTours = tourArray.size(); + + //get the first joint tour + TourFileAttributes tourAttributes = tourArray.get(0); + String purposeString = tourAttributes.tour_purpose; + int purpose = purposeIndexMap.get(purposeString); + int composition = tourAttributes.tour_composition; + int[] tourParticipants = getTourParticipantsArray(tourAttributes.tour_participants); + + Tour t1 = new Tour(household,purposeString, ModelStructure.JOINT_NON_MANDATORY_CATEGORY, purpose); + t1.setJointTourComposition(composition); + t1.setPersonNumArray(tourParticipants); + + //if the household has two joint tours, get the second + if(numberOfJointTours==2){ + tourAttributes = tourArray.get(2); + purposeString = tourAttributes.tour_purpose; + purpose = purposeIndexMap.get(purposeString); + composition = tourAttributes.tour_composition; + tourParticipants = getTourParticipantsArray(tourAttributes.tour_participants); + + Tour t2 = new Tour(household,purposeString, ModelStructure.JOINT_NON_MANDATORY_CATEGORY, purpose); + t2.setJointTourComposition(composition); + t2.setPersonNumArray(tourParticipants); + + //set in hh object + household.createJointTourArray(t1, t2); + tourAttributes.setModeledTourAttributes(t1); + tourAttributes.setModeledTourAttributes(t2); + }else{ + household.createJointTourArray(t1); + tourAttributes.setModeledTourAttributes(t1); + } + } + + + } + +// HELPER METHODS AND CLASSES + + /** + * Split the participants string around spaces and return the + * integer array of participant numbers. + * + * @param tourParticipants + * @return + */ + public int[] getTourParticipantsArray(String tourParticipants){ + + String[] values = tourParticipants.split(" "); + int[] array = new int[values.length]; + for (int i = 0; i < array.length; i++) + array[i] = Integer.parseInt(values[i]); + return array; + } + + /** + * Set household and person attributes for this household object. This method uses + * the data in the personFileAttributesMap to set the data members of the + * Person objects for all persons in the household. + * + * @param hhObject + */ + public void setHouseholdAndPersonAttributes(Household hhObject){ + + long hhid = (long) hhObject.getHhId(); + HouseholdFileAttributes hhAttributes = householdFileAttributesMap.get(hhid); + hhAttributes.setHouseholdAttributes(hhObject); + Person[] persons = hhObject.getPersons(); + for(int i=1;i 0) + { + String base = originalFileName.substring(0, lastDot); + String ext = originalFileName.substring(lastDot); + returnString = String.format("%s_%d%s", base, iteration, ext); + } else + { + returnString = String.format("%s_%d.csv", originalFileName, iteration); + } + + logger.info("writing " + originalFileName + " file to " + returnString); + + return returnString; + } + + public HashMap getHouseholdFileAttributesMap() { + return householdFileAttributesMap; + } + + public HashMap getPersonFileAttributesMap() { + return personFileAttributesMap; + } + + public HashMap> getIndividualTourAttributesMap() { + return individualTourAttributesMap; + } + + public HashMap> getJointTourAttributesMap() { + return jointTourAttributesMap; + } + + public boolean hasIndividualTourFile() { + return readIndividualTourFile; + } + + public boolean hasJointTourFile() { + return readJointTourFile; + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/utilities/RunModeChoice.java b/sandag_abm/src/main/java/org/sandag/abm/utilities/RunModeChoice.java new file mode 100644 index 0000000..883786d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/utilities/RunModeChoice.java @@ -0,0 +1,402 @@ +package org.sandag.abm.utilities; + +import java.nio.file.Paths; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.jppf.client.JPPFClient; +import org.sandag.abm.accessibilities.BuildAccessibilities; +import org.sandag.abm.application.SandagCtrampDmuFactory; +import org.sandag.abm.application.SandagHouseholdDataManager; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Household; +import org.sandag.abm.ctramp.HouseholdChoiceModelRunner; +import org.sandag.abm.ctramp.HouseholdDataManager; +import org.sandag.abm.ctramp.HouseholdDataManagerIf; +import org.sandag.abm.ctramp.HouseholdDataManagerRmi; +import org.sandag.abm.ctramp.HouseholdDataWriter; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.UsualWorkSchoolLocationChoiceModel; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.calculator.MatrixDataServerIf; +import com.pb.common.util.ResourceUtil; + +public class RunModeChoice { + + + private BuildAccessibilities aggAcc; + private JPPFClient jppfClient; + private static Logger logger = Logger.getLogger(RunModeChoice.class); + private HouseholdDataManagerIf householdDataManager; + private HashMap propertyMap; + private ResourceBundle resourceBundle; + // are used if no command line arguments are specified. + private int globalIterationNumber = 0; + private float iterationSampleRate = 0f; + private int sampleSeed = 0; + private SandagModelStructure modelStructure; + private SandagCtrampDmuFactory dmuFactory; + private MatrixDataServerIf ms; + private ModelOutputReader modelOutputReader; + + + /** + * Constructor. + * + * @param propertiesFile + * @param globalIterationNumber + * @param globalSampleRate + * @param sampleSeed + */ + public RunModeChoice(String propertiesFile, int globalIterationNumber, float globalSampleRate, int sampleSeed){ + + this.resourceBundle = ResourceBundle.getBundle(propertiesFile); + propertyMap = ResourceUtil.getResourceBundleAsHashMap ( propertiesFile); + this.globalIterationNumber = globalIterationNumber; + this.iterationSampleRate = globalSampleRate; + this.sampleSeed = sampleSeed; + + } + + /** + * Initialize data members + */ + public void initialize(){ + + startMatrixServer(propertyMap); + + // create modelStructure object + modelStructure = new SandagModelStructure(); + + householdDataManager = getHouseholdDataManager(); + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager after getting household manager"); + + // create a factory object to pass to various model components from which + // they can create DMU objects + dmuFactory = new SandagCtrampDmuFactory(modelStructure,propertyMap); + + modelOutputReader = new ModelOutputReader(propertyMap,modelStructure, globalIterationNumber); + + jppfClient = new JPPFClient(); + + } + + + /** + * Run all components. + * + */ + public void run(){ + + initialize(); + readModelOutputsAndCreateTours(); + runHouseholdModels(); + HouseholdDataWriter dataWriter = new HouseholdDataWriter( propertyMap, modelStructure, globalIterationNumber ); + dataWriter.writeDataToFiles(householdDataManager); + + } + + /** + * Read the model outputs and create tours. + */ + public void readModelOutputsAndCreateTours(){ + + modelOutputReader.readHouseholdDataOutput(); + modelOutputReader.readPersonDataOutput(); + modelOutputReader.readTourDataOutput(); + + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager before reading model output"); + + Household[] households = householdDataManager.getHhArray(); + for(Household household : households){ + + modelOutputReader.setHouseholdAndPersonAttributes(household); + + if(modelOutputReader.hasJointTourFile()) + modelOutputReader.createJointTours(household); + + if(modelOutputReader.hasIndividualTourFile()) + modelOutputReader.createIndividualTours(household); + } + householdDataManager.setHhArray(households); + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager after reading model output"); + + } + + + + /** + * Calculate and write work destination choice logsums for the synthetic population. + * + * @param propertyMap + */ + public void createWorkLogsums(){ + + + if (aggAcc == null) + { + logger.info("creating Accessibilities Object for UWSL."); + aggAcc = BuildAccessibilities.getInstance(); + aggAcc.setupBuildAccessibilities(propertyMap,false); +// aggAcc.setJPPFClient(jppfClient); + + aggAcc.calculateSizeTerms(); + aggAcc.calculateConstants(); + + boolean readAccessibilities = ResourceUtil.getBooleanProperty(resourceBundle, "acc.read.input.file"); + if (readAccessibilities) + { + String projectDirectory = Util.getStringValueFromPropertyMap(propertyMap,"Project.Directory"); + String accFileName = Paths.get(projectDirectory,Util.getStringValueFromPropertyMap(propertyMap, "acc.output.file")).toString(); + + aggAcc.readAccessibilityTableFromFile(accFileName); + + } else + { + + aggAcc.calculateDCUtilitiesDistributed(propertyMap); + + } + } + + // new the usual school and location choice model object + UsualWorkSchoolLocationChoiceModel usualWorkSchoolLocationChoiceModel = new UsualWorkSchoolLocationChoiceModel( + resourceBundle, "none", jppfClient, modelStructure, ms, dmuFactory, aggAcc); + + // calculate and get the array of worker size terms table - MGRAs by + // occupations + aggAcc.createWorkSegmentNameIndices(); + aggAcc.calculateWorkerSizeTerms(); + double[][] workerSizeTerms = aggAcc.getWorkerSizeTerms(); + + // run the model + logger.info("Starting usual work location choice for logsum calculations."); + usualWorkSchoolLocationChoiceModel.runWorkLocationChoiceModel(householdDataManager, workerSizeTerms); + logger.info("Finished with usual work location choice for logsum calculations."); + + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager after running school and work location choice"); + + } + + public void runHouseholdModels(){ + + logger.info("There are " + householdDataManager.getNumHouseholds()+" households in hh manager before running non-work logsums"); + + HouseholdChoiceModelRunner runner = new HouseholdChoiceModelRunner( propertyMap, jppfClient, "False", householdDataManager, ms, modelStructure, dmuFactory ); + runner.runHouseholdChoiceModels(); + + } + + + + /** + * Create the household data manager. Based on the code in MTCTM2TourBasedModel.runTourBasedModel() + * @return The household data manager interface. + */ + public HouseholdDataManagerIf getHouseholdDataManager( ){ + + + boolean localHandlers = false; + + String testString; + + HouseholdDataManagerIf householdDataManager; + String hhHandlerAddress = ""; + int hhServerPort = 0; + try + { + // get household server address. if none is specified a local server in + // the current process will be started. + hhHandlerAddress = resourceBundle.getString("RunModel.HouseholdServerAddress"); + try + { + // get household server port. + hhServerPort = Integer.parseInt(resourceBundle.getString("RunModel.HouseholdServerPort")); + localHandlers = false; + } catch (MissingResourceException e) + { + // if no household data server address entry is found, the object + // will be created in the local process + localHandlers = true; + } + } catch (MissingResourceException e) + { + localHandlers = true; + } + + + try + { + + if (localHandlers) + { + + // create a new local instance of the household array manager + householdDataManager = new SandagHouseholdDataManager(); + householdDataManager.setPropertyFileValues(propertyMap); + + // have the household data manager read the synthetic population + // files and apply its tables to objects mapping method. + String inputHouseholdFileName = resourceBundle.getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = resourceBundle.getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(iterationSampleRate, sampleSeed); + householdDataManager.setupHouseholdDataManager(modelStructure, inputHouseholdFileName, inputPersonFileName); + + } else + { + + householdDataManager = new HouseholdDataManagerRmi(hhHandlerAddress, hhServerPort, + SandagHouseholdDataManager.HH_DATA_SERVER_NAME); + testString = householdDataManager.testRemote(); + logger.info("HouseholdDataManager test: " + testString); + + householdDataManager.setPropertyFileValues(propertyMap); + } + + //always starting from scratch (RunModel.RestartWithHhServer=none) + householdDataManager.setDebugHhIdsFromHashmap(); + + String inputHouseholdFileName = resourceBundle + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_HH); + String inputPersonFileName = resourceBundle + .getString(HouseholdDataManager.PROPERTIES_SYNPOP_INPUT_PERS); + householdDataManager.setHouseholdSampleRate(iterationSampleRate, sampleSeed); + householdDataManager.setupHouseholdDataManager(modelStructure, inputHouseholdFileName, inputPersonFileName); + + }catch (Exception e) + { + + logger.error(String + .format("Exception caught setting up household data manager."), e); + throw new RuntimeException(); + + } + + return householdDataManager; + } + + + /** + * Start a new matrix server connection. + * + * @param properties + */ + private void startMatrixServer(HashMap properties) { + String serverAddress = (String) properties.get("RunModel.MatrixServerAddress"); + int serverPort = new Integer((String) properties.get("RunModel.MatrixServerPort")); + logger.info("connecting to matrix server " + serverAddress + ":" + serverPort); + + try{ + + MatrixDataManager mdm = MatrixDataManager.getInstance(); + ms = new MatrixDataServerRmi(serverAddress, serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + ms.testRemote(Thread.currentThread().getName()); + mdm.setMatrixDataServerObject(ms); + + } catch (Exception e) { + logger.error("could not connect to matrix server", e); + throw new RuntimeException(e); + + } + + } + + + public static void main(String[] args) { + + long startTime = System.currentTimeMillis(); + int globalIterationNumber = -1; + float iterationSampleRate = -1.0f; + int sampleSeed = -1; + + ResourceBundle rb = null; + + logger.info( String.format( "Generating Logsums from MTC Tour Based Model using CT-RAMP version %s, 22feb2011 build %s", CtrampApplication.VERSION, 2 ) ); + + if ( args.length == 0 ) { + logger.error( String.format( "no properties file base name (without .properties extension) was specified as an argument." ) ); + return; + } + else { + rb = ResourceBundle.getBundle( args[0] ); + + // optional arguments + for (int i=1; i < args.length; i++) { + + if (args[i].equalsIgnoreCase("-iteration")) { + globalIterationNumber = Integer.parseInt( args[i+1] ); + logger.info( String.format( "-iteration %d.", globalIterationNumber ) ); + } + + if (args[i].equalsIgnoreCase("-sampleRate")) { + iterationSampleRate = Float.parseFloat( args[i+1] ); + logger.info( String.format( "-sampleRate %.4f.", iterationSampleRate ) ); + } + + if (args[i].equalsIgnoreCase("-sampleSeed")) { + sampleSeed = Integer.parseInt( args[i+1] ); + logger.info( String.format( "-sampleSeed %d.", sampleSeed ) ); + } + + } + + if ( globalIterationNumber < 0 ) { + globalIterationNumber = 1; + logger.info( String.format( "no -iteration flag, default value %d used.", globalIterationNumber ) ); + } + + if ( iterationSampleRate < 0 ) { + iterationSampleRate = 1; + logger.info( String.format( "no -sampleRate flag, default value %.4f used.", iterationSampleRate ) ); + } + + if ( sampleSeed < 0 ) { + sampleSeed = 0; + logger.info( String.format( "no -sampleSeed flag, default value %d used.", sampleSeed ) ); + } + + } + + + String baseName; + if ( args[0].endsWith(".properties") ) { + int index = args[0].indexOf(".properties"); + baseName = args[0].substring(0, index); + } + else { + baseName = args[0]; + } + + + // create an instance of this class for main() to use. + RunModeChoice mainObject = new RunModeChoice( args[0], globalIterationNumber, iterationSampleRate, sampleSeed ); + + // Create logsums + try { + + logger.info ("Creating logsums."); + mainObject.run(); + + } + catch ( RuntimeException e ) { + logger.error ( "RuntimeException caught in com.pb.mtctm2.abm.reports.CreateLogsums.main() -- exiting.", e ); + System.exit(2); + } + + + logger.info (""); + logger.info (""); + logger.info ("CreateLogsums finished in " + ((System.currentTimeMillis() - startTime) / 60000.0) + " minutes."); + + System.exit(0); + + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/utilities/TapAtConsistencyCheck.java b/sandag_abm/src/main/java/org/sandag/abm/utilities/TapAtConsistencyCheck.java new file mode 100644 index 0000000..f930cca --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/utilities/TapAtConsistencyCheck.java @@ -0,0 +1,183 @@ +package org.sandag.abm.utilities; + +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; + +import com.linuxense.javadbf.DBFException; +import com.linuxense.javadbf.DBFReader; + +/** + * The TapAtConsistencyCheck program implements consistency checkng between TAPs in AT and Transit networks. + * There are three types of inconsistencies: + * 1) A TAP in AT network is not in Tranist network + * 2) A TAP in Transit network is not in AT network + * 3) Positions of a TAP are different in AT and Transit networks. + * + * @author wsu + * @mail Wu.Sun@sandag.org + * @version 13.3.0 + * @since 2016-06-20 + * + */ +public class TapAtConsistencyCheck { + private static Logger logger = Logger.getLogger(TapAtConsistencyCheck.class); + private HashMap > atMap; + private HashMap > tranMap; + private float xThreshold; + private float yThreshold; + private String message; + + public TapAtConsistencyCheck(ResourceBundle aRb, String folder){ + xThreshold=Float.parseFloat(aRb.getString("AtTransitConsistency.xThreshold")); + yThreshold=Float.parseFloat(aRb.getString("AtTransitConsistency.yThreshold")); + readAtTaps(folder); + logger.info("Finished reading TAPs in AT network."); + readTranTaps(folder); + logger.info("Finished reading TAPs in transit network."); + } + + public boolean validate(){ + boolean result=false; + message=compareMap(atMap,tranMap); + if(message.equalsIgnoreCase("OK")){ + result=true; + } + return result; + } + + + private void readAtTaps(String folder){ + atMap=new HashMap>(); + Object [] atTapObjects; + + try { + InputStream inputStream = new FileInputStream(folder+"\\SANDAG_Bike_Node.dbf"); + DBFReader atTapReader = new DBFReader( inputStream); + while( (atTapObjects = atTapReader.nextRecord()) != null) { + double tap_at = (double)atTapObjects[3]; + if(tap_at>0){ + ArrayList xy=new ArrayList(); + xy.add((float)atTapObjects[4]); + xy.add((float)atTapObjects[5]); + atMap.put((int)tap_at, xy); + } + } + inputStream.close(); + }catch( DBFException e) { + System.out.println( e.getMessage()); + logger.fatal(e.getMessage()); + System.exit(-1); + }catch( IOException e) { + System.out.println( e.getMessage()); + logger.fatal(e.getMessage()); + System.exit(-1); + } + } + + private void readTranTaps(String folder){ + tranMap=new HashMap>(); + Object [] tranTapObjects; + + try { + InputStream inputStream = new FileInputStream(folder+"\\tapcov.dbf"); + DBFReader tranTapReader = new DBFReader( inputStream); + while( (tranTapObjects = tranTapReader.nextRecord()) != null) { + double tap_tran = (double)tranTapObjects[16]; + ArrayList xy=new ArrayList(); + xy.add((double)tranTapObjects[7]); + xy.add((double)tranTapObjects[8]); + tranMap.put((int)tap_tran, xy); + } + inputStream.close(); + }catch( DBFException e) { + System.out.println( e.getMessage()); + logger.fatal(e.getMessage()); + System.exit(-1); + }catch( IOException e) { + System.out.println( e.getMessage()); + logger.fatal(e.getMessage()); + System.exit(-1); + } + } + +public String compareMap(HashMap> map1, HashMap> map2) { + + String message="OK"; + + if (map1.size()==0){ + message=new ErrorLogging().getAtError("AT4"); + logger.fatal(message); + return message; + } + + if (map2.size()==0){ + message=new ErrorLogging().getAtError("AT5"); + logger.fatal(message); + return message; + } + + for (Integer ch1 : map1.keySet()) { + Float x1=map1.get(ch1).get(0); + Float y1=map1.get(ch1).get(1); + + if(map2.get(ch1)==null||map2.get(ch1)==null){ + message=new ErrorLogging().getAtError("AT1")+"(in SANDAG_Bike_Node.dbf "+"TAP="+ch1+" x_at="+x1+" y_at="+y1+")"; + logger.fatal(message); + }else{ + Double x2=map2.get(ch1).get(0); + Double y2=map2.get(ch1).get(1); + if((Math.abs(x1-x2)>xThreshold)&&(Math.abs(y1-y2)>yThreshold)){ + message=new ErrorLogging().getAtError("AT3")+"("+"TAP="+ch1+" x_at="+x1+" y_at="+y1+" x_tran="+x2+" y_tran="+y2+")"; + logger.fatal(message); + } + } + + } + + for (Integer ch2 : map2.keySet()) { + Double x2=map2.get(ch2).get(0); + Double y2=map2.get(ch2).get(1); + + if(map1.get(ch2)==null||map1.get(ch2)==null){ + message=new ErrorLogging().getAtError("AT2")+"(in tapcov.dbf "+"TAP="+ch2+" x_tran="+x2+" y_tran="+y2+")"; + logger.fatal(message); + }else{ + Float x1=map1.get(ch2).get(0); + Float y1=map1.get(ch2).get(1); + //System.out.println("TAP="+ch2+" x_at="+x1+" y_at="+y1+" x_tran="+x2+" y_tran="+y2); + if((Math.abs(x1-x2)>xThreshold)&&(Math.abs(y1-y2)>yThreshold)){ + message=new ErrorLogging().getAtError("AT3")+"("+"TAP="+ch2+" x_at="+x1+" y_at="+y1+" x_tran="+x2+" y_tran="+y2+")"; + logger.fatal(message); + } + } + } + + return message; +} + + public static void main(String[] args) + { + ResourceBundle rb = null; + logger.info("Checking AT and Transit Network Consistency..."); + + if (args.length == 0) + { + logger.error(String.format("no properties file base name (without .properties extension) was specified as an argument.")); + System.exit(-1); + } else + { + rb = ResourceBundle.getBundle(args[0]); + TapAtConsistencyCheck mainObject = new TapAtConsistencyCheck(rb, args[1]); + if(!mainObject.validate()){ + logger.fatal(mainObject.message); + System.exit(-1); + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/validation/MainApplication.java b/sandag_abm/src/main/java/org/sandag/abm/validation/MainApplication.java new file mode 100644 index 0000000..f596b5c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/validation/MainApplication.java @@ -0,0 +1,437 @@ +package org.sandag.abm.validation; + +import java.io.*; +import java.nio.file.Files; +import org.apache.poi.xssf.usermodel.XSSFCell; +import org.apache.poi.xssf.usermodel.XSSFRow; +import org.apache.poi.xssf.usermodel.XSSFSheet; +import org.apache.poi.xssf.usermodel.XSSFWorkbook; +import java.sql.Connection; +import java.sql.DriverManager; +import java.sql.ResultSet; +import java.sql.ResultSetMetaData; +import java.sql.SQLException; +import java.sql.Statement; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.ResourceBundle; + +public class MainApplication { + + public static List getHighwayFlowData(int scenario, ResourceBundle rb) throws SQLException { + + System.out.println("Getting highway flow data for scenario " + scenario + " from database ..."); + + String query = "SELECT " + + " flow.scenario_id," + + " link.hwycov_id " + + " ,sum(CONVERT(bigint,(flow.flow + link_ab_tod.preload / 3.0))) as total_flow " + + "FROM " + + " abm_13_2_3.abm.hwy_flow flow " + + "JOIN abm_13_2_3.abm.hwy_link_ab_tod link_ab_tod " + + " ON flow.scenario_id = link_ab_tod.scenario_id AND flow.hwy_link_ab_tod_id = link_ab_tod.hwy_link_ab_tod_id " + + "JOIN abm_13_2_3.abm.hwy_link_tod link_tod " + + " ON link_ab_tod.scenario_id = link_tod.scenario_id AND link_ab_tod.hwy_link_tod_id = link_tod.hwy_link_tod_id " + + "JOIN abm_13_2_3.abm.hwy_link link " + + " ON link_tod.scenario_id = link.scenario_id AND link_tod.hwy_link_id = link.hwy_link_id " + + "JOIN ref.ifc ifc " + + " ON link.ifc = ifc.ifc " + + "WHERE " + + " flow.scenario_id = " + scenario + + "GROUP BY " + + " flow.scenario_id, link.hwycov_id " + + "ORDER BY " + + " hwycov_id"; + + System.out.println(""); + return getSqlData(query, rb); + } + + public static List getTransitBoardingByModeData(int scenario, ResourceBundle rb) throws SQLException { + + System.out.println("Getting transit boarding by mode data for scenario " + scenario + " from database ..."); + + String query = "SELECT transit_mode_desc,transit_access_mode_desc,sum(boardings) " + + "FROM ws.dbo.transitBoardingSummary(" + scenario + ") " + + "GROUP BY transit_mode_desc,transit_access_mode_desc " + + "ORDER BY transit_mode_desc,transit_access_mode_desc"; + System.out.println(""); + return getSqlData(query, rb); + } + + public static List getTransitBoardingByRouteData(int scenario, ResourceBundle rb) throws SQLException { + + System.out.println("Getting transit boarding by route data for scenario " + scenario + " from database ..."); + + String query = "SELECT rtt, sum(boardings) as boardings " + + "FROM " + + "(SELECT (config/1000) as rtt, boardings " + + "FROM ws.dbo.transitBoardingSummary(" + scenario + ")" + " AS boarding " + + "JOIN abm_13_2_3.abm.transit_route route " + + " ON boarding.route_id = route.transit_route_id " + + "WHERE scenario_id = " + scenario + ") as t " + + "GROUP BY rtt " + + "ORDER BY rtt"; + System.out.println(""); + return getSqlData(query, rb); + } + + public static List getSqlData(String query, ResourceBundle rb) throws SQLException { + + String dbHost = getProperty(rb, "database.host", null); + String dbName = getProperty(rb, "database.name", null); + String user = getProperty(rb, "database.user", null); + String password = getProperty(rb, "database.pwd", null); + + // System.out.println( dbHost ); + // System.out.println( user ); + // System.out.println( password ); + // System.out.println( dbName ); + + Connection conn = null; + conn = getConnectionToDatabase(dbHost, dbName, user, password); + + Statement stmt = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, ResultSet.CONCUR_READ_ONLY); + ResultSet rs = stmt.executeQuery(query); + ResultSetMetaData rsmd = rs.getMetaData(); + + int nCols = rsmd.getColumnCount(); + + List data = new ArrayList(); + StringBuilder row = null; + + while(rs.next()){ + row = new StringBuilder(); + for(int c = 1; c <= nCols; c++){ + row.append(rs.getString(c)); + + if(c < nCols) + row.append("|"); + } + data.add(row.toString()); + } + + conn.close(); + + return data; + } + + public static void printData(List data){ + for(String str: data) + System.out.println(str); + } + + public static void printRow(String[] vals) { + for (String i : vals) { + System.out.print(i); + System.out.print("\t"); + } + System.out.println(); + } + + //Wu modified to allow writing out files to a different location other than input file location + public static void writeHighwayDataToExcel(String input_file_name, String sheet_to_modify, List data, int scenario, String outputDir) throws IOException { + try { + InputStream input_file = new FileInputStream(new File(input_file_name)); + XSSFWorkbook wb = new XSSFWorkbook(input_file); + input_file.close(); + + XSSFSheet ws = wb.getSheet(sheet_to_modify); + int prevRows = ws.getLastRowNum(); + + XSSFRow row = null; + XSSFCell cell = null; + + // writing data to excel sheet + int r = 1; + for (String str : data) { + row = ws.getRow(r); + + if(row == null){ + // this will happen when the number of links in the template sheet + // are less than the number of highway links for the data obtained from database + ws.createRow(r); + row = ws.getRow(r); + } + + //System.out.println(str); + + String[] vals = str.split("\\|"); + + for(int c = 0; c < vals.length; c++){ + cell = row.getCell(c); + + if(cell == null){ + row.createCell(c); + cell = row.getCell(c); + } + + cell.setCellValue(Integer.valueOf(vals[c])); + } + r++; + } + + // delete additional existing rows, if any + // this is to remove excel rows if the highway links in the template sheet + // are more than the number of highway links for the data obtained from database) + for(int d = data.size() + 1; d < prevRows; d++){ + row = ws.getRow(d); + ws.removeRow(row); + } + + //update all formula calculation + wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); + wb.setForceFormulaRecalculation(true); + + // FormulaEvaluator evaluator = wb.getCreationHelper().createFormulaEvaluator(); + // + // for (int i = 0; i < wb.getNumberOfSheets(); i++) + // { + // Sheet sheet = wb.getSheetAt(i); + // System.out.println("Sheet name " + sheet.getSheetName()); + // for (Row ro : sheet) { + // if(sheet.getSheetName().equalsIgnoreCase("all_nb")){ + // System.out.println("row num " + ro.getRowNum()); + // } + // for (Cell c : ro) { + // if (c.getCellTypeEnum() == CellType.FORMULA) { + // if(sheet.getSheetName().equalsIgnoreCase("all_nb")){ + // System.out.println("col index " + c.getColumnIndex()); + // } + // try { + // evaluator.evaluateFormulaCellEnum(c); + // } catch (Exception e) { + // // TODO Auto-generated catch block + // e.printStackTrace(); + // } + // } + // } + // } + // } + + //forming output file name + String name = input_file_name.substring(0, input_file_name.lastIndexOf(".")); + String ext = input_file_name.substring(input_file_name.lastIndexOf(".") + 1); + String output_file_name = outputDir+name + "_s" + String.valueOf(scenario) + "." + ext; + + //writing out revised excel file + System.out.println("Writing highway data to excel file : " + output_file_name); + + File file = new File(output_file_name); + Files.deleteIfExists(file.toPath()); + + OutputStream output_file = new FileOutputStream(new File(output_file_name)); + wb.write(output_file); + wb.close(); + output_file.close(); + System.out.println(""); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static void writeBoardingDataToExcel(String input_file_name, String sheet_to_modify, List data, int scenario, String output_file_name) throws IOException { + try { + InputStream input_file = new FileInputStream(new File(input_file_name)); + XSSFWorkbook wb = new XSSFWorkbook(input_file); + input_file.close(); + + XSSFSheet ws = wb.getSheet(sheet_to_modify); + int prevRows = ws.getLastRowNum(); + + XSSFRow row = null; + XSSFCell cell = null; + + boolean[] colIsNumeric = null; + + // writing data to excel sheet + int r = 1; + for (String str : data) { + row = ws.getRow(r); + + if(row == null){ + // this will happen when the number of routes/modes in the template sheet + // are less than the number of routes/modes for the data obtained from database + ws.createRow(r); + row = ws.getRow(r); + } + + String[] vals = str.split("\\|"); + + //identify columns as string or int/double value + if(r == 1){ + colIsNumeric = new boolean[vals.length]; + Arrays.fill(colIsNumeric, Boolean.TRUE); + + for(int c = 0; c < vals.length; c++) + colIsNumeric[c] = isNumeric(vals[c]); + } + + for(int c = 0; c < vals.length; c++){ + + cell = row.getCell(c); + + if(cell == null){ + row.createCell(c); + cell = row.getCell(c); + } + if(colIsNumeric[c]) + cell.setCellValue(Double.valueOf(vals[c]).intValue()); + else + cell.setCellValue(vals[c]); + } + r++; + } + + // delete additional existing rows, if any + // this is to remove excel rows if the transit routes/modes in the template sheet + // are more than the number of transit routes/modes for the data obtained from database) + for(int d = data.size() + 1; d < prevRows; d++){ + row = ws.getRow(d); + ws.removeRow(row); + } + + //update all formula calculation + wb.getCreationHelper().createFormulaEvaluator().evaluateAll(); + wb.setForceFormulaRecalculation(true); + + //writing out revised excel file + System.out.println("Writing boarding data to excel file : " + output_file_name); + + File file = new File(output_file_name); + Files.deleteIfExists(file.toPath()); + + OutputStream output_file = new FileOutputStream(new File(output_file_name)); + wb.write(output_file); + output_file.close(); + System.out.println(""); + + } catch (FileNotFoundException e) { + e.printStackTrace(); + + } catch (IOException e) { + e.printStackTrace(); + } + } + + public static boolean isNumeric(String str) + { + try{ + double d = Double.parseDouble(str); + } + catch(NumberFormatException nfe) { + return false; + } + return true; + } + + public static String getProperty(ResourceBundle rb, String keyName, String defaultValue) { + + String keyValue = defaultValue; + + try { + keyValue = rb.getString(keyName); + } catch (RuntimeException e) { + //key was not found or resource bundle is null + if(rb == null) throw new RuntimeException("ResourceBundle is null", e); + } + + if(keyValue == null) return keyValue; //you can't trim a null. + + return keyValue.trim(); + } + + /** + * @param dbHost is database server name + * @param dbName is the name of the database we want to use in the server + * @param user is the name of the user used to login to access the database. Note for MS_SQL, user can be null, + * which indicates that standard MS Windows authentication will be used. In this case sqljdbc_auth.dll must be in the java library path. + * @param password is the user's password - not necessary if user is null. + * @return the connection instance for the URL formed for the specific database server specified + */ + + public static Connection getConnectionToDatabase(String dbHost, String dbName, String user, String password) { + Connection conn = null; + + try { + Class.forName("com.microsoft.sqlserver.jdbc.SQLServerDriver"); + } catch (ClassNotFoundException e1) { + throw new RuntimeException("Class not found ", e1); + } + + try { + String urlToConnect = "jdbc:sqlserver://" + dbHost + ";" + "database=" + dbName + ";" + + (user != null ? ("user=" + user + ";" + "password=" + password) : "integratedSecurity=True"); + + //System.out.println("urlToConnect " + urlToConnect); + conn = DriverManager.getConnection(urlToConnect); + } + catch (SQLException e) { + throw new RuntimeException("Cannot connect to database ", e); + } + return conn; + } + + public static void main(String[] args) throws Exception { + long startTime = System.currentTimeMillis(); + + + // Collection supportedFuncs = WorkbookEvaluator.getSupportedFunctionNames(); + // System.out.println(supportedFuncs); + // + // Collection unsupportedFuncs = WorkbookEvaluator.getNotSupportedFunctionNames(); + // System.err.println(unsupportedFuncs); + // System.exit(-1); + + if ( args.length < 2 ) { + System.out.println( "invalid number of command line arguments." ); + System.out.println( "two argument must be specified, 1) basename of the properties file and 2) scenario number"); + System.exit(-1); + } + + ResourceBundle rb = ResourceBundle.getBundle( args[0] ); + + int scenario = Integer.valueOf(args[1]); + + //Wu modified to allow writing out files to a different location other than input file location + String outputDir=args[2]; + + String sheet_to_modify = null; + + List flow_data = getHighwayFlowData(scenario, rb); + + // revise summary by class workbook + String summary_by_class_file = rb.getString("highway.summary.class.template"); + sheet_to_modify = rb.getString("sheet.to.modify.highway.summary"); + writeHighwayDataToExcel(summary_by_class_file, sheet_to_modify, flow_data, scenario,outputDir); + + // revise summary by corridor workbook + String summary_by_corridor_file = rb.getString("highway.summary.corridor.template"); + sheet_to_modify = rb.getString("sheet.to.modify.highway.summary"); + writeHighwayDataToExcel(summary_by_corridor_file, sheet_to_modify, flow_data, scenario, outputDir); + + // revise transit validation workbook + String transit_validation_file = rb.getString("transit.validation.template"); + + //forming transit output file name + String name = transit_validation_file.substring(0, transit_validation_file.lastIndexOf(".")); + String ext = transit_validation_file.substring(transit_validation_file.lastIndexOf(".") + 1); + String output_file_name = name + "_s" + String.valueOf(scenario) + "." + ext; + String transit_output_file =outputDir+output_file_name; + + List boarding_by_route_data = getTransitBoardingByRouteData(scenario, rb); + sheet_to_modify = rb.getString("sheet.to.modify.transit.boarding.route"); + writeBoardingDataToExcel(transit_validation_file, sheet_to_modify, boarding_by_route_data, scenario, transit_output_file); + + List boarding_by_mode_data = getTransitBoardingByModeData(scenario, rb); + sheet_to_modify = rb.getString("sheet.to.modify.transit.boarding.mode"); + writeBoardingDataToExcel(transit_output_file, sheet_to_modify, boarding_by_mode_data, scenario, transit_output_file); + + System.out.println( String.format( "%s%.1f%s", "Total Run Time - ", ( ( System.currentTimeMillis() - startTime ) / 1000.0 ), " seconds." ) ); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorDmuFactory.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorDmuFactory.java new file mode 100644 index 0000000..acf7f8c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorDmuFactory.java @@ -0,0 +1,55 @@ +/* + * Copyright 2005 PB Consult Inc. Licensed under the Apache License, Version 2.0 + * (the "License"); you may not use this file except in compliance with the + * License. You may obtain a copy of the License at + * http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law + * or agreed to in writing, software distributed under the License is + * distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY + * KIND, either express or implied. See the License for the specific language + * governing permissions and limitations under the License. + */ +package org.sandag.abm.visitor; + +import java.io.Serializable; + +/** + * ArcCtrampDmuFactory is a class that creates Visitor Model DMU objects + * + * @author Joel Freedman + */ +public class VisitorDmuFactory + implements VisitorDmuFactoryIf, Serializable +{ + + private VisitorModelStructure visitorModelStructure; + + public VisitorDmuFactory(VisitorModelStructure modelStructure) + { + this.visitorModelStructure = modelStructure; + } + + public VisitorTourModeChoiceDMU getVisitorTourModeChoiceDMU() + { + return new VisitorTourModeChoiceDMU(visitorModelStructure, null); + } + + public VisitorTourDestChoiceDMU getVisitorTourDestChoiceDMU() + { + return new VisitorTourDestChoiceDMU(visitorModelStructure); + } + + public VisitorStopLocationChoiceDMU getVisitorStopLocationChoiceDMU() + { + return new VisitorStopLocationChoiceDMU(visitorModelStructure); + } + + public VisitorTripModeChoiceDMU getVisitorTripModeChoiceDMU() + { + return new VisitorTripModeChoiceDMU(visitorModelStructure, null); + } + + public VisitorMicromobilityChoiceDMU getVisitorMicromobilityChoiceDMU() + { + return new VisitorMicromobilityChoiceDMU(); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorDmuFactoryIf.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorDmuFactoryIf.java new file mode 100644 index 0000000..d25e087 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorDmuFactoryIf.java @@ -0,0 +1,18 @@ +package org.sandag.abm.visitor; + +/** + * A DMU factory interface + */ +public interface VisitorDmuFactoryIf +{ + + VisitorTourModeChoiceDMU getVisitorTourModeChoiceDMU(); + + VisitorTourDestChoiceDMU getVisitorTourDestChoiceDMU(); + + VisitorStopLocationChoiceDMU getVisitorStopLocationChoiceDMU(); + + VisitorTripModeChoiceDMU getVisitorTripModeChoiceDMU(); + + VisitorMicromobilityChoiceDMU getVisitorMicromobilityChoiceDMU(); +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorMicromobilityChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorMicromobilityChoiceDMU.java new file mode 100644 index 0000000..8634f41 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorMicromobilityChoiceDMU.java @@ -0,0 +1,139 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +/** + */ +public class VisitorMicromobilityChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(VisitorMicromobilityChoiceDMU.class); + + protected HashMap methodIndexMap; + + private IndexValues dmuIndex; + protected int income; + protected float walkTime; + protected boolean isTransit; + protected boolean microTransitAvailable; + + + public VisitorMicromobilityChoiceDMU() + { + dmuIndex = new IndexValues(); + setupMethodIndexMap(); + + } + + public void setDmuIndexValues(int hhId, int zoneId, int origTaz, int destTaz) + { + dmuIndex.setHHIndex(hhId); + dmuIndex.setZoneIndex(zoneId); + dmuIndex.setOriginZone(origTaz); + dmuIndex.setDestZone(destTaz); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + } + + + public int getIncome() + { + return income; + } + + public void setIncome(int income) { + this.income = income; + } + + public float getWalkTime() { + return walkTime; + } + + public void setWalkTime(float walkTime) { + this.walkTime = walkTime; + } + + public boolean isTransit() { + return isTransit; + } + + public void setTransit(boolean isTransit) { + this.isTransit = isTransit; + } + + public boolean isMicroTransitAvailable() { + return microTransitAvailable; + } + + public void setMicroTransitAvailable(boolean microTransitAvailable) { + this.microTransitAvailable = microTransitAvailable; + } + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getIncome", 0); + methodIndexMap.put("getWalkTime", 1); + methodIndexMap.put("getIsTransit", 3); + methodIndexMap.put("getMicroTransitAvailable", 4); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + switch (variableIndex) + { + case 0: + return getIncome(); + case 1: + return getWalkTime(); + + case 3: + return isTransit()? 1 : 0; + case 4: + return isMicroTransitAvailable() ? 1 : 0; + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorMicromobilityChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorMicromobilityChoiceModel.java new file mode 100644 index 0000000..135bc8f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorMicromobilityChoiceModel.java @@ -0,0 +1,325 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.HashSet; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; + +public class VisitorMicromobilityChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("micromobility"); + + private static final String MM_CONTROL_FILE_TARGET = "visitor.micromobility.uec.file"; + private static final String MM_DATA_SHEET_TARGET = "visitor.micromobility.data.page"; + private static final String MM_MODEL_SHEET_TARGET = "visitor.micromobility.model.page"; + private static final String MT_TAP_FILE_TARGET = "active.microtransit.tap.file"; + private static final String MT_MAZ_FILE_TARGET = "active.microtransit.mgra.file"; + + public static final int MM_MODEL_WALK_ALT = 0; + public static final int MM_MODEL_MICROMOBILITY_ALT = 1; + public static final int MM_MODEL_MICROTRANSIT_ALT = 2; + + private ChoiceModelApplication mmModel; + private VisitorMicromobilityChoiceDMU mmDmuObject; + + private VisitorModelStructure modelStructure; + private MgraDataManager mgraDataManager; + + private HashSet microtransitTaps; + private HashSet microtransitMazs; + + public VisitorMicromobilityChoiceModel(HashMap propertyMap, + VisitorModelStructure myModelStructure, VisitorDmuFactoryIf dmuFactory) + { + + setupMicromobilityChoiceModelApplication(propertyMap, myModelStructure, dmuFactory); + } + + private void setupMicromobilityChoiceModelApplication(HashMap propertyMap, + VisitorModelStructure myModelStructure, VisitorDmuFactoryIf dmuFactory) + { + // logger.info("setting up micromobility choice model."); + + modelStructure = myModelStructure; + + // locate the micromobility choice UEC + String uecFileDirectory = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mmUecFile = uecFileDirectory + propertyMap.get(MM_CONTROL_FILE_TARGET); + + int dataSheet = Util.getIntegerValueFromPropertyMap(propertyMap, MM_DATA_SHEET_TARGET); + int modelSheet = Util.getIntegerValueFromPropertyMap(propertyMap, MM_MODEL_SHEET_TARGET); + + // create the micromobility choice model DMU object. + mmDmuObject = dmuFactory.getVisitorMicromobilityChoiceDMU(); + + // create the transponder choice model object + mmModel = new ChoiceModelApplication(mmUecFile, modelSheet, dataSheet, propertyMap, + (VariableTable) mmDmuObject); + + mgraDataManager = MgraDataManager.getInstance(); + String projectDirectory = propertyMap.get(CtrampApplication.PROPERTIES_PROJECT_DIRECTORY); + String microTransitTapFile = projectDirectory + propertyMap.get(MT_TAP_FILE_TARGET); + String microTransitMazFile = projectDirectory + propertyMap.get(MT_MAZ_FILE_TARGET); + + TableDataSet microTransitTapData = Util.readTableDataSet(microTransitTapFile); + TableDataSet microTransitMazData = Util.readTableDataSet(microTransitMazFile); + + microtransitTaps = new HashSet(); + microtransitMazs = new HashSet(); + + for(int i=1;i<=microTransitTapData.getRowCount();++i) { + + int tap = (int) microTransitTapData.getValueAt(i,"TAP"); + microtransitTaps.add(tap); + } + + for(int i=1;i<=microTransitMazData.getRowCount();++i) { + + int maz = (int) microTransitMazData.getValueAt(i,"MGRA"); + microtransitMazs.add(maz); + } + + } + + + public void applyModel(VisitorTour tour) { + + //apply to trips on tour + if(tour.getTrips()!=null) { + + for(VisitorTrip trip: tour.getTrips()) + applyModel(tour, trip); + } + + + } + + public void applyModel(VisitorTour tour, VisitorTrip trip) + { + + + if(!modelStructure.getTourModeIsWalk(trip.getTripMode()) && !modelStructure.getTourModeIsWalkTransit(trip.getTripMode())&& !modelStructure.getTourModeIsDriveTransit(trip.getTripMode())) + return; + + mmDmuObject.setIncome(tour.getIncome()); + int originMaz = trip.getOriginMgra(); + int destMaz = trip.getDestinationMgra(); + if(modelStructure.getTourModeIsWalk(trip.getTripMode())) + mmDmuObject.setTransit(false); + else + mmDmuObject.setTransit(true); + + + if(modelStructure.getTourModeIsWalk(trip.getTripMode())) { + + float walkTime = mgraDataManager.getMgraToMgraWalkTime(originMaz, destMaz); + mmDmuObject.setWalkTime(walkTime); + + //set destination to origin so that Z can be used to find origin zone access to mode in mgra data file in UEC + mmDmuObject.setDmuIndexValues(tour.getID(), originMaz, originMaz, originMaz); + + if(microtransitMazs.contains(originMaz) && microtransitMazs.contains(destMaz)) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + // compute utilities and choose micromobility choice alternative. + float logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + trip.setMicromobilityWalkLogsum(logsum); + + // if the choice model has at least one available alternative, make choice + byte chosenAlt = (byte) getChoice(tour, trip); + trip.setMicromobilityWalkMode(chosenAlt); + + // write choice model alternative info to log file + if (tour.getDebugChoiceModels()) + { + String decisionMaker = String.format("Tour "+tour.getID()+ " mode " +trip.getTripMode()); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Transponder Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + + + }else if(modelStructure.getTourModeIsWalkTransit(trip.getTripMode())) { + + //access + int tapPosition = mgraDataManager.getTapPosition(originMaz, trip.getBoardTap()); + float walkTime = mgraDataManager.getMgraToTapWalkTime(originMaz, tapPosition); + mmDmuObject.setWalkTime(walkTime); + + //set destination to origin so that Z can be used to find origin zone access to mode in mgra data file in UEC + mmDmuObject.setDmuIndexValues(tour.getID(), originMaz, originMaz, originMaz); + + if(microtransitTaps.contains(trip.getBoardTap())) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + // compute utilities and choose micromobility choice alternative. + float logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + trip.setMicromobilityAccessLogsum(logsum); + + // if the choice model has at least one available alternative, make choice + byte chosenAlt = (byte) getChoice( tour, trip); + trip.setMicromobilityAccessMode(chosenAlt); + + // write choice model alternative info to log file + if (tour.getDebugChoiceModels()) + { + String decisionMaker = String.format("Tour %d", tour.getID()+ " mode " +trip.getTripMode()); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Transponder Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + //egress + tapPosition = mgraDataManager.getTapPosition(destMaz, trip.getAlightTap()); + walkTime = mgraDataManager.getMgraToTapWalkTime(destMaz, tapPosition); + mmDmuObject.setWalkTime(walkTime); + + if(microtransitTaps.contains(trip.getAlightTap())) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + //set destination to closest mgra to alighting TAP so that Z can be used to find access to mode in mgra data file in UEC + int closestMazToAlightTap = mgraDataManager.getClosestMgra(trip.getAlightTap()); + mmDmuObject.setDmuIndexValues(tour.getID(), closestMazToAlightTap, closestMazToAlightTap, closestMazToAlightTap); + + // compute utilities and choose micromobility choice alternative. + logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + trip.setMicromobilityEgressLogsum(logsum); + + // if the choice model has at least one available alternative, make choice + chosenAlt = (byte) getChoice( tour, trip); + trip.setMicromobilityEgressMode(chosenAlt); + + // write choice model alternative info to log file + if (tour.getDebugChoiceModels()) + { + String decisionMaker = String.format("Tour %d", tour.getID()+ " mode " +trip.getTripMode()); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Transponder Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + } else if( modelStructure.getTourModeIsDriveTransit(trip.getTripMode()) ) { //drive-transit. Choose non-drive direction + + int tapPosition = 0; + float walkTime = 9999; + + if(trip.isInbound()) { //inbound, so access mode is walk + tapPosition = mgraDataManager.getTapPosition(originMaz, trip.getBoardTap()); + walkTime = mgraDataManager.getMgraToTapWalkTime(originMaz, tapPosition); + //set destination to origin so that Z can be used to find origin zone access to mode in mgra data file in UEC + mmDmuObject.setDmuIndexValues(tour.getID(), originMaz, originMaz, originMaz); + + if(microtransitTaps.contains(trip.getBoardTap())) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + }else { //outbound so egress mode is walk. + tapPosition = mgraDataManager.getTapPosition(destMaz, trip.getAlightTap()); + walkTime = mgraDataManager.getMgraToTapWalkTime(destMaz, tapPosition); + //set destination to closest mgra to alighting TAP so that Z can be used to find access to mode in mgra data file in UEC + int closestMazToAlightTap = mgraDataManager.getClosestMgra(trip.getAlightTap()); + mmDmuObject.setDmuIndexValues(tour.getID(), closestMazToAlightTap, closestMazToAlightTap, closestMazToAlightTap); + } + mmDmuObject.setWalkTime(walkTime); + + if(microtransitTaps.contains(trip.getAlightTap())) + mmDmuObject.setMicroTransitAvailable(true); + else + mmDmuObject.setMicroTransitAvailable(false); + + // compute utilities and choose micromobility choice alternative. + float logsum = (float) mmModel.computeUtilities(mmDmuObject, mmDmuObject.getDmuIndexValues()); + + // if the choice model has at least one available alternative, make choice + byte chosenAlt = (byte) getChoice(tour, trip); + + if(trip.isInbound()) { //inbound, set access + trip.setMicromobilityAccessMode(chosenAlt); + trip.setMicromobilityAccessLogsum(logsum); + }else { //outound, set egress + trip.setMicromobilityEgressMode(chosenAlt); + trip.setMicromobilityEgressLogsum(logsum); + } + + // write choice model alternative info to log file + if (tour.getDebugChoiceModels()) + { + String decisionMaker = String.format("Tour %d", tour.getID()+ " mode " +trip.getTripMode()); + mmModel.logAlternativesInfo("Micromobility Choice", decisionMaker, logger); + logger.info(String.format("%s result chosen for %s is %d", + "Transponder Choice", decisionMaker, chosenAlt)); + mmModel.logUECResults(logger, decisionMaker); + } + + } + + } + + + /** + * Select the micromobility mode from the UEC. This is helper code for applyModel(), where utilities have already been calculated. + * + * @param household + * @param person + * @param tour + * @param s + * @return The micromobility mode. + */ + private int getChoice(VisitorTour tour, VisitorTrip trip) { + // if the choice model has at least one available alternative, make + // choice. + int chosenAlt; + if (mmModel.getAvailabilityCount() > 0) + { + double randomNumber = tour.getRandom(); + chosenAlt = mmModel.getChoiceResult(randomNumber); + return chosenAlt; + } else + { + String decisionMaker = String.format("Tour %d", tour.getID()+ " mode " +trip.getTripMode()); + String errorMessage = String + .format("Exception caught for %s, no available micromobility choice alternatives to choose from in choiceModelApplication.", + decisionMaker); + logger.info(errorMessage); + + mmModel.logUECResults(logger, decisionMaker); + return MM_MODEL_WALK_ALT; + } + + } + + /** + * This method calculates a cost coefficient based on the following formula: + * + * costCoeff = incomeCoeff * 1/(max(income,1000)^incomeExponent) + * + * + * @param incomeCoeff + * @param incomeExponent + * @return A cost coefficent that should be multiplied by cost variables (cents) in tour mode choice + */ + public double calculateCostCoefficient(double income, double incomeCoeff, double incomeExponent){ + + return incomeCoeff * 1.0/(Math.pow(Math.max(income,1000.0),incomeExponent)); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorModel.java new file mode 100644 index 0000000..a45b6f5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorModel.java @@ -0,0 +1,499 @@ +package org.sandag.abm.visitor; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.concurrent.ForkJoinPool; +import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicInteger; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.crossborder.CrossBorderTripModeChoiceModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; +import com.pb.sawdust.util.concurrent.DnCRecursiveAction; + + +public class VisitorModel +{ + + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + public static final String RUN_MODEL_CONCURRENT_PROPERTY_KEY = "visitor.run.concurrent"; + public static final String CONCURRENT_PARALLELISM_PROPERTY_KEY = "visitor.concurrent.parallelism"; + + private MatrixDataServerRmi ms; + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + private static final Object INITIALIZATION_LOCK = new Object(); + + private HashMap rbMap; + private McLogsumsCalculator logsumsCalculator; + private AutoTazSkimsCalculator tazDistanceCalculator; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + + private boolean seek; + private int traceId; + private double sampleRate = 1; + private static int iteration=1; + + /** + * Constructor + * + * @param rbMap + */ + public VisitorModel(HashMap rbMap) + { + this.rbMap = rbMap; + synchronized (INITIALIZATION_LOCK) + { // lock to make sure only one of + // these actually initializes + // things so we don't cross + // threads + mgraManager = MgraDataManager.getInstance(rbMap); + tazManager = TazDataManager.getInstance(rbMap); + } + + seek = new Boolean(Util.getStringValueFromPropertyMap(rbMap, "visitor.seek")); + traceId = new Integer(Util.getStringValueFromPropertyMap(rbMap, "visitor.trace")); + + } + + // global variable used for reporting + private static final AtomicInteger TOUR_COUNTER = new AtomicInteger(0); + private final AtomicBoolean calculatorsInitialized = new AtomicBoolean(false); + + /** + * Run visitor model. + */ + private void runModel(VisitorTour[] tours, int start, int end){ + + + VisitorModelStructure modelStructure = new VisitorModelStructure(); + + VisitorDmuFactoryIf dmuFactory = new VisitorDmuFactory(modelStructure); + + if (!calculatorsInitialized.get()) + { + // only let one thread in to initialize + synchronized (calculatorsInitialized) + { + // if still not initialized, then this is the first in so do the + // initialization (otherwise skip) + if (!calculatorsInitialized.get()) + { + tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + calculatorsInitialized.set(true); + } + } + } + + + VisitorTourTimeOfDayChoiceModel todChoiceModel = new VisitorTourTimeOfDayChoiceModel(rbMap); + VisitorTourDestChoiceModel destChoiceModel = new VisitorTourDestChoiceModel(rbMap, modelStructure, dmuFactory, tazDistanceCalculator); + VisitorTourModeChoiceModel tourModeChoiceModel = destChoiceModel.getTourModeChoiceModel(); + //VisitorTripModeChoiceModel tripModeChoiceModel = tourModeChoiceModel.getTripModeChoiceModel(); + destChoiceModel.calculateSizeTerms(dmuFactory); + destChoiceModel.calculateTazProbabilities(dmuFactory); + + VisitorStopFrequencyModel stopFrequencyModel = new VisitorStopFrequencyModel(rbMap); + VisitorStopPurposeModel stopPurposeModel = new VisitorStopPurposeModel(rbMap); + VisitorStopTimeOfDayChoiceModel stopTodChoiceModel = new VisitorStopTimeOfDayChoiceModel(rbMap); + VisitorStopLocationChoiceModel stopLocationChoiceModel = new VisitorStopLocationChoiceModel(rbMap, modelStructure, dmuFactory, tazDistanceCalculator); + VisitorTripModeChoiceModel tripModeChoiceModel = new VisitorTripModeChoiceModel(rbMap, modelStructure, dmuFactory, tazDistanceCalculator); + VisitorMicromobilityChoiceModel micromobilityChoiceModel = new VisitorMicromobilityChoiceModel(rbMap,modelStructure, dmuFactory); + + double[][] mgraSizeTerms = destChoiceModel.getMgraSizeTerms(); + double[][] tazSizeTerms = destChoiceModel.getTazSizeTerms(); + double[][][] mgraProbabilities = destChoiceModel.getMgraProbabilities(); + stopLocationChoiceModel.setMgraSizeTerms(mgraSizeTerms); + stopLocationChoiceModel.setTazSizeTerms(tazSizeTerms); + stopLocationChoiceModel.setMgraProbabilities(mgraProbabilities); + stopLocationChoiceModel.setTripModeChoiceModel(tripModeChoiceModel); + + // Run models for array of tours + for (int i = start; i < end; i++) + { + VisitorTour tour = tours[i]; + + // sample tours + double rand = tour.getRandom(); + if (rand > sampleRate) continue; + + int tourCount = TOUR_COUNTER.incrementAndGet(); + if (tourCount % 1000 == 0) logger.info("Processing tour " + tourCount); + + if (seek && tour.getID() != traceId) continue; + + if (tour.getID() == traceId) + tour.setDebugChoiceModels(true); + + + todChoiceModel.calculateTourTOD(tour); + destChoiceModel.chooseDestination(tour); + tourModeChoiceModel.chooseTourMode(tour); + + stopFrequencyModel.calculateStopFrequency(tour); + stopPurposeModel.calculateStopPurposes(tour); + + int outboundStops = tour.getNumberOutboundStops(); + int inboundStops = tour.getNumberInboundStops(); + + // choose TOD for stops and location of each + if (outboundStops > 0) + { + VisitorStop[] stops = tour.getOutboundStops(); + for (VisitorStop stop : stops) + { + stopTodChoiceModel.chooseTOD(tour, stop); + stopLocationChoiceModel.chooseStopLocation(tour, stop); + } + } + if (inboundStops > 0) + { + VisitorStop[] stops = tour.getInboundStops(); + for (VisitorStop stop : stops) + { + stopTodChoiceModel.chooseTOD(tour, stop); + stopLocationChoiceModel.chooseStopLocation(tour, stop); + } + } + + // generate trips and choose mode for them + VisitorTrip[] trips = new VisitorTrip[outboundStops + inboundStops + 2]; + int tripNumber = 0; + + // outbound stops + if (outboundStops > 0) + { + VisitorStop[] stops = tour.getOutboundStops(); + for (VisitorStop stop : stops) + { + // generate a trip to the stop and choose a mode for it + trips[tripNumber] = new VisitorTrip(tour, stop, true); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + // generate a trip from the last stop to the tour destination + trips[tripNumber] = new VisitorTrip(tour, stops[stops.length - 1], false); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + + } else + { + // generate an outbound trip from the tour origin to the + // destination and choose a mode + trips[tripNumber] = new VisitorTrip(tour, true); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + + // inbound stops + if (inboundStops > 0) + { + VisitorStop[] stops = tour.getInboundStops(); + for (VisitorStop stop : stops) + { + // generate a trip to the stop and choose a mode for it + trips[tripNumber] = new VisitorTrip(tour, stop, true); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + // generate a trip from the last stop to the tour origin + trips[tripNumber] = new VisitorTrip(tour, stops[stops.length - 1], false); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } else + { + + // generate an inbound trip from the tour destination to the + // origin and choose a mode + trips[tripNumber] = new VisitorTrip(tour, false); + tripModeChoiceModel.chooseMode(tour, trips[tripNumber]); + ++tripNumber; + } + + // set the trips in the tour object + tour.setTrips(trips); + micromobilityChoiceModel.applyModel(tour); + + } + } + + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * @return the sampleRate + */ + public double getSampleRate() + { + return sampleRate; + } + + /** + * @param sampleRate + * the sampleRate to set + */ + public void setSampleRate(double sampleRate) + { + this.sampleRate = sampleRate; + } + + /** + * This class is the divide-and-conquer action (void return task) for + * running the visitor model using the fork-join framework. The + * divisible problem is an array of tours, and the actual work is the + * {@link VisitorModel#runModel(VisitorTour[],int,int)} method, + * applied to a section of the array. + */ + private class VisitorModelAction + extends DnCRecursiveAction + { + private final HashMap rbMap; + private final VisitorTour[] tours; + + private VisitorModelAction(HashMap rbMap, VisitorTour[] tours) + { + super(0, tours.length); + this.rbMap = rbMap; + this.tours = tours; + } + + private VisitorModelAction(HashMap rbMap, VisitorTour[] tours, + long start, long length, DnCRecursiveAction next) + { + super(start, length, next); + this.rbMap = rbMap; + this.tours = tours; + } + + @Override + protected void computeAction(long start, long length) + { + runModel(tours, (int) start, (int) (start + length)); + } + + @Override + protected DnCRecursiveAction getNextAction(long start, long length, DnCRecursiveAction next) + { + return new VisitorModelAction(rbMap, tours, start, length, next); + } + + @Override + protected boolean continueDividing(long length) + { + // if there are 3 extra tasks queued up, then start executing + // if there are 1000 or less tours to process, then start executing + // otherwise, keep dividing to build up tasks for the threads to + // process + return getSurplusQueuedTaskCount() < 3 && length > 5000; + } + } + + /** + * Run visitor model. + */ + public void runModel() + { + VisitorTourManager tourManager = new VisitorTourManager(rbMap); + tourManager.generateVisitorTours(); + VisitorTour[] tours = tourManager.getTours(); + + // get new keys to see if we want to run in concurrent mode, and the + // parallelism + // (defaults to single threaded and parallelism = # of processors) + // note that concurrent can use up memory very quickly, so setting the + // parallelism might be prudent + boolean concurrent = rbMap.containsKey(RUN_MODEL_CONCURRENT_PROPERTY_KEY) + && Boolean.valueOf(Util.getStringValueFromPropertyMap(rbMap, + RUN_MODEL_CONCURRENT_PROPERTY_KEY)); + int parallelism = rbMap.containsKey(CONCURRENT_PARALLELISM_PROPERTY_KEY) ? Integer + .valueOf(Util.getStringValueFromPropertyMap(rbMap, + CONCURRENT_PARALLELISM_PROPERTY_KEY)) : Runtime.getRuntime() + .availableProcessors(); + + if (concurrent) + { // use fork-join + VisitorModelAction action = new VisitorModelAction(rbMap, tours); + new ForkJoinPool(parallelism).execute(action); + action.getResult(); // wait for finish + } else + { // single-threaded: call the model runner in this thread + runModel(tours, 0, tours.length); + } + + tourManager.writeOutputFile(rbMap); + logger.info("Visitor Model successfully completed!"); + } + + /** + * @param args + */ + public static void main(String[] args) + { + Runtime gfg = Runtime.getRuntime(); + long memory1; + // checking the total memeory + System.out.println("Total memory is: "+ gfg.totalMemory()); + // checking free memory + memory1 = gfg.freeMemory(); + System.out.println("Initial free memory at Visitor model: "+ memory1); + // calling the garbage collector on demand + gfg.gc(); + memory1 = gfg.freeMemory(); + System.out.println("Free memory after garbage "+ "collection: " + memory1); + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running Visitor Model")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + VisitorModel visitorModel = new VisitorModel(pMap); + + float sampleRate = 1.0f; + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + logger.info("Visitor Model:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + visitorModel.setSampleRate(sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = visitorModel.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + visitorModel.ms = matrixServer; + } else + { + visitorModel.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + visitorModel.ms.testRemote("VisitorModel"); + + // these methods need to be called to set the matrix data + // manager in the matrix data server + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(visitorModel.ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + visitorModel.runModel(); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorModelStructure.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorModelStructure.java new file mode 100644 index 0000000..920f59a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorModelStructure.java @@ -0,0 +1,95 @@ +package org.sandag.abm.visitor; + +import org.sandag.abm.application.SandagModelStructure; + +public class VisitorModelStructure + extends SandagModelStructure +{ + + public static final byte NUMBER_VISITOR_PURPOSES = 6; + public static final byte WORK = 0; + public static final byte RECREATION = 1; + public static final byte DINING = 2; + + public static final String[] VISITOR_PURPOSES = {"WORK", "RECREATE", "DINING"}; + + // override on max tour mode, since we have taxi in this model. + public static final int MAXIMUM_TOUR_MODE_ALT_INDEX = 13; + + public static final byte NUMBER_VISITOR_SEGMENTS = 2; + public static final byte BUSINESS = 0; + public static final byte PERSONAL = 1; + + public static final String[] VISITOR_SEGMENTS = {"BUSINESS", "PERSONAL"}; + public static final byte DEPARTURE = 0; + public static final byte ARRIVAL = 1; + + public static final byte INCOME_SEGMENTS = 5; + + // note that time periods start at 1 and go to 40 + public static final byte TIME_PERIODS = 40; + + public static final int AM = 0; + public static final int PM = 1; + public static final int OP = 2; + public static final int[] SKIM_PERIODS = {AM, PM, OP}; + public static final String[] SKIM_PERIOD_STRINGS = {"AM", "PM", "OP"}; + public static final int UPPER_EA = 3; + public static final int UPPER_AM = 9; + public static final int UPPER_MD = 22; + public static final int UPPER_PM = 29; + public static final String[] MODEL_PERIOD_LABELS = {"EA", "AM", "MD", "PM", "EV"}; + + public static final byte TAXI = 13; + + /** + * Taxi tour mode + * + * @param tourMode + * @return + */ + public boolean getTourModeIsTaxi(int tourMode) + { + + if (tourMode == TAXI) return true; + else return false; + + } + + /** + * return the Skim period index 0=am, 1=pm, 2=off-peak + */ + public static int getSkimPeriodIndex(int departPeriod) + { + + int skimPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_AM) skimPeriodIndex = AM; + else if (departPeriod <= UPPER_MD) skimPeriodIndex = OP; + else if (departPeriod <= UPPER_PM) skimPeriodIndex = PM; + else skimPeriodIndex = OP; + + return skimPeriodIndex; + + } + + /** + * return the Model period index 0=EA, 1=AM, 2=MD, 3=PM, 4=EV + */ + public static int getModelPeriodIndex(int departPeriod) + { + + int modelPeriodIndex = 0; + + if (departPeriod <= UPPER_EA) modelPeriodIndex = 0; + else if (departPeriod <= UPPER_AM) modelPeriodIndex = 1; + else if (departPeriod <= UPPER_MD) modelPeriodIndex = 2; + else if (departPeriod <= UPPER_PM) modelPeriodIndex = 3; + else modelPeriodIndex = 4; + + return modelPeriodIndex; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStop.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStop.java new file mode 100644 index 0000000..86e0499 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStop.java @@ -0,0 +1,176 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import org.apache.log4j.Logger; + +public class VisitorStop + implements Serializable +{ + + private int id; + private int mode; + private int period; + private boolean inbound; + private int mgra; + private byte purpose; + + VisitorTour parentTour; + + public VisitorStop(VisitorTour parentTour, int id, boolean inbound) + { + this.parentTour = parentTour; + this.id = id; + this.inbound = inbound; + } + + /** + * @return the mgra + */ + public int getMgra() + { + return mgra; + } + + /** + * @param mgra + * the mgra to set + */ + public void setMgra(int mgra) + { + this.mgra = mgra; + } + + public void setMode(int mode) + { + this.mode = mode; + } + + public void setPeriod(int period) + { + this.period = period; + } + + /** + * @return the id + */ + public int getId() + { + return id; + } + + /** + * @param id + * the id to set + */ + public void setId(int id) + { + this.id = id; + } + + /** + * @return the inbound + */ + public boolean isInbound() + { + return inbound; + } + + /** + * @param inbound + * the inbound to set + */ + public void setInbound(boolean inbound) + { + this.inbound = inbound; + } + + /** + * @return the parentTour + */ + public VisitorTour getParentTour() + { + return parentTour; + } + + /** + * @param parentTour + * the parentTour to set + */ + public void setParentTour(VisitorTour parentTour) + { + this.parentTour = parentTour; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(byte stopPurposeIndex) + { + this.purpose = stopPurposeIndex; + } + + public byte getPurpose() + { + return purpose; + } + + public int getMode() + { + return mode; + } + + public int getStopPeriod() + { + return period; + } + + public VisitorTour getTour() + { + return parentTour; + } + + public int getStopId() + { + return id; + } + + public void logStopObject(Logger logger, int totalChars) + { + + String separater = ""; + for (int i = 0; i < totalChars; i++) + separater += "-"; + + String purposeString = VisitorModelStructure.VISITOR_PURPOSES[purpose]; + logHelper(logger, "stopId: ", id, totalChars); + logHelper(logger, "mgra: ", mgra, totalChars); + logHelper(logger, "mode: ", mode, totalChars); + logHelper(logger, "purpose: ", purposeString, totalChars); + logHelper(logger, "direction: ", inbound ? "inbound" : "outbound", totalChars); + logHelper(logger, inbound ? "outbound departPeriod: " : "inbound arrivePeriod: ", period, + totalChars); + logger.info(separater); + logger.info(""); + logger.info(""); + + } + + public static void logHelper(Logger logger, String label, int value, int totalChars) + { + int labelChars = label.length() + 2; + int remainingChars = totalChars - labelChars - 4; + String formatString = String.format(" %%%ds %%%dd", label.length(), remainingChars); + String logString = String.format(formatString, label, value); + logger.info(logString); + } + + public static void logHelper(Logger logger, String label, String value, int totalChars) + { + int labelChars = label.length() + 2; + int remainingChars = totalChars - labelChars - 4; + String formatString = String.format(" %%%ds %%%ds", label.length(), remainingChars); + String logString = String.format(formatString, label, value); + logger.info(logString); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopFrequencyModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopFrequencyModel.java new file mode 100644 index 0000000..ed33801 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopFrequencyModel.java @@ -0,0 +1,325 @@ +package org.sandag.abm.visitor; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the stop frequency model for visitor tours. It is currently + * based on a static probability distribution stored in an input file, and + * indexed into by tour purpose and duration. + * + * @author Freedman + * + */ +public class VisitorStopFrequencyModel +{ + private transient Logger logger = Logger.getLogger("visitorModel"); + + private double[][] cumProbability; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + private int[][] lowerBoundDurationHours; // by + // purpose, + // alternative: + // lower + // bound + // in + // hours + private int[][] upperBoundDurationHours; // by + // purpose, + // alternative: + // upper + // bound + // in + // hours + private int[][] outboundStops; // by + // purpose, + // alternative: + // number + // of + // outbound + // stops + private int[][] inboundStops; // by + // purpose, + // alternative: + // number + // of + // inbound + // stops + VisitorModelStructure modelStructure; + + /** + * Constructor. + */ + public VisitorStopFrequencyModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String stopFrequencyFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.stop.frequency.file"); + stopFrequencyFile = directory + stopFrequencyFile; + + modelStructure = new VisitorModelStructure(); + + readStopFrequencyFile(stopFrequencyFile); + + } + + /** + * Read the stop frequency distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readStopFrequencyFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating stop frequency probability distribution"); + + int purposes = modelStructure.VISITOR_PURPOSES.length; // start at 0 + + int[] alts = new int[purposes]; + + // take a pass through the data and see how many alternatives there are + // for each purpose + int rowCount = probabilityTable.getRowCount(); + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose"); + ++alts[purpose]; + } + + // initialize all the arrays + cumProbability = new double[purposes][]; + lowerBoundDurationHours = new int[purposes][]; + upperBoundDurationHours = new int[purposes][]; + outboundStops = new int[purposes][]; + inboundStops = new int[purposes][]; + + for (int i = 0; i < purposes; ++i) + { + cumProbability[i] = new double[alts[i]]; + lowerBoundDurationHours[i] = new int[alts[i]]; + upperBoundDurationHours[i] = new int[alts[i]]; + outboundStops[i] = new int[alts[i]]; + inboundStops[i] = new int[alts[i]]; + } + + // fill up arrays + int lastPurpose = 0; + int lastLowerBound = 0; + double cumProb = 0; + int alt = 0; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose"); + int lowerBound = (int) probabilityTable.getValueAt(row, "DurationLo"); + int upperBound = (int) probabilityTable.getValueAt(row, "DurationHi"); + int outStops = (int) probabilityTable.getValueAt(row, "Outbound"); + int inbStops = (int) probabilityTable.getValueAt(row, "Inbound"); + + // reset cumulative probability if new purpose or lower-bound + if (purpose != lastPurpose || lowerBound != lastLowerBound) + { + + // log cumulative probability just in case + logger.info("Cumulative probability for purpose " + purpose + " lower bound " + + lowerBound + " is " + cumProb); + cumProb = 0; + } + + if (purpose != lastPurpose) alt = 0; + + // calculate cumulative probability and store in array + cumProb += probabilityTable.getValueAt(row, "Percent"); + cumProbability[purpose][alt] = cumProb; + lowerBoundDurationHours[purpose][alt] = lowerBound; + upperBoundDurationHours[purpose][alt] = upperBound; + outboundStops[purpose][alt] = outStops; + inboundStops[purpose][alt] = inbStops; + + ++alt; + + lastPurpose = purpose; + lastLowerBound = lowerBound; + } + + logger.info("End calculating stop frequency probability distribution"); + + for (int purp = 0; purp < purposes; ++purp) + { + for (int a = 0; a < cumProbability[purp].length; ++a) + { + logger.info("Purpose " + purp + " lower " + lowerBoundDurationHours[purp][a] + + " upper " + upperBoundDurationHours[purp][a] + " cumProb " + + cumProbability[purp][a]); + } + } + + } + + /** + * Calculate number of stops for the tour. + * + * @param tour + * A visitor tour (with purpose and mode chosen) + */ + public void calculateStopFrequency(VisitorTour tour) + { + + int purpose = tour.getPurpose(); + double random = tour.getRandom(); + + int tourMode = tour.getTourMode(); + + if (!modelStructure.getTourModeIsSovOrHov(tourMode) + && !modelStructure.getTourModeIsTaxi(tourMode)) return; + + if (tour.getDebugChoiceModels()) + { + logger.info("Choosing stop frequency for purpose " + + modelStructure.VISITOR_PURPOSES[purpose] + " using random number " + random); + tour.logTourObject(logger, 100); + } + + for (int i = 0; i < cumProbability[purpose].length; ++i) + { + + if (!tourIsInRange(tour, lowerBoundDurationHours[purpose][i], + upperBoundDurationHours[purpose][i])) continue; + + if (tour.getDebugChoiceModels()) + { + logger.info("lower bound " + lowerBoundDurationHours[purpose][i] + " upper bound " + + upperBoundDurationHours[purpose][i]); + } + + if (random < cumProbability[purpose][i]) + { + int outStops = outboundStops[purpose][i]; + int inbStops = inboundStops[purpose][i]; + + if (outStops > 0) + { + VisitorStop[] stops = generateOutboundStops(tour, outStops); + tour.setOutboundStops(stops); + } + + if (inbStops > 0) + { + VisitorStop[] stops = generateInboundStops(tour, inbStops); + tour.setInboundStops(stops); + } + if (tour.getDebugChoiceModels()) + { + logger.info(""); + logger.info("Chose " + outStops + " outbound stops and " + inbStops + + " inbound stops"); + logger.info(""); + } + break; + } + } + + } + + /** + * Check if the tour duration is in range + * + * @param tour + * @param lowerBound + * @param upperBound + * @return True if tour duration is greater than or equal to lower and + */ + private boolean tourIsInRange(VisitorTour tour, int lowerBound, int upperBound) + { + + float depart = (float) tour.getDepartTime(); + float arrive = (float) tour.getArriveTime(); + + float halfHours = arrive + 1 - depart; // at least 30 minutes + float tourDurationInHours = halfHours * (float) 0.5; + + if ((tourDurationInHours >= (float) lowerBound) + && (tourDurationInHours <= (float) upperBound)) return true; + + return false; + } + + /** + * Generate an array of outbound stops, from tour origin to primary + * destination, in order. + * + * @param tour + * The parent tour. + * @param numberOfStops + * Number of stops from stop frequency model. + * @return The array of outbound stops. + */ + private VisitorStop[] generateOutboundStops(VisitorTour tour, int numberOfStops) + { + + VisitorStop[] stops = new VisitorStop[numberOfStops]; + + for (int i = 0; i < stops.length; ++i) + { + VisitorStop stop = new VisitorStop(tour, i, false); + stops[i] = stop; + stop.setInbound(false); + stop.setParentTour(tour); + } + + return stops; + } + + /** + * Generate an array of inbound stops, from primary dest back to tour + * origin, in order. + * + * @param tour + * Parent tour. + * @param numberOfStops + * Number of stops from stop frequency model. + * @return The array of inbound stops. + */ + private VisitorStop[] generateInboundStops(VisitorTour tour, int numberOfStops) + { + + VisitorStop[] stops = new VisitorStop[numberOfStops]; + + for (int i = 0; i < stops.length; ++i) + { + VisitorStop stop = new VisitorStop(tour, i, true); + stops[i] = stop; + stop.setInbound(true); + stop.setParentTour(tour); + + } + + return stops; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopLocationChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopLocationChoiceDMU.java new file mode 100644 index 0000000..8fabb9c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopLocationChoiceDMU.java @@ -0,0 +1,406 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class VisitorStopLocationChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger("visitorModel"); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected int purpose; + protected int stopsOnHalfTour; + protected int stopNumber; + protected int inboundStop; + protected int tourDuration; + + protected double[][] sizeTerms; // by + // purpose, + // alternative + // (taz + // or + // sampled + // mgra) + protected double[] correctionFactors; // by + // alternative + // (sampled + // mgra, + // for + // full + // model + // only) + + protected int[] sampleNumber; // by + // alternative + // (taz + // or + // sampled + // mgra) + + protected double[] osMcLogsumAlt; + protected double[] sdMcLogsumAlt; + + protected double[] tourOrigToStopDistanceAlt; + protected double[] stopToTourDestDistanceAlt; + + public VisitorStopLocationChoiceDMU(VisitorModelStructure modelStructure) + { + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + /** + * @return the stopsOnHalfTour + */ + public int getStopsOnHalfTour() + { + return stopsOnHalfTour; + } + + /** + * @param stopsOnHalfTour + * the stopsOnHalfTour to set + */ + public void setStopsOnHalfTour(int stopsOnHalfTour) + { + this.stopsOnHalfTour = stopsOnHalfTour; + } + + /** + * @return the stopNumber + */ + public int getStopNumber() + { + return stopNumber; + } + + /** + * @param stopNumber + * the stopNumber to set + */ + public void setStopNumber(int stopNumber) + { + this.stopNumber = stopNumber; + } + + /** + * @return the inboundStop + */ + public int getInboundStop() + { + return inboundStop; + } + + /** + * @param inboundStop + * the inboundStop to set + */ + public void setInboundStop(int inboundStop) + { + this.inboundStop = inboundStop; + } + + /** + * @return the tourDuration + */ + public int getTourDuration() + { + return tourDuration; + } + + /** + * @param tourDuration + * the tourDuration to set + */ + public void setTourDuration(int tourDuration) + { + this.tourDuration = tourDuration; + } + + /** + * @return the sampleNumber + */ + public int getSampleNumber(int alt) + { + return sampleNumber[alt]; + } + + /** + * @param sampleNumber + * the sampleNumber to set + */ + public void setSampleNumber(int[] sampleNumber) + { + this.sampleNumber = sampleNumber; + } + + /** + * @return the osMcLogsumAlt + */ + public double getOsMcLogsumAlt(int alt) + { + return osMcLogsumAlt[alt]; + } + + /** + * @param osMcLogsumAlt + * the osMcLogsumAlt to set + */ + public void setOsMcLogsumAlt(double[] osMcLogsumAlt) + { + this.osMcLogsumAlt = osMcLogsumAlt; + } + + /** + * @return the sdMcLogsumAlt + */ + public double getSdMcLogsumAlt(int alt) + { + return sdMcLogsumAlt[alt]; + } + + /** + * @param sdMcLogsumAlt + * the sdMcLogsumAlt to set + */ + public void setSdMcLogsumAlt(double[] sdMcLogsumAlt) + { + this.sdMcLogsumAlt = sdMcLogsumAlt; + } + + /** + * @return the tourOrigToStopDistanceAlt + */ + public double getTourOrigToStopDistanceAlt(int alt) + { + return tourOrigToStopDistanceAlt[alt]; + } + + /** + * @param tourOrigToStopDistanceAlt + * the tourOrigToStopDistanceAlt to set + */ + public void setTourOrigToStopDistanceAlt(double[] tourOrigToStopDistanceAlt) + { + this.tourOrigToStopDistanceAlt = tourOrigToStopDistanceAlt; + } + + /** + * @return the stopToTourDestDistanceAlt + */ + public double getStopToTourDestDistanceAlt(int alt) + { + return stopToTourDestDistanceAlt[alt]; + } + + /** + * @param stopToTourDestDistanceAlt + * the stopToTourDestDistanceAlt to set + */ + public void setStopToTourDestDistanceAlt(double[] stopToTourDestDistanceAlt) + { + this.stopToTourDestDistanceAlt = stopToTourDestDistanceAlt; + } + + /** + * @return the sizeTerms. The size term is the size of the alternative north + * of the border. It is indexed by alternative, where alternative is + * either taz-station pair or mgra-station pair, depending on + * whether the DMU is being used for the SOA model or the actual + * model. + */ + public double getSizeTerm(int alt) + { + return sizeTerms[purpose][alt]; + } + + /** + * @param sizeTerms + * the sizeTerms to set. The size term is the size of the + * alternative north of the border. It is indexed by alternative, + * where alternative is either taz-station pair or mgra-station + * pair, depending on whether the DMU is being used for the SOA + * model or the actual model. + */ + public void setSizeTerms(double[][] sizeTerms) + { + this.sizeTerms = sizeTerms; + } + + /** + * @return the correctionFactors + */ + public double getCorrectionFactor(int alt) + { + return correctionFactors[alt]; + } + + /** + * @param correctionFactors + * the correctionFactors to set + */ + public void setCorrectionFactors(double[] correctionFactors) + { + this.correctionFactors = correctionFactors; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the purpose + */ + public int getPurpose() + { + return purpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(int purpose) + { + this.purpose = purpose; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + methodIndexMap.put("getPurpose", 0); + methodIndexMap.put("getStopsOnHalfTour", 1); + methodIndexMap.put("getStopNumber", 2); + methodIndexMap.put("getInboundStop", 3); + methodIndexMap.put("getTourDuration", 4); + + methodIndexMap.put("getSizeTerm", 5); + methodIndexMap.put("getCorrectionFactor", 6); + methodIndexMap.put("getSampleNumber", 7); + methodIndexMap.put("getOsMcLogsumAlt", 8); + methodIndexMap.put("getSdMcLogsumAlt", 9); + methodIndexMap.put("getTourOrigToStopDistanceAlt", 10); + methodIndexMap.put("getStopToTourDestDistanceAlt", 11); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getPurpose(); + break; + case 1: + returnValue = getStopsOnHalfTour(); + break; + case 2: + returnValue = getStopNumber(); + break; + case 3: + returnValue = getInboundStop(); + break; + case 4: + returnValue = getTourDuration(); + break; + case 5: + returnValue = getSizeTerm(arrayIndex); + break; + case 6: + returnValue = getCorrectionFactor(arrayIndex); + break; + case 7: + returnValue = getSampleNumber(arrayIndex); + break; + case 8: + returnValue = getOsMcLogsumAlt(arrayIndex); + break; + case 9: + returnValue = getSdMcLogsumAlt(arrayIndex); + break; + case 10: + returnValue = getTourOrigToStopDistanceAlt(arrayIndex); + break; + case 11: + returnValue = getStopToTourDestDistanceAlt(arrayIndex); + break; + + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopLocationChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopLocationChoiceModel.java new file mode 100644 index 0000000..4a6bde0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopLocationChoiceModel.java @@ -0,0 +1,538 @@ +package org.sandag.abm.visitor; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.ConcreteAlternative; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class VisitorStopLocationChoiceModel +{ + + private transient Logger logger = Logger.getLogger("visitorModel"); + + private McLogsumsCalculator logsumHelper; + private VisitorModelStructure modelStructure; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private VisitorStopLocationChoiceDMU dmu; + private VisitorTripModeChoiceModel tripModeChoiceModel; + double logsum = 0; + private ChoiceModelApplication soaModel; + private ChoiceModelApplication destModel; + + // the following arrays are calculated in the station-destination choice + // model and passed in the constructor. + private double[][] mgraSizeTerms; // by + // purpose, + // MGRA + private double[][][] mgraProbabilities; // by + // purpose, + // TAZ, + // MGRA + + private TableDataSet alternativeData; // the + // alternatives, + // with + // a + // "dest" + // - + // indicating + // the + // destination + // TAZ + // in + // San + // Diego + // County + + // following are used for each taz alternative + private double[] soaTourOrigToStopDistanceAlt; // by + // TAZ + private double[] soaStopToTourDestDistanceAlt; // by + // TAZ + private double[][] tazSizeTerms; // by + // purpose, + // TAZ + // - + // set + // by + // constructor + + // following are used for sampled mgras + private int sampleRate; + private double[][] sampledSizeTerms; // by + // purpose, + // alternative + // (taz + // or + // sampled + // mgra) + private double[] correctionFactors; // by + // alternative + // (sampled + // mgra, + // for + // full + // model + // only) + private int[] sampledTazs; // by + // alternative + // (sampled + // taz) + private int[] sampledMgras; // by + // alternative(sampled + // mgra) + private double[] tourOrigToStopDistanceAlt; + private double[] stopToTourDestDistanceAlt; + private double[] osMcLogsumAlt; + private double[] sdMcLogsumAlt; + + HashMap frequencyChosen; + + private VisitorTrip trip; + + private int originMgra; // the + // origin + // MGRA + // of + // the + // stop + // (originMgra + // -> + // stopMgra + // -> + // destinationMgra) + private int destinationMgra; // the + // destination + // MGRA + // of + // the + // stop + // (originMgra + // -> + // stopMgra + // -> + // destinationMgra) + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public VisitorStopLocationChoiceModel(HashMap propertyMap, + VisitorModelStructure myModelStructure, VisitorDmuFactoryIf dmuFactory, AutoTazSkimsCalculator tazDistanceCalculator) + { + mgraManager = MgraDataManager.getInstance(propertyMap); + tazManager = TazDataManager.getInstance(propertyMap); + + modelStructure = myModelStructure; + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + // this sets by thread, so do it outside of initialization + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + setupStopLocationChoiceModel(propertyMap, dmuFactory); + + frequencyChosen = new HashMap(); + + trip = new VisitorTrip(); + + } + + /** + * Read the UEC file and set up the stop destination choice model. + * + * @param propertyMap + * @param dmuFactory + */ + private void setupStopLocationChoiceModel(HashMap rbMap, + VisitorDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up visitor stop location choice model.")); + + dmu = dmuFactory.getVisitorStopLocationChoiceDMU(); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String visitorStopLocationSoaFileName = Util.getStringValueFromPropertyMap(rbMap, + "visitor.slc.soa.uec.file"); + visitorStopLocationSoaFileName = uecFileDirectory + visitorStopLocationSoaFileName; + + int soaDataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "visitor.slc.soa.data.page")); + int soaModelPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "visitor.slc.soa.model.page")); + + String visitorStopLocationFileName = Util.getStringValueFromPropertyMap(rbMap, + "visitor.slc.uec.file"); + visitorStopLocationFileName = uecFileDirectory + visitorStopLocationFileName; + + int dataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "visitor.slc.data.page")); + int modelPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "visitor.slc.model.page")); + + // create a ChoiceModelApplication object for the SOA model. + soaModel = new ChoiceModelApplication(visitorStopLocationSoaFileName, soaModelPage, + soaDataPage, rbMap, (VariableTable) dmu); + + // create a ChoiceModelApplication object for the full model. + destModel = new ChoiceModelApplication(visitorStopLocationFileName, modelPage, dataPage, + rbMap, (VariableTable) dmu); + sampleRate = destModel.getAlternativeNames().length; + + // get the alternative data + UtilityExpressionCalculator uec = soaModel.getUEC(); + alternativeData = uec.getAlternativeData(); + int purposes = modelStructure.VISITOR_PURPOSES.length; + + sampledSizeTerms = new double[purposes][sampleRate + 1]; // by purpose, + // alternative + // (taz or + // sampled + // mgra) + correctionFactors = new double[sampleRate + 1]; // by alternative + // (sampled mgra, for + // full model only) + sampledTazs = new int[sampleRate + 1]; // by alternative (sampled taz) + sampledMgras = new int[sampleRate + 1]; // by alternative (sampled mgra) + tourOrigToStopDistanceAlt = new double[sampleRate + 1]; + stopToTourDestDistanceAlt = new double[sampleRate + 1]; + osMcLogsumAlt = new double[sampleRate + 1]; + sdMcLogsumAlt = new double[sampleRate + 1]; + + } + + /** + * Create a sample for the tour and stop. + * + * @param tour + * @param stop + */ + private void createSample(VisitorTour tour, VisitorStop stop) + { + + int purpose = tour.getPurpose(); + int origTaz = 0; + int destTaz = 0; + int period = modelStructure.AM; + + dmu.setPurpose(purpose); + boolean inbound = stop.isInbound(); + if (inbound) + { + dmu.setInboundStop(1); + dmu.setStopsOnHalfTour(tour.getNumberInboundStops()); + + // destination for inbound stops is always tour origin + destinationMgra = tour.getOriginMGRA(); + destTaz = mgraManager.getTaz(destinationMgra); + + // origin for inbound stops is tour destination if first stop, or + // last chosen stop location + if (stop.getId() == 0) + { + originMgra = tour.getDestinationMGRA(); + origTaz = mgraManager.getTaz(originMgra); + } else + { + VisitorStop[] stops = tour.getInboundStops(); + originMgra = stops[stop.getId() - 1].getMgra(); + origTaz = mgraManager.getTaz(originMgra); + } + + } else + { + dmu.setInboundStop(0); + dmu.setStopsOnHalfTour(tour.getNumberOutboundStops()); + + // destination for outbound stops is always tour destination + destinationMgra = tour.getDestinationMGRA(); + destTaz = mgraManager.getTaz(destinationMgra); + + // origin for outbound stops is tour origin if first stop, or last + // chosen stop location + if (stop.getId() == 0) + { + originMgra = tour.getOriginMGRA(); + origTaz = mgraManager.getTaz(originMgra); + } else + { + VisitorStop[] stops = tour.getOutboundStops(); + originMgra = stops[stop.getId() - 1].getMgra(); + origTaz = mgraManager.getTaz(originMgra); + } + } + dmu.setStopNumber(stop.getId() + 1); + dmu.setDmuIndexValues(origTaz, origTaz, origTaz, 0, false); + + // distances + soaTourOrigToStopDistanceAlt = logsumHelper.getAnmSkimCalculator().getTazDistanceFromTaz( + origTaz, period); + soaStopToTourDestDistanceAlt = logsumHelper.getAnmSkimCalculator().getTazDistanceToTaz( + destTaz, period); + dmu.setTourOrigToStopDistanceAlt(soaTourOrigToStopDistanceAlt); + dmu.setStopToTourDestDistanceAlt(soaStopToTourDestDistanceAlt); + + dmu.setSizeTerms(tazSizeTerms); + + // solve for each sample + frequencyChosen.clear(); + for (int sample = 1; sample <= sampleRate; ++sample) + { + + // solve the UEC + soaModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + // choose a TAZ + double random = tour.getRandom(); + ConcreteAlternative[] alts = soaModel.getAlternatives(); + double cumProb = 0; + double altProb = 0; + int sampledTaz = -1; + for (int i = 0; i < alts.length; ++i) + { + cumProb += alts[i].getProbability(); + if (random < cumProb) + { + sampledTaz = (int) alternativeData.getValueAt(i + 1, "dest"); + altProb = alts[i].getProbability(); + break; + } + } + + // set the sampled taz in the array + sampledTazs[sample] = sampledTaz; + + // now find an MGRA in the taz corresponding to the random number + // drawn: + // note that the indexing needs to be offset by the cumulative + // probability of the chosen taz and the + // mgra probabilities need to be scaled by the alternatives + // probability + int[] mgraArray = tazManager.getMgraArray(sampledTaz); + int mgraNumber = 0; + double[] mgraCumProb = mgraProbabilities[purpose][sampledTaz]; + + if (mgraCumProb == null) + { + logger.error("Error: mgraCumProb array is null for purpose " + purpose + + " sampledTaz " + sampledTaz + " hhID " + tour.getID()); + throw new RuntimeException(); + } + for (int i = 0; i < mgraCumProb.length; ++i) + { + cumProb += mgraCumProb[i] * altProb; + if (cumProb > random && mgraCumProb[i] > 0) + { + mgraNumber = mgraArray[i]; + sampledMgras[sample] = mgraNumber; + + // for now, store the probability in the correction factors + // array + correctionFactors[sample] = mgraCumProb[i] * altProb; + + break; + } + } + + // store frequency chosen + if (!frequencyChosen.containsKey(mgraNumber)) + { + frequencyChosen.put(mgraNumber, 1); + } else + { + int freq = frequencyChosen.get(mgraNumber); + frequencyChosen.put(mgraNumber, freq + 1); + } + + // set the size terms for the sample + sampledSizeTerms[purpose][sample] = mgraSizeTerms[purpose][mgraNumber]; + + // set the distances for the sample + tourOrigToStopDistanceAlt[sample] = soaTourOrigToStopDistanceAlt[sampledTaz]; + stopToTourDestDistanceAlt[sample] = soaStopToTourDestDistanceAlt[sampledTaz]; + + } + // calculate correction factors + for (int sample = 1; sample <= sampleRate; ++sample) + { + int mgra = sampledMgras[sample]; + int freq = frequencyChosen.get(mgra); + correctionFactors[sample] = (float) Math.log((double) freq / correctionFactors[sample]); + + } + + } + + /** + * Choose a stop location from the sample. + * + * @param tour + * The visitor tour. + * @param stop + * The visitor stop. + */ + public void chooseStopLocation(VisitorTour tour, VisitorStop stop) + { + + // create a sample of mgras and set all of the dmu properties + createSample(tour, stop); + dmu.setCorrectionFactors(correctionFactors); + dmu.setSizeTerms(sampledSizeTerms); + dmu.setTourOrigToStopDistanceAlt(stopToTourDestDistanceAlt); + dmu.setStopToTourDestDistanceAlt(stopToTourDestDistanceAlt); + dmu.setSampleNumber(sampledMgras); + + // calculate trip mode choice logsums to and from stop + for (int i = 1; i <= sampleRate; ++i) + { + + // to stop (originMgra -> stopMgra ) + trip.initializeFromStop(tour, stop, true); + trip.setOriginMgra(trip.getOriginMgra()); + trip.setDestinationMgra(sampledMgras[i]); + double logsum = tripModeChoiceModel.computeUtilities(tour, trip); + osMcLogsumAlt[i] = logsum; + + // from stop (stopMgra -> destinationMgra) + trip.initializeFromStop(tour, stop, false); + trip.setOriginMgra(sampledMgras[i]); + trip.setDestinationMgra(trip.getDestinationMgra()); + logsum = tripModeChoiceModel.computeUtilities(tour, trip); + sdMcLogsumAlt[i] = logsum; + + } + dmu.setOsMcLogsumAlt(osMcLogsumAlt); + dmu.setSdMcLogsumAlt(sdMcLogsumAlt); + + // log headers to traceLogger + if (tour.getDebugChoiceModels()) + { + String decisionMakerLabel = "Tour ID " + tour.getID() + " stop id " + stop.getId() + + " purpose " + modelStructure.VISITOR_PURPOSES[stop.getPurpose()]; + destModel.choiceModelUtilityTraceLoggerHeading( + "Intermediate stop location choice model", decisionMakerLabel); + } + + destModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + double random = tour.getRandom(); + int alt = destModel.getChoiceResult(random); + int destMgra = sampledMgras[alt]; + stop.setMgra(destMgra); + + // write UEC calculation results and choice + if (tour.getDebugChoiceModels()) + { + String decisionMakerLabel = "Tour ID " + tour.getID() + " stop id " + stop.getId() + + " purpose " + modelStructure.VISITOR_PURPOSES[stop.getPurpose()]; + String loggingHeader = String.format("%s %s", + "Intermediate stop location choice model", decisionMakerLabel); + destModel.logUECResults(logger, loggingHeader); + logger.info("Chose alternative " + alt + " mgra " + destMgra + " with random number " + + random); + logger.info(""); + logger.info(""); + } + + } + + /** + * @return the mgraSizeTerms + */ + public double[][] getMgraSizeTerms() + { + return mgraSizeTerms; + } + + /** + * @return the mgraProbabilities + */ + public double[][][] getMgraProbabilities() + { + return mgraProbabilities; + } + + /** + * @return the tazSizeTerms + */ + public double[][] getTazSizeTerms() + { + return tazSizeTerms; + } + + /** + * Set mgra size terms: must call before choosing location. + * + * @param mgraSizeTerms + */ + public void setMgraSizeTerms(double[][] mgraSizeTerms) + { + + if (mgraSizeTerms == null) + { + logger.error("Error attempting to set MGRASizeTerms in VisitorStopLocationChoiceModel: MGRASizeTerms are null"); + throw new RuntimeException(); + } + this.mgraSizeTerms = mgraSizeTerms; + } + + /** + * Set taz size terms: must call before choosing location. + * + * @param tazSizeTerms + */ + public void setTazSizeTerms(double[][] tazSizeTerms) + { + if (tazSizeTerms == null) + { + logger.error("Error attempting to set TazSizeTerms in VisitorStopLocationChoiceModel: TazSizeTerms are null"); + throw new RuntimeException(); + } + this.tazSizeTerms = tazSizeTerms; + } + + /** + * Set the mgra probabilities. Must call before choosing location. + * + * @param mgraProbabilities + */ + public void setMgraProbabilities(double[][][] mgraProbabilities) + { + if (mgraProbabilities == null) + { + logger.error("Error attempting to set mgraProbabilities in VisitorStopLocationChoiceModel: mgraProbabilities are null"); + throw new RuntimeException(); + } + this.mgraProbabilities = mgraProbabilities; + } + + /** + * Set trip mode choice model. Must call before choosing location. + * + * @param tripModeChoiceModel + */ + public void setTripModeChoiceModel(VisitorTripModeChoiceModel tripModeChoiceModel) + { + this.tripModeChoiceModel = tripModeChoiceModel; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopPurposeModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopPurposeModel.java new file mode 100644 index 0000000..2693a44 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopPurposeModel.java @@ -0,0 +1,233 @@ +package org.sandag.abm.visitor; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the stop purpose choice model for visitor tours. It is + * currently based on a static probability distribution stored in an input file, + * and indexed into by purpose, tour leg direction (inbound or outbound), the + * stop number, and whether there is just one or multiple stops on the tour leg. + * + * @author Freedman + * + */ +public class VisitorStopPurposeModel +{ + private transient Logger logger = Logger.getLogger("visitorModel"); + + private double[][] cumProbability; // by + // alternative, + // stop + // purpose: + // cumulative + // probability + // distribution + VisitorModelStructure modelStructure; + + HashMap arrayElementMap; // Hashmap + // used + // to + // get + // the + // element + // number + // of + // the + // cumProbability + // array + // based + // on + // the + // tour + // purpose, + // tour + // leg + // direction, + // stop + // number, + // and + // stop + // complexity. + + /** + * Constructor. + */ + public VisitorStopPurposeModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String stopFrequencyFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.stop.purpose.file"); + stopFrequencyFile = directory + stopFrequencyFile; + + modelStructure = new VisitorModelStructure(); + + arrayElementMap = new HashMap(); + readStopPurposeFile(stopFrequencyFile); + + } + + /** + * Read the stop frequency distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readStopPurposeFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating stop purpose probability distribution"); + + // take a pass through the data and see how many alternatives there are + // for each purpose + int rowCount = probabilityTable.getRowCount(); + int purposes = modelStructure.VISITOR_PURPOSES.length; // start at 0 + + cumProbability = new double[rowCount][purposes]; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "TourPurp"); + + int inbound = (int) probabilityTable.getValueAt(row, "Inbound"); + int stopNumber = (int) probabilityTable.getValueAt(row, "StopNum"); + int multiple = (int) probabilityTable.getValueAt(row, "Multiple"); + + // store cumulative probabilities + float cumProb = 0; + for (int p = 0; p < purposes; ++p) + { + String label = "StopPurp" + p; + cumProb += probabilityTable.getValueAt(row, label); + cumProbability[row - 1][p] += cumProb; + } + + if (Math.abs(cumProb - 1.0) > 0.00001) + logger.info("Cumulative probability for tour purpose " + purpose + " inbound " + + inbound + " stopNumber " + stopNumber + " multiple " + multiple + " is " + + cumProb); + + int key = getKey(purpose, inbound, stopNumber, multiple); + arrayElementMap.put(key, row - 1); + + } + + logger.info("End calculating stop purpose probability distribution"); + + } + + /** + * Get the key for the arrayElementMap. + * + * @param tourPurp + * Tour purpose + * @param isInbound + * 1 if the stop is on the inbound direction, else 0. + * @param stopNumber + * The number of the stop. + * @param multipleStopsOnLeg + * 1 if multiple stops on leg, else 0. + * @return arrayElementMap key. + */ + private int getKey(int tourPurp, int isInbound, int stopNumber, int multipleStopsOnLeg) + { + + return tourPurp * 1000 + isInbound * 100 + stopNumber * 10 + multipleStopsOnLeg; + } + + /** + * Calculate purposes all stops on the tour + * + * @param tour + * A cross border tour (with tour purpose) + */ + public void calculateStopPurposes(VisitorTour tour) + { + + // outbound stops first + if (tour.getNumberOutboundStops() != 0) + { + + int tourPurp = tour.getPurpose(); + VisitorStop[] stops = tour.getOutboundStops(); + int multiple = 0; + if (stops.length > 1) multiple = 1; + + // iterate through stop list and calculate purpose for each + for (int i = 0; i < stops.length; ++i) + { + int key = getKey(tourPurp, 0, i + 1, multiple); + int element = arrayElementMap.get(key); + double[] cumProb = cumProbability[element]; + double rand = tour.getRandom(); + int purpose = chooseFromDistribution(rand, cumProb); + stops[i].setPurpose((byte) purpose); + } + } + // inbound stops last + if (tour.getNumberInboundStops() != 0) + { + + int tourPurp = tour.getPurpose(); + VisitorStop[] stops = tour.getInboundStops(); + int multiple = 0; + if (stops.length > 1) multiple = 1; + + // iterate through stop list and calculate purpose for each + for (int i = 0; i < stops.length; ++i) + { + int key = getKey(tourPurp, 1, i + 1, multiple); + int element = arrayElementMap.get(key); + double[] cumProb = cumProbability[element]; + double rand = tour.getRandom(); + int purpose = chooseFromDistribution(rand, cumProb); + stops[i].setPurpose((byte) purpose); + } + } + } + + /** + * Choose purpose from the cumulative probability distribution + * + * @param random + * Uniformly distributed random number + * @param cumProb + * Cumulative probability distribution + * @return Stop purpose (0 init). + */ + private int chooseFromDistribution(double random, double[] cumProb) + { + + int choice = -1; + for (int i = 0; i < cumProb.length; ++i) + { + if (random < cumProb[i]) + { + choice = i; + break; + } + + } + return choice; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopTimeOfDayChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopTimeOfDayChoiceModel.java new file mode 100644 index 0000000..e5a2bd7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorStopTimeOfDayChoiceModel.java @@ -0,0 +1,365 @@ +package org.sandag.abm.visitor; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the TOD choice model for visitor tours. It is currently based + * on a static probability distribution stored in an input file, and indexed + * into by purpose. + * + * @author Freedman + * + */ +public class VisitorStopTimeOfDayChoiceModel +{ + private transient Logger logger = Logger.getLogger("visitorModel"); + + private double[][] outboundCumProbability; // by + // alternative: + // outbound + // cumulative + // probability + // distribution + private int[] outboundOffsets; // by + // alternative: + // offsets + // for + // outbound + // stop + // duration + // choice + + private double[][] inboundCumProbability; // by + // alternative: + // inbound + // cumulative + // probability + // distribution + private int[] inboundOffsets; // by + // alternative: + // offsets + // for + // inbound + // stop + // duration + // choice + private VisitorModelStructure modelStructure; + + private HashMap outboundElementMap; // Hashmap + // used + // to + // get + // the + // element + // number + // of + // the + // cumProbability + // array + // based + // on + // the + // tour duration and stop number. + + private HashMap inboundElementMap; // Hashmap + // used + // to + // get + // the + // element + // number + // of + // the + // cumProbability + // array + // based + // on + // the + + // tour duration and stop number. + + /** + * Constructor. + */ + public VisitorStopTimeOfDayChoiceModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String outboundDurationFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.stop.outbound.duration.file"); + String inboundDurationFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.stop.inbound.duration.file"); + + outboundDurationFile = directory + outboundDurationFile; + inboundDurationFile = directory + inboundDurationFile; + + modelStructure = new VisitorModelStructure(); + + outboundElementMap = new HashMap(); + readOutboundFile(outboundDurationFile); + + inboundElementMap = new HashMap(); + readInboundFile(inboundDurationFile); + } + + /** + * Read the outbound stop duration file and store the cumulative probability + * distribution as well as the offsets and set the key map to index into the + * probability array. + * + * @param fileName + */ + public void readOutboundFile(String fileName) + { + TableDataSet outboundTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + outboundTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + int columns = outboundTable.getColumnCount(); + int rows = outboundTable.getRowCount(); + outboundCumProbability = new double[rows][columns - 3]; + + // first three columns are index fields, rest are offsets + outboundOffsets = new int[columns - 3]; + for (int i = 4; i <= columns; ++i) + { + String offset = outboundTable.getColumnLabel(i); + outboundOffsets[i - 4] = new Integer(offset); + } + + // now fill in cumulative probability array + for (int row = 1; row <= rows; ++row) + { + + int lowerBound = (int) outboundTable.getValueAt(row, "RemainingLow"); + int upperBound = (int) outboundTable.getValueAt(row, "RemainingHigh"); + int stopNumber = (int) outboundTable.getValueAt(row, "Stop"); + + for (int duration = lowerBound; duration <= upperBound; ++duration) + { + int key = getKey(stopNumber, duration); + outboundElementMap.put(key, row - 1); + } + + // cumulative probability distribution + double cumProb = 0; + for (int col = 4; col <= columns; ++col) + { + cumProb += outboundTable.getValueAt(row, col); + outboundCumProbability[row - 1][col - 4] = cumProb; + } + + } + + } + + /** + * Read the inbound stop duration file and store the cumulative probability + * distribution as well as the offsets and set the key map to index into the + * probability array. + * + * @param fileName + */ + public void readInboundFile(String fileName) + { + TableDataSet inboundTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + inboundTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + int columns = inboundTable.getColumnCount(); + int rows = inboundTable.getRowCount(); + inboundCumProbability = new double[rows][columns - 3]; + + // first three columns are index fields, rest are offsets + inboundOffsets = new int[columns - 3]; + for (int i = 4; i <= columns; ++i) + { + String offset = inboundTable.getColumnLabel(i); + inboundOffsets[i - 4] = new Integer(offset); + } + + // now fill in cumulative probability array + for (int row = 1; row <= rows; ++row) + { + + int lowerBound = (int) inboundTable.getValueAt(row, "RemainingLow"); + int upperBound = (int) inboundTable.getValueAt(row, "RemainingHigh"); + int stopNumber = (int) inboundTable.getValueAt(row, "Stop"); + + for (int duration = lowerBound; duration <= upperBound; ++duration) + { + int key = getKey(stopNumber, duration); + inboundElementMap.put(key, row - 1); + } + // cumulative probability distribution + double cumProb = 0; + for (int col = 4; col <= columns; ++col) + { + cumProb += inboundTable.getValueAt(row, col); + inboundCumProbability[row - 1][col - 4] = cumProb; + } + + } + + } + + /** + * Get the key for the arrayElementMap. + * + * @param stopNumber + * stop number + * @param periodsRemaining + * Remaining time periods + * @return arrayElementMap key. + */ + private int getKey(int stopNumber, int periodsRemaining) + { + + return periodsRemaining * 10 + stopNumber; + } + + /** + * Choose the stop time of day period. + * + * @param tour + * @param stop + */ + public void chooseTOD(VisitorTour tour, VisitorStop stop) + { + + boolean inbound = stop.isInbound(); + int stopNumber = stop.getId() + 1; + int arrivalPeriod = tour.getArriveTime(); + + if (!inbound) + { + + // find the departure time + int departPeriod = 0; + if (stop.getId() == 0) departPeriod = tour.getDepartTime(); + else + { + VisitorStop[] stops = tour.getOutboundStops(); + departPeriod = stops[stop.getId() - 1].getStopPeriod(); + } + + int periodsRemaining = arrivalPeriod - departPeriod; + + int key = getKey(stopNumber, periodsRemaining); + int element = outboundElementMap.get(key); + double[] cumProb = outboundCumProbability[element]; + double random = tour.getRandom(); + + // iterate through the offset distribution, choose an offset, and + // set in the stop + if (tour.getDebugChoiceModels()) + { + logger.info("Stop TOD Choice Model for tour " + tour.getID() + " outbound stop " + + stop.getId() + " periods remaining " + periodsRemaining); + logger.info(" random number " + random); + } + for (int i = 0; i < cumProb.length; ++i) + { + if (random < cumProb[i]) + { + int offset = outboundOffsets[i]; + int period = departPeriod + offset; + stop.setPeriod(period); + + if (tour.getDebugChoiceModels()) + { + logger.info("***"); + logger.info("Chose alt " + i + " offset " + offset + " from depart period " + + departPeriod); + logger.info("Stop period is " + stop.getStopPeriod()); + + } + break; + + } + } + } else + { + // inbound stop + + // find the departure time + int departPeriod = 0; + + // first inbound stop + if (stop.getId() == 0) + { + + // there were outbound stops + if (tour.getOutboundStops() != null) + { + VisitorStop[] outboundStops = tour.getOutboundStops(); + departPeriod = outboundStops[outboundStops.length - 1].getStopPeriod(); + } else + { + // no outbound stops + departPeriod = tour.getDepartTime(); + } + } else + { + // not first inbound stop + VisitorStop[] stops = tour.getInboundStops(); + departPeriod = stops[stop.getId() - 1].getStopPeriod(); + } + + int periodsRemaining = arrivalPeriod - departPeriod; + + int key = getKey(stopNumber, periodsRemaining); + int element = inboundElementMap.get(key); + double[] cumProb = inboundCumProbability[element]; + double random = tour.getRandom(); + if (tour.getDebugChoiceModels()) + { + logger.info("Stop TOD Choice Model for tour " + tour.getID() + " inbound stop " + + stop.getId() + " periods remaining " + periodsRemaining); + logger.info("Random number " + random); + } + for (int i = 0; i < cumProb.length; ++i) + { + if (random < cumProb[i]) + { + int offset = inboundOffsets[i]; + int arrivePeriod = tour.getArriveTime(); + int period = arrivePeriod + offset; + stop.setPeriod(period); + + if (tour.getDebugChoiceModels()) + { + logger.info("***"); + logger.info("Chose alt " + i + " offset " + offset + " from arrive period " + + arrivePeriod); + logger.info("Stop period is " + stop.getStopPeriod()); + + } + break; + } + } + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTour.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTour.java new file mode 100644 index 0000000..1de6057 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTour.java @@ -0,0 +1,350 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Household; +import com.pb.common.math.MersenneTwister; + +public class VisitorTour + implements Serializable +{ + + private MersenneTwister random; + private int ID; + + // following variables determined via simulation + private byte segment; // 0 + // = + // business, + // 1 + // = + // personal + private byte purpose; + private byte numberOfParticipants; + private int income; + private int autoAvailable; + + private VisitorStop[] outboundStops; + private VisitorStop[] inboundStops; + + private VisitorTrip[] trips; + + private int departTime; + private int arriveTime; + + private boolean debugChoiceModels; + + // following variables chosen via choice models + private int originMGRA; + private int destinationMGRA; + private byte tourMode; + + private float valueOfTime; + /** + * Public constructor. + * + * @param seed + * A seed for the random number generator. + */ + public VisitorTour(long seed) + { + + random = new MersenneTwister(seed); + } + + /** + * @return the iD + */ + public int getID() + { + return ID; + } + + /** + * @param iD + * the iD to set + */ + public void setID(int iD) + { + ID = iD; + } + + /** + * @return the purpose + */ + public byte getPurpose() + { + return purpose; + } + + /** + * @return the outboundStops + */ + public VisitorStop[] getOutboundStops() + { + return outboundStops; + } + + /** + * @param outboundStops + * the outboundStops to set + */ + public void setOutboundStops(VisitorStop[] outboundStops) + { + this.outboundStops = outboundStops; + } + + /** + * @return the inboundStops + */ + public VisitorStop[] getInboundStops() + { + return inboundStops; + } + + /** + * @param inboundStops + * the inboundStops to set + */ + public void setInboundStops(VisitorStop[] inboundStops) + { + this.inboundStops = inboundStops; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(byte purpose) + { + this.purpose = purpose; + } + + /** + * @return the departTime + */ + public int getDepartTime() + { + return departTime; + } + + /** + * @param departTime + * the departTime to set + */ + public void setDepartTime(int departTime) + { + this.departTime = departTime; + } + + public VisitorTrip[] getTrips() + { + return trips; + } + + public void setTrips(VisitorTrip[] trips) + { + this.trips = trips; + } + + /** + * @return the originMGRA + */ + public int getOriginMGRA() + { + return originMGRA; + } + + /** + * @param originMGRA + * the originMGRA to set + */ + public void setOriginMGRA(int originMGRA) + { + this.originMGRA = originMGRA; + } + + /** + * @return the tour mode + */ + public byte getTourMode() + { + return tourMode; + } + + /** + * @param mode + * the tour mode to set + */ + public void setTourMode(byte mode) + { + this.tourMode = mode; + } + + /** + * Get a random number from the parties random class. + * + * @return A random number. + */ + public double getRandom() + { + return random.nextDouble(); + } + + /** + * @return the debugChoiceModels + */ + public boolean getDebugChoiceModels() + { + return debugChoiceModels; + } + + /** + * @param debugChoiceModels + * the debugChoiceModels to set + */ + public void setDebugChoiceModels(boolean debugChoiceModels) + { + this.debugChoiceModels = debugChoiceModels; + } + + /** + * Get the number of outbound stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberOutboundStops() + { + if (outboundStops == null) return 0; + else return outboundStops.length; + + } + + /** + * Get the number of return stops + * + * @return 0 if not initialized, else number of stops + */ + public int getNumberInboundStops() + { + if (inboundStops == null) return 0; + else return inboundStops.length; + + } + + /** + * @return the destinationMGRA + */ + public int getDestinationMGRA() + { + return destinationMGRA; + } + + /** + * @param destinationMGRA + * the destinationMGRA to set + */ + public void setDestinationMGRA(int destinationMGRA) + { + this.destinationMGRA = destinationMGRA; + } + + public void setArriveTime(int arriveTime) + { + this.arriveTime = arriveTime; + } + + public int getArriveTime() + { + return arriveTime; + } + + /** + * @return the numberOfParticipants + */ + public byte getNumberOfParticipants() + { + return numberOfParticipants; + } + + /** + * @param numberOfParticipants + * the numberOfParticipants to set + */ + public void setNumberOfParticipants(byte numberOfParticipants) + { + this.numberOfParticipants = numberOfParticipants; + } + + /** + * @return the income + */ + public int getIncome() + { + return income; + } + + /** + * @param income + * the income to set + */ + public void setIncome(int income) + { + this.income = income; + } + + /** + * @return the autoAvailable + */ + public int getAutoAvailable() + { + return autoAvailable; + } + + /** + * @param autoAvailable + * the autoAvailable to set + */ + public void setAutoAvailable(int autoAvailable) + { + this.autoAvailable = autoAvailable; + } + + /** + * @return the segment + */ + public byte getSegment() + { + return segment; + } + + /** + * @param segment + * the segment to set + */ + public void setSegment(byte segment) + { + this.segment = segment; + } + + public float getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(float valueOfTime) { + this.valueOfTime = valueOfTime; + } + + public void logTourObject(Logger logger, int totalChars) + { + + Household.logHelper(logger, "tourId: ", ID, totalChars); + Household.logHelper(logger, "tourPurpose: ", purpose, totalChars); + Household.logHelper(logger, "tourOrigMgra: ", originMGRA, totalChars); + Household.logHelper(logger, "tourDestMgra: ", destinationMGRA, totalChars); + Household.logHelper(logger, "tourDepartPeriod: ", departTime, totalChars); + Household.logHelper(logger, "tourArrivePeriod: ", arriveTime, totalChars); + Household.logHelper(logger, "tourMode: ", tourMode, totalChars); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourDestChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourDestChoiceDMU.java new file mode 100644 index 0000000..405ab33 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourDestChoiceDMU.java @@ -0,0 +1,317 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import java.util.HashMap; +import org.apache.log4j.Logger; +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class VisitorTourDestChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger("visitorModel"); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected float tourDepartPeriod; + protected float tourArrivePeriod; + protected int purpose; + protected double[][] sizeTerms; // by + // purpose, + // alternative + // (taz + // or + // sampled + // mgras) + protected double[] correctionFactors; // by + // alternative + // (sampled + // mgra, + // for + // full + // model + // only) + protected double[] tourModeLogsums; // by + // alternative + // (sampled + // mgra + // pair, + // for + // full + // model + // only) + protected int[] sampleMGRA; // by + // alternative + // (sampled + // mgra) + protected int[] sampleTAZ; // by + // alternative + // (sampled + // taz) + + protected double nmWalkTimeOut; + protected double nmWalkTimeIn; + protected double nmBikeTimeOut; + protected double nmBikeTimeIn; + protected double lsWgtAvgCostM; + protected double lsWgtAvgCostD; + protected double lsWgtAvgCostH; + + public VisitorTourDestChoiceDMU(VisitorModelStructure modelStructure) + { + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Get the tour mode choice logsum for the sampled station-mgra pair. + * + * @param alt + * Sampled station-mgra + * @return + */ + public double getTourModeLogsum(int alt) + { + return tourModeLogsums[alt]; + } + + /** + * Set the tour mode choice logsums + * + * @param poeNumbers + * An array of tour mode choice logsums, one for each alternative + * (sampled station-mgra) + */ + public void setTourModeLogsums(double[] logsums) + { + this.tourModeLogsums = logsums; + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + /** + * @return the sizeTerms. The size term is the size of the alternative north + * of the border. It is indexed by alternative, where alternative is + * either taz-station pair or mgra-station pair, depending on + * whether the DMU is being used for the SOA model or the actual + * model. + */ + public double getSizeTerm(int alt) + { + return sizeTerms[purpose][alt]; + } + + /** + * @param sizeTerms + * the sizeTerms to set. The size term is the size of the + * alternative north of the border. It is indexed by alternative, + * where alternative is either taz-station pair or mgra-station + * pair, depending on whether the DMU is being used for the SOA + * model or the actual model. + */ + public void setSizeTerms(double[][] sizeTerms) + { + this.sizeTerms = sizeTerms; + } + + /** + * @return the correctionFactors + */ + public double getCorrectionFactor(int alt) + { + return correctionFactors[alt]; + } + + /** + * @param correctionFactors + * the correctionFactors to set + */ + public void setCorrectionFactors(double[] correctionFactors) + { + this.correctionFactors = correctionFactors; + } + + public int getSampleMgra(int alt) + { + return sampleMGRA[alt]; + } + + public void setSampleMgra(int[] sampleNumber) + { + this.sampleMGRA = sampleNumber; + } + + public int getSampleTaz(int alt) + { + return sampleTAZ[alt]; + } + + public void setSampleTaz(int[] sampleNumber) + { + this.sampleTAZ = sampleNumber; + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the purpose + */ + public int getPurpose() + { + return purpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setPurpose(int purpose) + { + this.purpose = purpose; + } + + public float getTimeOutbound() + { + return tourDepartPeriod; + } + + public float getTimeInbound() + { + return tourArrivePeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(float tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(float tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTimeOutbound", 0); + methodIndexMap.put("getTimeInbound", 1); + methodIndexMap.put("getSizeTerm", 2); + methodIndexMap.put("getCorrectionFactor", 3); + methodIndexMap.put("getPurpose", 4); + methodIndexMap.put("getTourModeLogsum", 5); + methodIndexMap.put("getSampleMgra", 6); + methodIndexMap.put("getSampleTaz", 7); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + + case 0: + returnValue = getTimeOutbound(); + break; + case 1: + returnValue = getTimeInbound(); + break; + case 2: + returnValue = getSizeTerm(arrayIndex); + break; + case 3: + returnValue = getCorrectionFactor(arrayIndex); + break; + case 4: + returnValue = getPurpose(); + break; + case 5: + returnValue = getTourModeLogsum(arrayIndex); + break; + case 6: + returnValue = getSampleMgra(arrayIndex); + break; + case 7: + returnValue = getSampleTaz(arrayIndex); + break; + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + + } + + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourDestChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourDestChoiceModel.java new file mode 100644 index 0000000..800b310 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourDestChoiceModel.java @@ -0,0 +1,586 @@ +package org.sandag.abm.visitor; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +/** + * This class is used for both the sample of alternatives and the full + * destination choice model for visitor tours. + * + * + * @author Freedman + * + */ +public class VisitorTourDestChoiceModel +{ + + private double[][] mgraSizeTerms; // by + // purpose, + // MGRA + private double[][] tazSizeTerms; // by + // purpose, + // TAZ + private double[][][] mgraProbabilities; // by + // purpose, + // tazNumber, + // mgra + // index + // (sequential, + // 0-based) + private Matrix[] tazProbabilities; // by + // purpose, + // origin + // TAZ, + // destination + // TAZ + private TableDataSet alternativeData; // the + // alternatives, + // with + // a + // dest + // field + // indicating + // tazNumber + private int[] sampleMgras; // numbers + // of + // mgra + // for + // the + // sample + private int[] sampleTazs; // numbers + // of + // taz + // for + // the + // sample + private double[] sampleCorrectionFactors; // correction + // factors + // for + // sample + private double[][] sampleSizeTerms; // size + // terms + // for + // sample + private double[] sampleLogsums; // tour + // mc + // logsums + + private transient Logger logger = Logger.getLogger("visitorModel"); + + private TazDataManager tazManager; + private MgraDataManager mgraManager; + + private ChoiceModelApplication[] soaModel; + private ChoiceModelApplication[] destModel; + private UtilityExpressionCalculator sizeTermUEC; + private HashMap rbMap; + + private VisitorTourDestChoiceDMU dcDmu; + private VisitorTourModeChoiceModel tourModeChoiceModel; + + private HashMap frequencyChosen; // by + // mgra, + // number + // of + // times + // chosen + private int sampleRate; + + /** + * Constructor + * + * @param propertyMap + * Resource properties file map. + * @param dmuFactory + * Factory object for creation of airport model DMUs + */ + public VisitorTourDestChoiceModel(HashMap rbMap, + VisitorModelStructure modelStructure, VisitorDmuFactoryIf dmuFactory, AutoTazSkimsCalculator tazDistanceCalculator) + { + + this.rbMap = rbMap; + + tazManager = TazDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + String uecFileDirectory = Util.getStringValueFromPropertyMap(rbMap, + CtrampApplication.PROPERTIES_UEC_PATH); + String visitorDCSoaFileName = Util.getStringValueFromPropertyMap(rbMap, + "visitor.dc.soa.uec.file"); + visitorDCSoaFileName = uecFileDirectory + visitorDCSoaFileName; + + int dataPage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "visitor.dc.soa.data.page")); + int sizePage = Integer.parseInt(Util.getStringValueFromPropertyMap(rbMap, + "visitor.dc.soa.size.page")); + + // initiate a DMU + dcDmu = dmuFactory.getVisitorTourDestChoiceDMU(); + + // read the model pages from the property file, create one choice model + // for each soa model + soaModel = new ChoiceModelApplication[VisitorModelStructure.VISITOR_PURPOSES.length]; + for (int i = 0; i < soaModel.length; ++i) + { + + // get page from property file + String purpose = VisitorModelStructure.VISITOR_PURPOSES[i].toLowerCase(); + String purposeName = "visitor.dc.soa." + purpose + ".page"; + String purposeString = Util.getStringValueFromPropertyMap(rbMap, purposeName); + purposeString.replaceAll(" ", ""); + int destModelPage = Integer.parseInt(purposeString); + + // create a ChoiceModelApplication object for the filename, model + // page and data page. + soaModel[i] = new ChoiceModelApplication(visitorDCSoaFileName, destModelPage, dataPage, + rbMap, (VariableTable) dcDmu); + } + + // get the alternative data from the first segment + UtilityExpressionCalculator uec = soaModel[0].getUEC(); + alternativeData = uec.getAlternativeData(); + + // create a UEC to solve size terms for each MGRA + sizeTermUEC = new UtilityExpressionCalculator(new File(visitorDCSoaFileName), sizePage, + dataPage, rbMap, (VariableTable) dcDmu); + + // create the full model UECs + // read the model pages from the property file, create one choice model + // for each full model + String visitorDCFileName = Util.getStringValueFromPropertyMap(rbMap, "visitor.dc.uec.file"); + visitorDCFileName = uecFileDirectory + visitorDCFileName; + destModel = new ChoiceModelApplication[VisitorModelStructure.VISITOR_PURPOSES.length]; + for (int i = 0; i < destModel.length; ++i) + { + + // get page from property file + String purpose = VisitorModelStructure.VISITOR_PURPOSES[i].toLowerCase(); + String purposeName = "visitor.dc." + purpose + ".page"; + String purposeString = Util.getStringValueFromPropertyMap(rbMap, purposeName); + purposeString.replaceAll(" ", ""); + int destModelPage = Integer.parseInt(purposeString); + + // create a ChoiceModelApplication object for the filename, model + // page and data page. + destModel[i] = new ChoiceModelApplication(visitorDCFileName, destModelPage, dataPage, + rbMap, (VariableTable) dcDmu); + if (i == 0) sampleRate = destModel[i].getNumberOfAlternatives(); + } + + frequencyChosen = new HashMap(); + sampleMgras = new int[sampleRate + 1]; + sampleTazs = new int[sampleRate + 1]; + sampleCorrectionFactors = new double[sampleRate + 1]; + sampleSizeTerms = new double[destModel.length][sampleRate + 1]; + sampleLogsums = new double[sampleRate + 1]; + + tourModeChoiceModel = new VisitorTourModeChoiceModel(rbMap, modelStructure, dmuFactory, tazDistanceCalculator); + + } + + /** + * Calculate size terms + */ + public void calculateSizeTerms(VisitorDmuFactoryIf dmuFactory) + { + + logger.info("Calculating Visitor Tour Destination Choice Model MGRA Size Terms"); + + ArrayList mgras = mgraManager.getMgras(); + int[] mgraTaz = mgraManager.getMgraTaz(); + int maxMgra = mgraManager.getMaxMgra(); + int maxTaz = tazManager.getMaxTaz(); + int purposes = sizeTermUEC.getNumberOfAlternatives(); + + mgraSizeTerms = new double[purposes][maxMgra + 1]; + tazSizeTerms = new double[purposes][maxTaz + 1]; + IndexValues iv = new IndexValues(); + VisitorTourDestChoiceDMU aDmu = dmuFactory.getVisitorTourDestChoiceDMU(); + + // loop through mgras and calculate size terms + for (int mgra : mgras) + { + + int taz = mgraTaz[mgra]; + iv.setZoneIndex(mgra); + double[] utilities = sizeTermUEC.solve(iv, aDmu, null); + + // store the size terms + for (int purpose = 0; purpose < purposes; ++purpose) + { + + mgraSizeTerms[purpose][mgra] = utilities[purpose]; + tazSizeTerms[purpose][taz] += utilities[purpose]; + } + + } + + // now calculate probability of selecting each MGRA within each TAZ for + // SOA + mgraProbabilities = new double[purposes][maxTaz + 1][]; + int[] tazs = tazManager.getTazs(); + + for (int purpose = 0; purpose < purposes; ++purpose) + { + for (int taz = 0; taz < tazs.length; ++taz) + { + int tazNumber = tazs[taz]; + int[] mgraArray = tazManager.getMgraArray(tazNumber); + + // initialize the vector of mgras for this purpose-taz + mgraProbabilities[purpose][tazNumber] = new double[mgraArray.length]; + + // now calculate the cumulative probability distribution + double lastProb = 0.0; + for (int mgra = 0; mgra < mgraArray.length; ++mgra) + { + + int mgraNumber = mgraArray[mgra]; + if (tazSizeTerms[purpose][tazNumber] > 0.0) + mgraProbabilities[purpose][tazNumber][mgra] = lastProb + + mgraSizeTerms[purpose][mgraNumber] + / tazSizeTerms[purpose][tazNumber]; + lastProb = mgraProbabilities[purpose][tazNumber][mgra]; + } + if (tazSizeTerms[purpose][tazNumber] > 0.0 && Math.abs(lastProb - 1.0) > 0.000001) + logger.info("Error: purpose " + purpose + " taz " + tazNumber + + " cum prob adds up to " + lastProb); + } + + } + + // calculate logged size terms for mgra and taz vectors to be used in + // dmu + for (int purpose = 0; purpose < purposes; ++purpose) + { + for (int taz = 0; taz < tazSizeTerms[purpose].length; ++taz) + if (tazSizeTerms[purpose][taz] > 0.0) + tazSizeTerms[purpose][taz] = Math.log(tazSizeTerms[purpose][taz] + 1.0); + + for (int mgra = 0; mgra < mgraSizeTerms[purpose].length; ++mgra) + if (mgraSizeTerms[purpose][mgra] > 0.0) + mgraSizeTerms[purpose][mgra] = Math.log(mgraSizeTerms[purpose][mgra] + 1.0); + + } + logger.info("Finished Calculating Visitor Tour Destination Choice Model MGRA Size Terms"); + } + + /** + * Calculate taz probabilities. This method initializes and calculates the + * tazProbabilities array. + */ + public void calculateTazProbabilities(VisitorDmuFactoryIf dmuFactory) + { + + if (tazSizeTerms == null) + { + logger.error("Error: attemping to execute VisitorTourDestChoiceModel.calculateTazProbabilities() before calling calculateMgraProbabilities()"); + throw new RuntimeException(); + } + + logger.info("Calculating Visitor Model TAZ Probabilities Arrays"); + + // initialize taz probabilities array + int purposes = tazSizeTerms.length; + + // initialize the arrays + tazProbabilities = new Matrix[purposes]; + + // iterate through the alternatives in the alternatives file and set the + // size term and station logsum for each alternative + UtilityExpressionCalculator soaModelUEC = soaModel[0].getUEC(); + TableDataSet altData = soaModelUEC.getAlternativeData(); + + dcDmu.setSizeTerms(tazSizeTerms); + + // iterate through purposes + for (int purpose = 0; purpose < soaModel.length; ++purpose) + { + + tazProbabilities[purpose] = new Matrix("Prob_Matrix", "Probability Matrix", + altData.getRowCount() + 1, altData.getRowCount() + 1); + int[] tazs = altData.getColumnAsInt("dest"); + tazProbabilities[purpose].setExternalNumbersZeroBased(tazs); + + // iterate through origin zones, solve the UEC and store the results + // in the matrix + for (int taz = 0; taz < tazs.length; ++taz) + { + + int originTaz = (int) tazs[taz]; + + // set origin taz in dmu (destination set in UEC by alternative) + dcDmu.setDmuIndexValues(originTaz, originTaz, originTaz, originTaz, false); + + dcDmu.setPurpose(purpose); + + // Calculate utilities & probabilities + soaModel[purpose].computeUtilities(dcDmu, dcDmu.getDmuIndexValues()); + + // Store probabilities (by purpose) + double[] probabilities = soaModel[purpose].getCumulativeProbabilities(); + + for (int i = 0; i < probabilities.length; ++i) + { + + double cumProb = probabilities[i]; + int destTaz = (int) altData.getValueAt(i + 1, "dest"); + tazProbabilities[purpose].setValueAt(originTaz, destTaz, (float) cumProb); + } + } + } + logger.info("Finished Calculating Visitor Model TAZ Probabilities Arrays"); + } + + /** + * Choose a MGRA alternative for sampling + * + * @param tour + * VisitorTour with purpose and Random + */ + private void chooseMgraSample(VisitorTour tour) + { + + frequencyChosen.clear(); + + // choose sample, set station logsums and mgra size terms + int purpose = tour.getPurpose(); + int originTaz = mgraManager.getTaz(tour.getOriginMGRA()); + + for (int sample = 1; sample <= sampleRate; ++sample) + { + + // first find a TAZ and station + int alt = 0; + Matrix tazCumProb = tazProbabilities[purpose]; + double altProb = 0; + double cumProb = 0; + double random = tour.getRandom(); + int destinationTaz = -1; + for (int i = 0; i < tazCumProb.getColumnCount(); ++i) + { + destinationTaz = (int) tazCumProb.getExternalColumnNumber(i); + if (tazCumProb.getValueAt(originTaz, destinationTaz) > random) + { + alt = i; + if (i != 0) + { + cumProb = tazCumProb.getValueAt(originTaz, + tazCumProb.getExternalColumnNumber(i - 1)); + altProb = tazCumProb.getValueAt(originTaz, destinationTaz) + - tazCumProb.getValueAt(originTaz, + tazCumProb.getExternalColumnNumber(i - 1)); + } else + { + altProb = tazCumProb.getValueAt(originTaz, destinationTaz); + } + break; + } + } + + // get the taz number of the alternative, and an array of mgras in + // that taz + + int[] mgraArray = tazManager.getMgraArray(destinationTaz); + + // now find an MGRA in the taz corresponding to the random number + // drawn: + // note that the indexing needs to be offset by the cumulative + // probability of the chosen taz and the + // mgra probabilities need to be scaled by the alternatives + // probability + int mgraNumber = 0; + double[] mgraCumProb = mgraProbabilities[purpose][destinationTaz]; + for (int i = 0; i < mgraCumProb.length; ++i) + { + cumProb += mgraCumProb[i] * altProb; + if (cumProb > random && mgraCumProb[i] > 0) + { + mgraNumber = mgraArray[i]; + sampleMgras[sample] = mgraNumber; + sampleTazs[sample] = mgraManager.getTaz(mgraNumber); + + // for now, store the probability in the correction factors + // array + sampleCorrectionFactors[sample] = mgraCumProb[i] * altProb; + + break; + } + } + // store frequency chosen + if (!frequencyChosen.containsKey(mgraNumber)) + { + frequencyChosen.put(mgraNumber, 1); + } else + { + int freq = frequencyChosen.get(mgraNumber); + frequencyChosen.put(mgraNumber, freq + 1); + } + // set the size terms for the sample + sampleSizeTerms[purpose][sample] = mgraSizeTerms[purpose][mgraNumber]; + } + // calculate correction factors + for (int sample = 1; sample <= sampleRate; ++sample) + { + int mgra = sampleMgras[sample]; + int freq = frequencyChosen.get(mgra); + sampleCorrectionFactors[sample] = (float) Math.log((double) freq + / sampleCorrectionFactors[sample]); + + } + + } + + /** + * Use the tour mode choice model to calculate the logsum for each sampled + * mgra and store in the array. + * + * @param tour + * The visitor tour. + */ + private void calculateLogsumsForSample(VisitorTour tour) + { + + for (int sample = 1; sample <= sampleRate; ++sample) + { + + if (sampleMgras[sample] > 0) + { + + int destinationMgra = sampleMgras[sample]; + tour.setDestinationMGRA(destinationMgra); + + double logsum = tourModeChoiceModel.getModeChoiceLogsum(tour, logger, + "Sample logsum " + sample, "tour " + tour.getID() + " dest " + + destinationMgra); + sampleLogsums[sample] = logsum; + } else sampleLogsums[sample] = 0; + + } + + } + + /** + * Choose a destination MGRA for the tour. + * + * @param tour + * A cross border tour with a tour origin, purpose, attributes, + * and departure\arrival time and SENTRI availability members. + */ + public void chooseDestination(VisitorTour tour) + { + + chooseMgraSample(tour); + calculateLogsumsForSample(tour); + + double random = tour.getRandom(); + int purpose = tour.getPurpose(); + dcDmu.setPurpose(purpose); + + // set origin taz in dmu (destination set in UEC by alternative) + int originTaz = mgraManager.getTaz(tour.getOriginMGRA()); + dcDmu.setDmuIndexValues(0, 0, originTaz, 0, false); + + // set size terms for each sampled station-mgra pair corresponding to + // mgra + dcDmu.setSizeTerms(sampleSizeTerms); + + // set the correction factors + dcDmu.setCorrectionFactors(sampleCorrectionFactors); + + // set the tour mode choice logsums + dcDmu.setTourModeLogsums(sampleLogsums); + + // sampled mgra + dcDmu.setSampleMgra(sampleMgras); + + // sampled taz + dcDmu.setSampleTaz(sampleTazs); + + if (tour.getDebugChoiceModels()) + { + logger.info("***"); + logger.info("Choosing destination alternative from sample"); + tour.logTourObject(logger, 100); + + // log the sample + destModel[purpose].choiceModelUtilityTraceLoggerHeading( + "Visitor tour destination model", "tour " + tour.getID()); + } + + destModel[purpose].computeUtilities(dcDmu, dcDmu.getDmuIndexValues()); + + if (tour.getDebugChoiceModels()) + { + destModel[purpose].logUECResults(logger, "Visitor tour destination model"); + } + int alt = destModel[purpose].getChoiceResult(random); + + int primaryDestination = sampleMgras[alt]; + + if (tour.getDebugChoiceModels()) + { + logger.info("Chose destination MGRA " + primaryDestination); + } + + tour.setDestinationMGRA(primaryDestination); + } + + /** + * @return the tourModeChoiceModel + */ + public VisitorTourModeChoiceModel getTourModeChoiceModel() + { + return tourModeChoiceModel; + } + + /** + * @param tourModeChoiceModel + * the tourModeChoiceModel to set + */ + public void setTourModeChoiceModel(VisitorTourModeChoiceModel tourModeChoiceModel) + { + this.tourModeChoiceModel = tourModeChoiceModel; + } + + /** + * @return the mgraSizeTerms + */ + public double[][] getMgraSizeTerms() + { + return mgraSizeTerms; + } + + /** + * @return the tazSizeTerms + */ + public double[][] getTazSizeTerms() + { + return tazSizeTerms; + } + + /** + * @return the mgraProbabilities + */ + public double[][][] getMgraProbabilities() + { + return mgraProbabilities; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourEstimationFile.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourEstimationFile.java new file mode 100644 index 0000000..31acfca --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourEstimationFile.java @@ -0,0 +1,382 @@ +package org.sandag.abm.visitor; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.MatrixDataManager; +import com.pb.common.datafile.CSVFileWriter; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.MatrixType; +import com.pb.common.util.ResourceUtil; + +public class VisitorTourEstimationFile +{ + + public static final int MATRIX_DATA_SERVER_PORT = 1171; + public static final int MATRIX_DATA_SERVER_PORT_OFFSET = 0; + + private MatrixDataServerRmi ms; + private String inputFileName; + private String outputFileName; + private TableDataSet estimationData; + + private VisitorModelStructure myModelStructure; + private VisitorDmuFactoryIf dmuFactory; + private McLogsumsCalculator logsumsCalculator; + private VisitorTourModeChoiceModel tourModeChoiceModel; + private HashMap rbMap; + private AutoTazSkimsCalculator tazDistanceCalculator; + + private static Logger logger = Logger.getLogger(VisitorTourEstimationFile.class); + private static final int SAMPLE_SIZE = 30; + private MgraDataManager mgraManager; + + /** + * Default constructor + */ + public VisitorTourEstimationFile(HashMap propertyMap) + { + this.rbMap = propertyMap; + mgraManager = MgraDataManager.getInstance(propertyMap); + myModelStructure = new VisitorModelStructure(); + + dmuFactory = new VisitorDmuFactory(myModelStructure); + + } + + public void createEstimationFile() + { + tazDistanceCalculator = new AutoTazSkimsCalculator(rbMap); + tazDistanceCalculator.computeTazDistanceArrays(); + logsumsCalculator = new McLogsumsCalculator(); + logsumsCalculator.setupSkimCalculators(rbMap); + logsumsCalculator.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + tourModeChoiceModel = new VisitorTourModeChoiceModel(rbMap, myModelStructure, dmuFactory, tazDistanceCalculator); + + // open file + estimationData = openFile(inputFileName); + + // iterate through file and calculate logsums + calculateTourMCLogsums(); + + // write the file + writeFile(outputFileName, estimationData); + } + + /** + * Open a trip file and return the Tabledataset. + * + * @fileName The name of the trip file + * @return The tabledataset + */ + public TableDataSet openFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet tripData; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + tripData = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + return tripData; + } + + /** + * Write the file to disk. + * + * @param fileName + * Name of file + * @param data + * TableDataSet to write + */ + public void writeFile(String fileName, TableDataSet data) + { + logger.info("Begin writing the data to file " + fileName); + + try + { + CSVFileWriter csvFile = new CSVFileWriter(); + csvFile.writeFile(data, new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + logger.info("End writing the data to file " + fileName); + + } + + /** + * Calculate mode choice logsums + * + * TOURNUM: Unique ID SURVNUM: Number associated with traveler PersonType: 0 + * - Business, 1 - Personal Persons: Number of persons (in addition to + * traveler) on tour HHIncome: 1= $0-29,999; 2 = 30,000-59,999; 3 = + * 60,000-99,999; 4 = 100,000-149,000; 5=$150,000 or more; 6 = DK/Refused + * AutoAvail: 0 - No auto, 1 - Auto Available PURPOSE: 1 - Work, 2 - Other + * (non-dining) 3 - Dining originMGRA - origin of tour (hotel/overnight + * location) destMGRA - primary destination MGRA PeriodDepart: Period of + * Tour Departure from hotel/overnight location PeriodArrive: Period of Tour + * Arrival at primary destination SAMPLE_: 1:30 sampled alternatives + * + */ + public void calculateTourMCLogsums() + { + + int[] sample = new int[SAMPLE_SIZE]; + float[][] sampleLogsum = new float[SAMPLE_SIZE][estimationData.getRowCount()]; + float[] chosenLogsum = new float[estimationData.getRowCount()]; + String fieldName = null; + + for (int i = 0; i < estimationData.getRowCount(); ++i) + { + + if ((i + 1) <= 10 || (i + 1) % 100 == 0) + { + logger.info("Processing record " + (i + 1)); + } + int ID = (int) estimationData.getValueAt(i + 1, "TOURNUM"); + byte segment = (byte) estimationData.getValueAt(i + 1, "PersonType"); + byte purpose = (byte) estimationData.getValueAt(i + 1, "PURPOSE"); + byte income = (byte) estimationData.getValueAt(i + 1, "HHIncome"); + byte autoAvailable = (byte) estimationData.getValueAt(i + 1, "AutoAvail"); + byte participants = (byte) (estimationData.getValueAt(i + 1, "Persons") + 1); + int departTime = (int) estimationData.getValueAt(i + 1, "PeriodDepart"); + int arriveTime = (int) estimationData.getValueAt(i + 1, "PeriodArrive"); + int originMGRA = (int) estimationData.getValueAt(i + 1, "originMGRA"); + int destinationMGRA = (int) estimationData.getValueAt(i + 1, "destMGRA"); + + for (int j = 0; j < SAMPLE_SIZE; ++j) + { + fieldName = "SAMPLE_" + new Integer(j + 1).toString(); + sample[j] = (int) estimationData.getValueAt(i + 1, fieldName); + } + + VisitorTour tour = new VisitorTour(ID + 10000); + tour.setID(ID); + tour.setSegment(segment); + tour.setPurpose(purpose); + tour.setIncome(income); + tour.setAutoAvailable(autoAvailable); + tour.setNumberOfParticipants(participants); + tour.setDepartTime(departTime); + tour.setArriveTime(arriveTime); + tour.setOriginMGRA(originMGRA); + + if ((i + 1) == 1 || (i + 1) == 500) tour.setDebugChoiceModels(true); + else tour.setDebugChoiceModels(false); + + double logsum = 0; + // for each sampled destination + for (int j = 0; j < SAMPLE_SIZE; ++j) + { + + tour.setDestinationMGRA(sample[j]); + + // some of the samples are 0 + if (sample[j] > 0 && originMGRA > 0) + { + logsum = tourModeChoiceModel.getModeChoiceLogsum(tour, logger, + "DCEstimationFileLogsum", "ID " + ID); + sampleLogsum[j][i] = (float) logsum; + } + } + + // for the chosen destination + tour.setDestinationMGRA(destinationMGRA); + if (originMGRA > 0 && destinationMGRA > 0) + logsum = tourModeChoiceModel.getModeChoiceLogsum(tour, logger, + "DCEstimationFileLogsum", "ID " + ID); + chosenLogsum[i] = (float) logsum; + + } + + // append the logsum fields to the tabledata + estimationData.appendColumn(chosenLogsum, "CHSN_LS"); + + for (int j = 0; j < SAMPLE_SIZE; ++j) + { + fieldName = "SAMPLE_" + (j + 1) + "_LS"; + estimationData.appendColumn(sampleLogsum[j], fieldName); + } + + } + + /** + * Write the destination choice estimation file with logsums appended. + */ + public void writeDCEstimationFile(String name) + { + + } + + /** + * @param args + */ + public static void main(String[] args) + { + // TODO Auto-generated method stub + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + 2.0)); + + logger.info(String.format("Running Visitor Tour Estimation File Model")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + String inFile = args[1]; + String outFile = args[2]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + VisitorTourEstimationFile visitorEstimationFile = new VisitorTourEstimationFile(pMap); + + visitorEstimationFile.inputFileName = inFile; + visitorEstimationFile.outputFileName = outFile; + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = visitorEstimationFile.startMatrixServerProcess( + matrixServerAddress, serverPort, mt); + visitorEstimationFile.ms = matrixServer; + } else + { + visitorEstimationFile.ms = new MatrixDataServerRmi(matrixServerAddress, + serverPort, MatrixDataServer.MATRIX_DATA_SERVER_NAME); + visitorEstimationFile.ms.testRemote(Thread.currentThread().getName()); + + // these methods need to be called to set the matrix data + // manager in the matrix data server + MatrixDataManager mdm = MatrixDataManager.getInstance(); + mdm.setMatrixDataServerObject(visitorEstimationFile.ms); + } + + } + + } catch (Exception e) + { + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + visitorEstimationFile.createEstimationFile(); + + if (args.length < 3) + { + System.out + .println("Error: please specifiy inputFileName and outputFileName on command line"); + throw new RuntimeException(); + } + + } + + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourManager.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourManager.java new file mode 100644 index 0000000..3bf9f9b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourManager.java @@ -0,0 +1,531 @@ +package org.sandag.abm.visitor; + +import java.io.BufferedWriter; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.ArrayList; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.application.SandagTourBasedModel; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.Util; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.math.MersenneTwister; +import com.pb.common.util.ResourceUtil; + +public class VisitorTourManager +{ + + private static Logger logger = Logger.getLogger(SandagTourBasedModel.class); + + private VisitorTour[] tours; + + VisitorModelStructure modelStructure; + SandagModelStructure sandagStructure; + + TableDataSet businessTourFrequency; + TableDataSet personalTourFrequency; + TableDataSet partySizeFrequency; + TableDataSet autoAvailableFrequency; + TableDataSet incomeFrequency; + + TableDataSet mgraData; + + float occupancyRate; + float householdRate; + + float businessHotelPercent; + float businessHouseholdPercent; + + private boolean seek; + private int traceId; + + private MersenneTwister random; + + private boolean avAvailable; + + /** + * Constructor. Reads properties file and opens/stores all probability + * distributions for sampling. Estimates number of airport travel parties + * and initializes parties[]. + * + * @param resourceFile + * Property file. + * + * Creates the array of cross-border tours. + */ + public VisitorTourManager(HashMap rbMap) + { + + modelStructure = new VisitorModelStructure(); + sandagStructure = new SandagModelStructure(); + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String mgraFile = Util.getStringValueFromPropertyMap(rbMap, "mgra.socec.file"); + mgraFile = directory + mgraFile; + + occupancyRate = new Float(Util.getStringValueFromPropertyMap(rbMap, + "visitor.hotel.occupancyRate")); + householdRate = new Float(Util.getStringValueFromPropertyMap(rbMap, + "visitor.household.occupancyRate")); + + businessHotelPercent = new Float(Util.getStringValueFromPropertyMap(rbMap, + "visitor.hotel.businessPercent")); + businessHouseholdPercent = new Float(Util.getStringValueFromPropertyMap(rbMap, + "visitor.household.businessPercent")); + + String businessTourFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.business.tour.file"); + businessTourFile = directory + businessTourFile; + + String personalTourFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.personal.tour.file"); + personalTourFile = directory + personalTourFile; + + String partySizeFile = Util.getStringValueFromPropertyMap(rbMap, "visitor.partySize.file"); + partySizeFile = directory + partySizeFile; + + String autoAvailableFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.autoAvailable.file"); + autoAvailableFile = directory + autoAvailableFile; + + String incomeFile = Util.getStringValueFromPropertyMap(rbMap, "visitor.income.file"); + incomeFile = directory + incomeFile; + + businessTourFrequency = readFile(businessTourFile); + personalTourFrequency = readFile(personalTourFile); + partySizeFrequency = readFile(partySizeFile); + autoAvailableFrequency = readFile(autoAvailableFile); + incomeFrequency = readFile(incomeFile); + + mgraData = readFile(mgraFile); + + seek = new Boolean(Util.getStringValueFromPropertyMap(rbMap, "visitor.seek")); + traceId = new Integer(Util.getStringValueFromPropertyMap(rbMap, "visitor.trace")); + + float avShare = new Float(Util.getFloatValueFromPropertyMap(rbMap, "Mobility.AV.Share")); + if(avShare>0) + avAvailable=true; + + random = new MersenneTwister(1000001); + + } + + /** + * Read the file and return the TableDataSet. + * + * @param fileName + * @return data + */ + private TableDataSet readFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet data; + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + data = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + return data; + } + + /** + * Generate and attribute visitor tours + */ + public void generateVisitorTours() + { + + // calculate total number of cross border tours + ArrayList tourList = new ArrayList(); + + int rows = mgraData.getRowCount(); + + int tourCount = 0; + int personalCount = 0; + int businessCount = 0; + for (int i = 1; i <= rows; ++i) + { + + float hotelRooms = mgraData.getValueAt(i, "HotelRoomTotal"); + float households = mgraData.getValueAt(i, "hh"); + int mgraNumber = (int) mgraData.getValueAt(i, "mgra"); + + float hotelVisitorParties = hotelRooms * occupancyRate; + float householdVisitorParties = households * householdRate; + + int businessParties = Math.round(hotelVisitorParties * businessHotelPercent); + int personalParties = Math.round(hotelVisitorParties * (1.0f - businessHotelPercent)); + + businessParties += Math.round(householdVisitorParties * businessHouseholdPercent); + personalParties += Math.round(householdVisitorParties + * (1.0f - businessHouseholdPercent)); + + personalCount += personalParties; + businessCount += businessParties; + + // generate a tour for each business party + for (int j = 0; j < businessParties; ++j) + { + + int[] tourPurposes = simulateTours(businessTourFrequency); + + for (int k = 0; k < tourPurposes.length; ++k) + { + VisitorTour tour = new VisitorTour(tourCount + 1000001); + tour.setID(tourCount + 1); + tour.setOriginMGRA(mgraNumber); + tour.setSegment(modelStructure.BUSINESS); + tour.setPurpose((byte) tourPurposes[k]); + calculateSize(tour); + calculateAutoAvailability(tour); + calculateIncome(tour); + tourList.add(tour); + ++tourCount; + } + } + + // generate a tour for each personal party + for (int j = 0; j < personalParties; ++j) + { + + int[] tourPurposes = simulateTours(personalTourFrequency); + + for (int k = 0; k < tourPurposes.length; ++k) + { + VisitorTour tour = new VisitorTour(tourCount + 1000001); + tour.setID(tourCount + 1); + tour.setOriginMGRA(mgraNumber); + tour.setSegment(modelStructure.PERSONAL); + tour.setPurpose((byte) tourPurposes[k]); + calculateSize(tour); + calculateAutoAvailability(tour); + calculateIncome(tour); + tourList.add(tour); + ++tourCount; + } + } + + } + + if (tourList.isEmpty()) + { + logger.error("Visitor tour list is empty!!"); + throw new RuntimeException(); + } + + tours = new VisitorTour[tourList.size()]; + for (int i = 0; i < tours.length; ++i) + tours[i] = tourList.get(i); + + logger.info("Total personal parties: " + personalCount); + logger.info("Total business parties: " + businessCount); + + logger.info("Total visitor tours: " + tourCount); + + } + + /** + * Calculate the number of tours for this travel party, by purpose. Return + * an array whose length equals the number of tours, where each element is + * the purpose of the tour. + * + * @param tourFrequency + * A tableDataSet with the following fields + * WorkTours,RecreationTours,DiningTours,Percent + * @return An array dimensioned to number of tours to generate, with the + * purpose of each. + */ + private int[] simulateTours(TableDataSet tourFrequency) + { + + int[] tourPurposes; + double rand = random.nextDouble(); + + double cumProb = 0.0; + int row = -1; + for (int i = 0; i < tourFrequency.getRowCount(); ++i) + { + + float percent = tourFrequency.getValueAt(i + 1, "Percent"); + cumProb += percent; + if (rand < cumProb) + { + row = i + 1; + break; + } + } + int workTours = (int) tourFrequency.getValueAt(row, "WorkTours"); + int recTours = (int) tourFrequency.getValueAt(row, "RecreationTours"); + int diningTours = (int) tourFrequency.getValueAt(row, "DiningTours"); + + int totalTours = workTours + recTours + diningTours; + tourPurposes = new int[totalTours]; + + int workSet = 0; + int recSet = 0; + int diningSet = 0; + for (int j = 0; j < tourPurposes.length; ++j) + { + + if (workTours > 0 && workSet < workTours) + { + tourPurposes[j] = modelStructure.WORK; + ++workSet; + } else if (recTours > 0 && recSet < recTours) + { + tourPurposes[j] = modelStructure.RECREATION; + ++recSet; + } else if (diningTours > 0 && diningSet < diningTours) + { + tourPurposes[j] = modelStructure.DINING; + ++diningSet; + } + } + return tourPurposes; + } + + /** + * Calculate the size of the tour and store in tour object. + * + * @param tour + */ + private void calculateSize(VisitorTour tour) + { + + byte purp = tour.getPurpose(); + String purpString = modelStructure.VISITOR_PURPOSES[purp]; + String columnName = purpString.toLowerCase(); + + double cumProb = 0; + double rand = tour.getRandom(); + byte size = -1; + int rowCount = partySizeFrequency.getRowCount(); + for (int i = 1; i <= rowCount; ++i) + { + cumProb += partySizeFrequency.getValueAt(i, columnName); + if (rand < cumProb) + { + size = (byte) partySizeFrequency.getValueAt(i, "PartySize"); + break; + } + } + if (size == -1) + { + logger.error("Error attempting to choose party size for visitor tour " + tour.getID()); + throw new RuntimeException(); + } + tour.setNumberOfParticipants(size); + } + + /** + * Calculate whether autos are available for this tour. + * + * @param tour + */ + private void calculateAutoAvailability(VisitorTour tour) + { + + byte purp = tour.getPurpose(); + String purpString = modelStructure.VISITOR_PURPOSES[purp]; + String columnName = purpString.toLowerCase(); + + double rand = tour.getRandom(); + boolean autoAvailable = false; + double probability = autoAvailableFrequency.getValueAt(1, columnName); + if (rand < probability) autoAvailable = true; + + tour.setAutoAvailable(autoAvailable ? 1 : 0); + } + + /** + * Calculate the income of the tour + * + * @param tour + */ + private void calculateIncome(VisitorTour tour) + { + byte segment = tour.getSegment(); + String segmentString = modelStructure.VISITOR_SEGMENTS[segment]; + String columnName = segmentString.toLowerCase(); + + double rand = tour.getRandom(); + int income = -1; + double cumProb = 0; + int rowCount = incomeFrequency.getRowCount(); + for (int i = 1; i <= rowCount; ++i) + { + cumProb += incomeFrequency.getValueAt(i, columnName); + if (rand < cumProb) + { + income = (int) incomeFrequency.getValueAt(i, "Income"); + break; + } + } + if (income == -1) + { + logger.error("Error attempting to choose party size for visitor tour " + tour.getID()); + throw new RuntimeException(); + } + tour.setIncome(income); + + } + + /** + * Create a text file and write all records to the file. + * + */ + public void writeOutputFile(HashMap rbMap) + { + + // Open file and print header + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String tourFileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "visitor.tour.output.file"); + String tripFileName = directory + + Util.getStringValueFromPropertyMap(rbMap, "visitor.trip.output.file"); + + logger.info("Writing visitor tours to file " + tourFileName); + logger.info("Writing visitor trips to file " + tripFileName); + + PrintWriter tourWriter = null; + try + { + tourWriter = new PrintWriter(new BufferedWriter(new FileWriter(tourFileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + tourFileName + " for writing\n"); + throw new RuntimeException(); + } + String tourHeaderString = new String( + "id,segment,purpose,autoAvailable,partySize,income,departTime,arriveTime,originMGRA,destinationMGRA,tourMode,avAvailable,outboundStops,inboundStops,valueOfTime\n"); + tourWriter.print(tourHeaderString); + + PrintWriter tripWriter = null; + try + { + tripWriter = new PrintWriter(new BufferedWriter(new FileWriter(tripFileName))); + } catch (IOException e) + { + logger.fatal("Could not open file " + tripFileName + " for writing\n"); + throw new RuntimeException(); + } + String tripHeaderString = new String( + "tourID,tripID,originPurp,destPurp,originMGRA,destinationMGRA,inbound,originIsTourDestination,destinationIsTourDestination,period,tripMode,avAvailable,boardingTap,alightingTap,set,valueOfTime,partySize," + +"micro_walkMode,micro_trnAcc,micro_trnEgr,parkingCost\n"); + tripWriter.print(tripHeaderString); + + // Iterate through the array, printing records to the file + for (int i = 0; i < tours.length; ++i) + { + + VisitorTour tour = tours[i]; + + if (seek && tour.getID() != traceId) continue; + + VisitorTrip[] trips = tours[i].getTrips(); + + if (trips == null) continue; + + writeTour(tour, tourWriter); + + for (int j = 0; j < trips.length; ++j) + { + writeTrip(tour, trips[j], j + 1, tripWriter); + } + } + + tourWriter.close(); + tripWriter.close(); + + } + + /** + * Write the tour to the PrintWriter + * + * @param tour + * @param writer + */ + private void writeTour(VisitorTour tour, PrintWriter writer) + { + String record = new String(tour.getID() + "," + tour.getSegment() + "," + tour.getPurpose() + + "," + tour.getAutoAvailable() + "," + tour.getNumberOfParticipants() + "," + + tour.getIncome() + "," + tour.getDepartTime() + "," + tour.getArriveTime() + "," + + tour.getOriginMGRA() + "," + tour.getDestinationMGRA() + "," + tour.getTourMode() + "," + + (avAvailable?1:0) + + "," + tour.getNumberOutboundStops() + "," + tour.getNumberInboundStops() + + "," + String.format("%9.2f",tour.getValueOfTime())+ "\n"); + writer.print(record); + + } + + /** + * Write the trip to the PrintWriter + * + * @param tour + * @param trip + * @param tripNumber + * @param writer + */ + private void writeTrip(VisitorTour tour, VisitorTrip trip, int tripNumber, PrintWriter writer) + { + String record = new String(tour.getID() + "," + tripNumber + "," + trip.getOriginPurpose() + + "," + trip.getDestinationPurpose() + "," + trip.getOriginMgra() + "," + + trip.getDestinationMgra() + "," + trip.isInbound() + "," + + trip.isOriginIsTourDestination() + "," + trip.isDestinationIsTourDestination() + + "," + trip.getPeriod() + "," + trip.getTripMode() + "," + (avAvailable?1:0) +"," + + trip.getBoardTap() + "," + trip.getAlightTap() + "," + trip.getSet() + + "," + String.format("%9.2f",trip.getValueOfTime())+ "," + tour.getNumberOfParticipants()+"," + +trip.getMicromobilityWalkMode()+"," +trip.getMicromobilityAccessMode()+"," +trip.getMicromobilityEgressMode() + + "," + String.format("%9.2f", trip.getParkingCost()) +"\n"); + writer.print(record); + } + + + /** + * @return the parties + */ + public VisitorTour[] getTours() + { + return tours; + } + + public static void main(String[] args) + { + + String propertiesFile = null; + HashMap pMap; + + logger.info(String.format("SANDAG Activity Based Model using CT-RAMP version %s", + CtrampApplication.VERSION)); + + logger.info(String.format("Running Cross Border Model Tour Manager")); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + VisitorTourManager apm = new VisitorTourManager(pMap); + apm.generateVisitorTours(); + apm.writeOutputFile(pMap); + + logger.info("Cross-Border Tour Manager successfully completed!"); + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourModeChoiceDMU.java new file mode 100644 index 0000000..3fa9b3c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourModeChoiceDMU.java @@ -0,0 +1,570 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.TourModeChoiceDMU; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class VisitorTourModeChoiceDMU + implements Serializable, VariableTable +{ + protected transient Logger logger = Logger.getLogger(VisitorTourModeChoiceDMU.class); + + public static final int WTW = McLogsumsCalculator.WTW; + public static final int WTD = McLogsumsCalculator.WTD; + public static final int DTW = McLogsumsCalculator.DTW; + protected static final int NUM_ACC_EGR = McLogsumsCalculator.NUM_ACC_EGR; + + protected static final int OUT = McLogsumsCalculator.OUT; + protected static final int IN = McLogsumsCalculator.IN; + protected static final int NUM_DIR = McLogsumsCalculator.NUM_DIR; + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected float tourDepartPeriod; + protected float tourArrivePeriod; + protected double origDuDen; + protected double origEmpDen; + protected double origTotInt; + protected double destDuDen; + protected double destEmpDen; + protected double destTotInt; + + protected int partySize; + protected int autoAvailable; + protected int income; + protected int tourPurpose; + + protected float pTazTerminalTime; + protected float aTazTerminalTime; + + protected double nmWalkTimeOut; + protected double nmWalkTimeIn; + protected double nmBikeTimeOut; + protected double nmBikeTimeIn; + protected double lsWgtAvgCostM; + protected double lsWgtAvgCostD; + protected double lsWgtAvgCostH; + + protected double[][] transitLogSum; + protected float origTaxiWaitTime; + protected float destTaxiWaitTime; + protected float origSingleTNCWaitTime; + protected float destSingleTNCWaitTime; + protected float origSharedTNCWaitTime; + protected float destSharedTNCWaitTime; + + public VisitorTourModeChoiceDMU(VisitorModelStructure modelStructure, Logger aLogger) + { + if (aLogger == null) aLogger = Logger.getLogger(TourModeChoiceDMU.class); + logger = aLogger; + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + //accEgr by in/outbound + transitLogSum = new double[NUM_ACC_EGR][NUM_DIR]; + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + public void setLsWgtAvgCostM(double cost) + { + lsWgtAvgCostM = cost; + } + + public void setLsWgtAvgCostD(double cost) + { + lsWgtAvgCostD = cost; + } + + public void setLsWgtAvgCostH(double cost) + { + lsWgtAvgCostH = cost; + } + + public double getMonthlyParkingCost() + { + return lsWgtAvgCostM; + } + + public double getDailyParkingCost() + { + return lsWgtAvgCostD; + } + + public double getHourlyParkingCost() + { + return lsWgtAvgCostH; + } + + public float getTimeOutbound() + { + return tourDepartPeriod; + } + + public float getTimeInbound() + { + return tourArrivePeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(float tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(float tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + public void setOrigDuDen(double arg) + { + origDuDen = arg; + } + + public void setOrigEmpDen(double arg) + { + origEmpDen = arg; + } + + public void setOrigTotInt(double arg) + { + origTotInt = arg; + } + + public void setDestDuDen(double arg) + { + destDuDen = arg; + } + + public void setDestEmpDen(double arg) + { + destEmpDen = arg; + } + + public void setDestTotInt(double arg) + { + destTotInt = arg; + } + + public int getTourPurpose() + { + return tourPurpose; + } + + public void setTourPurpose(int tourPurpose) + { + this.tourPurpose = tourPurpose; + } + + public double getODUDen() + { + return origDuDen; + } + + public double getOEmpDen() + { + return origEmpDen; + } + + public double getOTotInt() + { + return origTotInt; + } + + public double getDDUDen() + { + return destDuDen; + } + + public double getDEmpDen() + { + return destEmpDen; + } + + public double getDTotInt() + { + return destTotInt; + } + + public void setNmWalkTimeOut(double nmWalkTime) + { + nmWalkTimeOut = nmWalkTime; + } + + public double getNm_walkTime_out() + { + return nmWalkTimeOut; + } + + public void setNmWalkTimeIn(double nmWalkTime) + { + nmWalkTimeIn = nmWalkTime; + } + + public double getNm_walkTime_in() + { + return nmWalkTimeIn; + } + + public void setNmBikeTimeOut(double nmBikeTime) + { + nmBikeTimeOut = nmBikeTime; + } + + public double getNm_bikeTime_out() + { + return nmBikeTimeOut; + } + + public void setNmBikeTimeIn(double nmBikeTime) + { + nmBikeTimeIn = nmBikeTime; + } + + public double getNm_bikeTime_in() + { + return nmBikeTimeIn; + } + + public void setPTazTerminalTime(float time) + { + pTazTerminalTime = time; + } + + public void setATazTerminalTime(float time) + { + aTazTerminalTime = time; + } + + public double getPTazTerminalTime() + { + return pTazTerminalTime; + } + + public double getATazTerminalTime() + { + return aTazTerminalTime; + } + + public int getPartySize() + { + return partySize; + } + + public void setPartySize(int partySize) + { + this.partySize = partySize; + } + + public int getAutoAvailable() + { + return autoAvailable; + } + + public void setAutoAvailable(int autoAvailable) + { + this.autoAvailable = autoAvailable; + } + + public int getIncome() + { + return income; + } + + public void setIncome(int income) + { + this.income = income; + } + + public void setTransitLogSum(int accEgr, boolean inbound, double value){ + transitLogSum[accEgr][inbound == true ? 1 : 0] = value; + } + + protected double getTransitLogSum(int accEgr,boolean inbound){ + return transitLogSum[accEgr][inbound == true ? 1 : 0]; + } + + + + public float getOrigTaxiWaitTime() { + return origTaxiWaitTime; + } + + + + public void setOrigTaxiWaitTime(float origTaxiWaitTime) { + this.origTaxiWaitTime = origTaxiWaitTime; + } + + + + public float getDestTaxiWaitTime() { + return destTaxiWaitTime; + } + + + + public void setDestTaxiWaitTime(float destTaxiWaitTime) { + this.destTaxiWaitTime = destTaxiWaitTime; + } + + + + public float getOrigSingleTNCWaitTime() { + return origSingleTNCWaitTime; + } + + + + public void setOrigSingleTNCWaitTime(float origSingleTNCWaitTime) { + this.origSingleTNCWaitTime = origSingleTNCWaitTime; + } + + + + public float getDestSingleTNCWaitTime() { + return destSingleTNCWaitTime; + } + + + + public void setDestSingleTNCWaitTime(float destSingleTNCWaitTime) { + this.destSingleTNCWaitTime = destSingleTNCWaitTime; + } + + + + public float getOrigSharedTNCWaitTime() { + return origSharedTNCWaitTime; + } + + + + public void setOrigSharedTNCWaitTime(float origSharedTNCWaitTime) { + this.origSharedTNCWaitTime = origSharedTNCWaitTime; + } + + + + public float getDestSharedTNCWaitTime() { + return destSharedTNCWaitTime; + } + + + + public void setDestSharedTNCWaitTime(float destSharedTNCWaitTime) { + this.destSharedTNCWaitTime = destSharedTNCWaitTime; + } + + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTimeOutbound", 0); + methodIndexMap.put("getTimeInbound", 1); + methodIndexMap.put("getPTazTerminalTime", 14); + methodIndexMap.put("getATazTerminalTime", 15); + methodIndexMap.put("getODUDen", 16); + methodIndexMap.put("getOEmpDen", 17); + methodIndexMap.put("getOTotInt", 18); + methodIndexMap.put("getDDUDen", 19); + methodIndexMap.put("getDEmpDen", 20); + methodIndexMap.put("getDTotInt", 21); + methodIndexMap.put("getMonthlyParkingCost", 23); + methodIndexMap.put("getDailyParkingCost", 24); + methodIndexMap.put("getHourlyParkingCost", 25); + methodIndexMap.put("getPartySize", 30); + methodIndexMap.put("getAutoAvailable", 31); + methodIndexMap.put("getIncome", 32); + methodIndexMap.put("getTourPurpose", 33); + + methodIndexMap.put("getIvtCoeff", 56); + methodIndexMap.put("getCostCoeff", 57); + methodIndexMap.put("getWalkSetLogSum", 59); + methodIndexMap.put("getPnrSetLogSum", 60); + methodIndexMap.put("getKnrSetLogSum", 61); + + methodIndexMap.put( "getOrigTaxiWaitTime", 70 ); + methodIndexMap.put( "getDestTaxiWaitTime", 71 ); + methodIndexMap.put( "getOrigSingleTNCWaitTime", 72 ); + methodIndexMap.put( "getDestSingleTNCWaitTime", 73 ); + methodIndexMap.put( "getOrigSharedTNCWaitTime", 74 ); + methodIndexMap.put( "getDestSharedTNCWaitTime", 75 ); + + methodIndexMap.put("getNm_walkTime_out", 90); + methodIndexMap.put("getNm_walkTime_in", 91); + methodIndexMap.put("getNm_bikeTime_out", 92); + methodIndexMap.put("getNm_bikeTime_in", 93); + + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + case 0: + returnValue = getTimeOutbound(); + break; + case 1: + returnValue = getTimeInbound(); + break; + case 14: + returnValue = getPTazTerminalTime(); + break; + case 15: + returnValue = getATazTerminalTime(); + break; + case 16: + returnValue = getODUDen(); + break; + case 17: + returnValue = getOEmpDen(); + break; + case 18: + returnValue = getOTotInt(); + break; + case 19: + returnValue = getDDUDen(); + break; + case 20: + returnValue = getDEmpDen(); + break; + case 21: + returnValue = getDTotInt(); + break; + case 23: + returnValue = getMonthlyParkingCost(); + break; + case 24: + returnValue = getDailyParkingCost(); + break; + case 25: + returnValue = getHourlyParkingCost(); + break; + case 30: + returnValue = getPartySize(); + break; + case 31: + returnValue = getAutoAvailable(); + break; + case 32: + returnValue = getIncome(); + break; + case 33: + returnValue = getTourPurpose(); + break; + case 59: + returnValue = getTransitLogSum(WTW, true) + getTransitLogSum(WTW, false); + break; + case 60: + returnValue = getTransitLogSum(WTD, true) + getTransitLogSum(DTW, false); + break; + case 61: + returnValue = getTransitLogSum(WTD, true) + getTransitLogSum(DTW, false); + break; + case 70: return getOrigTaxiWaitTime(); + case 71: return getDestTaxiWaitTime(); + case 72: return getOrigSingleTNCWaitTime(); + case 73: return getDestSingleTNCWaitTime(); + case 74: return getOrigSharedTNCWaitTime(); + case 75: return getDestSharedTNCWaitTime(); + case 90: + returnValue = getNm_walkTime_out(); + break; + case 91: + returnValue = getNm_walkTime_in(); + break; + case 92: + returnValue = getNm_bikeTime_out(); + break; + case 93: + returnValue = getNm_bikeTime_in(); + break; + default: + logger.error("method number = " + variableIndex + " not found"); + throw new RuntimeException("method number = " + variableIndex + " not found"); + } + + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourModeChoiceModel.java new file mode 100644 index 0000000..87572d1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourModeChoiceModel.java @@ -0,0 +1,399 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import java.util.HashMap; +import java.util.Random; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.TNCAndTaxiWaitTimeCalculator; +import org.sandag.abm.ctramp.TourModeChoiceDMU; +import org.sandag.abm.ctramp.TripModeChoiceDMU; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class VisitorTourModeChoiceModel + implements Serializable +{ + + private transient Logger logger = Logger.getLogger("visitorModel"); + + public static final boolean DEBUG_BEST_PATHS = false; + + private MgraDataManager mgraManager; + + protected static final int OUT = McLogsumsCalculator.OUT; + protected static final int IN = McLogsumsCalculator.IN; + protected static final int NUM_DIR = McLogsumsCalculator.NUM_DIR; + + private static final String PROPERTIES_UEC_TOUR_MODE_CHOICE = "visitor.mc.uec.file"; + private static final String PROPERTIES_UEC_TOUR_DATA_SHEET = "visitor.mc.data.page"; + private static final String PROPERTIES_UEC_TOUR_MODEL_SHEET = "visitor.mc.model.page"; + + private ChoiceModelApplication mcModel; + private VisitorTourModeChoiceDMU mcDmuObject; + private TripModeChoiceDMU tripDmuObject; + private McLogsumsCalculator logsumHelper; + + private VisitorModelStructure modelStructure; + + private String tourCategory; + + private String[] modeAltNames; + + private boolean saveUtilsProbsFlag = false; + private AutoTazSkimsCalculator tazDistanceCalculator; + + //added for TNC and Taxi modes + TNCAndTaxiWaitTimeCalculator tncTaxiWaitTimeCalculator = null; + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public VisitorTourModeChoiceModel(HashMap propertyMap, + VisitorModelStructure myModelStructure, VisitorDmuFactoryIf dmuFactory, AutoTazSkimsCalculator tazDistanceCalculator) + { + + mgraManager = MgraDataManager.getInstance(propertyMap); + modelStructure = myModelStructure; + this.tazDistanceCalculator = tazDistanceCalculator; + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + tripDmuObject = new TripModeChoiceDMU(modelStructure,logger); + mcDmuObject = dmuFactory.getVisitorTourModeChoiceDMU(); + setupModeChoiceModelApplicationArray(propertyMap); + + tncTaxiWaitTimeCalculator = new TNCAndTaxiWaitTimeCalculator(); + tncTaxiWaitTimeCalculator.createWaitTimeDistributions(propertyMap); + + } + + /** + * Set up the mode choice model. + * + * @param propertyMap + */ + private void setupModeChoiceModelApplicationArray(HashMap propertyMap) + { + + logger.info(String.format("setting up visitor tour mode choice model.")); + + // locate the individual mandatory tour mode choice model UEC + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String mcUecFile = Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_TOUR_MODE_CHOICE); + mcUecFile = uecPath + mcUecFile; + + logger.info("Will read mcUECFile " + mcUecFile); + int dataPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_TOUR_DATA_SHEET)); + int modelPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_TOUR_MODEL_SHEET)); + + // default is to not save the tour mode choice utils and probs for each + // tour + String saveUtilsProbsString = propertyMap + .get(CtrampApplication.PROPERTIES_SAVE_TOUR_MODE_CHOICE_UTILS); + if (saveUtilsProbsString != null) + { + if (saveUtilsProbsString.equalsIgnoreCase("true")) saveUtilsProbsFlag = true; + } + + mcModel = new ChoiceModelApplication(mcUecFile, modelPage, dataPage, propertyMap, + (VariableTable) mcDmuObject); + modeAltNames = mcModel.getAlternativeNames(); + + } + + public double getModeChoiceLogsum(VisitorTour tour, Logger modelLogger, + String choiceModelDescription, String decisionMakerLabel) + { + + setDmuAttributes(tour); + + // log headers to traceLogger + if (tour.getDebugChoiceModels()) + { + mcModel.choiceModelUtilityTraceLoggerHeading(choiceModelDescription, decisionMakerLabel); + } + + + mcModel.computeUtilities(mcDmuObject, mcDmuObject.getDmuIndexValues()); + double logsum = mcModel.getLogsum(); + + // write UEC calculation results to separate model specific log file + if (tour.getDebugChoiceModels()) + { + String loggingHeader = String.format("%s %s", choiceModelDescription, + decisionMakerLabel); + mcModel.logUECResults(modelLogger, loggingHeader); + modelLogger.info(choiceModelDescription + " Logsum value: " + logsum); + modelLogger.info(""); + modelLogger.info(""); + } + + return logsum; + + } + + /** + * Set the DMU attributes for the tour. + * + * @param tour + */ + private void setDmuAttributes(VisitorTour tour) + { + + // update the MC dmuObjects for this person + int originTaz = mgraManager.getTaz(tour.getOriginMGRA()); + int destinationTaz = mgraManager.getTaz(tour.getDestinationMGRA()); + mcDmuObject.setDmuIndexValues(tour.getID(), originTaz, originTaz, destinationTaz, + tour.getDebugChoiceModels()); + + mcDmuObject.setTourDepartPeriod(tour.getDepartTime()); + mcDmuObject.setTourArrivePeriod(tour.getArriveTime()); + mcDmuObject.setIncome((byte) tour.getIncome()); + mcDmuObject.setAutoAvailable(tour.getAutoAvailable()); + mcDmuObject.setPartySize(tour.getNumberOfParticipants()); + mcDmuObject.setTourPurpose(tour.getPurpose()); + double ivtCoeff = -0.015; + double costCoeff = -0.0017; + tripDmuObject.setIvtCoeff(ivtCoeff); + tripDmuObject.setCostCoeff(costCoeff); + + logsumHelper.setNmTripMcDmuAttributes( tripDmuObject, tour.getOriginMGRA(), tour.getDestinationMGRA(), + tour.getDepartTime(),tour.getDebugChoiceModels()); + double nmWalkTimeOut = tripDmuObject.getNm_walkTime(); + double nmBikeTimeOut = tripDmuObject.getNm_bikeTime(); + mcDmuObject.setNmWalkTimeOut(nmWalkTimeOut); + mcDmuObject.setNmBikeTimeOut(nmBikeTimeOut); + logsumHelper.setNmTripMcDmuAttributes( tripDmuObject, tour.getDestinationMGRA(), tour.getOriginMGRA(), + tour.getArriveTime(),tour.getDebugChoiceModels()); + double nmWalkTimeIn = tripDmuObject.getNm_walkTime(); + double nmBikeTimeIn = tripDmuObject.getNm_bikeTime(); + mcDmuObject.setNmWalkTimeOut(nmWalkTimeIn); + mcDmuObject.setNmBikeTimeOut(nmBikeTimeIn); + + + double walkTransitLogsumOut = -999.0; + double driveTransitLogsumOut = -999.0; + double walkTransitLogsumIn = -999.0; + double driveTransitLogsumIn = -999.0; + + // walk-transit out logsum + logsumHelper.setWtwTripMcDmuAttributes( tripDmuObject, tour.getOriginMGRA(), tour.getDestinationMGRA(), + tour.getDepartTime(),tour.getDebugChoiceModels()); + + walkTransitLogsumOut = tripDmuObject.getTransitLogSum(McLogsumsCalculator.WTW); + + // walk-transit in logsum + logsumHelper.setWtwTripMcDmuAttributes( tripDmuObject,tour.getDestinationMGRA(), tour.getOriginMGRA(), + tour.getArriveTime(),tour.getDebugChoiceModels()); + + walkTransitLogsumIn = tripDmuObject.getTransitLogSum(McLogsumsCalculator.WTW); + + //drive-transit out logsum + logsumHelper.setDtwTripMcDmuAttributes( tripDmuObject, tour.getOriginMGRA(), tour.getDestinationMGRA(), + tour.getDepartTime(),tour.getDebugChoiceModels()); + + driveTransitLogsumOut = tripDmuObject.getTransitLogSum(McLogsumsCalculator.DTW); + + //drive-transit in logsum + logsumHelper.setWtdTripMcDmuAttributes( tripDmuObject, tour.getDestinationMGRA(),tour.getOriginMGRA(), + tour.getArriveTime(),tour.getDebugChoiceModels()); + + driveTransitLogsumIn = tripDmuObject.getTransitLogSum(McLogsumsCalculator.WTD); + + mcDmuObject.setTransitLogSum(McLogsumsCalculator.WTW,false,walkTransitLogsumOut); + mcDmuObject.setTransitLogSum(McLogsumsCalculator.WTW,true,walkTransitLogsumIn); + mcDmuObject.setTransitLogSum(McLogsumsCalculator.DTW,false,driveTransitLogsumOut); + mcDmuObject.setTransitLogSum(McLogsumsCalculator.WTD,true,driveTransitLogsumIn); + + float SingleTNCWaitTimeOrig = 0; + float SingleTNCWaitTimeDest = 0; + float SharedTNCWaitTimeOrig = 0; + float SharedTNCWaitTimeDest = 0; + float TaxiWaitTimeOrig = 0; + float TaxiWaitTimeDest = 0; + float popEmpDenOrig = (float) mgraManager.getPopEmpPerSqMi(tour.getOriginMGRA()); + float popEmpDenDest = (float) mgraManager.getPopEmpPerSqMi(tour.getDestinationMGRA()); + + double rnum = tour.getRandom(); + SingleTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SingleTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSingleTNCWaitTimeDistribution(rnum, popEmpDenDest); + SharedTNCWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenOrig); + SharedTNCWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromSharedTNCWaitTimeDistribution(rnum, popEmpDenDest); + TaxiWaitTimeOrig = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenOrig); + TaxiWaitTimeDest = (float) tncTaxiWaitTimeCalculator.sampleFromTaxiWaitTimeDistribution(rnum, popEmpDenDest); + + mcDmuObject.setOrigTaxiWaitTime(TaxiWaitTimeOrig); + mcDmuObject.setDestTaxiWaitTime(TaxiWaitTimeDest); + mcDmuObject.setOrigSingleTNCWaitTime(SingleTNCWaitTimeOrig); + mcDmuObject.setDestSingleTNCWaitTime(SingleTNCWaitTimeDest); + mcDmuObject.setOrigSharedTNCWaitTime(SharedTNCWaitTimeOrig); + mcDmuObject.setDestSharedTNCWaitTime(SharedTNCWaitTimeDest); + + + } + + /** + * Use to choose tour mode and set result in tour object. + * + * @param tour + * The crossborder tour + */ + public void chooseTourMode(VisitorTour tour) + { + + byte tourMode = (byte) getModeChoice(tour); + tour.setTourMode(tourMode); + } + + /** + * Get the choice of mode for the tour, and return as an integer (don't + * store in tour object) + * + * @param tour + * @return + */ + private int getModeChoice(VisitorTour tour) + { + + String choiceModelDescription = ""; + String decisionMakerLabel = ""; + String loggingHeader = ""; + String separator = ""; + String purposeName = modelStructure.VISITOR_PURPOSES[tour.getPurpose()]; + + if (tour.getDebugChoiceModels()) + { + + tour.logTourObject(logger, 100); + logger.info("Logging tour mode choice model"); + } + + setDmuAttributes(tour); + + mcModel.computeUtilities(mcDmuObject, mcDmuObject.getDmuIndexValues()); + + if (tour.getDebugChoiceModels()) + mcModel.logUECResults(logger, "Visitor tour mode choice model"); + + double rn = tour.getRandom(); + + // if the choice model has at least one available alternative, make + // choice. + int chosen; + if (mcModel.getAvailabilityCount() > 0) + { + + chosen = mcModel.getChoiceResult(rn); + + //value of time; lookup vot from the UEC + UtilityExpressionCalculator uec = mcModel.getUEC(); + int votIndex = uec.lookupVariableIndex("vot"); + float vot = (float) uec.getValueForIndex(votIndex); + + tour.setValueOfTime(vot); + + } else + { + + tour.logTourObject(logger, loggingHeader.length()); + + mcModel.logUECResults(logger, loggingHeader); + logger.info(""); + logger.info(""); + + logger.error(String + .format("Exception caught for HHID=%d, no available %s tour mode alternatives to choose from in choiceModelApplication.", + tour.getID(), tourCategory)); + throw new RuntimeException(); + } + + // debug output + if (tour.getDebugChoiceModels()) + { + + double[] utilities = mcModel.getUtilities(); // 0s-indexing + double[] probabilities = mcModel.getProbabilities(); // 0s-indexing + boolean[] availabilities = mcModel.getAvailabilities(); // 1s-indexing + String[] altNames = mcModel.getAlternativeNames(); // 0s-indexing + + logger.info("Tour Id: " + tour.getID()); + logger.info("Alternative Utility Probability CumProb"); + logger.info("-------------------- -------------- -------------- --------------"); + + double cumProb = 0.0; + for (int k = 0; k < mcModel.getNumberOfAlternatives(); k++) + { + cumProb += probabilities[k]; + String altString = String.format("%-3d %s", k + 1, altNames[k]); + logger.info(String.format("%-20s%15s%18.6e%18.6e%18.6e", altString, + availabilities[k + 1], utilities[k], probabilities[k], cumProb)); + } + + logger.info(" "); + String altString = String.format("%-3d %s", chosen, altNames[chosen - 1]); + logger.info(String.format("Choice: %s, with rn=%.8f", altString, rn)); + + logger.info(separator); + logger.info(""); + logger.info(""); + + // write choice model alternative info to log file + mcModel.logAlternativesInfo(choiceModelDescription, decisionMakerLabel); + mcModel.logSelectionInfo(choiceModelDescription, decisionMakerLabel, rn, chosen); + mcModel.logLogitCalculations(choiceModelDescription, decisionMakerLabel); + + } + + if (saveUtilsProbsFlag) + { + + // get the utilities and probabilities arrays for the tour mode + // choice + // model for this tour and save them to the tour object + double[] dUtils = mcModel.getUtilities(); + double[] dProbs = mcModel.getProbabilities(); + + float[] utils = new float[dUtils.length]; + float[] probs = new float[dUtils.length]; + for (int k = 0; k < dUtils.length; k++) + { + utils[k] = (float) dUtils[k]; + probs[k] = (float) dProbs[k]; + } + + // tour.setTourModalUtilities(utils); + // tour.setTourModalProbabilities(probs); + + } + + return chosen; + + } + + public String[] getModeAltNames(int purposeIndex) + { + return modeAltNames; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourTimeOfDayChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourTimeOfDayChoiceModel.java new file mode 100644 index 0000000..f12d379 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTourTimeOfDayChoiceModel.java @@ -0,0 +1,192 @@ +package org.sandag.abm.visitor; + +import java.io.File; +import java.io.IOException; +import java.util.HashMap; +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.Util; +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; + +/** + * This class is the TOD choice model for cross border tours. It is currently + * based on a static probability distribution stored in an input file, and + * indexed into by purpose. + * + * @author Freedman + * + */ +public class VisitorTourTimeOfDayChoiceModel +{ + private transient Logger logger = Logger.getLogger("visitorModel"); + + private double[][] cumProbability; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + private int[][] outboundPeriod; // by + // purpose, + // alternative: + // outbound + // period + private int[][] returnPeriod; // by + // purpose, + // alternative: + // return + // period + VisitorModelStructure modelStructure; + + /** + * Constructor. + */ + public VisitorTourTimeOfDayChoiceModel(HashMap rbMap) + { + + String directory = Util.getStringValueFromPropertyMap(rbMap, "Project.Directory"); + String stationDiurnalFile = Util.getStringValueFromPropertyMap(rbMap, + "visitor.tour.tod.file"); + stationDiurnalFile = directory + stationDiurnalFile; + + modelStructure = new VisitorModelStructure(); + + readTODFile(stationDiurnalFile); + + } + + /** + * Read the TOD distribution in the file and populate the arrays. + * + * @param fileName + */ + private void readTODFile(String fileName) + { + + logger.info("Begin reading the data in file " + fileName); + TableDataSet probabilityTable; + + try + { + OLD_CSVFileReader csvFile = new OLD_CSVFileReader(); + probabilityTable = csvFile.readFile(new File(fileName)); + } catch (IOException e) + { + throw new RuntimeException(e); + } + + logger.info("End reading the data in file " + fileName); + + logger.info("Begin calculating tour TOD probability distribution"); + + int purposes = modelStructure.VISITOR_PURPOSES.length; // start at 0 + int periods = modelStructure.TIME_PERIODS; // start at 1 + int periodCombinations = periods * (periods + 1) / 2; + + cumProbability = new double[purposes][periodCombinations]; // by + // purpose, + // alternative: + // cumulative + // probability + // distribution + outboundPeriod = new int[purposes][periodCombinations]; // by purpose, + // alternative: + // outbound + // period + returnPeriod = new int[purposes][periodCombinations]; // by purpose, + // alternative: + // return period + + // fill up arrays + int rowCount = probabilityTable.getRowCount(); + int lastPurpose = -99; + double cumProb = 0; + int alt = 0; + for (int row = 1; row <= rowCount; ++row) + { + + int purpose = (int) probabilityTable.getValueAt(row, "Purpose"); + int outPer = (int) probabilityTable.getValueAt(row, "EntryPeriod"); + int retPer = (int) probabilityTable.getValueAt(row, "ReturnPeriod"); + + // continue if return period before outbound period + if (retPer < outPer) continue; + + // reset if new purpose + if (purpose != lastPurpose) + { + + // log cumulative probability just in case + if (lastPurpose != -99) + logger.info("Cumulative probability for purpose " + purpose + " is " + cumProb); + cumProb = 0; + alt = 0; + } + + // calculate cumulative probability and store in array + cumProb += probabilityTable.getValueAt(row, "Percent"); + cumProbability[purpose][alt] = cumProb; + outboundPeriod[purpose][alt] = outPer; + returnPeriod[purpose][alt] = retPer; + + ++alt; + + lastPurpose = purpose; + } + + logger.info("End calculating tour TOD probability distribution"); + + } + + /** + * Calculate tour time of day for the tour. + * + * @param tour + * A cross border tour (with purpose) + */ + public void calculateTourTOD(VisitorTour tour) + { + + int purpose = tour.getPurpose(); + double random = tour.getRandom(); + + int depart = -1; + int arrive = -1; + if (tour.getDebugChoiceModels()) + { + logger.info("Choosing tour time of day for purpose " + + modelStructure.VISITOR_PURPOSES[purpose] + " using random number " + random); + tour.logTourObject(logger, 100); + } + + for (int i = 0; i < cumProbability[purpose].length; ++i) + { + + if (random < cumProbability[purpose][i]) + { + depart = outboundPeriod[purpose][i]; + arrive = returnPeriod[purpose][i]; + tour.setDepartTime(depart); + tour.setArriveTime(arrive); + break; + } + } + if((depart ==-1)||(arrive==-1)){ + logger.fatal("Error: did not find outbound or return period for tour"); + logger.fatal("Depart period, arrive period = "+depart+","+arrive); + logger.fatal("Random number: "+random); + tour.logTourObject(logger,100); + throw new RuntimeException(); + } + + + if (tour.getDebugChoiceModels()) + { + logger.info(""); + logger.info("Chose depart period " + tour.getDepartTime() + " and arrival period " + + tour.getArriveTime()); + logger.info(""); + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTrip.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTrip.java new file mode 100644 index 0000000..32f7dc8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTrip.java @@ -0,0 +1,518 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; + +public class VisitorTrip + implements Serializable +{ + + private int originMgra; + private int destinationMgra; + private int tripMode; + private byte originPurpose; + private byte destinationPurpose; + private byte period; + private boolean inbound; + private boolean firstTrip; + private boolean lastTrip; + private boolean originIsTourDestination; + private boolean destinationIsTourDestination; + byte micromobilityWalkMode; + byte micromobilityAccessMode; + byte micromobilityEgressMode; + float micromobilityWalkLogsum; + float micromobilityAccessLogsum; + float micromobilityEgressLogsum; + + float parkingCost; + + private int boardTap; + private int alightTap; + private int set = -1; + + private float valueOfTime; + + /** + * Default constructor; nothing initialized. + */ + public VisitorTrip() + { + + } + + /** + * Create a cross border trip from a tour leg (no stops). + * + * @param tour + * The tour. + * @param outbound + * Outbound direction + */ + public VisitorTrip(VisitorTour tour, boolean outbound) + { + + initializeFromTour(tour, outbound); + } + + /** + * Initilize from the tour. + * + * @param tour + * The tour. + * @param outbound + * Outbound direction. + */ + public void initializeFromTour(VisitorTour tour, boolean outbound) + { + // Note: mode is unknown + if (outbound) + { + this.originMgra = tour.getOriginMGRA(); + this.destinationMgra = tour.getDestinationMGRA(); + this.originPurpose = -1; + this.destinationPurpose = tour.getPurpose(); + this.period = (byte) tour.getDepartTime(); + this.inbound = false; + this.firstTrip = true; + this.lastTrip = false; + this.originIsTourDestination = false; + this.destinationIsTourDestination = true; + } else + { + this.originMgra = tour.getDestinationMGRA(); + this.destinationMgra = tour.getOriginMGRA(); + this.originPurpose = tour.getPurpose(); + this.destinationPurpose = -1; + this.period = (byte) tour.getArriveTime(); + this.inbound = true; + this.firstTrip = false; + this.lastTrip = true; + this.originIsTourDestination = true; + this.destinationIsTourDestination = false; + } + + } + + /** + * Create a visitor trip from a tour\stop. Note: trip mode is unknown. Stop + * period is only known for first, last stop on tour. + * + * @param tour + * The tour. + * @param stop + * The stop + */ + public VisitorTrip(VisitorTour tour, VisitorStop stop, boolean toStop) + { + + initializeFromStop(tour, stop, toStop); + } + + /** + * Initialize from stop attributes. A trip will be created to the stop if + * toStop is true, else a trip will be created from the stop. Use after all + * stop locations are known, or else reset the stop origin and destination + * mgras accordingly after using. + * + * @param tour + * @param stop + * @param toStop + */ + public void initializeFromStop(VisitorTour tour, VisitorStop stop, boolean toStop) + { + + this.inbound = stop.isInbound(); + this.destinationIsTourDestination = false; + this.originIsTourDestination = false; + + // if trip to stop, destination is stop mgra; else origin is stop mgra + if (toStop) + { + this.destinationMgra = stop.getMgra(); + this.destinationPurpose = stop.getPurpose(); + } else + { + this.originMgra = stop.getMgra(); + this.originPurpose = stop.getPurpose(); + } + VisitorStop[] stops; + + if (!inbound) stops = tour.getOutboundStops(); + else stops = tour.getInboundStops(); + + // if outbound, and trip is to stop + if (!inbound && toStop) + { + + // first trip on outbound journey, origin is tour origin + if (stop.getId() == 0) + { + this.originMgra = tour.getOriginMGRA(); + this.originPurpose = -1; + this.period = (byte) tour.getDepartTime(); + } else + { + // not first trip on outbound journey, origin is last stop + this.originMgra = stops[stop.getId() - 1].getMgra(); // last + // stop + // location + this.originPurpose = stops[stop.getId() - 1].getPurpose(); // last + // stop + // location + this.period = (byte) stops[stop.getId() - 1].getStopPeriod(); + } + } else if (!inbound && !toStop) + { + // outbound and trip is from stop to either next stop or tour + // destination. + + // last trip on outbound journey, destination is tour destination + if (stop.getId() == (stops.length - 1)) + { + this.destinationMgra = tour.getDestinationMGRA(); + this.destinationPurpose = tour.getPurpose(); + this.destinationIsTourDestination = true; + } else + { + // not last trip on outbound journey, destination is next stop + this.destinationMgra = stops[stop.getId() + 1].getMgra(); + this.destinationPurpose = stops[stop.getId() + 1].getPurpose(); + } + + // the period for the trip is the origin for the trip + if (stop.getId() == 0) this.period = (byte) tour.getDepartTime(); + else this.period = (byte) stops[stop.getId() - 1].getStopPeriod(); + + } else if (inbound && toStop) + { + // inbound, trip is to stop from either tour destination or last + // stop. + + // first inbound trip; origin is tour destination + if (stop.getId() == 0) + { + this.originMgra = tour.getDestinationMGRA(); + this.originPurpose = tour.getPurpose(); + this.originIsTourDestination = true; + } else + { + // not first inbound trip; origin is last stop + this.originMgra = stops[stop.getId() - 1].getMgra(); // last + // stop + // location + this.originPurpose = stops[stop.getId() - 1].getPurpose(); + } + + // the period for the trip is the destination for the trip + if (stop.getId() == stops.length - 1) this.period = (byte) tour.getArriveTime(); + else this.period = (byte) stops[stop.getId() + 1].getStopPeriod(); + } else + { + // inbound, trip is from stop to either next stop or tour origin. + + // last trip, destination is back to tour origin + if (stop.getId() == (stops.length - 1)) + { + this.destinationMgra = tour.getOriginMGRA(); + this.destinationPurpose = -1; + this.period = (byte) tour.getArriveTime(); + } else + { + // not last trip, destination is next stop + this.destinationMgra = stops[stop.getId() + 1].getMgra(); + this.destinationPurpose = stops[stop.getId() + 1].getPurpose(); + this.period = (byte) stops[stop.getId() + 1].getStopPeriod(); + } + } + + // code period for first trip on tour + if (toStop && !inbound && stop.getId() == 0) + { + this.firstTrip = true; + this.lastTrip = false; + this.period = (byte) tour.getDepartTime(); + } + // code period for last trip on tour + if (!toStop && inbound && stop.getId() == (stops.length - 1)) + { + this.firstTrip = false; + this.lastTrip = true; + this.period = (byte) tour.getArriveTime(); + } + + } + + /** + * @return the period + */ + public byte getPeriod() + { + return period; + } + + /** + * @param period + * the period to set + */ + public void setPeriod(byte period) + { + this.period = period; + } + + /** + * @return the origin purpose + */ + public byte getOriginPurpose() + { + return originPurpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setOriginPurpose(byte purpose) + { + this.originPurpose = purpose; + } + + /** + * @return the destination purpose + */ + public byte getDestinationPurpose() + { + return destinationPurpose; + } + + /** + * @param purpose + * the purpose to set + */ + public void setDestinationPurpose(byte purpose) + { + this.destinationPurpose = purpose; + } + + /** + * @return the originMgra + */ + public int getOriginMgra() + { + return originMgra; + } + + /** + * @param originMgra + * the originMgra to set + */ + public void setOriginMgra(int originMgra) + { + this.originMgra = originMgra; + } + + /** + * @return the destinationMgra + */ + public int getDestinationMgra() + { + return destinationMgra; + } + + /** + * @param destinationMgra + * the destinationMgra to set + */ + public void setDestinationMgra(int destinationMgra) + { + this.destinationMgra = destinationMgra; + } + + /** + * @return the tripMode + */ + public int getTripMode() + { + return tripMode; + } + + /** + * @param tripMode + * the tripMode to set + */ + public void setTripMode(int tripMode) + { + this.tripMode = tripMode; + } + + public int getBoardTap() { + return boardTap; + } + + public void setBoardTap(int boardTap) { + this.boardTap = boardTap; + } + + public int getAlightTap() { + return alightTap; + } + + public void setAlightTap(int alightTap) { + this.alightTap = alightTap; + } + + public int getSet() { + return set; + } + + public void setSet(int set) { + this.set = set; + } + + /** + * @return the inbound + */ + public boolean isInbound() + { + return inbound; + } + + /** + * @param inbound + * the inbound to set + */ + public void setInbound(boolean inbound) + { + this.inbound = inbound; + } + + /** + * @return the firstTrip + */ + public boolean isFirstTrip() + { + return firstTrip; + } + + /** + * @param firstTrip + * the firstTrip to set + */ + public void setFirstTrip(boolean firstTrip) + { + this.firstTrip = firstTrip; + } + + /** + * @return the lastTrip + */ + public boolean isLastTrip() + { + return lastTrip; + } + + /** + * @param lastTrip + * the lastTrip to set + */ + public void setLastTrip(boolean lastTrip) + { + this.lastTrip = lastTrip; + } + + /** + * @return the originIsTourDestination + */ + public boolean isOriginIsTourDestination() + { + return originIsTourDestination; + } + + /** + * @param originIsTourDestination + * the originIsTourDestination to set + */ + public void setOriginIsTourDestination(boolean originIsTourDestination) + { + this.originIsTourDestination = originIsTourDestination; + } + + /** + * @return the destinationIsTourDestination + */ + public boolean isDestinationIsTourDestination() + { + return destinationIsTourDestination; + } + + /** + * @param destinationIsTourDestination + * the destinationIsTourDestination to set + */ + public void setDestinationIsTourDestination(boolean destinationIsTourDestination) + { + this.destinationIsTourDestination = destinationIsTourDestination; + } + + public float getValueOfTime() { + return valueOfTime; + } + + public void setValueOfTime(float valueOfTime) { + this.valueOfTime = valueOfTime; + } + public float getParkingCost() { + return parkingCost; + } + + public void setParkingCost(float parkingCost) { + this.parkingCost = parkingCost; + } + + public void setMicromobilityWalkMode(byte micromobilityWalkMode) { + this.micromobilityWalkMode=micromobilityWalkMode; + } + + public byte getMicromobilityWalkMode() { + return micromobilityWalkMode; + } + public float getMicromobilityWalkLogsum() { + return micromobilityWalkLogsum; + } + + public void setMicromobilityWalkLogsum(float micromobilityWalkLogsum) { + this.micromobilityWalkLogsum = micromobilityWalkLogsum; + } + + public byte getMicromobilityAccessMode() { + return micromobilityAccessMode; + } + + public void setMicromobilityAccessMode(byte micromobilityAccessMode) { + this.micromobilityAccessMode = micromobilityAccessMode; + } + + public byte getMicromobilityEgressMode() { + return micromobilityEgressMode; + } + + public void setMicromobilityEgressMode(byte micromobilityEgressMode) { + this.micromobilityEgressMode = micromobilityEgressMode; + } + + public float getMicromobilityAccessLogsum() { + return micromobilityAccessLogsum; + } + + public void setMicromobilityAccessLogsum(float micromobilityAccessLogsum) { + this.micromobilityAccessLogsum = micromobilityAccessLogsum; + } + + public float getMicromobilityEgressLogsum() { + return micromobilityEgressLogsum; + } + + public void setMicromobilityEgressLogsum(float micromobilityEgressLogsum) { + this.micromobilityEgressLogsum = micromobilityEgressLogsum; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripModeChoiceDMU.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripModeChoiceDMU.java new file mode 100644 index 0000000..c984730 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripModeChoiceDMU.java @@ -0,0 +1,883 @@ +package org.sandag.abm.visitor; + +import java.io.Serializable; +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.internalexternal.InternalExternalTripModeChoiceDMU; + +import com.pb.common.calculator.IndexValues; +import com.pb.common.calculator.VariableTable; + +public class VisitorTripModeChoiceDMU + implements Serializable, VariableTable +{ + + protected transient Logger logger = Logger.getLogger(InternalExternalTripModeChoiceDMU.class); + + protected HashMap methodIndexMap; + protected IndexValues dmuIndex; + + protected int tourDepartPeriod; + protected int tourArrivePeriod; + protected int tripPeriod; + protected int outboundStops; + protected int returnStops; + protected int firstTrip; + protected int lastTrip; + protected int tourPurpose; + protected int segment; + protected int partySize; + protected int autoAvailable; + protected int income; + + // tour mode + protected int tourModeIsDA; + protected int tourModeIsS2; + protected int tourModeIsS3; + protected int tourModeIsWalk; + protected int tourModeIsBike; + protected int tourModeIsWalkTransit; + protected int tourModeIsPNRTransit; + protected int tourModeIsKNRTransit; + protected int tourModeIsMaas; + protected int tourModeIsTNCTransit; + + + protected float hourlyParkingCostTourDest; + protected float dailyParkingCostTourDest; + protected float monthlyParkingCostTourDest; + protected int tripOrigIsTourDest; + protected int tripDestIsTourDest; + protected float hourlyParkingCostTripOrig; + protected float hourlyParkingCostTripDest; + + protected double nmWalkTime; + protected double nmBikeTime; + + protected double ivtCoeff; + protected double costCoeff; + protected double walkTransitLogsum; + protected double pnrTransitLogsum; + protected double knrTransitLogsum; + + protected float waitTimeTaxi; + protected float waitTimeSingleTNC; + protected float waitTimeSharedTNC; + + + protected int outboundHalfTourDirection; + + public VisitorTripModeChoiceDMU(VisitorModelStructure modelStructure, Logger aLogger) + { + if (aLogger == null) aLogger = Logger.getLogger("visitorModel"); + logger = aLogger; + setupMethodIndexMap(); + dmuIndex = new IndexValues(); + + } + + /** + * Set this index values for this tour mode choice DMU object. + * + * @param hhIndex + * is the DMU household index + * @param zoneIndex + * is the DMU zone index + * @param origIndex + * is the DMU origin index + * @param destIndex + * is the DMU desatination index + */ + public void setDmuIndexValues(int hhIndex, int zoneIndex, int origIndex, int destIndex, + boolean debug) + { + dmuIndex.setHHIndex(hhIndex); + dmuIndex.setZoneIndex(zoneIndex); + dmuIndex.setOriginZone(origIndex); + dmuIndex.setDestZone(destIndex); + + dmuIndex.setDebug(false); + dmuIndex.setDebugLabel(""); + if (debug) + { + dmuIndex.setDebug(true); + dmuIndex.setDebugLabel("Debug MC UEC"); + } + + } + + public IndexValues getDmuIndexValues() + { + return dmuIndex; + } + + /** + * @return the tripPeriod + */ + public int getTripPeriod() + { + return tripPeriod; + } + + /** + * @param tripPeriod + * the tripPeriod to set + */ + public void setTripPeriod(int tripPeriod) + { + this.tripPeriod = tripPeriod; + } + + /** + * @return the outboundStops + */ + public int getOutboundStops() + { + return outboundStops; + } + + /** + * @param outboundStops + * the outboundStops to set + */ + public void setOutboundStops(int outboundStops) + { + this.outboundStops = outboundStops; + } + + /** + * @return the returnStops + */ + public int getReturnStops() + { + return returnStops; + } + + /** + * @param returnStops + * the returnStops to set + */ + public void setReturnStops(int returnStops) + { + this.returnStops = returnStops; + } + + /** + * @return the firstTrip + */ + public int getFirstTrip() + { + return firstTrip; + } + + /** + * @param firstTrip + * the firstTrip to set + */ + public void setFirstTrip(int firstTrip) + { + this.firstTrip = firstTrip; + } + + /** + * @return the lastTrip + */ + public int getLastTrip() + { + return lastTrip; + } + + /** + * @param lastTrip + * the lastTrip to set + */ + public void setLastTrip(int lastTrip) + { + this.lastTrip = lastTrip; + } + + /** + * @return the tourModeIsDA + */ + public int getTourModeIsDA() + { + return tourModeIsDA; + } + + /** + * @param tourModeIsDA + * the tourModeIsDA to set + */ + public void setTourModeIsDA(int tourModeIsDA) + { + this.tourModeIsDA = tourModeIsDA; + } + + /** + * @return the tourModeIsS2 + */ + public int getTourModeIsS2() + { + return tourModeIsS2; + } + + /** + * @param tourModeIsS2 + * the tourModeIsS2 to set + */ + public void setTourModeIsS2(int tourModeIsS2) + { + this.tourModeIsS2 = tourModeIsS2; + } + + /** + * @return the tourModeIsS3 + */ + public int getTourModeIsS3() + { + return tourModeIsS3; + } + + /** + * @param tourModeIsS3 + * the tourModeIsS3 to set + */ + public void setTourModeIsS3(int tourModeIsS3) + { + this.tourModeIsS3 = tourModeIsS3; + } + + /** + * @return the tourModeIsWalk + */ + public int getTourModeIsWalk() + { + return tourModeIsWalk; + } + + /** + * @param tourModeIsWalk + * the tourModeIsWalk to set + */ + public void setTourModeIsWalk(int tourModeIsWalk) + { + this.tourModeIsWalk = tourModeIsWalk; + } + + /** + * @return the tourModeIsBike + */ + public int getTourModeIsBike() + { + return tourModeIsBike; + } + + /** + * @param tourModeIsBike + * the tourModeIsBike to set + */ + public void setTourModeIsBike(int tourModeIsBike) + { + this.tourModeIsBike = tourModeIsBike; + } + + /** + * @return the tourModeIsWalkTransit + */ + public int getTourModeIsWalkTransit() + { + return tourModeIsWalkTransit; + } + + /** + * @param tourModeIsWalkTransit + * the tourModeIsWalkTransit to set + */ + public void setTourModeIsWalkTransit(int tourModeIsWalkTransit) + { + this.tourModeIsWalkTransit = tourModeIsWalkTransit; + } + + /** + * @return the tourModeIsPNRTransit + */ + public int getTourModeIsPNRTransit() + { + return tourModeIsPNRTransit; + } + + /** + * @param tourModeIsPNRTransit + * the tourModeIsPNRTransit to set + */ + public void setTourModeIsPNRTransit(int tourModeIsPNRTransit) + { + this.tourModeIsPNRTransit = tourModeIsPNRTransit; + } + + /** + * @return the tourModeIsKNRTransit + */ + public int getTourModeIsKNRTransit() + { + return tourModeIsKNRTransit; + } + + /** + * @param tourModeIsKNRTransit + * the tourModeIsKNRTransit to set + */ + public void setTourModeIsKNRTransit(int tourModeIsKNRTransit) + { + this.tourModeIsKNRTransit = tourModeIsKNRTransit; + } + + /** + * @return the tourModeIsMaas + */ + public int getTourModeIsMaas() + { + return tourModeIsMaas; + } + + /** + * @param tourModeIsMaas + * the tourModeIsMaas to set + */ + public void setTourModeIsMaas(int tourModeIsMaas) + { + this.tourModeIsMaas = tourModeIsMaas; + } + + /** + * @return the hourlyParkingCostTourDest + */ + public float getHourlyParkingCostTourDest() + { + return hourlyParkingCostTourDest; + } + + /** + * @param hourlyParkingCostTourDest + * the hourlyParkingCostTourDest to set + */ + public void setHourlyParkingCostTourDest(float hourlyParkingCostTourDest) + { + this.hourlyParkingCostTourDest = hourlyParkingCostTourDest; + } + + /** + * @return the dailyParkingCostTourDest + */ + public float getDailyParkingCostTourDest() + { + return dailyParkingCostTourDest; + } + + /** + * @param dailyParkingCostTourDest + * the dailyParkingCostTourDest to set + */ + public void setDailyParkingCostTourDest(float dailyParkingCostTourDest) + { + this.dailyParkingCostTourDest = dailyParkingCostTourDest; + } + + /** + * @return the monthlyParkingCostTourDest + */ + public float getMonthlyParkingCostTourDest() + { + return monthlyParkingCostTourDest; + } + + /** + * @param monthlyParkingCostTourDest + * the monthlyParkingCostTourDest to set + */ + public void setMonthlyParkingCostTourDest(float monthlyParkingCostTourDest) + { + this.monthlyParkingCostTourDest = monthlyParkingCostTourDest; + } + + /** + * @return the tripOrigIsTourDest + */ + public int getTripOrigIsTourDest() + { + return tripOrigIsTourDest; + } + + /** + * @param tripOrigIsTourDest + * the tripOrigIsTourDest to set + */ + public void setTripOrigIsTourDest(int tripOrigIsTourDest) + { + this.tripOrigIsTourDest = tripOrigIsTourDest; + } + + /** + * @return the tripDestIsTourDest + */ + public int getTripDestIsTourDest() + { + return tripDestIsTourDest; + } + + /** + * @param tripDestIsTourDest + * the tripDestIsTourDest to set + */ + public void setTripDestIsTourDest(int tripDestIsTourDest) + { + this.tripDestIsTourDest = tripDestIsTourDest; + } + + /** + * @return the hourlyParkingCostTripOrig + */ + public float getHourlyParkingCostTripOrig() + { + return hourlyParkingCostTripOrig; + } + + /** + * @param hourlyParkingCostTripOrig + * the hourlyParkingCostTripOrig to set + */ + public void setHourlyParkingCostTripOrig(float hourlyParkingCostTripOrig) + { + this.hourlyParkingCostTripOrig = hourlyParkingCostTripOrig; + } + + /** + * @return the hourlyParkingCostTripDest + */ + public float getHourlyParkingCostTripDest() + { + return hourlyParkingCostTripDest; + } + + /** + * @param hourlyParkingCostTripDest + * the hourlyParkingCostTripDest to set + */ + public void setHourlyParkingCostTripDest(float hourlyParkingCostTripDest) + { + this.hourlyParkingCostTripDest = hourlyParkingCostTripDest; + } + + /** + * @return the outboundHalfTourDirection + */ + public int getOutboundHalfTourDirection() + { + return outboundHalfTourDirection; + } + + /** + * @param outboundHalfTourDirection + * the outboundHalfTourDirection to set + */ + public void setOutboundHalfTourDirection(int outboundHalfTourDirection) + { + this.outboundHalfTourDirection = outboundHalfTourDirection; + } + + /** + * @return the tourDepartPeriod + */ + public int getTourDepartPeriod() + { + return tourDepartPeriod; + } + + /** + * @param tourDepartPeriod + * the tourDepartPeriod to set + */ + public void setTourDepartPeriod(int tourDepartPeriod) + { + this.tourDepartPeriod = tourDepartPeriod; + } + + /** + * @param tourArrivePeriod + * the tourArrivePeriod to set + */ + public void setTourArrivePeriod(int tourArrivePeriod) + { + this.tourArrivePeriod = tourArrivePeriod; + } + + /** + * @return the tourArrivePeriod + */ + public int getTourArrivePeriod() + { + return tourArrivePeriod; + } + + public double getNm_walkTime() + { + return nmWalkTime; + } + + public void setNonMotorizedWalkTime(double nmWalkTime) + { + this.nmWalkTime = nmWalkTime; + } + + public void setNonMotorizedBikeTime(double nmBikeTime) + { + this.nmBikeTime = nmBikeTime; + } + + public double getNm_bikeTime() + { + return nmBikeTime; + } + + /** + * @return the tourPurpose + */ + public int getTourPurpose() + { + return tourPurpose; + } + + /** + * @param tourPurpose + * the tourPurpose to set + */ + public void setTourPurpose(int tourPurpose) + { + this.tourPurpose = tourPurpose; + } + + /** + * @return the segment + */ + public int getSegment() + { + return segment; + } + + /** + * @param segment + * the segment to set + */ + public void setSegment(int segment) + { + this.segment = segment; + } + + public int getPartySize() + { + return partySize; + } + + public void setPartySize(int partySize) + { + this.partySize = partySize; + } + + public int getAutoAvailable() + { + return autoAvailable; + } + + public void setAutoAvailable(int autoAvailable) + { + this.autoAvailable = autoAvailable; + } + + public int getIncome() + { + return income; + } + + public void setIncome(int income) + { + this.income = income; + } + public double getIvtCoeff() { + return ivtCoeff; + } + + public void setIvtCoeff(double ivtCoeff) { + this.ivtCoeff = ivtCoeff; + } + + public double getCostCoeff() { + return costCoeff; + } + + public void setCostCoeff(double costCoeff) { + this.costCoeff = costCoeff; + } + + public double getWalkTransitLogsum() { + return walkTransitLogsum; + } + + public void setWalkTransitLogsum(double walkTransitLogsum) { + this.walkTransitLogsum = walkTransitLogsum; + } + + public double getPnrTransitLogsum() { + return pnrTransitLogsum; + } + + public void setPnrTransitLogsum(double pnrTransitLogsum) { + this.pnrTransitLogsum = pnrTransitLogsum; + } + + public double getKnrTransitLogsum() { + return knrTransitLogsum; + } + + public void setKnrTransitLogsum(double knrTransitLogsum) { + this.knrTransitLogsum = knrTransitLogsum; + } + + public float getWaitTimeTaxi() { + return waitTimeTaxi; + } + + public void setWaitTimeTaxi(float waitTimeTaxi) { + this.waitTimeTaxi = waitTimeTaxi; + } + + public float getWaitTimeSingleTNC() { + return waitTimeSingleTNC; + } + + public void setWaitTimeSingleTNC(float waitTimeSingleTNC) { + this.waitTimeSingleTNC = waitTimeSingleTNC; + } + + public float getWaitTimeSharedTNC() { + return waitTimeSharedTNC; + } + + public void setWaitTimeSharedTNC(float waitTimeSharedTNC) { + this.waitTimeSharedTNC = waitTimeSharedTNC; + } + + + private void setupMethodIndexMap() + { + methodIndexMap = new HashMap(); + + methodIndexMap.put("getTourDepartPeriod", 0); + methodIndexMap.put("getTourArrivePeriod", 1); + methodIndexMap.put("getTripPeriod", 2); + methodIndexMap.put("getSegment", 3); + methodIndexMap.put("getTourPurpose", 4); + methodIndexMap.put("getOutboundStops", 5); + methodIndexMap.put("getReturnStops", 6); + methodIndexMap.put("getFirstTrip", 7); + methodIndexMap.put("getLastTrip", 8); + methodIndexMap.put("getTourModeIsDA", 9); + methodIndexMap.put("getTourModeIsS2", 10); + methodIndexMap.put("getTourModeIsS3", 11); + methodIndexMap.put("getTourModeIsWalk", 12); + methodIndexMap.put("getTourModeIsBike", 13); + methodIndexMap.put("getTourModeIsWalkTransit", 14); + methodIndexMap.put("getTourModeIsPNRTransit", 15); + methodIndexMap.put("getTourModeIsKNRTransit", 16); + methodIndexMap.put("getTourModeIsMaas", 17); + methodIndexMap.put("getTourModeIsTNCTransit", 18); + + methodIndexMap.put("getHourlyParkingCostTourDest", 20); + methodIndexMap.put("getDailyParkingCostTourDest", 21); + methodIndexMap.put("getMonthlyParkingCostTourDest", 22); + methodIndexMap.put("getTripOrigIsTourDest", 23); + methodIndexMap.put("getTripDestIsTourDest", 24); + methodIndexMap.put("getHourlyParkingCostTripOrig", 25); + methodIndexMap.put("getHourlyParkingCostTripDest", 26); + + methodIndexMap.put("getPartySize", 30); + methodIndexMap.put("getAutoAvailable", 31); + methodIndexMap.put("getIncome", 32); + + methodIndexMap.put("getIvtCoeff", 60); + methodIndexMap.put("getCostCoeff", 61); + + methodIndexMap.put("getWalkSetLogSum", 62); + methodIndexMap.put("getPnrSetLogSum", 63); + methodIndexMap.put("getKnrSetLogSum", 64); + + methodIndexMap.put("getWaitTimeTaxi", 70); + methodIndexMap.put("getWaitTimeSingleTNC", 71); + methodIndexMap.put("getWaitTimeSharedTNC", 72); + + methodIndexMap.put("getNm_walkTime", 90); + methodIndexMap.put("getNm_bikeTime", 91); + + } + + public double getValueForIndex(int variableIndex, int arrayIndex) + { + + double returnValue = -1; + + switch (variableIndex) + { + case 0: + returnValue = getTourDepartPeriod(); + break; + case 1: + returnValue = getTourArrivePeriod(); + break; + case 2: + returnValue = getTripPeriod(); + break; + case 3: + returnValue = getSegment(); + break; + case 4: + returnValue = getTourPurpose(); + break; + case 5: + returnValue = getOutboundStops(); + break; + case 6: + returnValue = getReturnStops(); + break; + case 7: + returnValue = getFirstTrip(); + break; + case 8: + returnValue = getLastTrip(); + break; + case 9: + returnValue = getTourModeIsDA(); + break; + case 10: + returnValue = getTourModeIsS2(); + break; + case 11: + returnValue = getTourModeIsS3(); + break; + case 12: + returnValue = getTourModeIsWalk(); + break; + case 13: + returnValue = getTourModeIsBike(); + break; + case 14: + returnValue = getTourModeIsWalkTransit(); + break; + case 15: + returnValue = getTourModeIsPNRTransit(); + break; + case 16: + returnValue = getTourModeIsKNRTransit(); + break; + case 17: + returnValue = getTourModeIsMaas(); + break; + case 18: + returnValue = getTourModeIsTNCTransit(); + break; + case 20: + returnValue = getHourlyParkingCostTourDest(); + break; + case 21: + returnValue = getDailyParkingCostTourDest(); + break; + case 22: + returnValue = getMonthlyParkingCostTourDest(); + break; + case 23: + returnValue = getTripOrigIsTourDest(); + break; + case 24: + returnValue = getTripDestIsTourDest(); + break; + case 25: + returnValue = getHourlyParkingCostTripOrig(); + break; + case 26: + returnValue = getHourlyParkingCostTripDest(); + break; + case 30: + returnValue = getPartySize(); + break; + case 31: + returnValue = getAutoAvailable(); + break; + case 32: + returnValue = getIncome(); + break; + case 60: + returnValue = getIvtCoeff(); + break; + case 61: + returnValue = getCostCoeff(); + break; + case 62: + returnValue = getWalkTransitLogsum(); + break; + case 63: + returnValue = getPnrTransitLogsum(); + break; + case 64: + returnValue = getKnrTransitLogsum(); + break; + case 70: return getWaitTimeTaxi(); + case 71: return getWaitTimeSingleTNC(); + case 72: return getWaitTimeSharedTNC(); + case 90: + returnValue = getNm_walkTime(); + break; + case 91: + returnValue = getNm_bikeTime(); + break; + default: + logger.error( "method number = " + variableIndex + " not found" ); + throw new RuntimeException( "method number = " + variableIndex + " not found" ); + } + return returnValue; + + } + + public int getIndexValue(String variableName) + { + return methodIndexMap.get(variableName); + } + + public int getAssignmentIndexValue(String variableName) + { + throw new UnsupportedOperationException(); + } + + public double getValueForIndex(int variableIndex) + { + throw new UnsupportedOperationException(); + } + + public void setValue(String variableName, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public void setValue(int variableIndex, double variableValue) + { + throw new UnsupportedOperationException(); + } + + public int getTourModeIsTNCTransit() { + return tourModeIsTNCTransit; + } + + public void setTourModeIsTNCTransit(int tourModeIsTNCTransit) { + this.tourModeIsTNCTransit = tourModeIsTNCTransit; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripModeChoiceModel.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripModeChoiceModel.java new file mode 100644 index 0000000..bd2196c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripModeChoiceModel.java @@ -0,0 +1,327 @@ +package org.sandag.abm.visitor; + +import java.util.HashMap; + +import org.apache.log4j.Logger; +import org.sandag.abm.accessibilities.AutoAndNonMotorizedSkimsCalculator; +import org.sandag.abm.accessibilities.AutoTazSkimsCalculator; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.McLogsumsCalculator; +import org.sandag.abm.ctramp.TripModeChoiceDMU; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.calculator.VariableTable; +import com.pb.common.newmodel.ChoiceModelApplication; +import com.pb.common.newmodel.UtilityExpressionCalculator; + +public class VisitorTripModeChoiceModel +{ + + private transient Logger logger = Logger.getLogger("visitorModel"); + + private AutoAndNonMotorizedSkimsCalculator anm; + private McLogsumsCalculator logsumHelper; + private VisitorModelStructure modelStructure; + private TazDataManager tazs; + private MgraDataManager mgraManager; + private double[] lsWgtAvgCostM; + private double[] lsWgtAvgCostD; + private double[] lsWgtAvgCostH; + private VisitorTripModeChoiceDMU dmu; + private ChoiceModelApplication tripModeChoiceModel; + double logsum = 0; + + private static final String PROPERTIES_UEC_DATA_SHEET = "visitor.trip.mc.data.page"; + private static final String PROPERTIES_UEC_MODEL_SHEET = "visitor.trip.mc.model.page"; + private static final String PROPERTIES_UEC_FILE = "visitor.trip.mc.uec.file"; + private TripModeChoiceDMU mcDmuObject; + private AutoTazSkimsCalculator tazDistanceCalculator; + + /** + * Constructor. + * + * @param propertyMap + * @param myModelStructure + * @param dmuFactory + * @param myLogsumHelper + */ + public VisitorTripModeChoiceModel(HashMap propertyMap, + VisitorModelStructure myModelStructure, VisitorDmuFactoryIf dmuFactory, AutoTazSkimsCalculator tazDistanceCalculator) + { + tazs = TazDataManager.getInstance(propertyMap); + mgraManager = MgraDataManager.getInstance(propertyMap); + + lsWgtAvgCostM = mgraManager.getLsWgtAvgCostM(); + lsWgtAvgCostD = mgraManager.getLsWgtAvgCostD(); + lsWgtAvgCostH = mgraManager.getLsWgtAvgCostH(); + + modelStructure = myModelStructure; + this.tazDistanceCalculator = tazDistanceCalculator; + + logsumHelper = new McLogsumsCalculator(); + logsumHelper.setupSkimCalculators(propertyMap); + logsumHelper.setTazDistanceSkimArrays( + tazDistanceCalculator.getStoredFromTazToAllTazsDistanceSkims(), + tazDistanceCalculator.getStoredToTazFromAllTazsDistanceSkims()); + + SandagModelStructure modelStructure = new SandagModelStructure(); + mcDmuObject = new TripModeChoiceDMU(modelStructure, logger); + + setupTripModeChoiceModel(propertyMap, dmuFactory); + + } + + /** + * Read the UEC file and set up the trip mode choice model. + * + * @param propertyMap + * @param dmuFactory + */ + private void setupTripModeChoiceModel(HashMap propertyMap, + VisitorDmuFactoryIf dmuFactory) + { + + logger.info(String.format("setting up visitor trip mode choice model.")); + + dmu = dmuFactory.getVisitorTripModeChoiceDMU(); + + int dataPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_DATA_SHEET)); + int modelPage = new Integer(Util.getStringValueFromPropertyMap(propertyMap, + PROPERTIES_UEC_MODEL_SHEET)); + + String uecPath = propertyMap.get(CtrampApplication.PROPERTIES_UEC_PATH); + String tripModeUecFile = propertyMap.get(PROPERTIES_UEC_FILE); + tripModeUecFile = uecPath + tripModeUecFile; + + tripModeChoiceModel = new ChoiceModelApplication(tripModeUecFile, modelPage, dataPage, + propertyMap, (VariableTable) dmu); + + } + + /** + * Calculate utilities and return logsum for the tour and stop. + * + * @param tour + * @param trip + */ + public double computeUtilities(VisitorTour tour, VisitorTrip trip) + { + + setDmuAttributes(tour, trip); + + tripModeChoiceModel.computeUtilities(dmu, dmu.getDmuIndexValues()); + + if (tour.getDebugChoiceModels()) + { + tour.logTourObject(logger, 100); + tripModeChoiceModel.logUECResults(logger, "Visitor trip mode choice model"); + + } + + logsum = tripModeChoiceModel.getLogsum(); + + if (tour.getDebugChoiceModels()) logger.info("Returning logsum " + logsum); + + return logsum; + + } + + /** + * Choose a mode and store in the trip object. + * + * @param tour + * VisitorTour + * @param trip + * VisitorTrip + * + */ + public void chooseMode(VisitorTour tour, VisitorTrip trip) + { + + computeUtilities(tour, trip); + + double rand = tour.getRandom(); + try{ + int mode = tripModeChoiceModel.getChoiceResult(rand); + trip.setTripMode(mode); + + //value of time; lookup vot, votS2, or votS3 from the UEC depending on chosen mode + UtilityExpressionCalculator uec = tripModeChoiceModel.getUEC(); + + int votIndex = uec.lookupVariableIndex("vot"); + double vot = uec.getValueForIndex(votIndex); + trip.setValueOfTime((float)vot); + + float parkingCost = getTripParkingCost(mode); + trip.setParkingCost(parkingCost); + + if(modelStructure.getTripModeIsTransit(mode)){ + double[][] bestTapPairs = null; + + if (modelStructure.getTripModeIsWalkTransit(mode)){ + bestTapPairs = logsumHelper.getBestWtwTripTaps(); + } + else if (modelStructure.getTripModeIsPnrTransit(mode)||modelStructure.getTripModeIsKnrTransit(mode)){ + if (!trip.isInbound()) + bestTapPairs = logsumHelper.getBestDtwTripTaps(); + else + bestTapPairs = logsumHelper.getBestWtdTripTaps(); + } + double rn = tour.getRandom(); + int pathIndex = logsumHelper.chooseTripPath(rn, bestTapPairs, tour.getDebugChoiceModels(), logger); + int boardTap = (int) bestTapPairs[pathIndex][0]; + int alightTap = (int) bestTapPairs[pathIndex][1]; + int set = (int) bestTapPairs[pathIndex][2]; + trip.setBoardTap(boardTap); + trip.setAlightTap(alightTap); + trip.setSet(set); + } + + }catch(Exception e){ + logger.info("Error calculating visitor trip mode choice with rand="+rand); + tour.logTourObject(logger, 100); + logger.error(e.getMessage()); + } + + } + + /** + * Return parking cost from UEC if auto trip, else return 0. + * + * @param tripMode + * @return Parking cost if auto mode, else 0 + */ + public float getTripParkingCost(int tripMode) { + + float parkingCost=0; + + if(modelStructure.getTripModeIsSovOrHov(tripMode)) { + UtilityExpressionCalculator uec = tripModeChoiceModel.getUEC(); + int parkingCostIndex = uec.lookupVariableIndex("parkingCost"); + parkingCost = (float) uec.getValueForIndex(parkingCostIndex); + return parkingCost; + } + return parkingCost; + } + + + /** + * Set DMU attributes. + * + * @param tour + * @param trip + */ + public void setDmuAttributes(VisitorTour tour, VisitorTrip trip) + { + + int tourDestinationMgra = tour.getDestinationMGRA(); + int tripOriginMgra = trip.getOriginMgra(); + int tripDestinationMgra = trip.getDestinationMgra(); + + int tripOriginTaz = mgraManager.getTaz(tripOriginMgra); + int tripDestinationTaz = mgraManager.getTaz(tripDestinationMgra); + + int tourMode = tour.getTourMode(); + + dmu.setDmuIndexValues(tripOriginTaz, tripDestinationTaz, tripOriginTaz, tripDestinationTaz, + tour.getDebugChoiceModels()); + + dmu.setTourDepartPeriod(tour.getDepartTime()); + dmu.setTourArrivePeriod(tour.getArriveTime()); + dmu.setTripPeriod(trip.getPeriod()); + + // set trip mc dmu values for transit logsum (gets replaced below by uec values) + double c_ivt = -0.03; + double c_cost = - 0.0033; + + // Solve trip mode level utilities + mcDmuObject.setIvtCoeff(c_ivt); + mcDmuObject.setCostCoeff(c_cost); + double walkTransitLogsum = -999.0; + double driveTransitLogsum = -999.0; + + logsumHelper.setNmTripMcDmuAttributes(mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + dmu.setNonMotorizedWalkTime(mcDmuObject.getNm_walkTime()); + dmu.setNonMotorizedBikeTime(mcDmuObject.getNm_bikeTime()); + + logsumHelper.setWtwTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(),tour.getDebugChoiceModels()); + walkTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTW); + + dmu.setWalkTransitLogsum(walkTransitLogsum); + if (!trip.isInbound()) + { + logsumHelper.setDtwTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.DTW); + } else + { + logsumHelper.setWtdTripMcDmuAttributes( mcDmuObject, trip.getOriginMgra(), trip.getDestinationMgra(), trip.getPeriod(), tour.getDebugChoiceModels()); + driveTransitLogsum = mcDmuObject.getTransitLogSum(McLogsumsCalculator.WTD); + } + + dmu.setPnrTransitLogsum(driveTransitLogsum); + dmu.setKnrTransitLogsum(driveTransitLogsum); + + dmu.setTourPurpose(tour.getPurpose()); + + dmu.setOutboundStops(tour.getNumberInboundStops()); + dmu.setReturnStops(tour.getNumberInboundStops()); + + if (trip.isFirstTrip()) dmu.setFirstTrip(1); + else dmu.setFirstTrip(0); + + if (trip.isLastTrip()) dmu.setLastTrip(1); + else dmu.setLastTrip(0); + + if (modelStructure.getTourModeIsSov(tourMode)) dmu.setTourModeIsDA(1); + else dmu.setTourModeIsDA(0); + + if (modelStructure.getTourModeIsS2(tourMode)) dmu.setTourModeIsS2(1); + else dmu.setTourModeIsS2(0); + + if (modelStructure.getTourModeIsS3(tourMode)) dmu.setTourModeIsS3(1); + else dmu.setTourModeIsS3(0); + + if (modelStructure.getTourModeIsWalk(tourMode)) dmu.setTourModeIsWalk(1); + else dmu.setTourModeIsWalk(0); + + if (modelStructure.getTourModeIsBike(tourMode)) dmu.setTourModeIsBike(1); + else dmu.setTourModeIsBike(0); + + if (modelStructure.getTourModeIsWalkTransit(tourMode)) dmu.setTourModeIsWalkTransit(1); + else dmu.setTourModeIsWalkTransit(0); + + if (modelStructure.getTourModeIsPnr(tourMode)) dmu.setTourModeIsPNRTransit(1); + else dmu.setTourModeIsPNRTransit(0); + + if (modelStructure.getTourModeIsKnr(tourMode)) dmu.setTourModeIsKNRTransit(1); + else dmu.setTourModeIsKNRTransit(0); + + if (modelStructure.getTourModeIsMaas(tourMode)) dmu.setTourModeIsMaas(1); + else dmu.setTourModeIsMaas(0); + + if (modelStructure.getTourModeIsTncTransit(tourMode)) dmu.setTourModeIsTNCTransit(1); + else dmu.setTourModeIsTNCTransit(0); + + if (trip.isOriginIsTourDestination()) dmu.setTripOrigIsTourDest(1); + else dmu.setTripOrigIsTourDest(0); + + if (trip.isDestinationIsTourDestination()) dmu.setTripDestIsTourDest(1); + else dmu.setTripDestIsTourDest(0); + + dmu.setIncome((byte) tour.getIncome()); + dmu.setAutoAvailable(tour.getAutoAvailable()); + dmu.setPartySize(tour.getNumberOfParticipants()); + + dmu.setHourlyParkingCostTourDest((float) lsWgtAvgCostH[tourDestinationMgra]); + dmu.setDailyParkingCostTourDest((float) lsWgtAvgCostD[tourDestinationMgra]); + dmu.setMonthlyParkingCostTourDest((float) lsWgtAvgCostM[tourDestinationMgra]); + dmu.setHourlyParkingCostTripOrig((float) lsWgtAvgCostH[tripOriginMgra]); + dmu.setHourlyParkingCostTripDest((float) lsWgtAvgCostH[tripDestinationMgra]); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripTables.java b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripTables.java new file mode 100644 index 0000000..7a715bf --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/abm/visitor/VisitorTripTables.java @@ -0,0 +1,682 @@ +package org.sandag.abm.visitor; + +import gnu.cajo.invoke.Remote; +import gnu.cajo.utils.ItemServer; + +import java.io.File; +import java.io.IOException; +import java.rmi.RemoteException; +import java.util.HashMap; +import java.util.MissingResourceException; +import java.util.ResourceBundle; + +import org.apache.log4j.Logger; +import org.sandag.abm.application.SandagModelStructure; +import org.sandag.abm.ctramp.CtrampApplication; +import org.sandag.abm.ctramp.MatrixDataServer; +import org.sandag.abm.ctramp.MatrixDataServerRmi; +import org.sandag.abm.ctramp.Util; +import org.sandag.abm.modechoice.MgraDataManager; +import org.sandag.abm.modechoice.TapDataManager; +import org.sandag.abm.modechoice.TazDataManager; + +import com.pb.common.datafile.OLD_CSVFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.MatrixWriter; +import com.pb.common.util.ResourceUtil; + +public class VisitorTripTables +{ + + private static Logger logger = Logger.getLogger("tripTables"); + public static final int MATRIX_DATA_SERVER_PORT = 1171; + + private TableDataSet tripData; + + // Some parameters + private int[] modeIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // total + // modes, + // returns + // 0=auto + // modes, + // 1=non-motor, + // 2=transit, + // 3= + // other + private int[] matrixIndex; // an + // index + // array, + // dimensioned + // by + // number + // of + // modes, + // returns + // the + // element + // of + // the + // matrix + // array + // to + // store + // value + + // array modes: AUTO, NON-MOTORIZED, TRANSIT, OTHER + private int autoModes = 0; + private int tranModes = 0; + private int nmotModes = 0; + private int othrModes = 0; + + // one file per time period + private int numberOfPeriods; + + private HashMap rbMap; + + // matrices are indexed by modes, vot bins, submodes + private Matrix[][][] matrix; + + private ResourceBundle rb; + private MgraDataManager mgraManager; + private TazDataManager tazManager; + private TapDataManager tapManager; + private SandagModelStructure modelStructure; + + private MatrixDataServerRmi ms; + private float sampleRate; + private static int iteration=1; + private static final String VOT_THRESHOLD_LOW = "valueOfTime.threshold.low"; + private static final String VOT_THRESHOLD_MED = "valueOfTime.threshold.med"; + private float valueOfTimeThresholdLow = 0; + private float valueOfTimeThresholdMed = 0; + //value of time bins by mode group + int[] votBins = {3,1,1,1}; + public int numSkimSets; + + public VisitorTripTables(HashMap rbMap) + { + + this.rbMap = rbMap; + tazManager = TazDataManager.getInstance(rbMap); + tapManager = TapDataManager.getInstance(rbMap); + mgraManager = MgraDataManager.getInstance(rbMap); + + modelStructure = new SandagModelStructure(); + + // Time period limits + numberOfPeriods = modelStructure.getNumberModelPeriods(); + + // number of modes + modeIndex = new int[modelStructure.MAXIMUM_TOUR_MODE_ALT_INDEX + 1]; + matrixIndex = new int[modeIndex.length]; + + numSkimSets = Util.getIntegerValueFromPropertyMap(rbMap,"utility.bestTransitPath.skim.sets"); + + // set the mode arrays + for (int i = 1; i < modeIndex.length; ++i) + { + if (modelStructure.getTourModeIsSovOrHov(i)) + { + modeIndex[i] = 0; + matrixIndex[i] = autoModes; + ++autoModes; + } else if (modelStructure.getTourModeIsNonMotorized(i)) + { + modeIndex[i] = 1; + matrixIndex[i] = nmotModes; + ++nmotModes; + } else if (modelStructure.getTourModeIsWalkTransit(i) + || modelStructure.getTourModeIsDriveTransit(i)) + { + modeIndex[i] = 2; + matrixIndex[i] = tranModes; + ++tranModes; + } else + { + modeIndex[i] = 3; + matrixIndex[i] = othrModes; + ++othrModes; + } + } + //value of time thresholds + valueOfTimeThresholdLow = new Float(rbMap.get(VOT_THRESHOLD_LOW)); + valueOfTimeThresholdMed = new Float(rbMap.get(VOT_THRESHOLD_MED)); + } + + /** + * Initialize all the matrices for the given time period. + * + * @param periodName + * The name of the time period. + */ + public void initializeMatrices(String periodName) + { + + /* + * This won't work because external stations aren't listed in the MGRA + * file int[] tazIndex = tazManager.getTazsOneBased(); int tazs = + * tazIndex.length-1; + */ + // Instead, use maximum taz number + int maxTaz = tazManager.getMaxTaz(); + int[] tazIndex = new int[maxTaz + 1]; + + // assume zone numbers are sequential + for (int i = 1; i < tazIndex.length; ++i) + tazIndex[i] = i; + + // get the tap index + int[] tapIndex = tapManager.getTaps(); + int taps = tapIndex.length - 1; + + // Initialize matrices; one for each mode group (auto, non-mot, tran, + // other) + // All matrices will be dimensioned by TAZs except for transit, which is + // dimensioned by TAPs + int numberOfModes = 4; + matrix = new Matrix[numberOfModes][][]; + for (int i = 0; i < numberOfModes; ++i) + { + + String modeName; + + matrix[i] = new Matrix[votBins[i]][]; + + for(int j = 0; j< votBins[i];++j){ + if (i == 0) + { + matrix[i][j] = new Matrix[autoModes]; + for (int k = 0; k < autoModes; ++k) + { + modeName = modelStructure.getModeName(k + 1); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 1) + { + matrix[i][j] = new Matrix[nmotModes]; + for (int k = 0; k < nmotModes; ++k) + { + modeName = modelStructure.getModeName(k + 1 + autoModes); + matrix[i][j][k] = new Matrix(modeName + "_" + periodName, "", maxTaz, maxTaz); + matrix[i][j][k].setExternalNumbers(tazIndex); + } + } else if (i == 2) + { + matrix[i][j] = new Matrix[tranModes*numSkimSets]; + for (int k = 0; k < tranModes; ++k) + { + for(int l=0;l1) + votBin = getValueOfTimeBin(valueOfTime); + + if (mode == 0) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + vehicleTrips)); + } else if (mode == 1) + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } else if (mode == 2) + { + + if (boardTap == 0 || alightTap == 0) continue; + + //store transit trips in matrices + mat = (matrixIndex[tripMode]*numSkimSets)+set; + float value = matrix[mode][votBin][mat].getValueAt(boardTap, alightTap); + matrix[mode][votBin][mat].setValueAt(boardTap, alightTap, (value + personTrips)); + + // Store PNR transit trips in SOV free mode skim (mode 0 mat 0) + if (modelStructure.getTourModeIsDriveTransit(tripMode)) + { + + // add the tNCVehicle trip portion to the trip table + if (!inbound) + { // from origin to lot (boarding tap) + int PNRTAZ = tapManager.getTazForTap(boardTap); + value = matrix[0][votBin][0].getValueAt(originTAZ, PNRTAZ); + matrix[0][votBin][0].setValueAt(originTAZ, PNRTAZ, (value + vehicleTrips)); + + } else + { // from lot (alighting tap) to destination + int PNRTAZ = tapManager.getTazForTap(alightTap); + value = matrix[0][votBin][0].getValueAt(PNRTAZ, destinationTAZ); + matrix[0][votBin][0].setValueAt(PNRTAZ, destinationTAZ, (value + vehicleTrips)); + } + + } + } else + { + float value = matrix[mode][votBin][mat].getValueAt(originTAZ, destinationTAZ); + matrix[mode][votBin][mat].setValueAt(originTAZ, destinationTAZ, (value + personTrips)); + } + + //logger.info("End creating trip tables for period " + timePeriod); + } + } + + /** + * Return the value of time bin 0 through 2 based on the thresholds provided in the property map + * @param valueOfTime + * @return value of time bin 0 through 2 + */ + public int getValueOfTimeBin(float valueOfTime){ + + if(valueOfTime1) + end[i][j] = "_" + per + "_"+ votBinName[j]+ ".omx"; + else + end[i][j] = "_" + per + ".omx"; + } + } + for (int i = 0; i < 4; ++i){ + for(int j = 0; j < votBins[i];++j){ + try + { + //Delete the file if it exists + File f = new File(fileName[i]+end[i][j]); + if(f.exists()){ + logger.info("Deleting existing trip file: "+fileName[i]+end[i][j]); + f.delete(); + } + if (ms != null) ms.writeMatrixFile(fileName[i]+end[i][j], matrix[i][j], mt); + else writeMatrixFile(fileName[i]+end[i][j], matrix[i][j]); + } catch (Exception e) + { + logger.error("exception caught writing " + mt.toString() + " matrix file = " + + fileName[i] +end[i][j] + ", for mode index = " + i, e); + throw new RuntimeException(); + } + } + } + + } + + /** + * Utility method to write a set of matrices to disk. + * + * @param fileName + * The file name to write to. + * @param m + * An array of matrices + */ + public void writeMatrixFile(String fileName, Matrix[] m) + { + + // auto trips + MatrixWriter writer = MatrixWriter.createWriter(fileName); + String[] names = new String[m.length]; + + for (int i = 0; i < m.length; i++) + { + names[i] = m[i].getName(); + logger.info(m[i].getName() + " has " + m[i].getRowCount() + " rows, " + + m[i].getColumnCount() + " cols, and a total of " + m[i].getSum()); + } + + writer.writeMatrices(names, m); + } + + /** + * Start matrix server + * + * @param serverAddress + * @param serverPort + * @param mt + * @return + */ + private MatrixDataServerRmi startMatrixServerProcess(String serverAddress, int serverPort, + MatrixType mt) + { + + String className = MatrixDataServer.MATRIX_DATA_SERVER_NAME; + MatrixDataServerRmi matrixServer = new MatrixDataServerRmi(serverAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + + // bind this concrete object with the cajo library objects for managing + // RMI + try + { + Remote.config(serverAddress, serverPort, null, 0); + } catch (Exception e) + { + logger.error(String.format( + "UnknownHostException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + try + { + ItemServer.bind(matrixServer, className); + } catch (RemoteException e) + { + logger.error(String.format( + "RemoteException. serverAddress = %s, serverPort = %d -- exiting.", + serverAddress, serverPort), e); + throw new RuntimeException(); + } + + return matrixServer; + + } + + /** + * @param args + */ + public static void main(String[] args) + { + + HashMap pMap; + String propertiesFile = null; + + logger.info(String.format( + "SANDAG Visitor Model Trip Table Generation Program using CT-RAMP version %s", + CtrampApplication.VERSION)); + + if (args.length == 0) + { + logger.error(String + .format("no properties file base name (without .properties extension) was specified as an argument.")); + return; + } else propertiesFile = args[0]; + + float sampleRate = 1.0f; + for (int i = 1; i < args.length; ++i) + { + if (args[i].equalsIgnoreCase("-sampleRate")) + { + sampleRate = Float.parseFloat(args[i + 1]); + } + if (args[i].equalsIgnoreCase("-iteration")) + { + iteration = Integer.parseInt(args[i + 1]); + } + } + logger.info("Visitor Model Trip Table:"+String.format("-sampleRate %.4f.", sampleRate)+"-iteration " + iteration); + pMap = ResourceUtil.getResourceBundleAsHashMap(propertiesFile); + VisitorTripTables tripTables = new VisitorTripTables(pMap); + tripTables.setSampleRate(sampleRate); + + String matrixServerAddress = ""; + int serverPort = 0; + try + { + // get matrix server address. if "none" is specified, no server will + // be + // started, and matrix io will ocurr within the current process. + matrixServerAddress = Util.getStringValueFromPropertyMap(pMap, + "RunModel.MatrixServerAddress"); + try + { + // get matrix server port. + serverPort = Util.getIntegerValueFromPropertyMap(pMap, "RunModel.MatrixServerPort"); + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, leave undefined + // -- + // it's eithe not needed or show could create an error. + } + } catch (MissingResourceException e) + { + // if no matrix server address entry is found, set to localhost, and + // a + // separate matrix io process will be started on localhost. + matrixServerAddress = "localhost"; + serverPort = MATRIX_DATA_SERVER_PORT; + } + + MatrixDataServerRmi matrixServer = null; + String matrixTypeName = Util.getStringValueFromPropertyMap(pMap, "Results.MatrixType"); + MatrixType mt = MatrixType.lookUpMatrixType(matrixTypeName); + + try + { + + if (!matrixServerAddress.equalsIgnoreCase("none")) + { + + if (matrixServerAddress.equalsIgnoreCase("localhost")) + { + matrixServer = tripTables.startMatrixServerProcess(matrixServerAddress, + serverPort, mt); + tripTables.ms = matrixServer; + } else + { + tripTables.ms = new MatrixDataServerRmi(matrixServerAddress, serverPort, + MatrixDataServer.MATRIX_DATA_SERVER_NAME); + tripTables.ms.testRemote("VisitorTripTables"); + + // mdm = MatrixDataManager.getInstance(); + // mdm.setMatrixDataServerObject(ms); + } + + } + + } catch (Exception e) + { + + logger.error( + String.format("exception caught running ctramp model components -- exiting."), + e); + throw new RuntimeException(); + + } + + tripTables.createTripTables(mt); + + } + + /** + * @return the sampleRate + */ + public double getSampleRate() + { + return sampleRate; + } + + /** + * @param sampleRate + * the sampleRate to set + */ + public void setSampleRate(float sampleRate) + { + this.sampleRate = sampleRate; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/AlternativeUsesMatrices.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/AlternativeUsesMatrices.java new file mode 100644 index 0000000..d6cda4b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/AlternativeUsesMatrices.java @@ -0,0 +1,42 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel; + +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.MatrixReader; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public interface AlternativeUsesMatrices extends CodedAlternative { + + void addCoefficient(String index1, String index2, String matrix, double coefficient) throws CoefficientFormatError; + + + /** + * Method readMatrices. + * @param matrixCacheReader + */ + void readMatrices(MatrixCacheReader matrixCacheReader); + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/ChangingTravelAttributeGetter.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/ChangingTravelAttributeGetter.java new file mode 100644 index 0000000..f69c70c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/ChangingTravelAttributeGetter.java @@ -0,0 +1,52 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +/* + * An interface that determines the travel time between two points, given a time (represented by a double) and + * a tNCVehicle type (represented by a char). + */ +package org.sandag.cvm.activityTravel; + +/** + * @author jabraham + * + * An interface that determines a travel attribute between two points, given a time (represented by a double) and + * a tNCVehicle type (represented by a char). For instance if there are matrices of travel time for peak and off-peak, + * and implementation of this interface would be able to determine whether time was in the peak or off-peak, and + * then return the travel conditions appropriately. + */ +public interface ChangingTravelAttributeGetter { + /** + * + * This method returns the travel attribute associated with travelling from origin to destination at time time by + * tNCVehicle type vehicleType + * + * @param origin + * @param destination + * @param time + * @param vehicleType + * @return + */ + public abstract double getTravelAttribute( + int origin, + int destination, + double time, + char vehicleType); +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/CodedAlternative.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/CodedAlternative.java new file mode 100644 index 0000000..738846d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/CodedAlternative.java @@ -0,0 +1,35 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel; + + +import org.sandag.cvm.common.model.Alternative; + + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public interface CodedAlternative extends Alternative { + + public String getCode(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/CoefficientFormatError.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/CoefficientFormatError.java new file mode 100644 index 0000000..fc937a4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/CoefficientFormatError.java @@ -0,0 +1,61 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class CoefficientFormatError extends Exception { + + /** + * Constructor for CoefficientFormatError. + */ + public CoefficientFormatError() { + super(); + } + + /** + * Constructor for CoefficientFormatError. + * @param message + */ + public CoefficientFormatError(String message) { + super(message); + } + + /** + * Constructor for CoefficientFormatError. + * @param message + * @param cause + */ + public CoefficientFormatError(String message, Throwable cause) { + super(message, cause); + } + + /** + * Constructor for CoefficientFormatError. + * @param cause + */ + public CoefficientFormatError(Throwable cause) { + super(cause); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/DurationModel.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/DurationModel.java new file mode 100644 index 0000000..9009825 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/DurationModel.java @@ -0,0 +1,91 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel; + +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +//import org.sandag.cvm.calgary.commercial.GenerateCommercialTours; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.MatrixReader; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class DurationModel implements ModelUsesMatrices, RealNumberDistribution { + + protected double a=0; + protected double b=0; + protected double c=0; + protected double d=0; + protected double e=0; + protected double f=0; + + + /** @return stop duration in hours + */ + public double sampleValue() { + double x = -Math.random(); + double y = a*Math.exp(b*x)+c*Math.exp(d*x)+f; + if (y<0) y=0; + if (y>24) y = 24; + return y; + } + + /** + * Method addCoefficient. + * @param alternative + * @param index1 + * @param index2 + * @param matrix + * @param coefficient + */ + public void addCoefficient ( + String alternative, + String index1, + String index2, + String matrix, + double coefficient) throws CoefficientFormatError { + if (index1.equals("a")) a = coefficient; + else if(index1.equals("b")) b = coefficient; + else if(index1.equals("c")) c = coefficient; + else if(index1.equals("d")) d = coefficient; + else if (index1.equals("e")) e = coefficient; + else if(index1.equals("f")) f = coefficient; + else throw new CoefficientFormatError("Duration model coefficients must have index1 as a,b,c or d"); + } + + /** + * Method readMatrices. + * @param matrixReader + */ + public void readMatrices(MatrixCacheReader matrixReader) {} + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { +// readMatrices(GenerateCommercialTours.matrixReader); + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/HouseholdInterface.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/HouseholdInterface.java new file mode 100644 index 0000000..9449313 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/HouseholdInterface.java @@ -0,0 +1,46 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +/* + * Created on 24-Mar-2005 + * + */ +package org.sandag.cvm.activityTravel; + +import java.util.Collection; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public interface HouseholdInterface { + + /** + * @return the ID of the household + */ + public int getId(); + + /** + * @return a collection containing the Persons in the household + */ + public Collection getPersons(); + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/LoggingStopAlternative.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/LoggingStopAlternative.java new file mode 100644 index 0000000..6bd9ac2 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/LoggingStopAlternative.java @@ -0,0 +1,79 @@ +package org.sandag.cvm.activityTravel; + +import org.apache.log4j.Logger; + +public class LoggingStopAlternative extends StopAlternative { + + + static Logger logger = Logger.getLogger(LoggingStopAlternative.class); + static double[] co = new double[10]; + + static boolean loggedParts = false; + +// @Override + public double getUtility() { + if (!loggedParts) { + logger.info("Parts of utility function are travel,destination,returnHomeTravel,returnHomeDisutility,travelDisutility,returnHomeTime,travelTime,angle,zoneType,sizeTerm"); + loggedParts=true; + } + + co[0] = c.travelUtilityFunction.calcForIndex(c.myTour.getCurrentLocation(),location); + co[1] = c.destinationUtilityFunction.calcForIndex(location,1); + // TODO should be logsum of trip mode + co[2] = c.returnHomeUtilityFunction.calcForIndex(location,c.myTour.getOriginZone()); + if (c.disutilityToOriginCoefficient!=0) { + co[3] = c.disutilityToOriginCoefficient*c.myTour.getTravelDisutilityTracker().getTravelAttribute(location,c.myTour.getOriginZone(),c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + } else co[3]=0; + if (c.disutilityToNextStopCoefficient!=0) { + co[4] = c.disutilityToNextStopCoefficient*c.myTour.getTravelDisutilityTracker().getTravelAttribute(c.myTour.getCurrentLocation(),location,c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + } else co[4] = 0; + if (c.timeToOriginCoefficient!=0) { + double timeToOriginUtility = c.timeToOriginCoefficient*c.myTour.getElapsedTravelTimeCalculator().getTravelAttribute(location,c.myTour.getOriginZone(),c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + // Doug and Kevin Hack of Jan 5 2004 +// if (myTour.getTotalElapsedTime()>240.0) timeToOriginUtility*=3; + co[5] = timeToOriginUtility; + } else co[5]=0; + if (c.timeToNextStopCoefficient!=0) { + double timeToNextStopUtility = c.timeToNextStopCoefficient*c.myTour.getElapsedTravelTimeCalculator().getTravelAttribute(c.myTour.getCurrentLocation(),location,c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + // Doug and Kevin Hack of Jan 5 2004 +// if (myTour.getTotalElapsedTime()>240.0) timeToNextStopUtility*=3; + co[6] = timeToNextStopUtility; + } else co[6]=0; + + if (c.xMatrix !=null && c.yMatrix != null) { + + double xOrig = c.xMatrix.getValueAt(c.myTour.getOriginZone(),1); + double yOrig = c.yMatrix.getValueAt(c.myTour.getOriginZone(),1); + double xNow = c.xMatrix.getValueAt(c.myTour.getCurrentLocation(),1); + double yNow = c.yMatrix.getValueAt(c.myTour.getCurrentLocation(),1); + double xMaybe = c.xMatrix.getValueAt(location,1); + double yMaybe = c.yMatrix.getValueAt(location,1); + double angle1 = Math.atan2(yNow-yOrig,xNow-xOrig); + double angle2 = Math.atan2(yMaybe-yNow,xMaybe-xNow); + double angle = (angle2-angle1)+Math.PI; + if (angle > Math.PI*2) angle -= Math.PI*2; + if (angle <0) angle += Math.PI*2; + if (angle > Math.PI) angle =2*Math.PI-angle; + co[7]= c.angleCoefficient*angle*180/Math.PI; + } else co[7]=0; + co[8]= c.zoneTypeUtilityFunction.calcForIndex(c.myTour.getCurrentLocation(),location); + if (c.sizeTermCoefficient !=0) { + double sizeTermValue = Math.log(c.sizeTerm.calcForIndex(location,1)); + co[9]= c.sizeTermCoefficient*sizeTermValue; + } else co[9]=0; + StringBuffer logStatement = new StringBuffer("OD "+c.getTour().getCurrentLocation()+","+location+" :"); + double uti=0; + for (int index=0;indexduration in hours + */ + public float duration; + /** + * location represents the location of the stop + */ + public int location; + /** + * purpose represents the purpose of the stop + */ + public int purpose; + public double travelTimeMinutes; + public String tripMode = "NA"; + public final int previousLocation; + public final double departureTimeFromPreviousStop; + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/StopAlternative.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/StopAlternative.java new file mode 100644 index 0000000..9249773 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/StopAlternative.java @@ -0,0 +1,106 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel; + + +public class StopAlternative implements CodedAlternative { + final StopChoice c; + public final int location; + public double getUtility() { + + if (c.maxDist >0) { + assert c.distanceMatrix!=null : "Distance Matrix didn't get initialized, yet maxDist set to "+c.maxDist; + double distance = c.distanceMatrix.getValueAt(c.myTour.getOriginZone(),location); + + if((distance<-99999) || (distance>99999)) + distance=0; + + if (distance >c.maxDist) { + return Double.NEGATIVE_INFINITY; + } + } + + boolean firstStop = (c.myTour.getStopCounts()[0]==0); + + double utility = c.travelUtilityFunction.calcForIndex(c.myTour.getCurrentLocation(),location); + utility += c.destinationUtilityFunction.calcForIndex(location,1); + utility += c.returnHomeUtilityFunction.calcForIndex(location,c.myTour.getOriginZone()); + + if (c.disutilityToOriginCoefficient!=0 || c.disutilityToOriginAdditionalCoefficientForStopGT1!=0) { + double coefficient = c.disutilityToOriginCoefficient + (firstStop ? 0 : c.disutilityToOriginAdditionalCoefficientForStopGT1); + utility += coefficient*c.myTour.getTravelDisutilityTracker().getTravelAttribute(location,c.myTour.getOriginZone(),c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + } + if (c.disutilityToNextStopCoefficient!=0 || c.disutilityToNextStopAdditionalCoefficientForStopGT1 !=0) { + double coefficient = c.disutilityToNextStopCoefficient + (firstStop ? 0 : c.disutilityToNextStopAdditionalCoefficientForStopGT1); + utility += coefficient*c.myTour.getTravelDisutilityTracker().getTravelAttribute(c.myTour.getCurrentLocation(),location,c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + } + if (c.timeToOriginCoefficient!=0) { + double timeToOriginUtility = c.timeToOriginCoefficient*c.myTour.getElapsedTravelTimeCalculator().getTravelAttribute(location,c.myTour.getOriginZone(),c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + // Doug and Kevin Hack of Jan 5 2004 +// if (myTour.getTotalElapsedTime()>240.0) timeToOriginUtility*=3; + utility += timeToOriginUtility; + } + if (c.timeToNextStopCoefficient!=0) { + double timeToNextStopUtility = c.timeToNextStopCoefficient*c.myTour.getElapsedTravelTimeCalculator().getTravelAttribute(c.myTour.getCurrentLocation(),location,c.myTour.getCurrentTimeHrs(),c.myTour.getMyVehicleTourType().vehicleType); + // Doug and Kevin Hack of Jan 5 2004 +// if (myTour.getTotalElapsedTime()>240.0) timeToNextStopUtility*=3; + utility += timeToNextStopUtility; + } + + + if (c.xMatrix !=null && c.yMatrix != null) { + // angle calculation and max distance + + double xOrig = c.xMatrix.getValueAt(c.myTour.getOriginZone(),1); + double yOrig = c.yMatrix.getValueAt(c.myTour.getOriginZone(),1); + double xNow = c.xMatrix.getValueAt(c.myTour.getCurrentLocation(),1); + double yNow = c.yMatrix.getValueAt(c.myTour.getCurrentLocation(),1); + double xMaybe = c.xMatrix.getValueAt(location,1); + double yMaybe = c.yMatrix.getValueAt(location,1); + + double angle1 = Math.atan2(yNow-yOrig,xNow-xOrig); + double angle2 = Math.atan2(yMaybe-yNow,xMaybe-xNow); + double angle = (angle2-angle1)+Math.PI; + if (angle > Math.PI*2) angle -= Math.PI*2; + if (angle <0) angle += Math.PI*2; + if (angle > Math.PI) angle =2*Math.PI-angle; + utility += c.angleCoefficient*angle*180/Math.PI; + } + utility += c.zoneTypeUtilityFunction.calcForIndex(c.myTour.getCurrentLocation(),location); + if (c.sizeTermCoefficient !=0) { + double sizeTermValue = Math.log(c.sizeTerm.calcForIndex(location,1)); + utility += c.sizeTermCoefficient*sizeTermValue; + } + return utility; + } + + public StopAlternative(StopChoice choice, int stopLocation) { + this.location = stopLocation; + this.c = choice; + } + + public String getCode() { + return String.valueOf(location); + } + + + + + } \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/StopChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/StopChoice.java new file mode 100644 index 0000000..38f419a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/StopChoice.java @@ -0,0 +1,230 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel; + +import org.apache.log4j.Logger; + +import org.sandag.cvm.common.emme2.IndexConditionFunction; +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import org.sandag.cvm.common.model.LogitModel; +import com.pb.common.matrix.*; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + * Modified 2014 for trip mode choice + */ +public abstract class StopChoice extends LogitModel implements ModelUsesMatrices { + + static int angleCalculationCounter = 50; + public static MatrixCacheReader myMatrixCacheReader=null; + + static Logger logger = Logger.getLogger(StopChoice.class); + /*private static Boolean useTripModeChoice = null;*/ + + + + protected double angleCoefficient; + protected double maxDist; + + protected IndexLinearFunction destinationUtilityFunction = new IndexLinearFunction(); + + protected double disutilityToNextStopAdditionalCoefficientForStopGT1; + protected double disutilityToNextStopCoefficient; + protected double disutilityToOriginAdditionalCoefficientForStopGT1; + protected double disutilityToOriginCoefficient; + protected Tour myTour; + protected IndexLinearFunction returnHomeUtilityFunction = new IndexLinearFunction(); + protected IndexLinearFunction sizeTerm = null; + protected double sizeTermCoefficient = 0; + protected double timeToNextStopCoefficient; + protected double timeToOriginCoefficient; + protected IndexLinearFunction travelUtilityFunction = new IndexLinearFunction(); + protected Matrix xMatrix; + private String xMatrixName; + protected Matrix yMatrix; + private String yMatrixName; + protected IndexConditionFunction zoneTypeUtilityFunction = new IndexConditionFunction(); + public Matrix distanceMatrix; + private String distanceMatrixName; + /** + * Method addCoefficient. + * @param alternative + * @param index1 + * @param index2 + * @param matrix + * @param coefficient + */ + public void addCoefficient( + String alternative, + String index1, + String index2, + String matrix, + double coefficient) throws CoefficientFormatError { + if (!alternative.equals("zone")) throw new RuntimeException("StopAlternative coefficients must have \"zone\" as alternative"); + + //If Index1 is "cstop" then Index2 must equal "nstop", and the term in the utility function is the entry from the mf matrix identified in the Matrix field, indexed with i being the current stop location and j being the next stop location whose utility is being evaluated. + if(index1.equals("cstop")) { + if(index2.equals("nstop")) { + travelUtilityFunction.addCoefficient(matrix,coefficient); + } else throw new CoefficientFormatError("cstop coefficients for next stop location must index an mf matrix using nstop as the J"); + } + + + else if (index1.equals("nstop")) { + //If Index1 is "nstop" and Index2 is "origin" then Matrix identifies an mf matrix, and the term in the utility function is the matrix value indexed with i being the next stop location whose utility is being evaluated and j is the origin of the tour. + if(index2.equals("origin")) { + returnHomeUtilityFunction.addCoefficient(matrix,coefficient); + //If Index1 is "nstop" and Index2 is blank, then Matrix identifies an mo or md matrix. The next stop location under consideration is used to retrieve the appropriate entry from the matrix. + } else if (index2.equals("") ||index2.equals("none")) { + destinationUtilityFunction.addCoefficient(matrix,coefficient); + } else throw new CoefficientFormatError("nstop coefficients for next stop location must have index2=\"\" or index2 = origin"); + } + else if (index1.equals("angle")) { + angleCoefficient = coefficient; + setXYNames(matrix, index2); + } + else if (index1.equals("travelDisutility")) { + if (index2.equals("nstop")) { + disutilityToNextStopCoefficient+=coefficient; + } else if (index2.equals("origin")) { + disutilityToOriginCoefficient+=coefficient; + } else if (index2.equalsIgnoreCase("nstopx")){ + disutilityToNextStopAdditionalCoefficientForStopGT1 += coefficient; + } else if (index2.equalsIgnoreCase("originx")) { + disutilityToOriginAdditionalCoefficientForStopGT1 += coefficient; + } else { + throw new CoefficientFormatError("travelDisutility coefficients for next stop must have be to either \"origin\" or to \"nstop\""); + } + } + else if (index1.equals("travelTime")) { + if (index2.equals("nstop")) { + timeToNextStopCoefficient+=coefficient; + } else if (index2.equals("origin")) { + timeToOriginCoefficient+=coefficient; + } else { + throw new CoefficientFormatError("travelDisutility coefficients for next stop must have be to either \"origin\" or to \"nstop\""); + } + } + else if (index1.equals("sizeTerm1")) { + sizeTermCoefficient += coefficient; + if (sizeTerm== null) sizeTerm = new IndexLinearFunction(); + sizeTerm.addCoefficient(matrix,1.0); + } + else if (index1.equals("sizeTerm2") || index1.equals("sizeTermx")) { + if (sizeTerm== null) sizeTerm = new IndexLinearFunction(); + sizeTerm.addCoefficient(matrix,coefficient); + } + else if (index1.equals("maxDist")) { + maxDist = coefficient; + distanceMatrixName = matrix; + } + else { + int destinationCondition; + int originCondition; + try { + destinationCondition = Integer.valueOf(index1).intValue(); + } catch (NumberFormatException e) { + throw new CoefficientFormatError("Can't convert "+index1+" to a number, not allowed as an index type for stop location choice"); + } + boolean twoTypeCondition=false; + try { + originCondition = Integer.valueOf(index2).intValue(); + zoneTypeUtilityFunction.addCoefficient(matrix,destinationCondition,originCondition,coefficient); + twoTypeCondition= true; + } catch (NumberFormatException e) { + } + if (!twoTypeCondition) { + zoneTypeUtilityFunction.addCoefficient(matrix,destinationCondition,coefficient); + } + } + } + private void setXYNames(String xName, String yName) { + if (xMatrixName==null) { + xMatrixName = xName; + } else{ + if (!xMatrixName.equals(xName)) { + String msg = "xName for angle and maxdist needs to be the same, "+xMatrixName+"!="+xName; + logger.fatal(msg); + throw new RuntimeException(msg); + } + } + if (yMatrixName == null) { + yMatrixName = yName; + } else { + if (!yMatrixName.equals(yName)) { + String msg = "yName for angle and maxdist needs to be the same, "+yMatrixName+"!="+yName; + logger.fatal(msg); + throw new RuntimeException(msg); + } + } + } + /** + * Returns the myTour. + * @return CommercialTour + */ + public Tour getTour() { + return myTour; + } + public void init() { + if (myMatrixCacheReader==null) throw new RuntimeException("StopChoice needs an initialized Emme2MatrixReader before it can be initialized"); + readMatrices(myMatrixCacheReader); + } + + /** + * Method readMatrices. + * @param matrixReader + */ + public void readMatrices(MatrixCacheReader mr) { + travelUtilityFunction.readMatrices(mr); + destinationUtilityFunction.readMatrices(mr); + returnHomeUtilityFunction.readMatrices(mr); + zoneTypeUtilityFunction.readMatrices(mr); + if (sizeTerm != null) sizeTerm.readMatrices(mr); + if (xMatrixName != null) xMatrix = mr.readMatrix(xMatrixName); + if (yMatrixName!=null) yMatrix = mr.readMatrix(yMatrixName); + if (distanceMatrixName!=null) { + distanceMatrix = mr.readMatrix(distanceMatrixName); + } else { + logger.warn("Distance matrix name not specified, no maximum distance set"); + } + } + + /** + * Sets the myTour. + * @param myTour The myTour to set + */ + public void setTour(Tour myTour) { + this.myTour = myTour; + } + /*public static Boolean getUseTripModeChoice() { + return useTripModeChoice; + } + public static void setUseTripModeChoice(Boolean useTripModeChoice) { + StopChoice.useTripModeChoice = useTripModeChoice; + }*/ + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/Tour.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/Tour.java new file mode 100644 index 0000000..7ed78ef --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/Tour.java @@ -0,0 +1,290 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +/* + * Created on Feb 4, 2005 + * + */ +package org.sandag.cvm.activityTravel; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.apache.log4j.Logger; + +//import org.sandag.cvm.calgary.commercial.TourStartTimeModel; +//import org.sandag.cvm.calgary.commercial.WeekendTravelTimeTracker; +import org.sandag.cvm.activityTravel.cvm.TourStartTimeModel; +import org.sandag.cvm.common.model.DiscreteChoiceModelInterface; +import org.sandag.cvm.common.model.NoAlternativeAvailable; + + +/** + * @author jabraham + * + * This is a representation of a tour. + */ +public abstract class Tour implements TourInterface { + + public abstract ChangingTravelAttributeGetter getElapsedTravelTimeCalculator(); + public abstract TourStartTimeModel getTourStartTimeModel(); + +// @Override + public String toString() { + StringBuffer buff = new StringBuffer("Tour from "+originZone+" via "); + for (int i=0;istops is an ArrayList containing instances of Tour.Stop, one for each stop made on the tour + */ + protected ArrayList stops = new ArrayList(); + + private double tourStartTimeHrs = 0; + private double travelTimeMinutes; + + static Logger logger = Logger.getLogger(Tour.class); + + /** + * Adds a stop to the stops and alsu updates travelTimeMinutes and currentTimeHrs + * @param newStop + */ + protected void addStop(Stop newStop) { + int lastStopLocation = getOrigin(); + if (stops.size()!=0) lastStopLocation = ((Stop) stops.get(stops.size()-1)).location; + stops.add(newStop); + // TODO need to use trip mode not tour mode for travel time tracking. + // TODO should account for toll/non toll for travel time tracking (e.g. if toll is a trip mode.) + double legTravelTime = getElapsedTravelTimeCalculator().getTravelAttribute(lastStopLocation,newStop.location,currentTimeHrs,myVehicleTourType.getVehicleType()); + if (legTravelTime == 0 ) { + // a problem + logger.warn("Leg travel time is zero for "+lastStopLocation + " to " + newStop.location); + } + newStop.travelTimeMinutes=legTravelTime; + travelTimeMinutes+=legTravelTime; + currentTimeHrs += (legTravelTime/60 + newStop.duration); + } + + protected double calcCurrentTime() { + double travelTime =0; + double currentTimeCalc = getTourStartTimeHrs(); + Iterator stopIt = stops.iterator(); + int lastStop = getOriginZone(); + while (stopIt.hasNext()) { + Stop stop = (Stop) stopIt.next(); + // TODO need to use trip mode not tour mode for travel time tracking. + double legTravelTime = getElapsedTravelTimeCalculator().getTravelAttribute(lastStop,stop.location,currentTimeCalc,myVehicleTourType.getVehicleType()); + travelTime += legTravelTime; + currentTimeCalc += legTravelTime/60; + currentTimeCalc += stop.duration; + lastStop = stop.location; + } + return currentTimeCalc; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#getCurrentTimeHrs() + */ + public double getCurrentTimeHrs() { + return currentTimeHrs; + } + + /** + * Method getLastStopType. + * @return int + */ + public int getLastStopType() { + if (stops.size()==0) return 0; + Stop theLastStop = (Stop) stops.get(stops.size()-1); + return theLastStop.purpose; + } + + /** + * @return Returns the myVehicleTourType. + */ + public TourType getMyVehicleTourType() { + return myVehicleTourType; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#getOrigin() + */ + public int getOrigin() { + return getOriginZone(); + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#getOriginZone() + */ + public int getOriginZone() { + return originZone; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#getStopCount() + */ + public int[] getStopCounts() { + int[] stopCounter = new int[getMaxTourTypes()+1]; + Iterator stopIt = stops.iterator(); + while (stopIt.hasNext()) { + Stop stop = (Stop) stopIt.next(); + stopCounter[0]++; + stopCounter[stop.purpose]++; + } + return stopCounter; + } + + public abstract int getMaxTourTypes(); + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#getTotalElapsedTime() + */ + public double getTotalElapsedTimeHrs() { + return getCurrentTimeHrs()-getTourStartTimeHrs(); + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#getTotalTravelTimeMinutes() + */ + public double getTotalTravelTimeMinutes() { + return travelTimeMinutes; + } + + /** + * Method getTourStartTime. + * @return double + */ + protected double getTourStartTimeHrs() { + return tourStartTimeHrs; + } + + /** + * Method getTourTypeCode. + * @return A string grepresenting the type of tour -- perhaps representing the types + * of activities that occur in the tour. + */ + protected String getTourTypeCode() { + return myVehicleTourType.getCode().substring(1); + } + + /** + * Method getVehicleCode. + * @return a string representing the tNCVehicle code used for the tour + */ + protected String getVehicleCode() { + return myVehicleTourType.getCode().substring(0,1); + } + + /** + * @return Returns the vehicleTourTypeChoice. + */ + public abstract VehicleTourTypeChoice getVehicleTourTypeChoice(); + + /** + * Method sampleStartTime. + */ + public void sampleStartTime() { + tourStartTimeHrs = getTourStartTimeModel().sampleValue(); + if (stops.size()==0) currentTimeHrs = tourStartTimeHrs; + else currentTimeHrs = calcCurrentTime(); + + } + + /** + * This method uses a random number generator to sample the stops along the tour -- their location, + * duration and purpose. + */ + public abstract void sampleStops(); + + /** + * This method uses a random number generator to sample the type of tour, including + * the type of tNCVehicle(s) used for the tour and perhaps some information about the types + * of activities that occur along the tour. + */ + public void sampleVehicleAndTourType() { + getVehicleTourTypeChoice().setMyTour(this); + try { + myVehicleTourType = (TourType) getVehicleTourTypeChoice().monteCarloChoice(); + } catch (NoAlternativeAvailable e) { + myVehicleTourType = null; + //Leave it null for an error to occur when it's actually needed + } + } + + /** + * @param currentTimeHrs The currentTimeHrs to set. + */ + protected void setCurrentTimeHrs(double currentTimeHrs) { + this.currentTimeHrs = currentTimeHrs; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#setOrigin(int) + */ + public void setOrigin(int z) { + setOriginZone(z); + } + + void setOriginZone(int originZone) { + this.originZone = originZone; + } + + /** + * @param tourStartTimeHrs The time when the tour starts. + */ + protected void setTourStartTimeHrs(double tourStartTimeHrs) { + this.tourStartTimeHrs = tourStartTimeHrs; + } + + /** + * @param vehicleTourTypeChoice The vehicleTourTypeChoice to set. + */ + public abstract void setVehicleTourTypeChoice(VehicleTourTypeChoice vehicleTourTypeChoice); + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.TourInterface#getCurrentLocation() + */ + public int getCurrentLocation() { + if (stops.size()==0) return getOriginZone(); + Stop stop = (Stop) stops.get(stops.size()-1); + return stop.location; + } + + public abstract ChangingTravelAttributeGetter getTravelDisutilityTracker() ; + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourInterface.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourInterface.java new file mode 100644 index 0000000..c755573 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourInterface.java @@ -0,0 +1,61 @@ +package org.sandag.cvm.activityTravel; + +public interface TourInterface { + + /** + * Method getCurrentTime + * @deprecated + * @return double current time of day in hours + */ + public double getCurrentTimeHrs(); + + /** + * Method getCurrentTime + * @return double current time of day in minutes + */ + public double getCurrentTimeMinutes(); + + /** + * Method getOrigin. + * @return an int representing the origin location of the tour. + */ + public int getOrigin(); + + /** + * @return the integer representing the origin of the tour + */ + public int getOriginZone(); + + /** + * Method getStopCount. + * @return int[] an integer array counting the stops that occur by type. Element 0 + * is the total number of stops; other elements correspond to different stop purposes + */ + public int[] getStopCounts(); + + /** + * Method getTotalElapsedTime. + * @deprecated + * @return double total elapsed time in hours + */ + public double getTotalElapsedTimeHrs(); + + /** + * Method getTotalElapsedTime. + * @return double total elapsed time in hours + */ + public double getTotalElapsedTimeMinutes(); + + /** + * Method getTotalTravelTime. + * @return double total travel time in minutes + */ + public double getTotalTravelTimeMinutes(); + + /** + * Method getCurrentLocation. + * @return int + */ + public int getCurrentLocation(); + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourNextStopPurposeChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourNextStopPurposeChoice.java new file mode 100644 index 0000000..1ddaeaa --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourNextStopPurposeChoice.java @@ -0,0 +1,45 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +/* + * Created on 25-Feb-2005 + * + */ +package org.sandag.cvm.activityTravel; + +import org.sandag.cvm.common.model.DiscreteChoiceModelInterface; + + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public interface TourNextStopPurposeChoice extends DiscreteChoiceModelInterface { + /** + * sets the tour to be used for independent variables to influence the choice of next stop purpose + * @param myTour + */ + public abstract void setMyTour(Tour myTour); + /** + * @return the tour currently being used for information that influences the next stop purpose choice + */ + public abstract Tour getMyTour(); +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourType.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourType.java new file mode 100644 index 0000000..fefb6a1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TourType.java @@ -0,0 +1,115 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +/* + * Created on Feb 4, 2005 + * + */ +package org.sandag.cvm.activityTravel; + +/** + * @author jabraham + * + * This class is a representation of a type of tour. Contained it in + * are counters for the number of instances of the type of tour and trips + * as well as a choice model for choosing a tNCVehicle type for the tour. + * The class is identified by a name which is a String. + */ +public abstract class TourType { + + /** + * @param tourType a string representing the type of tour, which may also have information on tNCVehicle types + * @param vehicleType a char representing the type of tNCVehicle + * @param theChoiceModel the choice model associated with the tour type + */ + public TourType(String tourType, char vehicleType, VehicleTourTypeChoice theChoiceModel){ + myChoice = theChoiceModel; + this.tourTypeName = tourType; + this.vehicleType= vehicleType; + } + + /** + * tourCount is a counter for the number of tours of this type. + */ + protected int tourCount = 0; + protected int tripCount = 0; + + /** + * This class can serve as a place to keep track of the number of tours and trips of different types. + * This method increments the number of tours and trips. + * @param tours the number of tours to increment the tour counter by + * @param trips the number of trips to increment the trip counter by + */ + public void incrementTourAndTripCount(int tours, int trips) { + tourCount += tours; + tripCount += trips; + } + + /** + * tourTypeName is the unique identifier of the type of tour + */ + public final String tourTypeName; + /** + * vehicleType is the identifier for the tNCVehicle type used in the tour + */ + public final char vehicleType; + + /** + * @return the tourTypeName + */ + public String getCode() { + return getTourTypeName(); + } + + /** + * @return the tourTypeName + */ + public String getTourTypeName() { + return tourTypeName; + } + + /** + * @return the char representing the tNCVehicle type + */ + public char getVehicleType() { + return vehicleType; + } + + /** + * @return the utility of this alternative + */ + public abstract double getUtility(); + + /** + * @return Returns the tourCount. + */ + public int getTourCount() { + return tourCount; + } + + /** + * @return Returns the tripCount. + */ + public int getTripCount() { + return tripCount; + } + + protected final VehicleTourTypeChoice myChoice; + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TravelTimeTracker.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TravelTimeTracker.java new file mode 100644 index 0000000..14ef56a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TravelTimeTracker.java @@ -0,0 +1,117 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel; + +import java.util.ArrayList; +import java.util.Iterator; + +import org.sandag.cvm.activityTravel.ChangingTravelAttributeGetter; +import org.sandag.cvm.activityTravel.ModelUsesMatrices; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public abstract class TravelTimeTracker + implements ChangingTravelAttributeGetter, ModelUsesMatrices { + + protected final ArrayList travelTimeMatrices = new ArrayList(); + + + + public static class TravelTimeMatrixSpec { + final String name; + Matrix matrix; + final float startTime; + final float endTime; + final char vehicleType; + + public TravelTimeMatrixSpec(String name, float startTime, float endTime, char vehicleType) { + this.name = name; + this.startTime = startTime; + this.endTime=endTime; + this.vehicleType = vehicleType; + } + + /** + * Method readMatrices. + * @param matrixReader + */ + void readMatrices(MatrixCacheReader matrixReader) { + matrix = matrixReader.readMatrix(name); + } + + /** + * Method getTimeFromMatrix. + * @param origin + * @param destination + * @return double + * + * Note: modified to return 0 if value is greater than 99999 + */ + double getTimeFromMatrix(int origin, int destination) { + double value= matrix.getValueAt(origin,destination); + if((value>(-99999)) && (value<99999)) + return value; + else + return 0; + } + + + + } + + /** + * Method get. + * @param lastStop + * @param i + * @param currentTime + * @return double + */ + public double getTravelAttribute(int origin, int destination, double timeOfDay, char vehicleType) { + TravelTimeMatrixSpec defaultMatrix = null; + while (timeOfDay>=24.00) timeOfDay -=24.00; + for (int i =0; i=s.startTime && timeOfDay < s.endTime && s.vehicleType == vehicleType) return s.getTimeFromMatrix(origin,destination); + else if (s.startTime <0) defaultMatrix = s; + } + } + if (defaultMatrix==null) throw new RuntimeException("no default travel time matrix for tNCVehicle type "+vehicleType); + return defaultMatrix.getTimeFromMatrix(origin,destination); + } + + public void readMatrices(MatrixCacheReader matrixReader) { + Iterator it = travelTimeMatrices.iterator(); + while (it.hasNext()) { + TravelTimeMatrixSpec s = (TravelTimeMatrixSpec) it.next(); + s.readMatrices(matrixReader); + } + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TripMode.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TripMode.java new file mode 100644 index 0000000..4c0f205 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TripMode.java @@ -0,0 +1,74 @@ +package org.sandag.cvm.activityTravel; + +import org.sandag.cvm.common.emme2.MatrixCacheReader; + +public abstract class TripMode { + + /** + * First part of string is tNCVehicle type aka tour mode. + * Followed by a colon and then the trip mode. + * e.g L:T means tour "Light" and trip-mode "toll" + */ + protected final String myType; + protected final TripModeChoice myChoiceModel; + public final char vehicleType; + public final String tripMode; + protected int origin; + protected int destination; + protected double timeOfDay; + + public TripMode( + TripModeChoice choiceModel, + String type) { + myType = type; + myChoiceModel = choiceModel; + vehicleType = myType.split(":")[0].charAt(0); + tripMode = myType.split(":")[1]; + + } + + + public abstract double getUtility(); + + + public String getCode() { + return myType; + } + + public abstract void readMatrices(MatrixCacheReader matrixReader); + + public abstract void addCoefficient(String index1, String index2, + String matrix, double coefficient) throws CoefficientFormatError; + + public int getDestination() { + return destination; + } + + public void setDestination(int destination) { + this.destination = destination; + } + + public int getOrigin() { + return origin; + } + + public void setOrigin(int origin) { + this.origin = origin; + } + + public void setTime(double time) { + timeOfDay = time; + + } + + public String logOriginDestination() { + return String.valueOf(origin)+" to "+destination; + } + + public String getTripMode() { + return tripMode; + } + + + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TripModeChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TripModeChoice.java new file mode 100644 index 0000000..391a6eb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/TripModeChoice.java @@ -0,0 +1,96 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +/* + * Created on Feb 4, 2005 + * + */ +package org.sandag.cvm.activityTravel; + +import java.util.Iterator; + +import org.apache.log4j.Logger; + +import org.sandag.cvm.activityTravel.cvm.CommercialTripMode; +import org.sandag.cvm.common.emme2.MatrixAndTAZTableCache; +import org.sandag.cvm.common.model.Alternative; +import org.sandag.cvm.common.model.ChoiceModelOverflowException; +import org.sandag.cvm.common.model.DiscreteChoiceModelInterface; +import org.sandag.cvm.common.model.LogitModel; +import org.sandag.cvm.common.model.NoAlternativeAvailable; + + +/** + * @author jabraham + * + * A model of tNCVehicle type together with tour type + */ +public abstract class TripModeChoice implements ChangingTravelAttributeGetter { + + protected LogitModel myLogitModel = new LogitModel(); + + protected static Logger logger = Logger.getLogger(TripModeChoice.class); + + protected Tour theTour; + + /** + * @param myTour the tour to consider when making the tour type choice + */ + public void setMyTour(Tour myTour) { + theTour = myTour; + } + + + + /** + * @return the tour associated with the tour type choice + */ + public Tour getMyTour() { + return theTour; + } + + + + @Override + public double getTravelAttribute(int origin, int destination, double time, + char vehicleType) { + Iterator m = myLogitModel.getAlternativesIterator(); + while (m.hasNext()) { + TripMode tm = (TripMode) m.next(); + tm.setOrigin(origin); + tm.setDestination(destination); + tm.setTime(time); + } + return myLogitModel.getUtility(); + } + + + + public void readMatrices(MatrixAndTAZTableCache matrixReader) { + Iterator m = myLogitModel.getAlternativesIterator(); + while (m.hasNext()) { + CommercialTripMode tm = (CommercialTripMode) m.next(); + tm.readMatrices(matrixReader); + } + } + + + public abstract TripMode chooseTripModeForDestination(int location) throws ChoiceModelOverflowException, NoAlternativeAvailable; + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/VehicleTourTypeChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/VehicleTourTypeChoice.java new file mode 100644 index 0000000..d87ec63 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/VehicleTourTypeChoice.java @@ -0,0 +1,51 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +/* + * Created on Feb 4, 2005 + * + */ +package org.sandag.cvm.activityTravel; + +import org.sandag.cvm.common.model.DiscreteChoiceModelInterface; + + +/** + * @author jabraham + * + * A model of tNCVehicle type together with tour type + */ +public interface VehicleTourTypeChoice extends DiscreteChoiceModelInterface { + /** + * @param myTour the tour to consider when making the tour type choice + */ + public void setMyTour(Tour myTour); + + /** + * + */ + public void writeTourAndTripSummary(); + + /** + * @return the tour associated with the tour type choice + */ + Tour getMyTour(); + + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/ZonePairDisutility.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/ZonePairDisutility.java new file mode 100644 index 0000000..a2ffddd --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/ZonePairDisutility.java @@ -0,0 +1,7 @@ +package org.sandag.cvm.activityTravel; + +public interface ZonePairDisutility { + + public abstract double calcForIndex(int i, int j); + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/AlogitLogitModelNest.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/AlogitLogitModelNest.java new file mode 100644 index 0000000..6c04cf1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/AlogitLogitModelNest.java @@ -0,0 +1,21 @@ +package org.sandag.cvm.activityTravel.cvm; + +import org.sandag.cvm.common.model.LogitModel; + +public class AlogitLogitModelNest extends LogitModel { + + double nestingCoefficient = 1.0; + + public void setAlogitNestingCoefficient(double coefficient) { + nestingCoefficient = coefficient; + } + + @Override + public double getUtility() { + if (getDispersionParameter()!=1.0) { + throw new RuntimeException("Alogit nesting always needs a dispersion parameter of 1.0 in the lower level nests"); + } + return super.getUtility()*nestingCoefficient; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialNextStopChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialNextStopChoice.java new file mode 100644 index 0000000..c937cad --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialNextStopChoice.java @@ -0,0 +1,64 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel.cvm; + +import org.sandag.cvm.activityTravel.StopAlternative; +import org.sandag.cvm.activityTravel.StopChoice; +import com.pb.common.matrix.Matrix; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class CommercialNextStopChoice extends StopChoice { + + private String segmentId; + + /** + * Constructor for VehicleTypeChoice. + */ + + public CommercialNextStopChoice(int[] zoneNums, int notEqualToOrLowerThan, int notEqualToOrHigherThan, String segmentID) { + super(); + this.segmentId = segmentID; + for (int z = 1;z notEqualToOrLowerThan && theNumber < notEqualToOrHigherThan) { + this.addAlternative(new StopAlternative(this, zoneNums[z])); + } + } + } + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { + readMatrices(GenerateCommercialTours.matrixReader); + } + + @Override + public String toString() { + return "Stop choice for "+segmentId; + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialNextStopPurposeChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialNextStopPurposeChoice.java new file mode 100644 index 0000000..7409cc7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialNextStopPurposeChoice.java @@ -0,0 +1,249 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.activityTravel.cvm; + +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import org.sandag.cvm.common.model.LogitModel; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.MatrixReader; + +import java.util.*; + +import org.apache.log4j.Logger; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class CommercialNextStopPurposeChoice extends LogitModel implements ModelUsesMatrices, TourNextStopPurposeChoice { + + /** + * Constructor for VehicleTypeChoice. + */ + + final static int SERVICE = 1; + final static int GOODS = 2; + final static int OTHER = 3; + final static int RETURNTOORIGIN = 4; + private static Logger logger = Logger.getLogger(CommercialNextStopPurposeChoice.class); + + final char tourType; + + /** + * Constructor CommercialNextStopPurposeChoice. + * @param c + */ + public CommercialNextStopPurposeChoice(char c) { + if (c == 'S' || c == 's') this.addAlternative(new NextStopPurpose(SERVICE)); + if (c == 'G' || c == 'g') this.addAlternative(new NextStopPurpose(GOODS)); + this.addAlternative(new NextStopPurpose(OTHER)); + this.addAlternative(new NextStopPurpose(RETURNTOORIGIN)); + tourType = c; + } + + static String decodeStopPurpose(int s) { + if (s==SERVICE) return "Srv"; + if (s==GOODS) return "Gds"; + if (s==OTHER) return "Oth"; + if (s==RETURNTOORIGIN) return "Est"; + String msg = "Bad stop purpose code "+s; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + + private CommercialTour myTour; + + + public class NextStopPurpose implements AlternativeUsesMatrices { + double[] transitionConstants = {0,0,0,0}; + double[] stopCountCoefficients = {0,0,0,0}; + /** + * Constructor VehicleTypeAlternative. + * @param stopType + */ + public NextStopPurpose(int stopType) { + this.stopType = stopType; + } + + double constant = 0; + + final int stopType; + IndexLinearFunction previousStopUtility = new IndexLinearFunction(); + IndexLinearFunction originUtility = new IndexLinearFunction(); + IndexLinearFunction returnToOriginUtility = new IndexLinearFunction(); + double timeToOriginCoefficient = 0; + double disutilityToOriginCoefficient = 0; + double totalTravelTimeCoefficient = 0; + double totalTripTimeCoefficient = 0; + public double getUtility() { + double utility = previousStopUtility.calcForIndex(myTour.getCurrentLocation(),1); + utility += originUtility.calcForIndex(getMyTour().getOriginZone(),1); + int previousStopType= myTour.getLastStopType(); + utility += transitionConstants[previousStopType]; + int[] stopCounts = getMyTour().getStopCounts(); + // can't return home on first stop + if (stopCounts[0]==0 && stopType==RETURNTOORIGIN) utility += Double.NEGATIVE_INFINITY; + utility += stopCountCoefficients[0]*Math.log(stopCounts[0] +1) + + stopCountCoefficients[1]*Math.log(stopCounts[1]+1) + + stopCountCoefficients[2]*Math.log(stopCounts[2]+1) + + stopCountCoefficients[3]*Math.log(stopCounts[3]+1); + double returnHomeUtility = returnToOriginUtility.calcForIndex(myTour.getCurrentLocation(),getMyTour().getOriginZone()); + + // make people return home more -- Doug and Kevin Hack of Jan 5th + //if (myTour.getTotalElapsedTime()>240.0) returnHomeUtility *=3; + utility += returnHomeUtility; + + utility += totalTravelTimeCoefficient*getMyTour().getTotalTravelTimeMinutes(); + utility += totalTripTimeCoefficient*getMyTour().getTotalElapsedTimeHrs(); + utility += timeToOriginCoefficient*getMyTour().getElapsedTravelTimeCalculator().getTravelAttribute(myTour.getCurrentLocation(),getMyTour().getOrigin(),getMyTour().getCurrentTimeHrs(),getMyTour().getMyVehicleTourType().vehicleType); + utility += disutilityToOriginCoefficient*getMyTour().getTravelDisutilityTracker().getTravelAttribute(myTour.getCurrentLocation(),getMyTour().getOrigin(),getMyTour().getCurrentTimeHrs(),getMyTour().getMyVehicleTourType().vehicleType); + utility += constant; + return utility; + } + + /** + * Method addParameter. + * @param matrix + * @param coefficient + */ + public void addCoefficient(String index1, String index2, String matrix, double coefficient) throws CoefficientFormatError { + if(index1.equals("origin")) { + originUtility.addCoefficient(matrix,coefficient); + } else if (index1.equals("cstop")) { + if (index2.equals("origin")) returnToOriginUtility.addCoefficient(matrix,coefficient); + else previousStopUtility.addCoefficient(matrix,coefficient); + } else if (index1.equals("prevStopType")) { + if (index2.equals("goods")) transitionConstants[GOODS] = coefficient; + else if (index2.equals("service")) transitionConstants[SERVICE] = coefficient; + else if (index2.equals("other")) transitionConstants[OTHER] = coefficient; + else if (index2.equals("return")) transitionConstants[RETURNTOORIGIN]= coefficient; + else throw new RuntimeException("previous stop type not known: "+index2); + } else if (index1.equals("logStopCount")) { + if (index2.equals("goods")) stopCountCoefficients[GOODS] = coefficient; + else if (index2.equals("service")) stopCountCoefficients[SERVICE] = coefficient; + else if (index2.equals("other")) stopCountCoefficients[OTHER] = coefficient; + else if (index2.equals("all")) stopCountCoefficients[0] = coefficient; + else throw new RuntimeException("stop count type not known: "+index2); + } else if (index1.equals("timeAccumulator")) { + totalTravelTimeCoefficient += coefficient; + } else if (index1.equals("totalAccumulator")) { + totalTripTimeCoefficient += coefficient; + } else if (index1.equals("travelDisutility") && index2.equals("origin")) { + disutilityToOriginCoefficient += coefficient; + } else if (index1.equals("travelTime") && index2.equals("origin")) { + timeToOriginCoefficient += coefficient; + } else if (index1.equals("") && index2.equals("")) { + constant += coefficient; + } else { + throw new CoefficientFormatError("invalid indexing "+index1+ ","+index2+" in matrix "+matrix +" for next stop purpose model "); + } + } + + + + /** + * Method readMatrices. + * @param mr + */ + public void readMatrices(MatrixCacheReader mr) { + previousStopUtility.readMatrices(mr); + originUtility.readMatrices(mr); + returnToOriginUtility.readMatrices(mr); + } + + /** + * Method getStopPurposeCode. + * @return String + */ + public String getCode() { + if (stopType == SERVICE) return "S"; + if (stopType == OTHER) return "O"; + if (stopType == GOODS) return "G"; + if (stopType == RETURNTOORIGIN) return "R"; + return null; + } + + @Override + public String toString() { + return "StopPurpose:"+getCode(); + } + + + +} + + /** + * Method addParameter. + * @param alternative + * @param matrix + * @param coefficient + */ + public void addCoefficient( + String alternative, + String index1, + String index2, + String matrix, + double coefficient) throws CoefficientFormatError { + Iterator alternativeIterator = alternatives.iterator(); + boolean found = false; + while (alternativeIterator.hasNext()) { + AlternativeUsesMatrices alt = (AlternativeUsesMatrices) alternativeIterator.next(); + if (alternative.equals(alt.getCode())) { + alt.addCoefficient(index1,index2,matrix,coefficient); + found = true; + } + } + if (!found) throw new CoefficientFormatError("Bad alternative in next stop purpose choice model: "+alternative); + } + + /** + * Method readMatrices. + * @param matrixReader + */ + public void readMatrices(MatrixCacheReader matrixCacheReader) { + Iterator alternativeIterator = alternatives.iterator(); + while (alternativeIterator.hasNext()) { + AlternativeUsesMatrices alt = (AlternativeUsesMatrices) alternativeIterator.next(); + alt.readMatrices(matrixCacheReader); + } + } + + public void setMyTour(Tour myTour) { + this.myTour = (CommercialTour) myTour; + } + + public Tour getMyTour() { + return myTour; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { + readMatrices(GenerateCommercialTours.matrixReader); + } + + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTour.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTour.java new file mode 100644 index 0000000..279c3ba --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTour.java @@ -0,0 +1,328 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel.cvm; +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import org.sandag.cvm.common.model.*; + +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.PrintWriter; +import java.util.*; + +import org.apache.log4j.Logger; + +import com.pb.common.matrix.*; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class CommercialTour extends Tour { + + static Logger logger = Logger.getLogger(CommercialTour.class); + + + private final PrintWriter tripLog; + private Hashtable models; + private final GenerateCommercialTours generator; + + + +// private String myTripOutputMatrixName; +// Matrix emme2OutputMatrix; + + static class TripOutputMatrixSpec { + + final String name; + boolean write; + Matrix matrix; + final float startTime; + final float endTime; + final char vehicleType; + public final String tripMode; + + TripOutputMatrixSpec(String name, String type, float startTime, float endTime, char vehicleType, String tripMode) { + if (type.equals("tripOut")) { + write = true; + } else if (type.equals("timeDef")) { + write = false; + } else { + String msg = "Invalid type in index1 in TripMatrix "+type; + logger.fatal(msg); + throw new RuntimeException(msg); + } + this.name = name; + this.startTime = startTime; + this.endTime=endTime; + this.vehicleType = vehicleType; + this.tripMode = tripMode; + } + + @Override + public String toString() { + return "Outmatrix "+name+":"+vehicleType+"("+startTime+":"+endTime+")"; + } + + /** + * Method readMatrices. + * @param matrixReader + */ + void readMatrices(MatrixCacheReader matrixReader) { + matrix = null; + if (write) matrix = matrixReader.readMatrix(name); + } + + public void createMatrix(int size,int[] externalNumbers) { + matrix = new Matrix(name, "Trips for "+vehicleType+" between "+startTime+" and "+endTime,size,size); + matrix.setExternalNumbers(externalNumbers); + } + + } + + + + public CommercialTour(Hashtable models, GenerateCommercialTours generator, PrintWriter tripLog, int tourNumber) { + super(); + this.tripLog = tripLog; + this.generator = generator; + this.models = models; + tourNum = tourNumber; + } + + /** + * Method sampleVehicleAndTourType. + */ + public void sampleVehicleAndTourType() { + synchronized (generator.vehicleTourTypeChoice) { + generator.vehicleTourTypeChoice.setMyTour(this); + try { + myVehicleTourType = (TourType) generator.vehicleTourTypeChoice.monteCarloElementalChoice(); + myNextStopPurposeChoice = (CommercialNextStopPurposeChoice) models.get(myVehicleTourType.getCode()+"StopType"); + ((CommercialNextStopPurposeChoice) myNextStopPurposeChoice).setMyTour(this); + } catch (NoAlternativeAvailable e) { + throw new RuntimeException(e); + } + } + } + + /** + * Method addTripsToMatrix. + */ + public void addTripsToMatrix() { + int trips = 0; + Iterator stopIterator = stops.iterator(); + int lastLocation = getOriginZone(); + double currentTime = getTourStartTimeHrs(); + String prevStopType = "Est"; + while (stopIterator.hasNext()) { + Stop s = (Stop) stopIterator.next(); + trips ++; + int location = s.location; + // FIXME should take into account trip mode. + double legTravelTime = getElapsedTravelTimeCalculator().getTravelAttribute(lastLocation,location,currentTime,myVehicleTourType.getVehicleType()); + float midPointOfTripTime = (float) (currentTime + legTravelTime/60/2); + + String newStopType = CommercialNextStopPurposeChoice.decodeStopPurpose(s.purpose); + + String mNameForTripLog = "None"; + + TripOutputMatrixSpec spec = generator.getTripOutputMatrixSpec(getVehicleCode().charAt(0),s.tripMode,midPointOfTripTime); + if (spec!=null) { + mNameForTripLog = spec.name; + if (spec.write) { + synchronized(spec.matrix) { + // increment stop count in the matrix if this matrix is going to be written out + float mTripCountEntry = spec.matrix.getValueAt(lastLocation,location); + mTripCountEntry++; + spec.matrix.setValueAt(lastLocation,location,mTripCountEntry); + } + } + } + // write to trip log + if (tripLog !=null) { + tripLog.print("3,"+tourNum+",1,"+trips+",1,"+getOriginZone()+","+generator.segmentString1+","+prevStopType+","+newStopType+","+lastLocation+","+location+","+mNameForTripLog+","+getVehicleCode()+","+currentTime+","); + } + boolean tollAvailable = isTollAvailable(lastLocation,location,currentTime); + if (s.tripMode.equals("T") && !tollAvailable) { + logger.error("No toll available but toll chosen for "+s); + } + + currentTime += legTravelTime/60; + currentTime += s.duration; + if (tripLog !=null) { + tripLog.println(currentTime+","+s.duration+","+getTourTypeCode()+","+generator.segmentString2+","+s.tripMode+","+tollAvailable); + } + lastLocation = location; + prevStopType = newStopType; + } + myVehicleTourType.incrementTourAndTripCount(1,trips); + } + + /** + * Method sampleStops. + */ + public void sampleStops() { + ((CommercialNextStopPurposeChoice) myNextStopPurposeChoice).setMyTour(this); + CommercialNextStopChoice myNextStopModel; + do { + Stop thisStop = new Stop(this, getCurrentLocation(),getCurrentTimeHrs()); + Alternative temp; + try { + temp = myNextStopPurposeChoice.monteCarloChoice(); + } catch (NoAlternativeAvailable e) { + logger.fatal("no valid purpose alternative available for "+this, e); + throw new RuntimeException("no valid purpose alternative available for "+this, e); + } catch (RuntimeException e) { + logger.fatal("Cannot sample stops for "+this, e); + throw new RuntimeException("Cannot sample stops for "+this, e); + } + CommercialNextStopPurposeChoice.NextStopPurpose nextStopPurpose = (CommercialNextStopPurposeChoice.NextStopPurpose) temp; + thisStop.purpose=nextStopPurpose.stopType; + if (thisStop.purpose==CommercialNextStopPurposeChoice.RETURNTOORIGIN) { + thisStop.location=getOriginZone(); + chooseTripMode(thisStop); + addStop(thisStop); + break; + } + String nextStopModelCode = getVehicleCode()+getTourTypeCode()+nextStopPurpose.getCode() + "StopLocation"; + myNextStopModel = (CommercialNextStopChoice) models.get(nextStopModelCode); + if (myNextStopModel == null) throw new RuntimeException("Can't find stop model "+nextStopModelCode); + myNextStopModel.setTour(this); + try { + temp = myNextStopModel.monteCarloChoice(); + } catch (NoAlternativeAvailable e) { + logger.error("no valid location alternative available from "+this.toString()+" for "+generator.segmentString+" stop purpose "+nextStopModelCode); + throw new RuntimeException("no valid location alternative available from "+this.toString()); + } + thisStop.location = ((StopAlternative) temp).location; + DurationModel myDurationModel = (DurationModel) models.get(myVehicleTourType.getCode()+"Duration"); + thisStop.duration = (float) myDurationModel.sampleValue(); + chooseTripMode(thisStop); + addStop(thisStop); + } while (true); + } + + private void chooseTripMode(Stop thisStop) { + if (generator.isUseTripModes()) { + CommercialVehicleTripModeChoice tmc = (CommercialVehicleTripModeChoice) generator.getTravelDisutilityTracker(getVehicleCode()); + tmc.setMyTour(this); + TripMode m; + try { + m = (TripMode) tmc.chooseTripModeForDestination(thisStop.location); + } catch (ChoiceModelOverflowException | NoAlternativeAvailable e) { + String msg = "Can't sample trip mode for "+this; + logger.fatal(msg); + throw new RuntimeException(msg); + } + thisStop.tripMode=m.getCode().split(":")[1]; + } + } + + private boolean isTollAvailable(int origin, int destination, double timeOfDay) { + if (!generator.isUseTripModes()) { + return false; + } + CommercialVehicleTripModeChoice tmc = (CommercialVehicleTripModeChoice) generator.getTravelDisutilityTracker(getVehicleCode()); + tmc.setMyTour(this); + + return tmc.isTollAvailable(origin,destination,timeOfDay); + } + + /** + * Method getTourTypeCode. + * @return String + */ + public String getTourTypeCode() { + return myVehicleTourType.getCode().substring(1); + } + + + /** + * Method getVehicleCode. + */ + public String getVehicleCode() { + return myVehicleTourType.getCode().substring(0,1); + } + + + private int tourNum; + + + + + /** + * @return + */ + public int getOriginZoneType() { + return Math.round(generator.landUseTypeMatrix.getValueAt(getOriginZone(),1)); + } + + public ChangingTravelAttributeGetter getTravelDisutilityTracker() { + if (generator.isUseTripModes()) { + return generator.getTravelDisutilityTracker(getVehicleCode()); + } + return generator.getTravelDisutilityTracker(); + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.Tour#getMaxTourTypes() + */ + public int getMaxTourTypes() { + return 4; + } + + public double getCurrentTimeMinutes() { + return getCurrentTimeHrs()*60; + } + + public double getTotalElapsedTimeMinutes() { + return getTotalElapsedTimeHrs()*60; + } + + @Override + public VehicleTourTypeChoice getVehicleTourTypeChoice() { + // TODO Auto-generated method stub + return null; + } + + @Override + public void setVehicleTourTypeChoice( + VehicleTourTypeChoice vehicleTourTypeChoice) { + // TODO Auto-generated method stub + + } + + @Override + public ChangingTravelAttributeGetter getElapsedTravelTimeCalculator() { + // FIXME should use trip modes, like getTravelDisutilityTracker() does. + return generator.getElapsedTravelTimeCalculator(); + } + + @Override + public TourStartTimeModel getTourStartTimeModel() { + return generator.getTourStartTimeModel(); + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTravelTimeTracker.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTravelTimeTracker.java new file mode 100644 index 0000000..3a4be51 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTravelTimeTracker.java @@ -0,0 +1,77 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.activityTravel.cvm; + +import org.sandag.cvm.activityTravel.ChangingTravelAttributeGetter; +import org.sandag.cvm.activityTravel.CoefficientFormatError; +import org.sandag.cvm.activityTravel.ModelUsesMatrices; +import org.sandag.cvm.activityTravel.TravelTimeTracker; + + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class CommercialTravelTimeTracker extends TravelTimeTracker implements ModelUsesMatrices, ChangingTravelAttributeGetter { + + /** + * Method addCoefficient. + * @param alternative + * @param index1 + * @param index2 + * @param matrix + * @param coefficient + */ + public void addCoefficient ( + String alternative, + String index1, + String index2, + String matrix, + double coefficient) throws CoefficientFormatError + { + if (alternative.length()!=1) { + throw new CoefficientFormatError("Alternative must be L, M, I or H for TravelTimeMatrix"); + } + char vehicleType = alternative.charAt(0); + if (vehicleType!='L' && vehicleType!='M' && vehicleType!='H' && vehicleType != 'I') { + throw new CoefficientFormatError("Alternative must be L, M, I or H for TravelTimeMatrix"); + } + if (index1.equals("default")) { + travelTimeMatrices.add(new TravelTimeMatrixSpec(matrix, -1, -1, vehicleType)); + } else if (index1.equals("")) { + travelTimeMatrices.add(new TravelTimeMatrixSpec(matrix, Float.valueOf(index2).floatValue(), (float) coefficient, vehicleType)); + } else throw new CoefficientFormatError("Index1 must be \"default\" or blank for TravelTimeMatrices"); + } + + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { + readMatrices(GenerateCommercialTours.matrixReader); + } + + + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTripMode.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTripMode.java new file mode 100644 index 0000000..fb7816c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialTripMode.java @@ -0,0 +1,256 @@ +package org.sandag.cvm.activityTravel.cvm; + +import org.apache.log4j.Logger; + +import org.sandag.cvm.activityTravel.AlternativeUsesMatrices; +import org.sandag.cvm.activityTravel.CodedAlternative; +import org.sandag.cvm.activityTravel.CoefficientFormatError; +import org.sandag.cvm.activityTravel.TripMode; +import org.sandag.cvm.activityTravel.TripModeChoice; +import org.sandag.cvm.activityTravel.TravelTimeTracker.TravelTimeMatrixSpec; +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixCacheReader; + +public class CommercialTripMode extends TripMode implements CodedAlternative , AlternativeUsesMatrices { + + CommercialTravelTimeTracker noTollDistance = new CommercialTravelTimeTracker(); + CommercialTravelTimeTracker noTollTime = new CommercialTravelTimeTracker(); + CommercialTravelTimeTracker tollDistance = new CommercialTravelTimeTracker(); + CommercialTravelTimeTracker totalDistance = new CommercialTravelTimeTracker(); + CommercialTravelTimeTracker tollTime = new CommercialTravelTimeTracker(); + CommercialTravelTimeTracker tollCost = new CommercialTravelTimeTracker(); + private static Logger logger = Logger.getLogger(CommercialTripMode.class); + + CommercialVehicleTripModeChoice getMyCM() { + return (CommercialVehicleTripModeChoice) myChoiceModel; + } + + public CommercialTripMode( + CommercialVehicleTripModeChoice choiceModel, + String type) { + super(choiceModel, type); + try { + switch (myType) { + case "M:T": + case "M:NT": //uses light-heavy truck skims + noTollDistance.addCoefficient("M", "default", "", "traffic_skims_MD:MD_TRK_L_DIST", 0); + noTollDistance.addCoefficient("M", "", "6", "traffic_skims_AM:AM_TRK_L_DIST", 9); + noTollDistance.addCoefficient("M", "", "15.5", "traffic_skims_PM:PM_TRK_L_DIST", 19); + noTollTime.addCoefficient("M", "default", "", "traffic_skims_MD:MD_TRK_L_TIME", 0); + noTollTime.addCoefficient("M", "", "6", "traffic_skims_AM:AM_TRK_L_TIME", 9); + noTollTime.addCoefficient("M", "", "15.5", "traffic_skims_PM:PM_TRK_L_TIME", 19); + tollDistance.addCoefficient("M", "default", "", "traffic_skims_MD:MD_TRK_L_DIST", 0); + tollDistance.addCoefficient("M", "", "6", "traffic_skims_AM:AM_TRK_L_DIST", 9); + tollDistance.addCoefficient("M", "", "15.5", "traffic_skims_PM:PM_TRK_L_DIST", 19); + totalDistance.addCoefficient("M", "default", "", "traffic_skims_MD:MD_TRK_L_DIST", 0); + totalDistance.addCoefficient("M", "", "6", "traffic_skims_AM:AM_TRK_L_DIST", 9); + totalDistance.addCoefficient("M", "", "15.5", "traffic_skims_PM:PM_TRK_L_DIST", 19); + tollTime.addCoefficient("M", "default", "", "traffic_skims_MD:MD_TRK_L_TIME", 0); + tollTime.addCoefficient("M", "", "6", "traffic_skims_AM:AM_TRK_L_TIME", 9); + tollTime.addCoefficient("M", "", "15.5", "traffic_skims_PM:PM_TRK_L_TIME", 19); + tollCost.addCoefficient("M", "default", "", "traffic_skims_MD:MD_TRK_L_TOLLCOST", 0); + tollCost.addCoefficient("M", "", "6", "traffic_skims_AM:AM_TRK_L_TOLLCOST", 9); + tollCost.addCoefficient("M", "", "15.5", "traffic_skims_PM:PM_TRK_L_TOLLCOST", 19); + break; + case "H:T": + case "H:NT": //uses heavy-heavy truck skims + noTollDistance.addCoefficient("H", "default", "", "traffic_skims_MD:MD_TRK_H_DIST", 0); + noTollDistance.addCoefficient("H", "", "6", "traffic_skims_AM:AM_TRK_H_DIST", 9); + noTollDistance.addCoefficient("H", "", "15.5", "traffic_skims_PM:PM_TRK_H_DIST", 19); + noTollTime.addCoefficient("H", "default", "", "traffic_skims_MD:MD_TRK_H_TIME", 0); + noTollTime.addCoefficient("H", "", "6", "traffic_skims_AM:AM_TRK_H_TIME", 9); + noTollTime.addCoefficient("H", "", "15.5", "traffic_skims_PM:PM_TRK_H_TIME", 19); + tollDistance.addCoefficient("H", "default", "", "traffic_skims_MD:MD_TRK_H_DIST", 0); + tollDistance.addCoefficient("H", "", "6", "traffic_skims_AM:AM_TRK_H_DIST", 9); + tollDistance.addCoefficient("H", "", "15.5", "traffic_skims_PM:PM_TRK_H_DIST", 19); + totalDistance.addCoefficient("H", "default", "", "traffic_skims_MD:MD_TRK_H_DIST", 0); + totalDistance.addCoefficient("H", "", "6", "traffic_skims_AM:AM_TRK_H_DIST", 9); + totalDistance.addCoefficient("H", "", "15.5", "traffic_skims_PM:PM_TRK_H_DIST", 19); + tollTime.addCoefficient("H", "default", "", "traffic_skims_MD:MD_TRK_H_TIME", 0); + tollTime.addCoefficient("H", "", "6", "traffic_skims_AM:AM_TRK_H_TIME", 9); + tollTime.addCoefficient("H", "", "15.5", "traffic_skims_PM:PM_TRK_H_TIME", 19); + tollCost.addCoefficient("H", "default", "", "traffic_skims_MD:MD_TRK_H_TOLLCOST", 0); + tollCost.addCoefficient("H", "", "6", "traffic_skims_AM:AM_TRK_H_TOLLCOST", 9); + tollCost.addCoefficient("H", "", "15.5", "traffic_skims_PM:PM_TRK_H_TOLLCOST", 19); + break; + case "I:T": + case "I:NT": //use medium-heavy truck skims + noTollDistance.addCoefficient("I", "default", "", "traffic_skims_MD:MD_TRK_M_DIST", 0); + noTollDistance.addCoefficient("I", "", "6", "traffic_skims_AM:AM_TRK_M_DIST", 9); + noTollDistance.addCoefficient("I", "", "15.5", "traffic_skims_PM:PM_TRK_M_DIST", 19); + noTollTime.addCoefficient("I", "default", "", "traffic_skims_MD:MD_TRK_M_TIME", 0); + noTollTime.addCoefficient("I", "", "6", "traffic_skims_AM:AM_TRK_M_TIME", 9); + noTollTime.addCoefficient("I", "", "15.5", "traffic_skims_PM:PM_TRK_M_TIME", 19); + tollDistance.addCoefficient("I", "default", "", "traffic_skims_MD:MD_TRK_M_DIST", 0); + tollDistance.addCoefficient("I", "", "6", "traffic_skims_AM:AM_TRK_M_DIST", 9); + tollDistance.addCoefficient("I", "", "15.5", "traffic_skims_PM:PM_TRK_M_DIST", 19); + totalDistance.addCoefficient("I", "default", "", "traffic_skims_MD:MD_TRK_M_DIST", 0); + totalDistance.addCoefficient("I", "", "6", "traffic_skims_AM:AM_TRK_M_DIST", 9); + totalDistance.addCoefficient("I", "", "15.5", "traffic_skims_PM:PM_TRK_M_DIST", 19); + tollTime.addCoefficient("I", "default", "", "traffic_skims_MD:MD_TRK_M_TIME", 0); + tollTime.addCoefficient("I", "", "6", "traffic_skims_AM:AM_TRK_M_TIME", 9); + tollTime.addCoefficient("I", "", "15.5", "traffic_skims_PM:PM_TRK_M_TIME", 19); + tollCost.addCoefficient("I", "default", "", "traffic_skims_MD:MD_TRK_M_TOLLCOST", 0); + tollCost.addCoefficient("I", "", "6", "traffic_skims_AM:AM_TRK_M_TOLLCOST", 9); + tollCost.addCoefficient("I", "", "15.5", "traffic_skims_PM:PM_TRK_M_TOLLCOST", 19); + break; + case "L:T": + case "L:NT": //light vehicles use high-VOT auto skims + noTollDistance.addCoefficient("L", "default", "", "traffic_skims_MD:MD_SOV_NT_H_DIST", 0); + noTollDistance.addCoefficient("L", "", "6", "traffic_skims_AM:AM_SOV_NT_H_DIST", 9); + noTollDistance.addCoefficient("L", "", "15.5", "traffic_skims_PM:PM_SOV_NT_H_DIST", 19); + noTollTime.addCoefficient("L", "default", "", "traffic_skims_MD:MD_SOV_NT_H_TIME", 0); + noTollTime.addCoefficient("L", "", "6", "traffic_skims_AM:AM_SOV_NT_H_TIME", 9); + noTollTime.addCoefficient("L", "", "15.5", "traffic_skims_PM:PM_SOV_NT_H_TIME", 19); + tollDistance.addCoefficient("L", "default", "", "traffic_skims_MD:MD_SOV_TR_H_DIST", 0); + tollDistance.addCoefficient("L", "", "6", "traffic_skims_AM:AM_SOV_TR_H_DIST", 9); + tollDistance.addCoefficient("L", "", "15.5", "traffic_skims_PM:PM_SOV_TR_H_DIST", 19); + totalDistance.addCoefficient("L", "default", "", "traffic_skims_MD:MD_SOV_TR_H_DIST", 0); + totalDistance.addCoefficient("L", "", "6", "traffic_skims_AM:AM_SOV_TR_H_DIST", 9); + totalDistance.addCoefficient("L", "", "15.5", "traffic_skims_PM:PM_SOV_TR_H_DIST", 19); + tollTime.addCoefficient("L", "default", "", "traffic_skims_MD:MD_SOV_TR_H_TIME", 0); + tollTime.addCoefficient("L", "", "6", "traffic_skims_AM:AM_SOV_TR_H_TIME", 9); + tollTime.addCoefficient("L", "", "15.5", "traffic_skims_PM:PM_SOV_TR_H_TIME", 19); + tollCost.addCoefficient("L", "default", "", "traffic_skims_MD:MD_SOV_TR_H_TOLLCOST", 0); + tollCost.addCoefficient("L", "", "6", "traffic_skims_AM:AM_SOV_TR_H_TOLLCOST", 9); + tollCost.addCoefficient("L", "", "15.5", "traffic_skims_PM:PM_SOV_TR_H_TOLLCOST", 19); + break; + default: + logger.fatal("Invalid tNCVehicle type in trip mode choice model "+myType); + throw new RuntimeException("Invalid tNCVehicle type in trip mode choice model "+myType); + } + } catch (CoefficientFormatError e) { + logger.fatal("Problem setting up coefficeint for trip modes", e); + throw new RuntimeException("Problem setting up coefficient for trip modes", e); + } + } + + @Override + public double getUtility() { + double tollOptTotalDistance = totalDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + double tollPortion = 0; + if (tollOptTotalDistance >0) { + //tollPortion = tollDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType)/tollOptTotalDistance; + tollPortion=0; + } + double tollDisutility = 0; + switch (myType) { + // FIXME parameterize them in the .CSV file + case "L:NT": + return getMyCM().dispersionParam*( + -0.313*noTollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.138*noTollDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.01 *tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType)); + + + case "I:NT": + case "M:NT": + return getMyCM().dispersionParam*( + -0.313*noTollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.492*noTollDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.01 *tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType)); + + case "H:NT": + return getMyCM().dispersionParam*( + -0.313*noTollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.580*noTollDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.01 *tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType)); + // return -999.0; + case "L:T": + + //if(toll<0.01 || toll>99999) + return -999.0; + /* + double toll = tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + + tollDisutility = + -0.313*tollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.138*tollOptTotalDistance+ + -0.01 * toll; + return getMyCM().dispersionParam * tollDisutility + + getMyCM().portionParam * tollPortion; */ + case "I:T": + case "M:T": + + //if(toll<0.01 || toll>99999) + return -999.0; + /* + toll = tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + + tollDisutility = + -0.313*tollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.492*tollOptTotalDistance+ + -0.01 * tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + return getMyCM().dispersionParam * tollDisutility + + getMyCM().portionParam * tollPortion; + */ + case "H:T": + + //if(toll<0.01 || toll>99999) + return -999.0; + /* toll = tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + + tollDisutility = + -0.313*tollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + -0.580*tollOptTotalDistance+ + -0.01 * tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + return getMyCM().dispersionParam * tollDisutility + + getMyCM().portionParam * tollPortion; + */ + } + String msg = "Invalid tNCVehicle toll trip mode "+myType; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + @Override + public void readMatrices(MatrixCacheReader matrixReader) { + tollCost.readMatrices(matrixReader); + noTollTime.readMatrices(matrixReader); + noTollDistance.readMatrices(matrixReader); + tollDistance.readMatrices(matrixReader); + totalDistance.readMatrices(matrixReader); + tollTime.readMatrices(matrixReader); + } + + @Override + public void addCoefficient(String index1, String index2, String matrix, + double coefficient) throws CoefficientFormatError { + logger.warn("Ignoring coefficeiint "+index1+" "+index2+" "+matrix+" "+coefficient+", trip mode matrix coefficients are still hardcoded"); + } + + public double getTollDistance() { + return tollDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + } + + public Double getTollTime() { + return tollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + } + + public Double getNonTollTime() { + return noTollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + } + + public String reportAttributes() { + switch (myType) { + // FIXME parameterize them in the .CSV file + case "L:NT": + case "I:NT": + case "M:NT": + case "H:NT": + return "time:"+noTollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + " dist:"+noTollDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + case "L:T": + case "I:T": + case "M:T": + case "H:T": + return "time:"+tollTime.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + " dist:"+totalDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + " tolldist:"+tollDistance.getTravelAttribute(origin, destination, timeOfDay, vehicleType)+ + " toll:"+tollCost.getTravelAttribute(origin, destination, timeOfDay, vehicleType); + } + logger.fatal("Oops invalid trip mode for reportATtributes()"); + throw new RuntimeException("Oops invalid trip mode for reportATtributes()"); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialVehicleTourType.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialVehicleTourType.java new file mode 100644 index 0000000..9a15850 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialVehicleTourType.java @@ -0,0 +1,112 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +/* + * Created on Feb 4, 2005 + * + */ +package org.sandag.cvm.activityTravel.cvm; + +import java.util.Enumeration; +import java.util.Hashtable; + +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; + + +public class CommercialVehicleTourType extends TourType implements AlternativeUsesMatrices { + public CommercialVehicleTourType(CommercialVehicleTourTypeChoice choice, String vehicleTourType) { + super (vehicleTourType, vehicleTourType.charAt(0), (VehicleTourTypeChoice) choice); + myId = vehicleTourType; + } + + final String myId; + + + + @Override + public String toString() { + return "VehicleTourType:"+myId; + + } + + /** + * Method readMatrices. + * @param mr + */ + public void readMatrices(MatrixCacheReader mr) { + utilityFunction.readMatrices(mr); + Enumeration it = conditionalUtilityFunctions.elements(); + while (it.hasMoreElements()) { + IndexLinearFunction bob = (IndexLinearFunction) it.nextElement(); + bob.readMatrices(mr); + } + } + + + + + IndexLinearFunction utilityFunction = new IndexLinearFunction(); + Hashtable conditionalUtilityFunctions = new Hashtable(); + + class TripOutputMatrixSpec { + String name; + Matrix matrix; + float startTime; + float endTime; + } + + public double getUtility() { + double utility = utilityFunction.calcForIndex(this.myChoice.getMyTour().getOriginZone(),1); + Integer myZoneType = new Integer(((CommercialTour) this.myChoice.getMyTour()).getOriginZoneType()); + ZonePairDisutility uf = (ZonePairDisutility) conditionalUtilityFunctions.get(myZoneType); + if (uf != null) { + utility += uf.calcForIndex(this.myChoice.getMyTour().getOriginZone(),1); + } + return utility; + } + + public void addCoefficient(String index1, String index2, String matrix, double coefficient) { + if (index1.equals("origin")) { + utilityFunction.addCoefficient(matrix,coefficient); + } else if (index1.equals("originLU") || index1.equals("originConstant")){ + Integer luCondition = Integer.valueOf(index2); + IndexLinearFunction conditionalUtilityFunction = (IndexLinearFunction) conditionalUtilityFunctions.get(luCondition); + if (conditionalUtilityFunction == null) { + conditionalUtilityFunction = new IndexLinearFunction(); + conditionalUtilityFunctions.put(luCondition,conditionalUtilityFunction); + } + if (index1.equals("originConstant")) { + conditionalUtilityFunction.addConstant(coefficient); + } else if (index1.equals("originLU")) { + conditionalUtilityFunction.addCoefficient(matrix,coefficient); + } + }else if (index1.equals("")) { + utilityFunction.addConstant(coefficient); + } else { + throw new RuntimeException("Invalid index1 for alternative "+getCode()); + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialVehicleTourTypeChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialVehicleTourTypeChoice.java new file mode 100644 index 0000000..1715143 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/CommercialVehicleTourTypeChoice.java @@ -0,0 +1,238 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.activityTravel.cvm; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Enumeration; +import java.util.Hashtable; +import java.util.Iterator; + +import org.apache.log4j.Logger; + +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import org.sandag.cvm.common.model.Alternative; +import org.sandag.cvm.common.model.LogitModel; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class CommercialVehicleTourTypeChoice extends LogitModel implements ModelUsesMatrices, VehicleTourTypeChoice { + + ArrayList alternativesWaitingToBeAddedToNestingStructure = new ArrayList(); + ArrayList allElementalAlternatives = new ArrayList(); + + private void addAlternativeInitially(CommercialVehicleTourType a) { + alternativesWaitingToBeAddedToNestingStructure.add(a); + allElementalAlternatives.add(a); + } + + /** + * Constructor for VehicleTypeChoice. + * @param types + */ + + // tour types are LS,LG,LO,MS,MG,MO,HS,HG,HO + public CommercialVehicleTourTypeChoice(String[] types, boolean nesting) { + super(); + for (String type : types) { + addAlternativeInitially(new CommercialVehicleTourType(this, type)); + } + if (!nesting) { + // no nesting structure specified + for (String type : types ) { + setUpNestingElement(type,"top",1.0); + } + } + + } + + private CommercialTour myTour; + private static Logger logger = Logger.getLogger(CommercialVehicleTourTypeChoice.class); + + /** + * Method addParameter. + * + * @param alternative + * @param matrix + * @param coefficient + * @throws CoefficientFormatError + */ + public void addCoefficient(String alternative, String index1, + String index2, String matrix, double coefficient) + throws CoefficientFormatError { + // if index1 is "nest" we will set up a nesting structure. + if (index1.equalsIgnoreCase("nest")) { + setUpNestingElement(alternative, matrix, coefficient); + } else { + boolean found = false; + Iterator myAltsIterator = allElementalAlternatives.iterator(); + while (myAltsIterator.hasNext()) { + Alternative alt = (Alternative) myAltsIterator.next(); + CommercialVehicleTourType vtt = (CommercialVehicleTourType) alt; + if (vtt.getCode().equals(alternative)) { + vtt.addCoefficient(index1, index2, matrix, coefficient); + found = true; + } + } + if (!found) throw new RuntimeException("can't find alternative "+alternative+" in vehicleTourType model"); + } + } + + private void setUpNestingElement(String alternativeName, String nestName, double coefficient) { + boolean found = false; + // first check if an elemental alternative; + for (int i=0;i myAltsIterator = myLogitModel.getAlternativesIterator(); + while (myAltsIterator.hasNext()) { + Alternative alt = myAltsIterator.next(); + CommercialTripMode tm = (CommercialTripMode) alt; + if (tm.getCode().equals(alternative)) { + tm.addCoefficient(index1, index2, matrix, coefficient); + found = true; + } + } + if (!found) { + if (index1.equalsIgnoreCase("dispersion")) { + dispersionParam = coefficient; + } else if (index1.equalsIgnoreCase("portion")) { + portionParam = coefficient; + } else { + throw new RuntimeException("can't find alternative "+alternative+" in TripMode model"); + } + } + } + + + /** + * Method readMatrices. + * @param matrixReader + */ + public void readMatrices(MatrixCacheReader matrixCacheReader) { + Iterator myAltsIterator = myLogitModel.getAlternativesIterator(); + while (myAltsIterator.hasNext()) { + CommercialTripMode tm = (CommercialTripMode) myAltsIterator.next(); + tm.readMatrices(matrixCacheReader); + } + } + + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { + readMatrices(GenerateCommercialTours.matrixReader); + } + + @Override + public TripMode chooseTripModeForDestination(int location) + throws ChoiceModelOverflowException, NoAlternativeAvailable { + CommercialTripMode choice = (CommercialTripMode) debugChooseTripModeForDestination(location); + if (choice.getTripMode().equals("T")) { + // going to check if any tolls are actually paid + double tollDistance = choice.getTollDistance(); + if (tollDistance ==0) { + // get the non toll alternative + Iterator it = myLogitModel.getAlternativesIterator(); + while (it.hasNext()) { + CommercialTripMode tm = (CommercialTripMode) it.next(); + if (tm.getTripMode().equals("NT")) { + choice = tm; + break; + } + } + } else { + // logTollTripChoice(); turn this off for now + } + } + return choice; + } + + + public TripMode debugChooseTripModeForDestination(int location) + throws ChoiceModelOverflowException, NoAlternativeAvailable { + /*// delete this debug stuff + Double tollTime = null; + Double nTollTime = null; + */ + + Iterator m = myLogitModel.getAlternativesIterator(); + while (m.hasNext()) { + CommercialTripMode tm = (CommercialTripMode) m.next(); + tm.setOrigin(getMyTour().getCurrentLocation()); + tm.setDestination(location); + tm.setTime(getMyTour().getCurrentTimeHrs()); + + /* delete this debug stuff + if (tm.getTripMode().equals("T")) { + tollTime = tm.getTollTime(); + } + if (tm.getTripMode().equals("NT")) { + nTollTime = tm.getNonTollTime(); + }*/ + } + + /* delete this debug stuff + if (tollTime==null || nTollTime==null) { + String msg = "Oops couldn't extract toll and non toll times for debugging purposes"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + if (nTollTime < tollTime ) { + logger.warn("nTollTime is less than tollTime for "+getMyTour().getCurrentLocation()+" to "+location); + } + if (nTollTime - tollTime > 5) { + // 5 minute savings! Check it out + logger.info("5 minute savings taking the toll road from "+getMyTour().getCurrentLocation()+" to "+location); + } + */ + return (TripMode) myLogitModel.monteCarloChoice(); + } + + + + protected void logTollTripChoice() { + + StringBuffer msg = new StringBuffer("Toll chosen:"); + msg.append(((CommercialTripMode) myLogitModel.alternativeAt(0)).logOriginDestination()); + msg.append(" for "); + msg.append(theTour.getMyVehicleTourType()); + msg.append(" "); + double utility1= ((CommercialTripMode) myLogitModel.alternativeAt(0)).getUtility(); + double utility2 = ((CommercialTripMode) myLogitModel.alternativeAt(1)).getUtility(); + double prob = Math.exp(utility1)/(Math.exp(utility2)+Math.exp(utility1)); + msg.append(((CommercialTripMode)myLogitModel.alternativeAt(0)).getTripMode()+" prob "+prob+" {"); + msg.append(((CommercialTripMode) myLogitModel.alternativeAt(0)).reportAttributes()); + msg.append(" or "); + msg.append(((CommercialTripMode) myLogitModel.alternativeAt(1)).reportAttributes()); + msg.append("}"); + logger.info(msg); + + } + + + public boolean isTollAvailable(int origin, int destination, double timeOfDay) { + Iterator it = myLogitModel.getAlternativesIterator(); + while (it.hasNext()) { + CommercialTripMode tm = (CommercialTripMode) it.next(); + tm.setOrigin(origin); + tm.setDestination(destination); + tm.setTime(timeOfDay); + if (tm.tripMode.equals("T")) { + if (tm.getTollDistance() ==0) return false; + } else { + return true; + } + } + throw new RuntimeException("No toll option for trip, can't report whether toll was actually available "); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/DurationModel2.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/DurationModel2.java new file mode 100644 index 0000000..068aeb5 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/DurationModel2.java @@ -0,0 +1,49 @@ +package org.sandag.cvm.activityTravel.cvm; + +import org.sandag.cvm.activityTravel.CoefficientFormatError; +import org.sandag.cvm.activityTravel.DurationModel; + +public class DurationModel2 extends DurationModel { + + int functionalForm; + static boolean durationInMinutes = false; + + @Override + public void addCoefficient(String alternative, String index1, String index2, String matrix, double coefficient) throws CoefficientFormatError { + if(index1.equals("functionForm")) { + if (index2.equals("power")) functionalForm =1; + else if (index2.equals("cubic")) functionalForm = 2; + else if (index2.equals("exponential")) functionalForm = 3; + else if (index2.equals("addedexponential")) functionalForm = 0; + else throw new CoefficientFormatError("functionalForm for tour start model must have index2 as \"power\", \"cubic\" or \"exponential\""); + } else { + super.addCoefficient(alternative, index1, index2, matrix, coefficient); + } + } + + @Override + public double sampleValue() { + double y=0; + double x = Math.random(); + switch (functionalForm) { + case 0: + y = super.sampleValue(); + break; + case 1: + y = a * Math.pow(x,b)+c*Math.pow(x,d) + e * x + f; + break; + case 2: + y = a+b*x+c*x*x+d*x*x*x; + break; + case 3: + y = c*Math.exp(a*x+b)+d; + break; + default: + throw new RuntimeException("Functional form for duration model must be 0,1,2 or 3"); + } + if (durationInMinutes) y=y/60; + if (y<0) y =0; + if (y>24) y = 24; + return y; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/GenerateCommercialTours.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/GenerateCommercialTours.java new file mode 100644 index 0000000..6be0c18 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/GenerateCommercialTours.java @@ -0,0 +1,855 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + + */ + +package org.sandag.cvm.activityTravel.cvm; + +/** + * @author John Abraham + * + * (c) 2003-2010 John Abraham + */ + +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixAndTAZTableCache; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import org.sandag.cvm.common.skims.HDF5MatrixReader; +import org.sandag.cvm.common.skims.OMXMatrixCollectionReader; +import org.sandag.cvm.common.skims.TranscadMatrixCollectionReader; +import org.sandag.cvm.common.datafile.CSVFileReader; +import org.sandag.cvm.common.datafile.TableDataSet; + +import com.pb.common.matrix.*; +import com.pb.common.util.ResourceUtil; + +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.activityTravel.cvm.CommercialTour.TripOutputMatrixSpec; + +import java.io.*; +import java.sql.*; +import java.util.*; +import java.util.concurrent.Callable; +import java.util.concurrent.ExecutionException; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.Future; + +import org.apache.log4j.Logger; + + +public class GenerateCommercialTours implements Runnable, Callable { + + private static Logger logger = Logger.getLogger(GenerateCommercialTours.class); + public static MatrixAndTAZTableCache matrixReader; + public static ResourceBundle propsResource; + + final ArrayList tripOutputMatrices = new ArrayList(); + final String segmentString; + final String segmentString1; + final String segmentString2; + + + public GenerateCommercialTours(String genColumn, boolean useTripModes) { + segmentString = genColumn; + String[] strings = genColumn.split("_"); + if (strings.length>0) segmentString1 = strings[0]; + else segmentString1 = ""; + if (strings.length>1) segmentString2 = strings[1]; + else segmentString2 = ""; + this.useTripModes = useTripModes; + } + + /** + * Generate commercial tours for Calgary EMME/2 model + * @param args is six strings, location of databank, location of coefficients file, name of coefficients file, minZone,maxZone, anyOldMatrixName + */ + public static void main(String[] args) { + + // check arguments + if (args.length != 1) { + System.out.println("Usage: java "+GenerateCommercialTours.class.getCanonicalName()+" propertiesFileName"); + throw new RuntimeException("Usage: java "+GenerateCommercialTours.class.getCanonicalName()+" propertiesFileName"); + } + try { + + try { + // basic setup of connections, variables, readers and the like + setupStaticData(args); + + //DurationModel2.durationInMinutes=ResourceUtil.getBooleanProperty(propsResource,"DurationInMinutes", false); + //TourStartTimeModel.startTimeInMinutes=ResourceUtil.getBooleanProperty(propsResource, "StartTimeInMinutes", false); + DurationModel2.durationInMinutes=silentlyCheckBooleanProperty(propsResource,"DurationInMinutes",false); + TourStartTimeModel.startTimeInMinutes=silentlyCheckBooleanProperty(propsResource, "StartTimeInMinutes",false); + + zones = zonalAttributes.getColumnAsInt(zonalAttributes.checkColumnPosition("TAZ")); + + String[] vehTypes = ResourceUtil.checkAndGetProperty(propsResource, "FirstPart").split(","); + String[] timePeriods = ResourceUtil.checkAndGetProperty(propsResource, "SecondPart").split(","); + ArrayList segmentRunners = new ArrayList(); + + if (ResourceUtil.getProperty(propsResource, "RunZones")!=null) { + logger.info("Setting up Run Zones "+ResourceUtil.getProperty(propsResource, "RunZones")); + setUpValidZones(ResourceUtil.getProperty(propsResource, "RunZones")); + } + /*if (ResourceUtil.getProperty(propsResource, "ExcludeZones")!=null) { + logger.info("Excluding Zones "+ResourceUtil.getProperty(propsResource, "ExcludeZones"); + excludeZones(ResourceUtil.getProperty(propsResource, "ExcludeZones")); + }*/ + TreeMap createdMatrices = new TreeMap(); + for (String vehType : vehTypes) { + for (String timePeriod : timePeriods) { + String genColumn = vehType + "_"+ timePeriod; + if (timePeriod.equals("")) { + genColumn = vehType; + timePeriod = null; + } + GenerateCommercialTours generator = new GenerateCommercialTours(genColumn, ResourceUtil.getBooleanProperty(propsResource, "UseTripModes")); + segmentRunners.add(generator); + generator.buildModelStructure(zones,minZone,maxZone,propsResource); + generator.generationEquation = new IndexLinearFunction(); + generator.prevGenerationEquation = new IndexLinearFunction(); + + // read the coefficients and make sure all the data is read in. + try { + readCoefficientFiles(csvInputFileReader, vehType, timePeriod); + } catch (IOException e) { + String msg = "Error reading coefficeint files "+vehType+" and "+timePeriod+ " from "+ResourceUtil.checkAndGetProperty(propsResource,"CSVFileLocation"); + logger.fatal(msg,e); + throw new RuntimeException(msg,e); + } + generator.setUpCoefficients(args, coefficients); + if (coefficients2!=null) generator.setUpCoefficients(args, coefficients2); + + // TODO move this to coefficent file + generator.setUpDisutilityGetters(); + + if (ResourceUtil.getBooleanProperty(propsResource, "UseSegmentNameInGeneration",true)) { + generator.generationEquation.addCoefficient(genColumn,1); + } + + String tripLogPath = ResourceUtil.getProperty(propsResource, "TripLogPath"); + if (tripLogPath !=null) { + if (!tripLogPath.equals("")) { + String tripLogFile = tripLogPath + + "Trip_"+genColumn+".csv"; + + generator.openTripLog(new File(tripLogFile)); + } + } + generator.readMatrices(); + if (ResourceUtil.getBooleanProperty(propsResource,"ReadOutputMatrices",true)) { + generator.readOutputMatrices(matrixReader); + } else { + generator.createEmptyOutputMatrices(matrixReader.getDim2MatrixSize(),matrixReader.getDim2MatrixExternalNumbers(),createdMatrices); + } + generator.landUseTypeMatrix = matrixReader.readMatrix(generator.landUseTypeMatrixName); + + + } + } + + int nThreads = ResourceUtil.getIntegerProperty(propsResource, "nThreads",8); + + threadpool = Executors.newFixedThreadPool(nThreads); + + List> runners; + try { + runners = threadpool.invokeAll(segmentRunners); + for (Future runner : runners) { + runner.get(); + } + } catch (InterruptedException e) { + logger.fatal("Thread was interrupted",e); + throw new RuntimeException("Thread was interrupted",e); + } catch (ExecutionException e) { + logger.fatal("Exception in one segment",e); + throw new RuntimeException("Exception in one segment",e); + } + + int totalTours = 0; + int totalTrips = 0; + for (GenerateCommercialTours generator : segmentRunners) { + totalTours += generator.totalTours; + totalTrips += generator.totalTrips; + logger.info("Trips for segment "+generator.segmentString); + generator.vehicleTourTypeChoice.writeTourAndTripSummary(); + } + + + logger.info("finished generating "+totalTours+" tours and "+totalTrips+" trips"); + + MatrixWriter writer = null; + if (ResourceUtil.getBooleanProperty(propsResource, "WriteEmmeApiMatrices",false)) { + try { + writer = setUpEmmeApiWriter(); + writeAllMatrices(writer,segmentRunners); + } finally { + if (writer !=null) { + try { + ((EmmeApiMatrixWriter) writer).close(); + } catch (IOException e) { + // oh well + } + } + } + } else if (ResourceUtil.getBooleanProperty(propsResource, "WriteDirectEmmeMatrices",false)) { + //writer = new Emme2MatrixWriter(file) + //writeMatrices(writer); + logger.error("WriteDirectEmmeMatrices is no longer supported, please use WriteEmmeApiMatrices instead. Matrices not written out!"); + } else if (ResourceUtil.getProperty(propsResource, "CSVOutputFileLocation")!=null) { + writer = new CSVMatrixWriter(new File(ResourceUtil.getProperty(propsResource, "CSVOutputFileLocation"))); + writeAllMatrices(writer, segmentRunners); + } else if (ResourceUtil.getProperty(propsResource, "TranscadCVMMatrixFile")!=null) { + writer = new TranscadMatrixWriter(new File(ResourceUtil.getProperty(propsResource, "TranscadCVMMatrixFile"))); + writeAllMatrices(writer, segmentRunners); + } else { + writer = new CSVMatrixWriter(new File(ResourceUtil.getProperty(propsResource, "CSVFileLocation")+File.pathSeparator+"TripMatrices.csv")); + writeAllMatrices(writer,segmentRunners); + } + + logger.info("Finished writing matrices"); + + + } catch (Throwable e) { + logger.fatal("Error in CVM program", e); + } + } finally { + if (threadpool!=null) { + threadpool.shutdown(); + } + if (matrixReader!=null) { + MatrixReader actualReader = matrixReader.getActualReader(); + if (actualReader instanceof EmmeApiMatrixReader) { + try { + ((EmmeApiMatrixReader) actualReader).close(); + } catch (IOException e) { + logger.warn("IOException trying to close EmmeApiMatrixReader",e); + } + } + } + } + } + + + + private static boolean silentlyCheckBooleanProperty( + ResourceBundle propsResource2, String name, boolean defaultVal) { + String str = ResourceUtil.getProperty(propsResource2, name); + if (str==null) return defaultVal; + if (str.equals("")) return defaultVal; + if (str.equalsIgnoreCase("True")) return true; + if (str.equalsIgnoreCase("False")) return false; + logger.error(name + "property should be boolean, it is "+name); + return defaultVal; + } + + private HashMap travelDisutilityTrackers = null; + + private void readMatrices() { + Iterator modelIterator = models.values().iterator(); + while (modelIterator.hasNext()) { + ModelUsesMatrices model = (ModelUsesMatrices) modelIterator.next(); + model.readMatrices(matrixReader); + } + generationEquation.readMatrices(matrixReader); + prevGenerationEquation.readMatrices(matrixReader); + } + + VehicleTourTypeChoice vehicleTourTypeChoice; + private final boolean useTripModes; + /** + * @return Returns the vehicleTourTypeChoice. + */ + public VehicleTourTypeChoice getVehicleTourTypeChoice() { + return vehicleTourTypeChoice; + } + + /** + * @param vehicleTourTypeChoice The vehicleTourTypeChoice to set. + */ + public void setVehicleTourTypeChoice(VehicleTourTypeChoice vehicleTourTypeChoiceParam) { + vehicleTourTypeChoice = vehicleTourTypeChoiceParam; + } + + + + private void generateTheTours() { + vehicleTourTypeChoice=(CommercialVehicleTourTypeChoice) models.get("VehicleTourType"); + setTourStartTimeModel((TourStartTimeModel) models.get("TourStartTime")); + setElapsedTravelTimeCalculator((CommercialTravelTimeTracker) models.get("TravelTimeMatrix")); + totalTours = 0; + int oldTotalTours = 0; + totalTrips = 0; + System.out.println("Generating tours..."); + for (int z = 1;z 100) { + String msg = null; + if (totalTours - oldTotalTours == tours) + msg = "Generating "+tours+" "+segmentString+" tours in zone "+zone+" ... "; + else + msg = "Generated "+(totalTours - oldTotalTours)+" "+segmentString+"tours, including "+tours+" currently being generated in zone "+zone; + logger.info(msg); + oldTotalTours = totalTours; + } + int tripCount = 0; + for (int tour = 0; tour < tours; tour ++) { + CommercialTour t = new CommercialTour(models,this,tripLog,getNextTourNumber()); + t.setOrigin(zone); + t.sampleStartTime(); + t.sampleVehicleAndTourType(); + t.sampleStops(); + t.addTripsToMatrix(); + tripCount += t.getStopCounts()[0]; + } + if (logger.isDebugEnabled()) logger.debug(tripCount+" trips generated from "+segmentString+" tours in zone "+zone+" ... "); + totalTrips += tripCount; + } + + } + } + + private void setUpDisutilityGetters() { + if (isUseTripModes()) { + // TODO this shouldn't be hardcoded + HashMap trackers = new HashMap(); + trackers.put("L", (ChangingTravelAttributeGetter) models.get("TripModeL")); + trackers.put("I", (ChangingTravelAttributeGetter) models.get("TripModeI")); + trackers.put("M", (ChangingTravelAttributeGetter) models.get("TripModeM")); + trackers.put("H", (ChangingTravelAttributeGetter) models.get("TripModeH")); + setTravelDisutilityTrackers(trackers); + } else { + HashMap trackers = new HashMap(); + trackers.put("",((CommercialTravelTimeTracker) models.get("TravelDisutilityMatrix"))); + } + } + + static TreeSet zoneSet = null; + + private boolean isValidZone(int zone) { + if (zone maxZone) return false; + if (zoneSet==null) return true; + if (zoneSet.contains(zone)) return true; + return false; + } + + + private static void setUpValidZones(String property) { + String[] zoneIds = property.split(","); + zoneSet = new TreeSet(); + for (String zoneId : zoneIds) { + zoneSet.add(Integer.valueOf(zoneId)); + } + } + + + + private static void setupStaticData(String[] args) { + try { + propsResource = new PropertyResourceBundle(new FileInputStream(args[0])); + } catch (FileNotFoundException e2) { + logger.fatal("Can't find file "+args[0]); + throw new RuntimeException("Can't find file "+args[0], e2); + } catch (IOException e2) { + logger.fatal("Can't read file "+args[1]); + throw new RuntimeException("Can't read file "+args[0], e2); + } + csvInputFileReader = new CSVFileReader(); + csvInputFileReader.setPadNulls(true); + csvInputFileReader.setMyDirectory(ResourceUtil.checkAndGetProperty(propsResource,"CSVFileLocation")); + try { + logger.info("Reading ZonalProperties"); + zonalAttributes = csvInputFileReader.readTable(ResourceUtil.getProperty(propsResource, "ZonalPropertiesFileName", "ZonalProperties.csv ")); + String file2 = ResourceUtil.getProperty(propsResource, "ZonalPropertiesFileName2"); + if (file2 !=null) { + logger.info("Reading ZonalProperties file 2"); + TableDataSet attributes2 = csvInputFileReader.readTable(file2); + appendNewDataSet(zonalAttributes, attributes2, "TAZ"); + } else { + logger.info("No ZonalPropertiesFileName2, just using one zonal properties file"); + } + } catch (IOException e1) { + String msg = "Error reading zonal properties files from "+ResourceUtil.checkAndGetProperty(propsResource,"CSVFileLocation")+" this might be ok if your zonal properties are stored with your matrices"; + logger.warn(msg,e1); + } + + minZone = ResourceUtil.getIntegerProperty(propsResource, "StartZone"); + maxZone = ResourceUtil.getIntegerProperty(propsResource, "EndZone"); + + if(ResourceUtil.getProperty(propsResource, "SkimDatabase") !=null) setUpDatabaseSkims(); + else if (ResourceUtil.getProperty(propsResource, "EmmeUserInitials") != null) setUpEmmeApiSkims(); + else if (ResourceUtil.getProperty(propsResource, "TranscadSkimLocation") != null) setUpTranscadSkims(); + else if (ResourceUtil.getProperty(propsResource, "OMXSkimLocation") != null) setUpOMXSkims(); + else setUpHDF5Skims(); + + } + + private static void setUpTranscadSkims() { + matrixReader = new MatrixAndTAZTableCache( + new TranscadMatrixCollectionReader(new File(ResourceUtil.checkAndGetProperty(propsResource, "TranscadSkimLocation"))), zonalAttributes); + } + + private static void setUpOMXSkims() { + matrixReader = new MatrixAndTAZTableCache( + new OMXMatrixCollectionReader(new File(ResourceUtil.checkAndGetProperty(propsResource, "OMXSkimLocation"))), zonalAttributes); + } + + private static void setUpHDF5Skims() { + String skimNameString = ResourceUtil.checkAndGetProperty(propsResource, "SkimNames"); + String[] skimNames = skimNameString.split(" *, *"); + + String nodeNameString = ResourceUtil.checkAndGetProperty(propsResource, "SkimFileNodeNames"); + String[] nodeNames = nodeNameString.split(" *, *"); + matrixReader = new MatrixAndTAZTableCache( + new HDF5MatrixReader(new File(ResourceUtil.checkAndGetProperty(propsResource, "SkimFile")), + nodeNames, + skimNames), zonalAttributes); + } + + private static void setUpEmmeApiSkims() { + String initials = ResourceUtil.checkAndGetProperty(propsResource, "EmmeUserInitials"); + String emmeBank = ResourceUtil.checkAndGetProperty(propsResource, "EmmeBank"); + String iks = ResourceUtil.getProperty(propsResource, "EmmeIKS"); + try { + if (iks==null) { + matrixReader = new MatrixAndTAZTableCache( + new EmmeApiMatrixReader(initials, emmeBank), zonalAttributes); + } else { + matrixReader = new MatrixAndTAZTableCache( + new EmmeApiMatrixReader(initials, emmeBank, iks, "", false), zonalAttributes); + } + } catch (IOException e) { + String msg = "Couldn't open the emme 2 databank "+emmeBank; + logger.fatal(msg,e); + throw new RuntimeException(msg,e); + } + } + + private static EmmeApiMatrixWriter setUpEmmeApiWriter() { + if (matrixReader.getActualReader() instanceof EmmeApiMatrixReader) { + return new EmmeApiMatrixWriter((EmmeApiMatrixReader) matrixReader.getActualReader()); + } else { + EmmeApiMatrixWriter writer; + String initials = ResourceUtil.checkAndGetProperty(propsResource, "EmmeUserInitials"); + String emmeBank = ResourceUtil.checkAndGetProperty(propsResource, "EmmeBank"); + String iks = ResourceUtil.getProperty(propsResource, "EmmeIKS"); + try { + if (iks==null) { + writer = new EmmeApiMatrixWriter(initials, emmeBank); + } else { + writer = new EmmeApiMatrixWriter(initials, emmeBank, iks, "", false); + } + } catch (IOException e) { + String msg = "Couldn't open the emme 2 databank "+emmeBank; + logger.fatal(msg,e); + throw new RuntimeException(msg,e); + } + return writer; + } + } + + + private static void setUpDatabaseSkims() { + Connection conn; + try { + conn = conn=DriverManager.getConnection( + ResourceUtil.checkAndGetProperty(propsResource, "SkimDatabase"), + ResourceUtil.checkAndGetProperty(propsResource, "SkimDatabaseUser"), + ResourceUtil.checkAndGetProperty(propsResource, "SkimDatabasePassword")); + } catch (SQLException e1) { + String msg = "Can't open skim database"; + logger.fatal(msg,e1); + throw new RuntimeException(msg,e1); + } + logger.info("Reading SQL Matrices"); + matrixReader=new MatrixAndTAZTableCache(new SQLMatrixReader(conn, + ResourceUtil.checkAndGetProperty(propsResource, "SkimQuery"), + ResourceUtil.checkAndGetProperty(propsResource, "OriginQuery"), + ResourceUtil.checkAndGetProperty(propsResource, "DestinationQuery") + ), zonalAttributes); + } + + private static void readCoefficientFiles(CSVFileReader reader, String name1, String name2) + throws IOException { + coefficients = reader.readTable(name1); + if (name2 != null) { + coefficients2 = reader.readTable(name2); + } else { + logger.info("No CoefficientFileName2, just using one coefficient file"); + } + } + + /** + * Takes the columns from one dataset and appends them to another dataset based on a common integer index column. + * This uses the indexing feature in the TableDataSet and so creates a new row index on the dataset using + * the common column name. If you are relying on the row indexing feature from a different column, you'll + * need to reindex it after. + * @param datasetToAppendTo the dataset to be modified by appending the new columns + * @param newData the dataset containing the new data to be appended to the other data set + * @param commonIndexColumn the name of the common index column + */ + private static void appendNewDataSet(TableDataSet datasetToAppendTo, TableDataSet newData, String commonIndexColumn) { + int originalTazColumnNum = datasetToAppendTo.checkColumnPosition(commonIndexColumn); + datasetToAppendTo.buildIndex(originalTazColumnNum); + int tazColumn = newData.checkColumnPosition(commonIndexColumn); + for (int column = 1; column <= newData.getColumnCount(); column++) { + if (column != tazColumn) { + String columnName = newData.getColumnLabel(column); + if (datasetToAppendTo.getColumnPosition(columnName)!=-1) { + String msg = "Duplicate column name "+columnName+" in first and second dataset"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + float[] newColumnVals = new float[datasetToAppendTo.getRowCount()]; + datasetToAppendTo.appendColumn(newColumnVals, columnName); + int newColumnNumber = datasetToAppendTo.checkColumnPosition(columnName); + for (int row = 1; row <= newData.getRowCount();row++) { + datasetToAppendTo.setIndexedValueAt(((int) newData.getValueAt(row, tazColumn)),newColumnNumber,newData.getValueAt(row,column)); + } + } + } + } + + private void setUpCoefficients(String[] args, + TableDataSet coefficients) { + try { + for (int row=1;row<=coefficients.getRowCount();row++) { + String modelName = coefficients.getStringValueAt(row,"Model"); + String matrix = coefficients.getStringValueAt(row,"Matrix"); + String alternative = coefficients.getStringValueAt(row,"Alternative"); + String index1 = coefficients.getStringValueAt(row,"Index1"); + String index2 = coefficients.getStringValueAt(row,"Index2"); + double coefficient = coefficients.getValueAt(row,"Value"); + if (modelName.equals("Generation")) { + if (index1.equalsIgnoreCase("origin")) { + generationEquation.addCoefficient(matrix,coefficient); + } else if (index1.equalsIgnoreCase("moms")) { + generationEquation.addCoefficient(matrix,index2); + } else { + throw new CoefficientFormatError("generation equations must have origin or MOMS in Index1"); + } + } else if (modelName.equalsIgnoreCase("PrevGeneration")) { + if (index1.equalsIgnoreCase("origin")) { + prevGenerationEquation.addCoefficient(matrix,coefficient); + } else if (index1.equalsIgnoreCase("moms")) { + prevGenerationEquation.addCoefficient(matrix,index2); + } else throw new CoefficientFormatError("generation equations must have origin or MOMS in Index1"); + + } else if (modelName.equals("TripMatrix")) { + if (alternative.contains(":")) { + String[] vehicleTour = alternative.split(":"); + tripOutputMatrices.add(new CommercialTour.TripOutputMatrixSpec(matrix, index1, Float.valueOf(index2).floatValue(), (float) coefficient, vehicleTour[0].charAt(0),vehicleTour[1])); + } else { + tripOutputMatrices.add(new CommercialTour.TripOutputMatrixSpec(matrix, index1, Float.valueOf(index2).floatValue(), (float) coefficient, alternative.charAt(0),"")); + } + } else if (modelName.equals("LandUseTypeCode")) { + setLandUseTypeMatrixName(matrix); + } else { + ModelUsesMatrices model = (ModelUsesMatrices) models.get(modelName); + if (model == null) throw new CoefficientFormatError("Bad model type in coefficients: "+modelName); + model.addCoefficient(alternative,index1,index2,matrix,coefficient); + } + + } + } catch (CoefficientFormatError e) { + System.out.println("Coefficient format error -- you have an invalid coefficient"); + System.out.println(e.toString()); + System.out.println("Aborting..."); + throw new RuntimeException("Coefficient format error -- you have an invalid coefficient",e); + } + } + + void setLandUseTypeMatrixName(String landUseTypeMatrixName) { + this.landUseTypeMatrixName = landUseTypeMatrixName; + } + + + /** + * Method buildModelStructure. + * @param propsResource2 + */ + private void buildModelStructure(int[] zoneNums, int lowNumber, int highNumber, ResourceBundle propsResource) { + models.put("VehicleTourType",new CommercialVehicleTourTypeChoice( + ResourceUtil.getProperty(propsResource,"VehicleTourTypes", + "LS,LG,LO,MS,MG,MO,IS,IG,IO,HS,HG,HO").split(","), + ResourceUtil.getBooleanProperty(propsResource,"NestingVTTChoice",true))); + + // don't use these anymore because tNCVehicle and tour type are joint in the same alternative. + // models.put("LTour", new TourTypeChoice()); + // models.put("MTour", new TourTypeChoice()); + // models.put("HTour", new TourTypeChoice()); + String stopTypeModelString = ResourceUtil.getProperty(propsResource, "StopTypeModels", + "LSStopType, LGStopType, LOStopType, MSStopType, MGStopType, MOStopType, ISStopType, IGStopType, IOStopType, HSStopType, HGStopType, HOStopType"); + String[] stopTypeModels = stopTypeModelString.split(","); + for (String stopTypeModel : stopTypeModels) { + models.put(stopTypeModel.trim(), new CommercialNextStopPurposeChoice(stopTypeModel.trim().charAt(1))); + } + + String[] stopLocationModels = ResourceUtil.getProperty(propsResource, "StopLocationModels", + "LSSStopLocation, LSOStopLocation, LGGStopLocation,LGOStopLocation,LOOStopLocation,MSSStopLocation,MSOStopLocation,MGGStopLocation,MGOStopLocation,MGOStopLocation,MOOStopLocation,ISSStopLocation,ISOStopLocation,IGGStopLocation,IGOStopLocation,IOOStopLocation,HSSStopLocation,HSOStopLocation,HGGStopLocation,HGOStopLocation,HOOStopLocation") + .split(","); + for (String stopLocationModel : stopLocationModels) { + models.put(stopLocationModel.trim(), new CommercialNextStopChoice(zoneNums, lowNumber-1, highNumber+1, stopLocationModel.trim())); + } + + String[] durationModels = ResourceUtil.getProperty(propsResource, "DurationModels", + "LODuration,LSDuration,LGDuration,MODuration,MSDuration,MGDuration,IODuration,ISDuration,IGDuration,HODuration,HSDuration,HGDuration") + .split(","); + for (String durationModel : durationModels) { + models.put(durationModel.trim(), new DurationModel2()); + } + + //TODO here is the place where we parameterize the trip mode choice + if (isUseTripModes()) { + /*String[] tripModeChoiceModels = ResourceUtil.getProperty(propsResource, "TripModeL,TripModelM,TripModeI,TripModeH") + .split(","); + for (String tripModeChoiceModel : tripModeChoiceModels) { + models.put(tripModeChoiceModel.trim(), new CommercialVehicleTripModeChoice(tripModeChoiceModels)); + }*/ + models.put("TripModeL", new CommercialVehicleTripModeChoice(new String[] {"L:T", "L:NT"})); + models.put("TripModeM", new CommercialVehicleTripModeChoice(new String[] {"M:T", "M:NT"})); + models.put("TripModeI", new CommercialVehicleTripModeChoice(new String[] {"I:T", "I:NT"})); + models.put("TripModeH", new CommercialVehicleTripModeChoice(new String[] {"H:T", "H:NT"})); + + } + + models.put("TourStartTime", new TourStartTimeModel()); + models.put("TravelTimeMatrix", new CommercialTravelTimeTracker()); + models.put("TravelDisutilityMatrix", new CommercialTravelTimeTracker()); + + ModelUsesMatrices dummyModel = new ModelUsesMatrices() { + public void readMatrices(MatrixCacheReader matrixReader) { + // nothing + } + public void addCoefficient(String alternative, String index1, + String index2, String matrixName, double coefficient) + throws CoefficientFormatError { + // nothing + } + public void init() { + // nothing + } + + }; + + // dummy models, placeholders for coefficients handled elsewhere (in python) + models.put("ShipNoShip", dummyModel); + models.put("GenPerEmployee", dummyModel); + models.put("TourTOD", dummyModel); + + } + + final Hashtable models = new Hashtable(); + private static int minZone; + private static int maxZone; + static TableDataSet coefficients; + static TableDataSet coefficients2; + static TableDataSet zonalAttributes; + private int totalTours; + private int totalTrips; + private IndexLinearFunction generationEquation; + private IndexLinearFunction prevGenerationEquation; + private static int globalTourNumber = 0; + private static int[] zones; + private static CSVFileReader csvInputFileReader; + private PrintWriter tripLog; + + + public static int getNextTourNumber() { + synchronized(GenerateCommercialTours.class){ + return globalTourNumber ++; + } + } + + void openTripLog(File tripLogFile) { + try { + logger.info("Opening log file "+tripLogFile); + tripLog = new PrintWriter(new FileWriter(tripLogFile)); + tripLog.println("Model,SerialNo,Person,Trip,Tour,HomeZone,ActorType,OPurp,DPurp,I,J,TripTime,Mode,StartTime,EndTime,StopDuration,TourType,OriginalTimePeriod,TripMode,TollAvailable"); + } catch (IOException e) { + logger.fatal("Can't open trip log file "+tripLogFile,e); + throw new RuntimeException("Can't open trip log file "+tripLogFile, e); + } + } + + void closeTripLog() { + if (tripLog !=null) { + tripLog.close(); + logger.info("Closing trip log file for "+segmentString); + } + } + + + String landUseTypeMatrixName; + Matrix landUseTypeMatrix; + private TourStartTimeModel tourStartTimeModel; + private ChangingTravelAttributeGetter elapsedTravelTimeCalculator; + private static ExecutorService threadpool; + + + /** + * Method readMatrices. + * @param matrixReader + */ + public void readOutputMatrices(MatrixCacheReader matrixReader) { + for (int i =0; i createdOnes) { + for (TripOutputMatrixSpec s : tripOutputMatrices) { + if (s.write) { + Matrix m = createdOnes.get(s.name); + if (m==null) { + s.createMatrix(size, externalNumbers); + createdOnes.put(s.name, s.matrix); + } else { + s.matrix = m; + } + } + } + } + + /** + * Method writeMatrices. + * @param matrixWriter + */ + void writeMatrices(MatrixWriter matrixWriter) { + ArrayList names = new ArrayList(); + ArrayList m = new ArrayList(); + for (int i =0; i0) { + matrixWriter.writeMatrices(names.toArray(new String[names.size()]), m.toArray(new Matrix[m.size()])); + } + } + + static void writeAllMatrices(MatrixWriter matrixWriter, ArrayList segmentRunners ) { + ArrayList names = new ArrayList(); + ArrayList m = new ArrayList(); + for (GenerateCommercialTours segment : segmentRunners) { + ArrayList tripSpecs = segment.tripOutputMatrices; + for (int i =0; i0) { + StringBuffer msg = new StringBuffer("Writing out matrices "); + for (String name : names) msg.append(","+name); + logger.info(msg); + matrixWriter.writeMatrices(names.toArray(new String[names.size()]), m.toArray(new Matrix[m.size()])); + } + } + + + + TripOutputMatrixSpec getTripOutputMatrixSpec(char vehicleType, String tripMode, float time) { + while (time>=24.00) time-=24.00; + for (int i =0; i=s.startTime && time < s.endTime && s.vehicleType==vehicleType && s.tripMode.equals(tripMode)) return s; + } + return null; + } + + @Override + public void run() { + logger.info("Starting segment "+segmentString); + generateTheTours(); + closeTripLog(); + System.out.println("DonE segement "+segmentString +"!"); + logger.info("DonE segement "+segmentString +"!"); + if (tripLog!=null) tripLog.close(); + } + + private void setElapsedTravelTimeCalculator( + // TODO should use trip modes like getTravelDisutilityTracker does + ChangingTravelAttributeGetter elapsedTravelTimeCalculator) { + this.elapsedTravelTimeCalculator = elapsedTravelTimeCalculator; + } + + public ChangingTravelAttributeGetter getElapsedTravelTimeCalculator() { + return elapsedTravelTimeCalculator; + } + + private void setTourStartTimeModel(TourStartTimeModel tourStartTimeModel) { + this.tourStartTimeModel = tourStartTimeModel; + } + + public TourStartTimeModel getTourStartTimeModel() { + return tourStartTimeModel; + } + + @Override + public Object call() throws Exception { + run(); + return null; + } + + ChangingTravelAttributeGetter getTravelDisutilityTracker() { + if (!isUseTripModes()) + return travelDisutilityTrackers.get(""); + else { + String msg = "Trip mode is being used, no defualt travel disutility tracker"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + } + + void setTravelDisutilityTrackers(HashMap trackers) { + this.travelDisutilityTrackers = trackers; + } + + public ChangingTravelAttributeGetter getTravelDisutilityTracker( + String vehicleCode) { + return travelDisutilityTrackers.get(vehicleCode); + + } + + public boolean isUseTripModes() { + return useTripModes; + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/TourStartTimeModel.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/TourStartTimeModel.java new file mode 100644 index 0000000..0dfc727 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/TourStartTimeModel.java @@ -0,0 +1,115 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.activityTravel.cvm; + +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.MatrixReader; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class TourStartTimeModel implements ModelUsesMatrices, RealNumberDistribution { + + /** returns tour start time in hours since midnight + */ + static boolean startTimeInMinutes = false; + + double periodStart; // base time for the TourStartTimeModel + int functionalForm; // power =1, cubic=2 or exponential =3 + double a; + double b; + double c; + double d; + double e; + double f; + + + public double sampleValue() { + double x = Math.random(); + double y=0; + switch (functionalForm) { + case 1: + y = a * Math.pow(x,b)+c*Math.pow(x,d) + e * x + f; + break; + case 2: + y = a+b*x+c*x*x+d*x*x*x; + break; + case 3: + y = c*Math.exp(a*x+b)+d; + break; + } + if (startTimeInMinutes) y = y/60; + if (y<0) y =0; + if (y>24) y = 24; + y += periodStart; + return y; + } + + + /** + * Method addCoefficient. + * @param alternative + * @param index1 + * @param index2 + * @param matrix + * @param coefficient + */ + public void addCoefficient ( + String alternative, + String index1, + String index2, + String matrix, + double coefficient) throws CoefficientFormatError { + if (index1.equals("a")) a = coefficient; + else if(index1.equals("b")) b = coefficient; + else if(index1.equals("c")) c = coefficient; + else if(index1.equals("d")) d = coefficient; + else if(index1.equals("e")) e = coefficient; + else if(index1.equals("f")) f = coefficient; + else if(index1.equals("functionForm")) { + if (index2.equals("power")) functionalForm =1; + else if (index2.equals("cubic")) functionalForm = 2; + else if (index2.equals("exponential")) functionalForm = 3; + else throw new CoefficientFormatError("functionalForm for tour start model must have index2 as \"power\", \"cubic\" or \"exponential\""); + } + else if (index1.equals("periodStart")) periodStart=coefficient; + else throw new CoefficientFormatError("Tour start time model model coefficients must have index1 as a,b,c,d,e,f, periodStart or functionalForm"); + } + + /** + * Method readMatrices. + * @param matrixReader + */ + public void readMatrices(MatrixCacheReader matrixReader) {} + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { + readMatrices(GenerateCommercialTours.matrixReader); + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/VehicleTourTypeNest.java b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/VehicleTourTypeNest.java new file mode 100644 index 0000000..25df5d7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/activityTravel/cvm/VehicleTourTypeNest.java @@ -0,0 +1,16 @@ +package org.sandag.cvm.activityTravel.cvm; + +import org.sandag.cvm.common.model.LogitModel; + +public class VehicleTourTypeNest extends AlogitLogitModelNest { + final String myCode; + + public VehicleTourTypeNest(String code) { + myCode = code; + } + + public String getCode() { + return myCode; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/GenerateWeekendTours.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/GenerateWeekendTours.java new file mode 100644 index 0000000..2c97491 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/GenerateWeekendTours.java @@ -0,0 +1,292 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.calgary.weekend; + +import com.pb.common.matrix.*; +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.*; + +import java.io.*; +import java.sql.*; +import java.util.*; +import org.sandag.cvm.common.datafile.*; +import org.apache.log4j.Logger; + +public class GenerateWeekendTours { + + private static Logger logger = Logger.getLogger("org.sandag.cvm.calgary.weekend"); + public static MatrixCacheReader matrixReader; + public static TableDataSetCollection inputData; + static Properties props = new Properties(); + + + /** + * Generate commercial tours for Calgary EMME/2 model + * @param args is six strings, location of databank, location of coefficients file, name of coefficients file, minZone,maxZone, anyOldMatrixName + */ + public static void main(String[] args) { + + FileInputStream fin = null; + try { + fin = new FileInputStream(args[0]); + } catch (FileNotFoundException e) { + System.out.println("error: be sure to put the location of the properties file on the command line"); + e.printStackTrace(); + System.exit(-1); + } + try { + props.load(fin); + } catch (IOException e) { + System.out.println("Error reading properties file "+args[0]); + System.exit(-1); + } + + // get emme/2 matrix + try { + matrixReader = new MatrixCacheReader(new Emme2MatrixReader(new File(props.getProperty("databank")))); + } catch (Exception e) { + System.out.println("Error opening emme2 databank \""+props.getProperty("databank")+"\""); + System.out.println(e); + e.printStackTrace(); + } + Matrix anyOldMatrix = matrixReader.readMatrix(props.getProperty("anyOldMatrixName")); + minZone = Integer.valueOf(props.getProperty("minZone")).intValue(); + maxZone = Integer.valueOf(props.getProperty("maxZone")).intValue(); + //int[] zones = anyOldMatrix.getExternalNumbers(); + buildModelStructure(matrixReader,anyOldMatrix,minZone,maxZone); + + // These next lines are just for testing in the case that you don't have an emme2 databank to load +// int[] zones = new int[10]; +// int minZone = 0; +// int maxZone = 10; +// buildModelStructure(null,minZone,maxZone); + + String inputLocation = props.getProperty("inputLocation"); + CSVFileReader inputDataReader = new CSVFileReader(); + inputDataReader.setMyDirectory(inputLocation); + // no output location for now + inputData = new TableDataSetCollection(inputDataReader, null); + + + TableDataSet coefficients = inputData.getTableDataSet(props.getProperty("coefficientsTable")); + + + try { + for (int cn= 1; cn <= coefficients.getRowCount(); cn++) { //cn is "coefficientNumber" + String modelName = coefficients.getStringValueAt(cn, "Model"); + String matrix = coefficients.getStringValueAt(cn,"Matrix"); + String alternative = coefficients.getStringValueAt(cn,"Alternative"); + String index1 = coefficients.getStringValueAt(cn,"Index1"); + String index2 = coefficients.getStringValueAt(cn,"Index2"); + double coefficient = coefficients.getValueAt(cn,"Value"); + ModelWithCoefficients model = (ModelWithCoefficients) models.get(modelName); + if (model == null) throw new CoefficientFormatError("Bad model type in coefficients: "+modelName); + model.addCoefficient(alternative,index1,index2,matrix,coefficient); + + } + } catch (CoefficientFormatError e) { + System.out.println("Coefficient format error -- you have an invalid coefficient"); + System.out.println(e.toString()); + e.printStackTrace(); + System.out.println("Aborting..."); + System.exit(-1); + } + + Iterator modelIterator = models.values().iterator(); + while (modelIterator.hasNext()) { + ModelWithCoefficients model = (ModelWithCoefficients) modelIterator.next(); + model.init(); + } + +// generationEquation.readMatrices(matrixReader); +// WeekendTour.readMatrices(matrixReader); +// +// CommercialTour.tourTypeChoiceModel=(CommercialVehicleTourTypeChoice) models.get("VehicleTourType"); +// CommercialTour.setTourStartTimeModel((TourStartTimeModel) models.get("TourStartTime")); +// CommercialTour.setElapsedTravelTimeCalculator((WeekendTravelTimeTracker) models.get("TravelTimeMatrix")); +// CommercialTour.travelDisutilityTracker = (WeekendTravelTimeTracker) models.get("TravelDisutilityMatrix"); + + //TODO the household dataset is probably too big to load in the whole thing, so instead step through the file one record at a time + TableDataSet households = inputData.getTableDataSet(props.getProperty("householdsTable")); + TableDataSet householdDetails = inputData.getTableDataSet(props.getProperty("householdDetailsTable")); + householdDetails.buildIndex(householdDetails.checkColumnPosition("hh_ID")); + // TODO read in person file + + int totalTours = 0; + int totalTrips = 0; + System.out.println("Generating tours..."); + for (int hhnum = 1;hhnum<=households.getRowCount();hhnum++) { + if (hhnum %10 == 0) System.out.print(hhnum+" "); + if (hhnum %200 == 0) System.out.println(); + + + WeekendHousehold household = new WeekendHousehold(households, hhnum, householdDetails); + // TODO should add people by reading them from a dataset + household.addPeople(); + + int zone = household.getHomeZone(); + + // TODO check if to generate tours from externals? Probably not. + if (zone>=minZone && zone <= maxZone) { + household.resetCurrentTime(); + WeekendTour tour = household.sampleNextWeekendTour(); + while (tour != null) { + totalTours++; + // TODO add the trips to the matrix; + // t.addTripsToMatrix(); + // TODO write the tour to the tour database + totalTrips += tour.getStopCounts()[0]; + tour = household.sampleNextWeekendTour(); + } + } + + } + System.out.println(); + + + System.out.println("finished generating "+totalTours+" tours and "+totalTrips+" trips , now writing trip matrices out to emme2 databank"); +// WeekendTour.tourTypeChoiceModel.writeTourAndTripSummary(); + Emme2MatrixWriter matrixWriter = new Emme2MatrixWriter(new File(props.getProperty("databank"))); + // TODO write out all of the trip matrices back into the emme2 databank +// WeekendTour.writeMatrices(matrixWriter); + System.out.println("done!"); + } + + /** + * Method buildModelStructure. + */ + private static void buildModelStructure(MatrixCacheReader matrixReader2, Matrix anyOldMatrix, int lowNumber, int highNumber) { + + TourInTimeBand titb = new TourInTimeBand(); + WeekendTour.setTourInTimeBand(titb); + models.put("tourInBand",titb); + NextWeekendTourStartTime ttnt = new NextWeekendTourStartTime(); + WeekendTour.setTourStartTimeModel(ttnt); + models.put("tourStart", ttnt); + WeekendTourTypeChoice wttc = new WeekendTourTypeChoice(); + wttc.setMatrixReader(matrixReader2); + models.put("tourType", wttc); + WeekendTour.tourTypeChoiceModel= wttc; + models.put("workPrimaryStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone) ); + models.put("schoolPrimaryStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("relCivicPrimaryStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("exercisePrimaryStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("outOfTownPrimaryStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("workIntermediateStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone) ); + models.put("schoolIntermediateStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("relCivicIntermediateStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("exerciseIntermediateStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("outOfTownIntermediateStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("workReturnStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone) ); + models.put("schoolReturnStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("relCivicReturnStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("exerciseReturnStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("outOfTownReturnStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("SELSEReturnStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("chaufReturnStop", new WeekendStopChoice(anyOldMatrix,minZone,maxZone)); + models.put("workStopType", new WeekendStopPurposeChoice("workStopType")); + models.put("schoolStopType", new WeekendStopPurposeChoice("schoolStopType")); + models.put("exerciseStopType", new WeekendStopPurposeChoice("exerciseStopType")); + models.put("relCivicStopType", new WeekendStopPurposeChoice("relCivicStopType")); + models.put("outOfTownStopType", new WeekendStopPurposeChoice("outOfTownStopType")); + models.put("chaufStopType", new WeekendStopPurposeChoice("chaufStopType")); + models.put("SELSEStopType", new WeekendStopPurposeChoice("SELSEStopType")); + models.put("workDuration", new DurationModel()); + models.put("shopDuration", new DurationModel()); + models.put("relCivicDuration", new DurationModel()); + models.put("eatDuration", new DurationModel()); + models.put("entLeisureDuration", new DurationModel()); + models.put("socialDuration", new DurationModel()); + models.put("exerciseDuration", new DurationModel()); + models.put("schoolDuration", new DurationModel()); + models.put("outOfTownDuration", new DurationModel()); + models.put("pickUpDuration", new DurationModel()); + models.put("dropOffDuration", new DurationModel()); + + // models.put("VehicleTourType",new CommercialVehicleTourTypeChoice()); +//// models.put("LTour", new TourTypeChoice()); +//// models.put("MTour", new TourTypeChoice()); +//// models.put("HTour", new TourTypeChoice()); +// models.put("LSStopType", new CommercialNextStopPurposeChoice('S')); +// models.put("LGStopType", new CommercialNextStopPurposeChoice('G')); +// models.put("LOStopType", new CommercialNextStopPurposeChoice('O')); +// models.put("MSStopType", new CommercialNextStopPurposeChoice('S')); +// models.put("MGStopType", new CommercialNextStopPurposeChoice('G')); +// models.put("MOStopType", new CommercialNextStopPurposeChoice('O')); +// models.put("HSStopType", new CommercialNextStopPurposeChoice('S')); +// models.put("HGStopType", new CommercialNextStopPurposeChoice('G')); +// models.put("HOStopType", new CommercialNextStopPurposeChoice('O')); +// models.put("LSSStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("LSOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("LGGStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("LGOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("LOOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("MSSStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("MSOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("MGGStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("MGOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("MOOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("HSSStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("HSOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("HGGStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("HGOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("HOOStopLocation", new WeekendStopChoice(anyOldMatrix, lowNumber, highNumber)); +// models.put("LODuration", new DurationModel()); +// models.put("LSDuration", new DurationModel()); +// models.put("LGDuration", new DurationModel()); +// models.put("MODuration", new DurationModel()); +// models.put("MSDuration", new DurationModel()); +// models.put("MGDuration", new DurationModel()); +// models.put("HODuration", new DurationModel()); +// models.put("HSDuration", new DurationModel()); +// models.put("HGDuration", new DurationModel()); + + WeekendTravelTimeTracker timeTracker = new WeekendTravelTimeTracker(); + models.put("TravelTimeMatrix",timeTracker); + WeekendTour.setElapsedTravelTimeCalculator(timeTracker); + + WeekendTravelTimeTracker disutilTracker = new WeekendTravelTimeTracker(); + models.put("TravelDisutilityMatrix", disutilTracker); + WeekendTour.setTravelDisutilityTracker(disutilTracker); + } + + + static final Hashtable models = new Hashtable(); + private static int minZone; + private static int maxZone; + +// public static ResultSet readCoefficients(String parameterFileLocation, String tableName) { +// ResultSet results = null; +// try { +// Class.forName("org.relique.jdbc.csv.CsvDriver"); +// Connection conn = DriverManager.getConnection("jdbc:relique:csv:" + parameterFileLocation); +// Statement stmt = conn.createStatement(); +// results = stmt.executeQuery("SELECT * FROM "+tableName); +// return results; +// } +// catch(Exception e) +// { +// System.out.println("JDBC Error connecting to "+parameterFileLocation+" "+ e); +// e.printStackTrace(); +// System.exit(-1); +// } +// return results; +// } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/NextWeekendTourStartTime.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/NextWeekendTourStartTime.java new file mode 100644 index 0000000..95d72e7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/NextWeekendTourStartTime.java @@ -0,0 +1,101 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.calgary.weekend; + +import org.sandag.cvm.activityTravel.*; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class NextWeekendTourStartTime + implements ModelWithCoefficients, RealNumberDistribution { + + double startTime = 0; + double endTime = 1; + private WeekendHousehold myHousehold; + + /** + * + */ + public NextWeekendTourStartTime() { + super(); + // TODO Auto-generated constructor stub + } + + /* (non-Javadoc) + * @see org.sandag.cvm.calgary.weekend.ModelWithCoefficients#addCoefficient(java.lang.String, java.lang.String, java.lang.String, java.lang.String, double) + */ + public void addCoefficient( + String alternative, + String index1, + String index2, + String matrixName, + double coefficient) + throws CoefficientFormatError { + if (alternative.equalsIgnoreCase("EndTime")) { + endTime = coefficient; + } else if (alternative.equalsIgnoreCase("StartTime")) { + startTime = coefficient; + } else { + throw new CoefficientFormatError("Valid coefficients for tour start time model are \"StartTime\" and \"EndTime\""); + } + + } + + /* (non-Javadoc) + * @see org.sandag.cvm.calgary.weekend.ModelWithCoefficients#init() + */ + public void init() { + // Nothing to do here. + + } + + public void shiftTime(double shift) { + startTime+=shift; + endTime +=shift; + } + + public void resetStart() { + endTime = endTime-startTime; + startTime = 0; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.common.model.SingleValueRealDistribution#sampleValue() + */ + public double sampleValue() { + // TODO use a different distribution? + double timeToNextTour = Math.random()*(endTime-startTime); + return timeToNextTour+startTime; + } + + public void setMyHousehold(WeekendHousehold myHousehold) { + this.myHousehold = myHousehold; + } + + public WeekendHousehold getMyHousehold() { + return myHousehold; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/TourInTimeBand.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/TourInTimeBand.java new file mode 100644 index 0000000..09a2f9a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/TourInTimeBand.java @@ -0,0 +1,185 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.calgary.weekend; + +import java.util.ArrayList; + +import org.sandag.cvm.activityTravel.AlternativeUsesMatrices; +import org.sandag.cvm.activityTravel.CoefficientFormatError; +import org.sandag.cvm.activityTravel.ModelWithCoefficients; +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import org.sandag.cvm.common.model.Alternative; +import org.sandag.cvm.common.model.LogitModel; +import org.sandag.cvm.common.model.NoAlternativeAvailable; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.MatrixReader; + +/** + * @author jabraham + * + * Controls the time bands, increments through them, and has the model as + * to whether another tour occurs in the time band + */ +public class TourInTimeBand extends LogitModel implements ModelWithCoefficients { + + ArrayList bandStarts = new ArrayList(); + double dayEnd = 24*60; + final Alternative noTour; + final Alternative makeATour; + int currentBand = 0; + double makeATourConstant = 0; + WeekendHousehold currentHousehold=null; + + double getCurrentBandStart() { + if (currentBand >= bandStarts.size()) { + return dayEnd; + } else { + return ((Double)bandStarts.get(currentBand)).doubleValue(); + } + } + + double getCurrentBandEnd() { + if (currentBand +1 >= bandStarts.size()) { + return dayEnd; + } else { + return ((Double)bandStarts.get(currentBand+1)).doubleValue(); + } + } + + /* (non-Javadoc) + * @see org.sandag.cvm.calgary.weekend.ModelWithCoefficients#addCoefficient(java.lang.String, java.lang.String, java.lang.String, java.lang.String, double) + */ + public void addCoefficient(String alternative, String index1, String index2, String matrixName, double coefficient) throws CoefficientFormatError { + Double lastBandStart = null; + if (bandStarts.size() == 0) lastBandStart = new Double(Double.NEGATIVE_INFINITY); + else lastBandStart =(Double)(bandStarts.get(bandStarts.size()-1)); + if (alternative.equalsIgnoreCase("bandStart")) { + if (coefficient <= lastBandStart.doubleValue()) { + throw new CoefficientFormatError("Start bands for tour time band model need to be specified in increasing order"); + } + bandStarts.add(new Double(coefficient)); + } else if (alternative.equalsIgnoreCase("dayEnd")) { + if (coefficient <= lastBandStart.doubleValue()) { + throw new CoefficientFormatError("End of day for tour time band model need to be greater than last time band"); + } + dayEnd = coefficient; + } else if (alternative.equalsIgnoreCase("constant")) { + makeATourConstant = coefficient; + } else { + throw new CoefficientFormatError("Bad coefficient for tour band model "+alternative+" "+index1+" "+index2+" "+matrixName); + } + + // TODO other coefficients + + } + + /* (non-Javadoc) + * @see org.sandag.cvm.calgary.weekend.ModelWithCoefficients#init() + */ + public void init() { + // TODO read matrices if necessary + } + + public TourInTimeBand() { + super(); + noTour = new AlternativeUsesMatrices() { + public void addCoefficient(String index1, String index2, String matrix, double coefficient) throws CoefficientFormatError { + throw new CoefficientFormatError("The NoTour alternative has no coefficients and baseline utility zero"); + } + + public void readMatrices(MatrixCacheReader mr) { + // nothing to do + } + + public String getCode() { + return "noTour"; + } + + public double getUtility() { + return 0; + } + }; + makeATour = new AlternativeUsesMatrices() { + public void addCoefficient(String index1, String index2, String matrix, double coefficient) throws CoefficientFormatError { + throw new CoefficientFormatError("The NoTour alternative has no coefficients and baseline utility zero"); + } + + public void readMatrices(MatrixCacheReader mr) { + // read matrices if we need to. + } + + public String getCode() { + return "makeATour"; + } + + public double getUtility() { + if (getCurrentBandEnd()<=getCurrentBandStart()){ + return Double.NEGATIVE_INFINITY; + } + return makeATourConstant + Math.log(getCurrentBandEnd()-getCurrentBandStart()) + Math.log(currentHousehold.countPeopleAtHome()); + // TODO add in other parameters related to number of people at home and household size etc. + } + }; + addAlternative(noTour); + addAlternative(makeATour); + } + + public boolean beyondLastBand() { + if (currentBand>=bandStarts.size()) return true; + return false; + } + + /** + * @return + */ + public boolean tourStartsInBand() { + Alternative chosen=null; + try { + chosen = this.monteCarloChoice(); + } catch (NoAlternativeAvailable e) { + e.printStackTrace(); + throw new RuntimeException("Error in TourStartsInBand module",e); + } + return chosen == makeATour; + } + + /** + * @param currentTime + */ + public void setBandBasedOnTime(double currentTime) { + if (bandStarts.size() == 0) { + currentBand = 0; + return; + } + if (currentTime > dayEnd) { + currentBand = bandStarts.size(); + return; + } + if (currentTime < ((Double)bandStarts.get(0)).doubleValue()) { + throw new RuntimeException("Current household time isn't in any time band"); + } + for (currentBand = bandStarts.size()-1;currentBand >=0;currentBand--) { + if (currentTime >= ((Double)bandStarts.get(currentBand)).doubleValue()) { + return; + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendHousehold.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendHousehold.java new file mode 100644 index 0000000..d27d19f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendHousehold.java @@ -0,0 +1,366 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.calgary.weekend; +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.sandag.cvm.activityTravel.HouseholdInterface; +import org.sandag.cvm.activityTravel.PersonInterface; +import org.sandag.cvm.common.datafile.TableDataSet; + + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class WeekendHousehold implements HouseholdInterface { + + ArrayList myPeople =null; + private static int incrementalId = 0; + int id; + private boolean incomeValid; + private float annualIncome; + private int numberOfVehicles; + private int adultOtherCount; // ao + private int adultWorkerNeedingCarCount; // awnc + private int adultWorkerNotNeedingCarCount; // awnnc + private int studentKto9Count; //kejs + private int postSecondaryStudentCount; //pss + private int seniorCount; // Sen + private int student10to12Count; //SHS + private int youthOtherCount; //YO + private double currentTime; + private boolean homelessHousehold = true; + private int homeZone = 0; + + static NextWeekendTourStartTime myTourStartTimeModel = null; + + public WeekendHousehold(TableDataSet populationHouseholds, int rowNum, TableDataSet sampleHouseholds) { + homeZone = (int) populationHouseholds.getValueAt(rowNum,"Zone"); + homelessHousehold = false; + int hhid = (int) populationHouseholds.getValueAt(rowNum,"HHID"); + int sampleRowNum = sampleHouseholds.getIndexedRowNumber(hhid); + fillInDataFromDataSet(sampleHouseholds, sampleRowNum); + id = incrementalId++; + } + + + + public WeekendHousehold(TableDataSet tds, int rowNum) { + // For integration with household synthesis, need to get household attributes + // and people information from another file. + id=(int) tds.getValueAt(rowNum,"hh_ID"); + fillInDataFromDataSet(tds,rowNum); + } + + void fillInDataFromDataSet(TableDataSet tds, int rowNum) { + //TODO check to see if value targets in synthesis deal with missing values properly + annualIncome = tds.getValueAt(rowNum,"Value"); + if (annualIncome < -100000) { + annualIncome = 0; + incomeValid = false; + } else { + incomeValid = true; + } + numberOfVehicles = (int) tds.getValueAt(rowNum,"CountOfveh_id"); + adultOtherCount = (int) tds.getValueAt(rowNum,"AO"); + adultWorkerNeedingCarCount = (int) tds.getValueAt(rowNum,"AWNC"); + adultWorkerNotNeedingCarCount = (int) tds.getValueAt(rowNum,"AWNNC"); + studentKto9Count = (int) tds.getValueAt(rowNum,"KEJS"); + postSecondaryStudentCount = (int) tds.getValueAt(rowNum,"PSS"); + seniorCount = (int)tds.getValueAt(rowNum,"Sen"); + student10to12Count = (int) tds.getValueAt(rowNum,"SHS"); + youthOtherCount = (int)tds.getValueAt(rowNum,"YO"); + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.HouseholdInterface#getId() + */ + public int getId() { + return id; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.HouseholdInterface#getPersons() + */ + public Collection getPersons() { + if (myPeople == null) { + makeMyPeople(); + } + return myPeople; + } + + private void makeMyPeople() { + // TODO add in other attributes of people as necessary + // TODO get RID of this method, as people should be read from the database. use AddPeople instead + myPeople = new ArrayList(); + int peopleToMake = getPersonCount(); + for (int p=0;p person.returnTime) person.atHome = true; + } + } + } + + + + double getCurrentTime() { + return currentTime; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendPerson.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendPerson.java new file mode 100644 index 0000000..2b4ee77 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendPerson.java @@ -0,0 +1,105 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.calgary.weekend; + +import org.sandag.cvm.activityTravel.HouseholdInterface; +import org.sandag.cvm.activityTravel.PersonInterface; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class WeekendPerson implements PersonInterface { + + WeekendHousehold myHousehold; + /** + * @param household + */ + public WeekendPerson(WeekendHousehold household) { + myHousehold = household; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.PersonInterface#getMyHousehold() + */ + public HouseholdInterface getMyHousehold() { + return myHousehold; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.PersonInterface#getAge() + */ + public int getAge() { + // TODO add age attribute + throw new RuntimeException("getAge() is not yet implemented for WeekendPerson"); + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.PersonInterface#getPersonID() + */ + public long getPersonID() { + // TODO Auto-generated method stub + throw new RuntimeException("getPersonID() is not yet implemented for WeekendPerson"); + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.PersonInterface#isFemale() + */ + public boolean isFemale() { + // TODO Auto-generated method stub + throw new RuntimeException("isFemale() is not yet implemented for WeekendPerson"); + } + + public boolean atHome= true; + + public double returnTime=0; + + /** + * @return Returns the atHome. + */ + public boolean isAtHome() { + return atHome; + } + + /** + * @param atHome The atHome to set. + */ + public void setAtHome(boolean atHome) { + this.atHome = atHome; + } + + /** + * @return Returns the returnTime. + */ + public double getReturnTime() { + return returnTime; + } + + /** + * @param returnTime The returnTime to set. + */ + public void setReturnTime(double returnTime) { + this.returnTime = returnTime; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendStopChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendStopChoice.java new file mode 100644 index 0000000..1b6ba0d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendStopChoice.java @@ -0,0 +1,54 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.calgary.weekend; + +import org.sandag.cvm.activityTravel.StopAlternative; +import org.sandag.cvm.activityTravel.StopChoice; +import com.pb.common.matrix.Matrix; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class WeekendStopChoice extends StopChoice { + + public WeekendStopChoice(Matrix r, int minZone, int maxZone) { + super(); + int[] zoneNums = r.getExternalNumbers(); + for (int z = 1;z= minZone && theNumber <= maxZone) { + this.addAlternative(new StopAlternative(this, zoneNums[z])); + } + } + } + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { + readMatrices(GenerateWeekendTours.matrixReader); + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendStopPurposeChoice.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendStopPurposeChoice.java new file mode 100644 index 0000000..c6c238c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendStopPurposeChoice.java @@ -0,0 +1,217 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.calgary.weekend; + +import org.sandag.cvm.activityTravel.*; +import org.sandag.cvm.common.emme2.IndexLinearFunction; +import org.sandag.cvm.common.emme2.MatrixCacheReader; +import org.sandag.cvm.common.model.LogitModel; +import org.sandag.cvm.common.model.NoAlternativeAvailable; +import com.pb.common.matrix.Emme2MatrixReader; +import com.pb.common.matrix.MatrixReader; + +import java.util.*; + +import org.apache.log4j.Logger; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2005 + */ +public class WeekendStopPurposeChoice extends LogitModel implements ModelUsesMatrices, TourNextStopPurposeChoice { + + + private static Logger logger = Logger.getLogger("org.sandag.cvm.calgary.weekend"); + Tour myTour; + static final int RETURN=WeekendTour.convertPurposeToInt("return"); + + public class NextStopPurpose implements AlternativeUsesMatrices { + public NextStopPurpose(int stopType) { + this.stopType = stopType; + } + + double[] transitionConstants = new double[14]; + double[] stopCountCoefficients = new double[14]; + double constant = 0; + + final int stopType; + IndexLinearFunction previousStopUtility = new IndexLinearFunction(); + IndexLinearFunction originUtility = new IndexLinearFunction(); + IndexLinearFunction returnToOriginUtility = new IndexLinearFunction(); + double timeToOriginCoefficient = 0; + double disutilityToOriginCoefficient = 0; + double totalTravelTimeCoefficient = 0; + double totalTripTimeCoefficient = 0; + public double getUtility() { + double utility = previousStopUtility.calcForIndex(myTour.getCurrentLocation(),1); + utility += originUtility.calcForIndex(getMyTour().getOriginZone(),1); + int previousStopType= myTour.getLastStopType(); + // TODO make sure the stop count code works properly for weekend model; default implementation just counts total stops, not by type + int[] stopCounts = getMyTour().getStopCounts(); + // can't return home on first stop + if (stopCounts[0]==0 && stopType==RETURN) utility += Double.NEGATIVE_INFINITY; + for (int type =0;type < stopCountCoefficients.length;type++) { + utility += stopCountCoefficients[type]*Math.log(stopCounts[type]+1); + } + double returnHomeUtility = returnToOriginUtility.calcForIndex(myTour.getCurrentLocation(),getMyTour().getOriginZone()); + + // make people return home more -- Doug and Kevin Hack of Jan 5th + //if (myTour.getTotalElapsedTime()>240.0) returnHomeUtility *=3; + utility += returnHomeUtility; + + utility += totalTravelTimeCoefficient*getMyTour().getTotalTravelTimeMinutes(); + utility += totalTripTimeCoefficient*getMyTour().getTotalElapsedTimeHrs(); + utility += timeToOriginCoefficient*myTour.getElapsedTravelTimeCalculator().getTravelAttribute(myTour.getCurrentLocation(),getMyTour().getOrigin(),getMyTour().getCurrentTimeHrs(),getMyTour().getMyVehicleTourType().vehicleType); + utility += disutilityToOriginCoefficient*getMyTour().getTravelDisutilityTracker().getTravelAttribute(myTour.getCurrentLocation(),getMyTour().getOrigin(),getMyTour().getCurrentTimeHrs(),getMyTour().getMyVehicleTourType().vehicleType); + utility += constant; + return utility; + } + + /** + * Method addParameter. + * @param matrix + * @param coefficient + */ + public void addCoefficient(String index1, String index2, String matrix, double coefficient) throws CoefficientFormatError { + if(index1.equals("origin")) { + originUtility.addCoefficient(matrix,coefficient); + } else if (index1.equals("cstop")) { + if (index2.equals("origin")) returnToOriginUtility.addCoefficient(matrix,coefficient); + else previousStopUtility.addCoefficient(matrix,coefficient); + } else if (index1.equals("prevStopType")) { + int type2 = WeekendTour.convertPurposeToInt(index2); + transitionConstants[type2] = coefficient; + } else if (index1.equals("logStopCount")) { + int type2 = WeekendTour.convertPurposeToInt(index2); + stopCountCoefficients[type2] = coefficient; + } else if (index1.equals("timeAccumulator")) { + totalTravelTimeCoefficient += coefficient; + } else if (index1.equals("totalAccumulator")) { + totalTripTimeCoefficient += coefficient; + } else if (index1.equals("travelDisutility") && index2.equals("origin")) { + disutilityToOriginCoefficient += coefficient; + } else if (index1.equals("travelTime") && index2.equals("origin")) { + timeToOriginCoefficient += coefficient; + } else if ((index1.equals("") || index1.equals("none")) && (index2.equals("") ||index2.equals("none"))) { + constant += coefficient; + } else { + throw new CoefficientFormatError("invalid indexing "+index1+ ","+index2+" in matrix "+matrix +" for next stop purpose model "); + } + } + + + + /** + * Method readMatrices. + * @param mr + */ + public void readMatrices(MatrixCacheReader mr) { + previousStopUtility.readMatrices(mr); + originUtility.readMatrices(mr); + returnToOriginUtility.readMatrices(mr); + } + + /** + * Method getStopPurposeCode. + * @return String + */ + public String getCode() { + return WeekendTour.convertPurposeToString(stopType); + } + +} + + /** + * Method addParameter. + * @param alternative + * @param matrix + * @param coefficient + */ + public void addCoefficient( + String alternative, + String index1, + String index2, + String matrix, + double coefficient) throws CoefficientFormatError { + Iterator alternativeIterator = alternatives.iterator(); + boolean found = false; + while (alternativeIterator.hasNext()) { + AlternativeUsesMatrices alt = (AlternativeUsesMatrices) alternativeIterator.next(); + if (alternative.equals(alt.getCode())) { + alt.addCoefficient(index1,index2,matrix,coefficient); + found = true; + } + } + if (!found) { + logger.info("adding alternative "+alternative+" to "+name); + NextStopPurpose newPurpose = new NextStopPurpose(WeekendTour.convertPurposeToInt(alternative)); + addAlternative(newPurpose); + newPurpose.addCoefficient(index1,index2,matrix,coefficient); + } + } + + /** + * Method readMatrices. + * @param matrixReader + */ + public void readMatrices(MatrixCacheReader mr) { + Iterator alternativeIterator = alternatives.iterator(); + while (alternativeIterator.hasNext()) { + AlternativeUsesMatrices alt = (AlternativeUsesMatrices) alternativeIterator.next(); + alt.readMatrices(mr); + } + } + + public void setMyTour(Tour myTour) { + this.myTour = myTour; + } + + public Tour getMyTour() { + return myTour; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.ModelWithCoefficients#init() + */ + public void init() { + readMatrices(GenerateWeekendTours.matrixReader); + } + + + final String name; + + public WeekendStopPurposeChoice(String myName) { + super(); + this.name = myName; + } + + int monteCarloSamplePurpose() { + NextStopPurpose purpose; + try { + purpose = (NextStopPurpose) monteCarloChoice(); + } catch (NoAlternativeAvailable e) { + e.printStackTrace(); + throw new RuntimeException("No valid purposes available",e); + } + return purpose.stopType; + } +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendTour.java b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendTour.java new file mode 100644 index 0000000..58e439c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/calgary/weekend/WeekendTour.java @@ -0,0 +1,345 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.calgary.weekend; + +import java.util.ArrayList; +import java.util.Iterator; +import java.util.List; + +import org.apache.log4j.Logger; + +import org.sandag.cvm.activityTravel.ChangingTravelAttributeGetter; +import org.sandag.cvm.activityTravel.RealNumberDistribution; +import org.sandag.cvm.activityTravel.Stop; +import org.sandag.cvm.activityTravel.StopAlternative; +import org.sandag.cvm.activityTravel.StopChoice; +import org.sandag.cvm.activityTravel.Tour; +import org.sandag.cvm.activityTravel.VehicleTourTypeChoice; +import org.sandag.cvm.activityTravel.cvm.TourStartTimeModel; +import org.sandag.cvm.common.model.NoAlternativeAvailable; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public class WeekendTour extends Tour { + + static final Logger logger = Logger.getLogger("org.sandag.cvm.calgary.weekend"); + + + /** + * The primaryPerson is the person who makes a full tour, from origin and back again. + */ + public WeekendPerson primaryPerson; + ArrayList otherPeople = new ArrayList(); // the other people in the tour + + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.Tour#sampleStops() + */ + public void sampleStops() { + String tourType = myVehicleTourType.getTourTypeName(); + if (tourType.equals("SELSE") || tourType.equals("chauf")) { + sampleReturnStops(); + } + else { + samplePrimaryStop(); + sampleIntermediateOutboundStop(); + samplePrimaryAndIntermediateDurationAndAddToStopList(); + sampleReturnStops(); + } + } + + private void samplePrimaryAndIntermediateDurationAndAddToStopList() { + if (intermediateStop !=null) { + String stopTypeCode = convertPurposeToString(intermediateStop.purpose); + RealNumberDistribution myDurationModel = (RealNumberDistribution) GenerateWeekendTours.models.get(stopTypeCode+"Duration"); + if (myDurationModel == null) throw new RuntimeException("Can't find duration model "+stopTypeCode+"Duration for stop type number "+intermediateStop.purpose); + intermediateStop.duration = (float) myDurationModel.sampleValue(); + addStop(intermediateStop); + } + String stopTypeCode = convertPurposeToString(primaryStop.purpose); + RealNumberDistribution myDurationModel = (RealNumberDistribution) GenerateWeekendTours.models.get(stopTypeCode+"Duration"); + if (myDurationModel == null) throw new RuntimeException("Can't find duration model "+stopTypeCode+"Duration for stop type number "+primaryStop.purpose); + primaryStop.duration = (float) myDurationModel.sampleValue(); + addStop(primaryStop); + } + + public static int convertPurposeToInt(String stopPurpose) { + if (stopPurpose.equals("work")) return 1; + if (stopPurpose.equals("school")) return 2; + if (stopPurpose.equals("exercise")) return 3; + if (stopPurpose.equals("relCivic")) return 4; + if (stopPurpose.equals("social")) return 5; + if (stopPurpose.equals("entLeisure")) return 6; + if (stopPurpose.equals("shop")) return 7; + if (stopPurpose.equals("eat")) return 8; + if (stopPurpose.equals("dropOff")) return 9; + if (stopPurpose.equals("outOfTown")) return 10; + if (stopPurpose.equals("return")) return 11; + if (stopPurpose.equals("pickUp")) return 12; + if (stopPurpose.equals("dropOff")) return 13; + throw new RuntimeException("stop purpose "+stopPurpose+" is not a valid stop purpose type"); + } + + + /** + * @return String representing the stop type + */ + public static String convertPurposeToString(int purpose) { + switch (purpose) { + case 1: + return "work"; + case 2: + return "school"; + case 3: + return "exercise"; + case 4: + return "relCivic"; + case 5: + return "social"; + case 6: + return "entLeisure"; + case 7: + return "shop"; + case 8: + return "eat"; + case 9: + return "dropOff"; + case 10: + return "outOfTown"; + case 11: + return "return"; + case 12: + return "pickUp"; + case 13: + return "dropOff"; + } + throw new RuntimeException("invalid stop purpose code "+purpose); + } + + Stop intermediateStop = null; + + private void sampleIntermediateOutboundStop() { + + //TODO smarter intermediate stop choice existance model + if (Math.random() > 0.3) return; // 70% chance of no intermediate stop + + StopChoice theModel; + String stopModelStringCode = getTourTypeCode()+"IntermediateStop"; + theModel = (StopChoice) GenerateWeekendTours.models.get(stopModelStringCode); + if (theModel == null) throw new RuntimeException("Can't find stop choice model for "+stopModelStringCode); + theModel.setTour(this); + intermediateStop = new Stop(this, getCurrentLocation(),getTotalElapsedTimeHrs()); + try { + intermediateStop.location = ((StopAlternative) theModel.monteCarloChoice()).location; + } catch (NoAlternativeAvailable e) { + e.printStackTrace(); + throw new RuntimeException("Can't find a viable intermediate stop alternative",e); + } + + WeekendStopPurposeChoice purposeModel = (WeekendStopPurposeChoice) GenerateWeekendTours.models.get(getTourTypeCode()+"StopType"); + if (purposeModel == null)throw new RuntimeException("Can't find stop purpose model for "+getTourTypeCode()); + purposeModel.setMyTour(this); + intermediateStop.purpose = purposeModel.monteCarloSamplePurpose(); + + } + + Stop primaryStop = null; + + private void samplePrimaryStop() { + StopChoice theModel; + String stopModelStringCode = getTourTypeCode()+"PrimaryStop"; + theModel = (StopChoice) GenerateWeekendTours.models.get(stopModelStringCode); + if (theModel == null) throw new RuntimeException("Can't find stop choice model for "+stopModelStringCode); + theModel.setTour(this); + // FIXME will need to rewrite start location and start time if there are any intermediate stops outbound + primaryStop = new Stop(this, getCurrentLocation(),getCurrentTimeHrs()); + try { + primaryStop.location= ((StopAlternative) theModel.monteCarloChoice()).location; + } catch (NoAlternativeAvailable e) { + e.printStackTrace(); + throw new RuntimeException("Can't find a viable primary stop alternative",e); + } + primaryStop.purpose = convertPurposeToInt(getTourTypeCode()); // assume tour type code with primary stops are subset of stop type codes + } + + final int returnStopTypeCode = convertPurposeToInt("return"); + + private void sampleReturnStops() { + StopChoice theModel; + String stopModelStringCode = getTourTypeCode()+"ReturnStop"; + theModel = (StopChoice) GenerateWeekendTours.models.get(stopModelStringCode); + if (theModel == null) throw new RuntimeException("Can't find stop choice model for "+stopModelStringCode); + final int maxReturnStops = 100; + int returnStops = 0; + Stop stop; + do { + theModel.setTour(this); + stop = new Stop(this, getCurrentLocation(),getCurrentTimeHrs()); + WeekendStopPurposeChoice purposeModel = (WeekendStopPurposeChoice) GenerateWeekendTours.models.get(getTourTypeCode()+"StopType"); + if (purposeModel == null)throw new RuntimeException("Can't find stop purpose model for "+getTourTypeCode()); + purposeModel.setMyTour(this); + stop.purpose = purposeModel.monteCarloSamplePurpose(); + if (stop.purpose == returnStopTypeCode) { + stop.location = getOriginZone(); + } + try { + stop.location= ((StopAlternative) theModel.monteCarloChoice()).location; + } catch (NoAlternativeAvailable e) { + e.printStackTrace(); + throw new RuntimeException("Can't find a viable return stop alternative",e); + } + if (stop.purpose != returnStopTypeCode) { + RealNumberDistribution myDurationModel = (RealNumberDistribution) GenerateWeekendTours.models.get(WeekendTour.convertPurposeToString(stop.purpose)+"Duration"); + if (myDurationModel == null) throw new RuntimeException("no "+WeekendTour.convertPurposeToString(stop.purpose)+"Duration model"); + stop.duration = (float) myDurationModel.sampleValue(); + } + addStop(stop); + returnStops ++; + } while (stop.purpose != returnStopTypeCode && returnStops <= maxReturnStops); + if (returnStops >= maxReturnStops) { + logger.warn("Return stops hit maximum, "+maxReturnStops); + } + } + + /** + * tourTypeChoiceModel is the choice model for the tNCVehicle tour type. It is currently + * a static variable, but it is accesssed by getters and setters so could be an instance variable instead, if + * different tours need different models for choosing the tour type + */ + static WeekendTourTypeChoice tourTypeChoiceModel; + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.Tour#getVehicleTourTypeChoice() + */ + public VehicleTourTypeChoice getVehicleTourTypeChoice() { + return tourTypeChoiceModel; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.activityTravel.Tour#setVehicleTourTypeChoice(org.sandag.cvm.activityTravel.VehicleTourTypeChoice) + */ + public void setVehicleTourTypeChoice(VehicleTourTypeChoice vehicleTourTypeChoice) { + WeekendTour.tourTypeChoiceModel = (WeekendTourTypeChoice) vehicleTourTypeChoice; + + } + + + static TourInTimeBand tourInTimeBand; + + /** + * @param titb + */ + public static void setTourInTimeBand(TourInTimeBand titb) { + tourInTimeBand = titb; + + } + + /** + * + */ + public void buildTourGroupAndFlagPeopleOutOfHome() { + primaryPerson.atHome = false; + List peopleInHousehold = (List) primaryPerson.getMyHousehold().getPersons(); + for (int p=0;p0.5) { + person.atHome = false; + otherPeople.add(person); + } + } + } + + } + + /** + * + */ + public void setReturnHomeTimesForGroupMembers() { + primaryPerson.returnTime = getCurrentTimeHrs(); + for (int p=0;p MAX_KEY_LENGTH) { + throw new IllegalArgumentException("Key is larger than permitted size of " + + MAX_KEY_LENGTH + " bytes"); + } + + file.seek(indexPositionToKeyFp(currentNumRecords)); + temp.writeTo(file); + file.seek(indexPositionToDataHeaderFp(currentNumRecords)); + newRecord.write(file); + newRecord.setIndexPosition(currentNumRecords); + writeNumRecordsHeader(currentNumRecords + 1); + } + + + /** + * Removes the record from the index. Replaces the target with the entry at the + * end of the index. + */ + protected void deleteEntryFromIndex(String key, DataHeader header, int currentNumRecords) + throws IOException { + + if (header.indexPosition != (currentNumRecords - 1)) { + String lastKey = readKeyFromIndex(currentNumRecords - 1); + DataHeader last = keyToDataHeader(lastKey); + + last.setIndexPosition(header.indexPosition); + file.seek(indexPositionToKeyFp(last.indexPosition)); + file.writeUTF(lastKey); + file.seek(indexPositionToDataHeaderFp(last.indexPosition)); + last.write(file); + } + + writeNumRecordsHeader(currentNumRecords - 1); + } + + + /** + * Adds the given record to the database. + */ + public synchronized void insertRecord(DataWriter rw) throws IOException { + String key = rw.getKey(); + + if (recordExists(key)) { + throw new IllegalArgumentException("Key exists: " + key); + } + + insureIndexSpace(getNumRecords() + 1); + + DataHeader newRecord = allocateRecord(key, rw.getDataLength()); + + writeRecordData(newRecord, rw); + addEntryToIndex(key, newRecord, getNumRecords()); + } + + + /** + * Updates an existing record. If the new contents do not fit in the original record, + * then the update is handled by deleting the old record and adding the new. + */ + public synchronized void updateRecord(DataWriter rw) throws IOException { + DataHeader header = keyToDataHeader(rw.getKey()); + + if (rw.getDataLength() > header.dataCapacity) { + deleteRecord(rw.getKey()); + insertRecord(rw); + } else { + writeRecordData(header, rw); + writeDataHeaderToIndex(header); + } + } + + + /** + * Reads a record. + */ + public synchronized DataReader readRecord(String key) throws IOException { + byte[] data = readRecordData(key); + + return new DataReader(key, data); + } + + + /** + * Reads the data for the record with the given key. + */ + protected byte[] readRecordData(String key) throws IOException { + return readRecordData(keyToDataHeader(key)); + } + + + /** + * Reads the record data for the given record header. + */ + protected byte[] readRecordData(DataHeader header) throws IOException { + byte[] buf = new byte[header.dataCount]; + + file.seek(header.dataPointer); + file.readFully(buf); + + return buf; + } + + + /** + * Updates the contents of the given record. An IOException is thrown if the + * new data does not fit in the space allocated to the record. The header's + * data count is updated, but not written to the file. + */ + protected void writeRecordData(DataHeader header, DataWriter rw) throws IOException { + if (rw.getDataLength() > header.dataCapacity) { + throw new IOException("Record data does not fit, header.dataCapacity="+ + header.dataCapacity+ + ", dataLength="+rw.getDataLength()); + } + + header.dataCount = rw.getDataLength(); + file.seek(header.dataPointer); + rw.writeTo((DataOutput) file); + } + + + /** + * Updates the contents of the given record. A DataFileException is thrown if + * the new data does not fit in the space allocated to the record. The header's + * data count is updated, but not written to the file. + */ + protected void writeRecordData(DataHeader header, byte[] data) throws IOException { + if (data.length > header.dataCapacity) { + throw new IOException("Record data does not fit, header.dataCapacity="+ + header.dataCapacity+ + ", dataLength="+data.length); + } + + header.dataCount = data.length; + file.seek(header.dataPointer); + file.write(data, 0, data.length); + } + + + /** + * Deletes a record. + */ + public synchronized void deleteRecord(String key) throws IOException { + DataHeader delRec = keyToDataHeader(key); + int currentNumRecords = getNumRecords(); + + if (getFileLength() == (delRec.dataPointer + delRec.dataCapacity)) { + // shrink file since this is the last record in the file + setFileLength(delRec.dataPointer); + } else { + DataHeader previous = getRecordAt(delRec.dataPointer - 1); + + if (previous != null) { + // append space of deleted record onto previous record + previous.dataCapacity += delRec.dataCapacity; + writeDataHeaderToIndex(previous); + } else { + // target record is first in the file and is deleted by adding its + // space to the second record. + DataHeader secondRecord = getRecordAt(delRec.dataPointer + + (long) delRec.dataCapacity); + byte[] data = readRecordData(secondRecord); + + secondRecord.dataPointer = delRec.dataPointer; + secondRecord.dataCapacity += delRec.dataCapacity; + writeRecordData(secondRecord, data); + writeDataHeaderToIndex(secondRecord); + } + } + + deleteEntryFromIndex(key, delRec, currentNumRecords); + } + + + // Checks to see if there is space for and additional index entry. If + // not, space is created by moving records to the end of the file. + protected void insureIndexSpace(int requiredNumRecords) throws IOException { + int originalFirstDataCapacity; + int currentNumRecords = getNumRecords(); + long endIndexPtr = indexPositionToKeyFp(requiredNumRecords); + + if (endIndexPtr > getFileLength() && currentNumRecords == 0) { + setFileLength(endIndexPtr); + dataStartPtr = endIndexPtr; + writeDataStartPtrHeader(dataStartPtr); + + return; + } + + // If first.dataCapacity is set to the actual data count BEFORE resetting + // dataStartPtr, and there is free space in 'first', then dataStartPtr will + // not be reset to the start of the second record. Capture the capacity + // first and use it to perform the reset. + while (endIndexPtr > dataStartPtr) { + DataHeader first = getRecordAt(dataStartPtr); + byte[] data = readRecordData(first); + first.dataPointer = getFileLength(); + originalFirstDataCapacity = first.dataCapacity; + first.dataCapacity = data.length; + setFileLength(first.dataPointer + data.length); + writeRecordData(first, data); + writeDataHeaderToIndex(first); + dataStartPtr += originalFirstDataCapacity; + writeDataStartPtrHeader(dataStartPtr); + } + } + + + /** + * Closes the file. + */ + public synchronized void close() throws IOException { + try { + file.close(); + } finally { + file = null; + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/BinaryFileReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/BinaryFileReader.java new file mode 100644 index 0000000..761b4b0 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/BinaryFileReader.java @@ -0,0 +1,114 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.ObjectInput; +import java.io.ObjectInputStream; +import java.util.ArrayList; +import org.apache.log4j.Logger; + +/** + * Reads a binary file containing a seriazlied TableDataSet class and creates + * an instance of a TableDataSet class. + * + * @author Tim Heier + * @version 1.0, 5/08/2004 + * + */ +public class BinaryFileReader extends TableDataFileReader implements DataTypes { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + //These attributes are initialized on each call to readFile() + private int columnCount; + private int rowCount; + private ArrayList columnData = new ArrayList(); + private ArrayList columnLabels = new ArrayList(); + private int[] columnType; + + + public BinaryFileReader () { + } + + + /** + * Reads a binary file containing serialized objects that make up a TableDataSet + * object. + * + * @param file name of file which contains the binary data + * @return a TableDataSet object + * + * @throws IOException when the file is not found + */ + public TableDataSet readFile(File file) throws IOException { + + TableDataSet table = null; + + try { + logger.debug("Opening file: "+file); + + //Open the file + ObjectInput inStream = new ObjectInputStream(new FileInputStream(file)); + + //Read magic number + int magicNumber = inStream.readInt(); + + //Read number of columns + int nCols = inStream.readInt(); + columnType = new int[nCols]; + + //Read titles + for (int c=0; c < nCols; c++) { + columnLabels.add( inStream.readUTF() ); + } + + //Read column data + for (int c=0; c < nCols; c++) { + Object colObj = inStream.readObject(); + columnData.add( colObj ); + } + inStream.close(); + + table = new TableDataSet(); + table.setName(file.toString()); + for (int i=0; i < nCols; i++) { + table.appendColumn(columnData.get(i), (String) columnLabels.get(i)); + } + } + catch (ClassNotFoundException e) { + logger.error("", e); + } + + return table; + } + + + public TableDataSet readTable(String tableName) throws IOException { + File fileName = new File (getMyDirectory() + File.separator + tableName + ".binTable"); + TableDataSet myTable = readFile(fileName); + myTable.setName(tableName); + return myTable; + } + + + public void close() { + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/BinaryFileWriter.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/BinaryFileWriter.java new file mode 100644 index 0000000..0d1f0fb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/BinaryFileWriter.java @@ -0,0 +1,106 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.io.FileOutputStream; +import java.io.IOException; +import java.io.ObjectOutput; +import java.io.ObjectOutputStream; +import java.util.ArrayList; +import org.apache.log4j.Logger; + + +/** + * Writes a TableDataSet class to a binary file. + * + * @author Tim Heier + * @version 1.0, 5/08/2004 + * + */ +public class BinaryFileWriter extends TableDataFileWriter implements DataTypes { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + + public BinaryFileWriter () { + } + + + /** + * Writes a binary file containing serialized objects that make up a TableDataSet + * object. + * + * @param tableData the tabledataset to be written out to file + * @param file the file where the data should be written + * + * @throws IOException is thrown when the file cannot be written to + */ + public void writeFile(TableDataSet tableData, File file) throws IOException { + + //Pull data out of tableData object for convenience + int nCols = tableData.getColumnCount(); + String[] columnLabels = tableData.getColumnLabels(); + ArrayList columnData = tableData.getColumnData(); + + try { + logger.debug("Opening file: "+file); + + //Create file + ObjectOutput outStream = new ObjectOutputStream(new FileOutputStream(file)); + + //Write magic number + outStream.writeInt(1); + + //Write number of columns + outStream.writeInt( nCols ); + + //Write titles + for (int c=0; c < nCols; c++) { + outStream.writeUTF( columnLabels[c] ); + } + + //Write column data + for (int c=0; c < nCols; c++) { + outStream.writeObject( columnData.get(c) ); + } + + outStream.close(); + } + catch (IOException e) { + throw e; + } + + } + + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataWriter#writeTable(org.sandag.cvm.common.datafile.TableDataSet, java.lang.String) + */ + public void writeTable(TableDataSet tableData, String tableName) throws IOException { + File file = new File (getMyDirectory().getPath() + File.separator + tableName + ".binTable"); + writeFile(tableData, file); + } + + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataWriter#close() + */ + public void close() { + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/CSVFileReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/CSVFileReader.java new file mode 100644 index 0000000..7f5637b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/CSVFileReader.java @@ -0,0 +1,810 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import org.apache.log4j.Logger; + +import java.io.*; +import java.net.URL; +import java.net.URLConnection; +import java.util.ArrayList; +import java.util.List; +import java.util.regex.Pattern; + + +/** + * Creates a TableData class from a CSV file. The default delimiter character is a comma. + * + * @author Tim Heier + * @version 1.0, 2/07/2004 + * + */ +public class CSVFileReader extends TableDataFileReader implements DataTypes { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + //Can be set by caller + private char delimiter = ','; + + //Pattern composed of regular expression used to parse CSV fields + private String pattern = ",(?=(?:[^\"]*\"[^\"]*\")*(?![^\"]*\"))"; + private Pattern regexPattern = Pattern.compile(pattern); + + //These attributes are initialized on each call to readFile() + private int columnCount; + private int rowCount; + private List columnData; + private ArrayList columnLabels; + private int[] columnType; + + private boolean padNulls=false; + + + public boolean isPadNulls() { + return padNulls; + } + + + public void setPadNulls(boolean padNulls) { + this.padNulls = padNulls; + } + + + public CSVFileReader () { + } + + + /** + * Sets the delimiters used by the StringTokenizer when reading column values. + * + * @param delimiter character separating fields in CSV file, default is a comma + */ + public void setDelimiter(char delimiter) { + this.delimiter = delimiter; + + //Update the pattern string with the new delimiter + pattern = Character.toString(delimiter) + pattern.substring(1); + regexPattern = Pattern.compile(pattern); + } + + + /** + * + * @return the delimiter in use + */ + public char getDelimiter() { + return delimiter; + } + + /** + * + * @return the pattern string used to parse CSV fields + */ + public String getPattern() { + return pattern; + } + + /** + * + * @param pattern new pattern string to be used when parsing CSV fields + */ + public void setPattern(String pattern) { + this.pattern = pattern; + regexPattern = Pattern.compile(pattern); + } + + + public TableDataSet readFile(File file) throws IOException { + return readFile(file, true); + } + + public TableDataSet readFile(String urlString) throws IOException { + return readFile(urlString, true); + } + + + /** + * Convenience method to load a CSV file into a table data class. + * + * @param file name of file to read + * @param columnLabelsPresent determines whether first line is treated + * as column titles + * @throws IOException + * + */ + public TableDataSet readFile(File file, boolean columnLabelsPresent) throws IOException { + return readFile(file, columnLabelsPresent, null); + } + + public TableDataSet readFile(String urlString, boolean columnLabelsPresent) throws IOException { + return readFile(urlString, columnLabelsPresent, null); + } + + + + + /** + * Convenience method to load a CSV file into a table data class. + * + * @param file name of file to read + * @param columnsToRead list of column labels that should be read - all other + * columns will be dropped from the table data set + * @throws IOException + * + */ + public TableDataSet readFile(File file, String[] columnsToRead) throws IOException { + return readFile(file, true, columnsToRead); + } + + + /** + * Main method which loads a CSV file into a table data class. + * + * @param file name of file to read + * @param columnLabelsPresent determines whether first line is treated + * as column titles + * @param columnsToRead list of column labels that should be read - all other + * columns will be dropped from the table data set + * @throws IOException + * + */ + public TableDataSet readFile(File file, boolean columnLabelsPresent, String[] columnsToRead) throws IOException { + + if ((columnsToRead != null) && (columnLabelsPresent == false)) { + throw new RuntimeException("Column lables provided as filter but there are no column labels in CSV file"); + } + + //Initialize class attributes + columnCount = 0; + rowCount = 0; + columnData = new ArrayList(); + columnLabels = new ArrayList(); + columnType = null; + + BufferedReader inStream = openFile(file); + + boolean[] readColumnFlag = null; + + if (columnLabelsPresent) { + readColumnFlag = readColumnLabels(inStream, columnsToRead); + boolean readAColumn=false; + for (boolean b: readColumnFlag) { + readAColumn = readAColumn || b; + } + if (!readAColumn) { + logger.fatal("No columns read when reading file "+file); + throw new RuntimeException("No columns read when reading file "+file); + } + } + readData(file, inStream, columnLabelsPresent, readColumnFlag); + + TableDataSet tds = makeTableDataSet(); + tds.setName(file.toString()); + return tds; + } + + /** + * Main method which loads a CSV file into a table data class. + * + * @param urlString http address of file to read + * @param columnLabelsPresent determines whether first line is treated + * as column titles + * @param columnsToRead list of column labels that should be read - all other + * columns will be dropped from the table data set + * @throws IOException + * + */ + public TableDataSet readFile(String urlString, boolean columnLabelsPresent, String[] columnsToRead) throws IOException { + + if ((columnsToRead != null) && (columnLabelsPresent == false)) { + throw new RuntimeException("Column lables provided as filter but there are no column labels in CSV file"); + } + + //Initialize class attributes + columnCount = 0; + rowCount = 0; + columnData = new ArrayList(); + columnLabels = new ArrayList(); + columnType = null; + + URL url; + URLConnection urlConn; + DataInputStream dis; + + url = new URL(urlString); + urlConn = url.openConnection(); + dis = new DataInputStream(urlConn.getInputStream()); + BufferedReader inStream = new BufferedReader(new InputStreamReader(dis)); + + + boolean[] readColumnFlag = null; + + if (columnLabelsPresent) { + readColumnFlag = readColumnLabels(inStream, columnsToRead); + boolean readAColumn=false; + for (boolean b: readColumnFlag) { + readAColumn = readAColumn || b; + } + if (!readAColumn) { + logger.fatal("No columns read when reading file "+ urlString); + throw new RuntimeException("No columns read when reading file "+ urlString); + } + } + readData(urlString, inStream, columnLabelsPresent, readColumnFlag); + + TableDataSet tds = makeTableDataSet(); + tds.setName(urlString.substring((urlString.lastIndexOf("/"))+1, urlString.length())); + System.out.println("Table Name is: " + tds.getName()); + return tds; + } + + + /* + * Read the csv file with a String[] of specified column formats (NUMBER or STRING), + * where the format is specified for all columns, all columns are read, + * and column headings must be present on the first line. + */ + public TableDataSet readFileWithFormats(File file, String[] columnFormats) throws IOException { + + boolean columnLabelsPresent = true; + String[] columnsToRead = null; + + if ((columnsToRead != null) && (columnLabelsPresent == false)) { + throw new RuntimeException("Column lables provided as filter but there are no column labels in CSV file"); + } + + //Initialize class attributes + columnCount = 0; + rowCount = 0; + columnData = new ArrayList(); + columnLabels = new ArrayList(); + columnType = null; + + BufferedReader inStream = openFile(file); + + boolean[] readColumnFlag = null; + + if (columnLabelsPresent) { + readColumnFlag = readColumnLabels(inStream, columnsToRead); + } + readData(file, inStream, columnLabelsPresent, readColumnFlag, columnFormats); + + TableDataSet tds = makeTableDataSet(); + tds.setName(file.toString()); + return tds; + } + + + private BufferedReader openFile(File file) throws IOException { + logger.debug("Opening file: "+file); + + BufferedReader inStream = null; + try { + inStream = new BufferedReader( new FileReader(file) ); + } + catch (IOException e) { + throw e; + } + + return inStream; + } + + + /** + * Read and parse the column titles from the first line of file. + */ + private boolean[] readColumnLabels(BufferedReader inStream, String[] columnsToRead) + throws IOException { + //Read the first line + String line = inStream.readLine(); + + //Test for an empty file + if (line == null) { + throw new IOException("Error: file looks like it's empty"); + } + + //Tokenize the first line + String[] tokens = parseTokens(line); + int count = tokens.length; + + boolean[] readColumnFlag = new boolean[count]; + + //Initialize the readColumnFlag to false if the caller has supplied a + //list of columns. It will be turned to true basedon a comparison of the + //column labels found in the file. Otherwise initialize to true. + for (int i=0; i < count; i++) { + if (columnsToRead != null) + readColumnFlag[i] = false; + else + readColumnFlag[i] = true; + } + + //Read column titles + int c = 0; + for (int i=0; i < count; i++) { + String column_name = tokens[i]; + + //Check if column should be read based on list supplied by caller + if (columnsToRead != null) { + for (int j=0; j < columnsToRead.length; j++) { + if (columnsToRead[j].equalsIgnoreCase(column_name)) { + readColumnFlag[c] = true; + + columnLabels.add(column_name); + columnCount++; + break; + } + } + } + else { + columnLabels.add(column_name); + columnCount++; + } + c++; //the actual columnn number in the file being read + } + + //Debugging output + String msg = "column read flag = "; + for (int i=0; i < readColumnFlag.length; i++) { + if (readColumnFlag[i] == true) + msg += "true"; + else + msg += "false"; + if (i < (readColumnFlag.length-1)) + msg += ", "; + } + msg += "\n"; + logger.debug(msg); + + + return readColumnFlag; + } + + + /** + * Read and parse data portion of file. + */ + private void readData(File file, BufferedReader inStream, boolean columnLabelsPresent, + boolean[] readColumnFlag) + throws IOException { + + int rowNumber = 0; + + //Determine the number of lines in the file + rowCount = findNumberOfLinesInFile(file); + + readRows(file.toString(), inStream, columnLabelsPresent, readColumnFlag, rowNumber); + inStream.close(); + } + + + private void readRows(String source, BufferedReader inStream, + boolean columnLabelsPresent, boolean[] readColumnFlag, int rowNumber) + throws IOException { + logger.debug("number of lines in file: " + rowCount); + if (columnLabelsPresent) { + rowCount--; + } + + //Process each line in the file + String line; + if (rowCount == 0) { + columnType = new int[columnCount]; + readColumnFlag = new boolean[columnCount]; + for (int col =0; col #.00 and fieldWidth = 8 + * %6.0f --> #.# and fieldWidth = 6 + * %.3f --> #.000 and fieldWidth = 3 + * + * @param tableData the TableDataSet to write + * @param file the destination file to write to + * @param fieldFormat an array of PaddedDecimalFormat objects, one for each column + * + */ + public void writeFile(TableDataSet tableData, File file, PaddedDecimalFormat[] fieldFormat) throws IOException { + String formatString; + PrintWriter outStream = null; + + //Pull data out of tableData object for convenience + int nCols = tableData.getColumnCount(); + int nRows = tableData.getRowCount(); + int[] columnType = tableData.getColumnType(); + String[] columnLabels = tableData.getColumnLabels(); + ArrayList columnData = tableData.getColumnData(); + + if (fieldFormat.length != nCols) { + throw new RuntimeException("Length of format array is " + fieldFormat.length + + " should be " + nCols); + } + + try { + outStream = new PrintWriter (new BufferedWriter( new FileWriter(file) ) ); + + //Print titles + for (int i = 0; i < columnLabels.length; i++) { + if (i != 0) + outStream.print(","); + outStream.print( columnLabels[i] ); + } + outStream.println(); + + //Print data + for (int r=0; r < nRows; r++) { + //float[] rowValues = getRowValues(r, 0); + + for (int c=0; c < nCols; c++) { + if (c != 0) + outStream.print(","); + + switch(columnType[c]) { + case STRING: + String[] s = (String[]) columnData.get(c); + if (quoteStrings) { + outStream.print("\""+ s[r]+"\"" ); + } else { + outStream.print(s[r]); + } + break; + case NUMBER: + float[] f = (float[]) columnData.get(c); + if (Float.isInfinite(f[r])) { + // don't want the infinity figure (sideways 8) in output file, want Infinity or -Infinity. + outStream.print(f[r]); + } else { + outStream.print( fieldFormat[c].format(f[r]) ); + } + break; + default: + throw new RuntimeException("unknown column data type: " + columnType[c]); + } + } + outStream.println(); + } + outStream.close(); + } + catch (IOException e) { + throw e; + } + + //Update dirty flag + tableData.setDirty(false); + } + + + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataWriter#writeTable(org.sandag.cvm.common.datafile.TableDataSet, java.lang.String) + */ + public void writeTable(TableDataSet tableData, String tableName) throws IOException { + File file = new File (getMyDirectory().getPath() + File.separator + tableName + ".csv"); + writeFile(tableData, file); + } + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataWriter#close() + */ + public void close() { + } + + public boolean isQuoteStrings() { + return quoteStrings; + } + + public void setQuoteStrings(boolean quoteStrings) { + this.quoteStrings = quoteStrings; + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/D211FileReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/D211FileReader.java new file mode 100644 index 0000000..55b45ca --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/D211FileReader.java @@ -0,0 +1,304 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Serializable; +import java.util.StringTokenizer; +import java.util.ArrayList; +import org.apache.log4j.Logger; + + +/** + * Reads a standard Emme/2 d211 text format file containing node and link records + * for a transportation network. + * + * @author Jim Hicks + * @version 1.0, 5/12/2004 + * + */ +public class D211FileReader implements Serializable { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + + + public D211FileReader () { + } + + + + public TableDataSet readNodeTable (File file) throws IOException { + + int record = 0; + boolean found_t_nodes_init = false; + boolean found_t_links_init = false; + + ArrayList nList = new ArrayList(); + ArrayList xList = new ArrayList(); + ArrayList yList = new ArrayList(); + + float[][] dataTable = null; + + TableDataSet table = null; + + + + try { + logger.debug( "Opening d211 file to read node records: " + file.getName() ); + + //Open the file + BufferedReader in = new BufferedReader(new FileReader(file)); + + String s = new String(); + while ((s = in.readLine()) != null) { + + record++; + + if ( s.indexOf("t nodes") >= 0 ) { + + found_t_nodes_init = true; + + } + else if ( s.indexOf("t links") >= 0 ) { + + found_t_links_init = true; + + } + else if (found_t_nodes_init && !found_t_links_init) { + + parseNode(s, nList, xList, yList); + + } + + } + + } + catch (Exception e) { + System.out.println ("IO Exception caught reading node table data from d211 format file: " + file.getName() + ", record number=" + record ); + e.printStackTrace(); + } + + + + dataTable = new float[nList.size()][3]; + for (int i=0; i < nList.size(); i++) { + try { + dataTable[i][0] = Integer.parseInt ( (String)nList.get(i) ); + dataTable[i][1] = Float.parseFloat ( (String)xList.get(i) ); + dataTable[i][2] = Float.parseFloat ( (String)yList.get(i) ); + } catch (Exception e) { + String msg = "Can't parse "+i+"th node"; + logger.fatal(msg,e); + throw new RuntimeException(msg,e); + } + } + + + ArrayList tableHeadings = new ArrayList(); + tableHeadings.add ("node"); + tableHeadings.add ("x"); + tableHeadings.add ("y"); + + + table = TableDataSet.create( dataTable, tableHeadings ); + + return table; + + } + + + + public TableDataSet readLinkTable (File file) throws IOException { + return readLinkTable ( file, 'a' ); + } + + + public TableDataSet readLinkTableMods (File file) throws IOException { + return readLinkTable ( file, 'm' ); + } + + + private TableDataSet readLinkTable (File file, char action) throws IOException { + + int record = 0; + boolean found_t_links_init = false; + + ArrayList anList = new ArrayList(); + ArrayList bnList = new ArrayList(); + ArrayList distList = new ArrayList(); + ArrayList modeList = new ArrayList(); + ArrayList typeList = new ArrayList(); + ArrayList lanesList = new ArrayList(); + ArrayList vdfList = new ArrayList(); + ArrayList ul1List = new ArrayList(); + ArrayList ul2List = new ArrayList(); + ArrayList ul3List = new ArrayList(); + ArrayList ul4List = new ArrayList(); + + float[][] dataTable = null; + String[] stringColumn = null; + + TableDataSet table = null; + + + + try { + logger.debug( "Opening d211 file to read link records: " + file.getName() ); + + //Open the file + BufferedReader in = new BufferedReader(new FileReader(file)); + + String s = new String(); + while ((s = in.readLine()) != null) { + + record++; + + if ( s.indexOf("t links") >= 0 ) { + + found_t_links_init = true; + + } + else if (found_t_links_init) { + + parseLink( s, action, anList, bnList, distList, modeList, typeList, lanesList, vdfList, ul1List, ul2List, ul3List, ul4List ); + + } + + } + + } + catch (Exception e) { + System.out.println ("IO Exception caught reading link table data from d211 format file: " + file.getName() + ", record number=" + record ); + e.printStackTrace(); + } + + + + dataTable = new float[anList.size()][10]; + stringColumn = new String[anList.size()]; + for (int i=0; i < anList.size(); i++) { + dataTable[i][0] = Integer.parseInt ( (String)anList.get(i) ); + dataTable[i][1] = Integer.parseInt ( (String)bnList.get(i) ); + dataTable[i][2] = Float.parseFloat ( (String)distList.get(i) ); + stringColumn[i] = (String)modeList.get(i); + dataTable[i][3] = Integer.parseInt ( (String)typeList.get(i) ); + dataTable[i][4] = Float.parseFloat ( (String)lanesList.get(i) ); + dataTable[i][5] = Integer.parseInt ( (String)vdfList.get(i) ); + + try { + dataTable[i][6] = Float.parseFloat ( (String)ul1List.get(i) ); + } + catch (Exception e) { + dataTable[i][6] = 0.0f; + } + try { + dataTable[i][7] = Float.parseFloat ( (String)ul2List.get(i) ); + } + catch (Exception e) { + dataTable[i][7] = 0.0f; + } + try { + dataTable[i][8] = Float.parseFloat ( (String)ul3List.get(i) ); + } + catch (Exception e) { + dataTable[i][8] = 0.0f; + } + try { + dataTable[i][9] = Float.parseFloat ( (String)ul4List.get(i) ); + } + catch (Exception e) { + dataTable[i][9] = 0.0f; + } + } + + + ArrayList tableHeadings = new ArrayList(); + tableHeadings.add ("anode"); + tableHeadings.add ("bnode"); + tableHeadings.add ("dist"); + tableHeadings.add ("type"); + tableHeadings.add ("lanes"); + tableHeadings.add ("vdf"); + tableHeadings.add ("ul1"); + tableHeadings.add ("ul2"); + tableHeadings.add ("ul3"); + tableHeadings.add ("ul4"); + + table = TableDataSet.create( dataTable, tableHeadings ); + table.appendColumn (stringColumn, "mode"); + + + + return table; + + } + + + + void parseNode ( String InputString, ArrayList n, ArrayList x, ArrayList y ) { + + StringTokenizer st = new StringTokenizer(InputString); + + if (st.hasMoreTokens()) { + + if ((st.nextToken()).charAt(0) == 'a') { // read only add records + + n.add ( st.nextToken() ); + x.add ( st.nextToken() ); + y.add ( st.nextToken() ); + + } + + } + + } + + + + + void parseLink ( String InputString, char action, ArrayList anList, ArrayList bnList, ArrayList distList, ArrayList modeList, ArrayList typeList, ArrayList lanesList, ArrayList vdfList, ArrayList ul1List, ArrayList ul2List, ArrayList ul3List, ArrayList ul4List ) { + + StringTokenizer st = new StringTokenizer(InputString); + int count = st.countTokens(); + + while (st.hasMoreTokens()) { + + if ( (st.nextToken()).charAt(0) == action ) { // process add or mod records as requested + + anList.add ( st.nextToken() ); + bnList.add ( st.nextToken() ); + distList.add ( st.nextToken() ); + modeList.add ( st.nextToken() ); + typeList.add ( st.nextToken() ); + lanesList.add ( st.nextToken() ); + vdfList.add ( st.nextToken() ); + ul1List.add ( st.nextToken() ); + if (st.hasMoreTokens()) ul2List.add ( st.nextToken() ); + if (st.hasMoreTokens()) ul3List.add ( st.nextToken() ); + if (st.hasMoreTokens()) ul4List.add ( st.nextToken() ); + + } + + } + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/D231FileReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/D231FileReader.java new file mode 100644 index 0000000..f991620 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/D231FileReader.java @@ -0,0 +1,129 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.io.FileReader; +import java.io.BufferedReader; +import java.io.IOException; +import java.io.Serializable; +import java.util.StringTokenizer; +import java.util.ArrayList; +import org.apache.log4j.Logger; + + +/** + * Reads a standard Emme/2 d231 text format file containing turn definitions + * for a transportation network. + * + * @author Jim Hicks + * @version 1.0, 5/12/2004 + * + */ +public class D231FileReader implements Serializable { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + + + public D231FileReader () { + } + + + + public float[][] readTurnTable (File file) throws IOException { + + int record = 0; + boolean found_t_turns_init = false; + + ArrayList values = new ArrayList(); + + float[][] dataTable = null; + + + try { + logger.debug( "Opening d231 file to read turn records: " + file.getName() ); + + //Open the file + BufferedReader in = new BufferedReader(new FileReader(file)); + + String s = new String(); + while ((s = in.readLine()) != null) { + + record++; + + if ( s.indexOf("t turns") >= 0 ) { + + found_t_turns_init = true; + + } + else if (found_t_turns_init) { + + values.add ( parseRecord ( s ) ); + + } + + } + + } + catch (Exception e) { + System.out.println ("IO Exception caught reading node table data from d211 format file: " + file.getName() + ", record number=" + record ); + e.printStackTrace(); + } + + + + dataTable = new float[values.size()][((float[])values.get(0)).length]; + for (int i=0; i < values.size(); i++) { + dataTable[i] = (float[])values.get(i); + } + + + return dataTable; + + } + + + + private float[] parseRecord ( String InputString ) { + + float[] values = new float[8]; + + StringTokenizer st = new StringTokenizer(InputString); + + + int i = 0; + + if (st.hasMoreTokens()) { + + if ((st.nextToken()).charAt(0) == 'a') { // read only add records + + while (st.hasMoreTokens()) { + + values[i] = Float.parseFloat ( st.nextToken() ); + i++; + + } + } + + } + + return values; + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DBFFileReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DBFFileReader.java new file mode 100644 index 0000000..b27c645 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DBFFileReader.java @@ -0,0 +1,225 @@ +/* + * Copyright 2006 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.io.FileInputStream; +import java.io.IOException; +import java.io.InputStream; +import java.util.ArrayList; +import java.util.List; + +import org.apache.log4j.Logger; + +import com.linuxense.javadbf.DBFException; +import com.linuxense.javadbf.DBFField; +import com.linuxense.javadbf.DBFReader; +import org.sandag.cvm.common.datafile.TableDataFileReader; +import org.sandag.cvm.common.datafile.TableDataSet; + +import static org.sandag.cvm.common.datafile.DataTypes.*; + +/** + * This class reads DBF files and stores them as TableDataSets. It uses the third party + * classes from com.linuxense.javadbf + * + * @author Erhardt + * @version 1.0 Nov 27, 2006 + * + */ +public class DBFFileReader extends TableDataFileReader { + + protected static transient Logger logger = Logger.getLogger(DBFFileReader.class); + + //These attributes are initialized on each call to readFile() + private int columnCount; + private int rowCount; + private List columnData; + private ArrayList columnLabels; + private int[] columnType; + private DBFField[] columnDBF; + + /** + * Default constructor. + * + */ + public DBFFileReader() { + + } + + /** + * @see org.sandag.cvm.common.datafile.TableDataFileReader#readFile(java.io.File) + */ + @Override + public TableDataSet readFile(File file) throws IOException { + + //Initialize class attributes + columnCount = 0; + rowCount = 0; + columnData = new ArrayList(); + columnLabels = new ArrayList(); + columnType = null; + + // open file + logger.debug("Opening file: "+file); + InputStream inStream = new FileInputStream(file); + DBFReader reader = new DBFReader(inStream); + + // read data + readHeader(reader); + readData(reader); + inStream.close(); + + // make table + TableDataSet tds = makeTableDataSet(); + tds.setName(file.toString()); + return tds; + } + + /** + * Reads the header information and sets up the table structure. + * + * @param reader + * @throws DBFException + */ + private void readHeader(DBFReader reader) throws DBFException { + + // Determine the number of columns in the file + columnCount = reader.getFieldCount(); + logger.debug("number of columns in file: " + columnCount); + + //Determine the number of lines in the file + rowCount = reader.getRecordCount(); + logger.debug("number of lines in file: " + rowCount); + + //Get the field descriptions + columnType = new int[columnCount]; + columnDBF = new DBFField[columnCount]; + for (int col=0; col 0) { + if (dataLength > maxElementSize) { + throw new IllegalArgumentException( + "Size of entry="+dataLength+" bytes is larger than maxElementSize=" + maxElementSize); + } + setFileLength(fp + maxElementSize); //all elements are maxElementSize in length + newRecord = new DataHeader(fp, maxElementSize); + } + else { + setFileLength(fp + dataLength); + newRecord = new DataHeader(fp, dataLength); + } + } + + return newRecord; + } + + + /** + * Returns the record to which the target file pointer belongs - meaning the specified location + * in the file is part of the record data of the DataHeader which is returned. Returns null if + * the location is not part of a record. (O(n) mem accesses) + */ + protected DataHeader getRecordAt(long targetFp) { + Enumeration e = memIndex.elements(); + + while (e.hasMoreElements()) { + DataHeader next = (DataHeader) e.nextElement(); + + if ((targetFp >= next.dataPointer) && (targetFp < (next.dataPointer + (long) next.dataCapacity))) { + return next; + } + } + + return null; + } + + + /** + * Closes the database. + */ + public synchronized void close() throws IOException { + try { + super.close(); + } finally { + memIndex.clear(); + memIndex = null; + } + } + + + /** + * Adds the new record to the in-memory index and calls the super class add + * the index entry to the file. + */ + protected void addEntryToIndex(String key, DataHeader newRecord, int currentNumRecords) throws IOException { + super.addEntryToIndex(key, newRecord, currentNumRecords); + memIndex.put(key, newRecord); + } + + + /** + * Removes the record from the index. Replaces the target with the entry at the + * end of the index. + */ + protected void deleteEntryFromIndex(String key, DataHeader header, int currentNumRecords) throws IOException { + super.deleteEntryFromIndex(key, header, currentNumRecords); + + DataHeader deleted = (DataHeader) memIndex.remove(key); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataHeader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataHeader.java new file mode 100644 index 0000000..091015c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataHeader.java @@ -0,0 +1,114 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.DataInput; +import java.io.DataOutput; +import java.io.IOException; + +public class DataHeader { + + /** + * File pointer to the first byte of record data (8 bytes). + */ + protected long dataPointer; + + /** + * Actual number of bytes of data held in this record (4 bytes). + */ + protected int dataCount; + + /** + * Number of bytes of data that this record can hold (4 bytes). + */ + protected int dataCapacity; + + /** + * Indicates this header's position in the file index. + */ + protected int indexPosition; + + protected DataHeader() { + } + + + protected DataHeader(long dataPointer, int dataCapacity) { + if (dataCapacity < 1) { + throw new IllegalArgumentException("Bad record size: " + dataCapacity); + } + + this.dataPointer = dataPointer; + this.dataCapacity = dataCapacity; + this.dataCount = 0; + } + + protected int getIndexPosition() { + return indexPosition; + } + + + protected void setIndexPosition(int indexPosition) { + this.indexPosition = indexPosition; + } + + + protected int getDataCapacity() { + return dataCapacity; + } + + + protected int getFreeSpace() { + return dataCapacity - dataCount; + } + + + protected void read(DataInput in) throws IOException { + dataPointer = in.readLong(); + dataCapacity = in.readInt(); + dataCount = in.readInt(); + } + + + protected void write(DataOutput out) throws IOException { + out.writeLong(dataPointer); + out.writeInt(dataCapacity); + out.writeInt(dataCount); + } + + + protected static DataHeader readHeader(DataInput in) throws IOException { + DataHeader r = new DataHeader(); + + r.read(in); + + return r; + } + + + /** + * Returns a new record header which occupies the free space of this record. + * Shrinks this record size by the size of its free space. + */ + protected DataHeader split() { + long newFp = dataPointer + (long) dataCount; + DataHeader newData = new DataHeader(newFp, getFreeSpace()); + + dataCapacity = dataCount; + + return newData; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataReader.java new file mode 100644 index 0000000..58bb994 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataReader.java @@ -0,0 +1,94 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.*; +import org.apache.log4j.Logger; + +public class DataReader { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + String key; + byte[] data; + ByteArrayInputStream in; + ObjectInputStream objIn; + + public DataReader(String key, byte[] data) { + this.key = key; + this.data = data; + in = new ByteArrayInputStream(data); + } + + public String getKey() { + return key; + } + + + public byte[] getData() { + return data; + } + + + public InputStream getInputStream() throws IOException { + return in; + } + + + public ObjectInputStream getObjectInputStream() throws IOException { + if (objIn == null) { + objIn = new ObjectInputStream(in); + } + + return objIn; + } + + + /** + * Reads the next object in the record using an ObjectInputStream. + */ + public Object readObject() throws IOException, OptionalDataException, ClassNotFoundException { + return getObjectInputStream().readObject(); + } + + + + /** + * Reads the serialized object from filename on disk using the specified key. + */ + public static Object readDiskObject ( String filename, String key ) { + + Object obj=null; + DataFile dataFile=null; + + try { + dataFile = new DataFile( filename, "r" ); + DataReader dr = dataFile.readRecord( key ); + obj = dr.readObject(); + } + catch (Exception e) { + logger.error("Exception thrown when reading DiskObject file: " + filename ); + e.printStackTrace(); + } + + return obj; + } + + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataTypes.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataTypes.java new file mode 100644 index 0000000..2de42ff --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataTypes.java @@ -0,0 +1,38 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.Serializable; + +/** + * Supported data types in table oriented data set classes. + * + * @author Tim Heier + * @version 1.0, 1/30/2003 + * + */ + +public interface DataTypes extends Serializable { + + //Supported data types + public final static int NULL = 0; + public final static int BOOLEAN = 1; + public final static int STRING = 2; + public final static int NUMBER = 3; + public final static int DOUBLE = 4; + public final static int OTHER = 1111; +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataWriter.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataWriter.java new file mode 100644 index 0000000..6a4420a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DataWriter.java @@ -0,0 +1,105 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.DataOutput; +import java.io.IOException; +import java.io.ObjectOutputStream; +import org.apache.log4j.Logger; + +public class DataWriter { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + private String key; + private DbByteArrayOutputStream out; + private ObjectOutputStream objOut; + + + public DataWriter(String key) { + this.key = key; + out = new DbByteArrayOutputStream(); + try { + objOut = new ObjectOutputStream(out); + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + + public String getKey() { + return key; + } + + + public void writeObject(Object o) throws IOException { + + //Reset the size of the underlying ByteArrayOutputStream so it can be reused + //out.reset(); + objOut.reset(); + objOut.writeObject(o); + objOut.flush(); + } + + + /** + * Returns the number of bytes in the data. + */ + public int getDataLength() { + return out.size(); + } + + + /** + * Writes the data out to the stream without re-allocating the buffer. + */ + public void writeTo(DataOutput str) throws IOException { + out.writeTo(str); + } + + + /** + * Writes the serialized contents of the object to filename on disk using the specified key. + */ + public static void writeDiskObject ( Object obj, String filename, String key ) { + + DataFile dataFile=null; + + try { + dataFile = new DataFile( filename, 1 ); + DataWriter dw = new DataWriter( key ); + dw.writeObject( obj ); + dataFile.insertRecord(dw); + } + catch (IOException e) { + logger.error( "IO Exception thrown when writing DiskObject file: " + filename ); + e.printStackTrace(); + } + + try { + dataFile.close(); + } + catch (IOException e) { + logger.error( "IO Exception thrown when closing DiskObject file: " + filename ); + e.printStackTrace(); + } + } + + +} + + diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DbByteArrayOutputStream.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DbByteArrayOutputStream.java new file mode 100644 index 0000000..4e4133c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DbByteArrayOutputStream.java @@ -0,0 +1,47 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.ByteArrayOutputStream; +import java.io.DataOutput; +import java.io.IOException; + +/** + * Extends ByteArrayOutputStream to provide a way of writing the buffer to + * a DataOutput without re-allocating it. + */ +public class DbByteArrayOutputStream extends ByteArrayOutputStream { + + public DbByteArrayOutputStream() { + super(); + } + + + public DbByteArrayOutputStream(int size) { + super(size); + } + + /** + * Writes the full contents of the buffer a DataOutput stream. + */ + public synchronized void writeTo(DataOutput dstr) throws IOException { + byte[] data = super.buf; + int l = super.size(); + + dstr.write(data, 0, l); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DiskObjectArray.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DiskObjectArray.java new file mode 100644 index 0000000..5bbb092 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/DiskObjectArray.java @@ -0,0 +1,227 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.io.FileNotFoundException; +import java.io.IOException; +import java.io.Serializable; + +/** + * + * @author Tim Heier + * @version 1.0, 8/13/2003 + * + */ + +public class DiskObjectArray implements Serializable { + + private String fileName; + private int arraySize; + private int maxElementSize; + + private String[] indexArray; + + private transient DataFile dataFile; + + private DiskObjectArray() { + } + + + /** + * Constructor called when creating/overwriting an existing file. + * + * @param fileName fully quallified file name of file used to + * @param arraySize number of elements in the array + * @param maxElementSize maximum size of an element that will be stored (in bytes) + * @throws IOException + */ + public DiskObjectArray(String fileName, int arraySize, int maxElementSize) throws IOException { + this.fileName = fileName; + this.arraySize = arraySize; + this.maxElementSize = maxElementSize; + + dataFile = new DataFile(fileName, arraySize, maxElementSize); + + //Number of elements in array - used when the data file is opened later + DataWriter dw = new DataWriter("arraySize"); + dw.writeObject( new Integer(arraySize) ); + dataFile.insertRecord(dw); + + //maximum size of an element that will be stored - used when the data file is opened later + dw = new DataWriter("maxElementSize"); + dw.writeObject( new Integer(maxElementSize) ); + dataFile.insertRecord(dw); + + indexArray = new String[arraySize+1]; + for (int i=0; i <=arraySize; i++) { + indexArray[i] = i + ""; + } + + } + + + /** + * Constructor called when opening an existing file. + * + * @param fileName fully qualified file name of data-file + * @throws IOException + */ + public DiskObjectArray(String fileName) throws IOException, FileNotFoundException { + this.fileName = fileName; + + File f = new File(fileName); + + if (! f.exists()) { + throw new FileNotFoundException("Database file could not be found: " + fileName); + } + + //Read size of array from data file and initialize indexArray + try { + dataFile = new DataFile(fileName, "rw"); + DataReader dr = dataFile.readRecord("arraySize"); + Integer i = (Integer) dr.readObject(); + this.arraySize = i.intValue(); + + dr = dataFile.readRecord("maxElementSize"); + i = (Integer) dr.readObject(); + this.maxElementSize = i.intValue(); + + //This is a small hack to set the max element size without calling a constructor + //dataFile.maxElementSize = this.maxElementSize; + + } + catch (IOException e) { + throw e; + } + catch (ClassNotFoundException e) { + e.printStackTrace(); + } + + indexArray = new String[arraySize+1]; + for (int i=0; i <=arraySize; i++) { + indexArray[i] = i + ""; + } + + } + + + public void add(int index, Object element) { + //Skip size check for maximum performance + //if (index > size || index < 0) { + // throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); + //} + + DataWriter dw = new DataWriter( indexArray[index] ); + try { + dw.writeObject( element ); + } + catch (IOException e) { + e.printStackTrace(); + } + + //Check size of element against the maximum allowed record size + if (dw.getDataLength() > maxElementSize) { + throw new IllegalArgumentException( + "Size of entry="+dw.getDataLength()+" bytes is larger than maxElementSize=" + maxElementSize); + } + + try { + //Update record if it exists already + if (dataFile.recordExists(indexArray[index])) { + dataFile.updateRecord( dw ); + } + else { + dataFile.insertRecord( dw ); + } + } + catch (Exception e) { + e.printStackTrace(); + } + } + + + /** + * Returns an element from the array. + * + * @param index array index + */ + public Object get(int index) { + //Skip size check for maximum performance + //if (index > size || index < 0) { + // throw new IndexOutOfBoundsException("Index: "+index+", Size: "+size); + //} + + DataReader dr = null; + Object obj = null; + try { + dr = dataFile.readRecord(indexArray[index]); + obj = dr.readObject(); + } + catch (Exception e) { + e.printStackTrace(); + } + + return obj; + } + + + /** + * Removes an element from the array. Can be an expensive operation so only + * delete when necessary. + * + * @param index array index + */ + public void remove(int index) { + try { + dataFile.deleteRecord( indexArray[index] ); + } + catch (IOException e) { + e.printStackTrace(); + } + + } + + + public String getFileName() { + return fileName; + } + + + public int getArraySize() { + return arraySize; + } + + + public int getMaxElementSize() { + return maxElementSize; + } + + /** + * Closes the underlying file. + * + */ + public void close() { + try { + dataFile.close(); + } + catch (IOException e) { + e.printStackTrace(); + } + } +} + diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/ExcelFileReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/ExcelFileReader.java new file mode 100644 index 0000000..f79a397 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/ExcelFileReader.java @@ -0,0 +1,692 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; + +import jxl.CellType; +import jxl.NumberCell; +import jxl.NumberFormulaCell; +import jxl.Workbook; +import jxl.Cell; +import jxl.Sheet; + +import org.apache.log4j.Logger; + + +/** + * Creates a TableData class from an Excel file. + * + * @author Joel Freedman + * @author John Abraham + * @version 1.1, 10/10/2007 + * + * New version checks for cell types and throws an error + * if it can't get a number value from a cell when it thinks + * it should (J. Abraham, Sept-Oct 2007) + */ +public class ExcelFileReader extends TableDataFileReader implements DataTypes { + + /** + * + */ + private static final long serialVersionUID = 1L; + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + //These attributes are initialized on each call to readFile() + private int columnCount; + private int rowCount; + private List columnData; + private ArrayList columnLabels; + private int[] columnType; + private String worksheetName; + private File workbookFile=null; + + + public ExcelFileReader () { + } + + /** + * Set the name of the worksheet to read in this excel workbook. + * @param name THe name of the worksheet to read. + */ + public void setWorksheetName(String name){ + worksheetName = name; + } + + public TableDataSet readFile(File file) throws IOException { + + if(worksheetName == null){ + logger.fatal("Error: must set worksheet to read using setWorksheetName method before reading"); + throw new RuntimeException(); + } + + return readFile(file, worksheetName, true); + } + + + /** + * Convenience method to load a Excel file into a table data class. + * + * @param file name of file to read + * @param columnLabelsPresent determines whether first line is treated + * as column titles + * @throws IOException + * + */ + public TableDataSet readFile(File file, String worksheetName, boolean columnLabelsPresent) throws IOException { + return readFile(file, worksheetName, columnLabelsPresent, null); + } + + + /** + * Convenience method to load a Excel file into a table data class. + * + * @param file name of file to read + * @param columnsToRead list of column labels that should be read - all other + * columns will be dropped from the table data set + * @throws IOException + * + */ + public TableDataSet readFile(File file, String worksheetName, String[] columnsToRead) throws IOException { + return readFile(file, worksheetName,true, columnsToRead); + } + + + /** + * Main method which loads an Excel file into a table data class. + * + * @param file name of file to read + * @param columnLabelsPresent determines whether first line is treated + * as column titles + * @param columnsToRead list of column labels that should be read - all other + * columns will be dropped from the table data set + * @throws IOException + * + */ + public TableDataSet readFile(File file, String worksheetName, boolean columnLabelsPresent, String[] columnsToRead) throws IOException { + + if ((columnsToRead != null) && (columnLabelsPresent == false)) { + throw new RuntimeException("Column lables provided as filter but there are no column labels in Excel file"); + } + + //Initialize class attributes + columnCount = 0; + rowCount = 0; + columnData = new ArrayList(); + columnLabels = new ArrayList(); + columnType = null; + + Workbook workbook = null; + //open workbook + try { + workbook = Workbook.getWorkbook( file); + } + catch (Throwable t) { + logger.error("Error attemting to open excel file " + file); + t.printStackTrace(); + } + + Sheet worksheet = workbook.getSheet(worksheetName); + if (worksheet==null) return null; + boolean[] readColumnFlag = null; + + if (columnLabelsPresent) { + readColumnFlag = readColumnLabels(worksheet, columnsToRead); + } + readData(worksheet, columnLabelsPresent, readColumnFlag); + + TableDataSet tds = makeTableDataSet(); + tds.setName(file.toString()); + return tds; + } + + + /** + * Read the excel file with a String[] of specified column formats (NUMBER or STRING), + * where the format is specified for all columns, all columns are read, + * and column headings must be present on the first line. + * + * @param file File object of excel workbook + * @param worksheetName the name of the worksheet to read + * @param columnFormats An array of column formats. + * + * @return A tableDataSet object containing the data in the worksheet. + */ + public TableDataSet readFileWithFormats(File file, String worksheetName, String[] columnFormats) throws IOException { + + boolean columnLabelsPresent = true; + String[] columnsToRead = null; + + if ((columnsToRead != null) && (columnLabelsPresent == false)) { + throw new RuntimeException("Column lables provided as filter but there are no column labels in Excel file"); + } + + //Initialize class attributes + columnCount = 0; + rowCount = 0; + columnData = new ArrayList(); + columnLabels = new ArrayList(); + columnType = null; + + Workbook workbook = openFile(file); + Sheet worksheet = workbook.getSheet(worksheetName); + + boolean[] readColumnFlag = null; + + if (columnLabelsPresent) { + readColumnFlag = readColumnLabels(worksheet, columnsToRead); + } + + readData( worksheet, columnLabelsPresent, readColumnFlag, columnFormats); + + TableDataSet tds = makeTableDataSet(); + tds.setName(file.toString()); + return tds; + } + + + /** + * Open file method. + * @param file The file. + * @return The workbook + * @throws IOException + */ + private Workbook openFile(File file) throws IOException { + logger.debug("Opening excel file: "+file); + + Workbook workbook = null; + //open workbook + try { + workbook = Workbook.getWorkbook( file ); + } + catch (Throwable t) { + logger.error("Error attemting to open excel file " + file); + t.printStackTrace(); + } + return workbook; + } + + /** + * Read and parse the column titles from the first line of file. + */ + private boolean[] readColumnLabels(Sheet worksheet, String[] columnsToRead) + throws IOException { + + + //Read the first cell + Cell cell = worksheet.getCell(0,0); + + //Test for an empty file + if (cell.getContents().length()==0) { + throw new IOException("Error: first row in sheet looks like it's empty"); + } + + int count = countNumberOfColumns(worksheet); + + boolean[] readColumnFlag = new boolean[count]; + + //Initialize the readColumnFlag to false if the caller has supplied a + //list of columns. It will be turned to true based on a comparison of the + //column labels found in the file. Otherwise initialize to true. + for (int i=0; i < count; i++) { + if (columnsToRead != null) + readColumnFlag[i] = false; + else + readColumnFlag[i] = true; + } + + //Read column titles + int c = 0; + for (int i=0; i < count; i++) { + cell = worksheet.getCell(i, 0); + String column_name = cell.getContents(); + + //Check if column should be read based on list supplied by caller + if (columnsToRead != null) { + for (int j=0; j < columnsToRead.length; j++) { + if (columnsToRead[j].equalsIgnoreCase(column_name)) { + readColumnFlag[c] = true; + + columnLabels.add(column_name); + columnCount++; + break; + } + } + } + else { + columnLabels.add(column_name); + columnCount++; + } + c++; //the actual columnn number in the file being read + } + + //Debugging output + String msg = "column read flag = "; + for (int i=0; i < readColumnFlag.length; i++) { + if (readColumnFlag[i] == true) + msg += "true"; + else + msg += "false"; + if (i < (readColumnFlag.length-1)) + msg += ", "; + } + msg += "\n"; + logger.debug(msg); + + + return readColumnFlag; + } + + + /** + * Read and parse data portion of file. + */ + private void readData(Sheet worksheet, boolean columnLabelsPresent, + boolean[] readColumnFlag) + throws IOException { + + //Determine the number of lines in the file + rowCount = countNumberOfRows(worksheet); + + logger.debug("number of rows in file: " + rowCount); + if (columnLabelsPresent) { + rowCount--; + } + + //Process each line in the file + if (rowCount == 0) { + columnType = new int[columnCount]; + readColumnFlag = new boolean[columnCount]; + for (int col =0; col 0) { + inStream.readLine(); + } + + // read the data + ArrayList[] columnData = readData(inStream, dictionary); + inStream.close(); + + // make the table + TableDataSet tds = makeTableDataSet(columnData, dictionary); + tds.setName(file.toString()); + + return tds; + } + + /** + * Opens the file, and creates a buffered file reader to that file. + * + * @param file The file to open. + * @return Reader for the file + * @throws IOException + */ + private BufferedReader openFile(File file) throws IOException { + logger.debug("Opening file: "+file); + + BufferedReader inStream = null; + try { + inStream = new BufferedReader( new FileReader(file) ); + } + catch (IOException e) { + throw e; + } + + return inStream; + } + + /** + * Read and parse data portion of file. + * + * @param inStream The stream of input data. + * @param dictionary The dictionary defining how the columns are set up. + * + * @return An ArrayList of data for each column read. + * + * @throws IOException + */ + private ArrayList[] readData(BufferedReader inStream, TableDataSet dictionary) throws IOException { + + // set up the start, end and type arrays + int start[] = new int[dictionary.getRowCount()]; + int end[] = new int[dictionary.getRowCount()]; + String type[] = new String[dictionary.getRowCount()]; + for (int i=0; i(); + } + if (type[i].equals("STRING")) { + columnData[i] = new ArrayList(); + } + } + + //Process each line in the file + String line; + int lineNum = 1; + while ((line = inStream.readLine()) != null) { + String[] lineData = new String[dictionary.getRowCount()]; + for (int i=0; i end) { + throw new RuntimeException("Start greater than end position: "+start+">"+end); + } + + String type = dictionary.getStringValueAt(i, "TYPE"); + if (!type.equals("NUMBER") && !type.equalsIgnoreCase("STRING")) { + throw new RuntimeException("Column type must be NUMBER or STRING."); + } + + int labelInFile = (int) dictionary.getValueAt(i, "LABELINFILE"); + if (labelInFile!=0 && labelInFile!=1) { + throw new RuntimeException("LABELINFILE must be 0 or 1."); + } + } + + return dictionary; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataReader#readTable(java.lang.String) + */ + public TableDataSet readTable(String tableName) throws IOException { + File fileName = new File (getMyDirectory() + File.separator + tableName + ".dat"); + TableDataSet me= readFile(fileName); + me.setName(tableName); + return me; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataReader#close() + */ + public void close() { + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/GeneralDecimalFormat.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/GeneralDecimalFormat.java new file mode 100644 index 0000000..14dc2bb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/GeneralDecimalFormat.java @@ -0,0 +1,53 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.text.*; + +/** + * This class provides a way to use scientific notation when necessary. + */ +public class GeneralDecimalFormat extends DecimalFormat { + final DecimalFormat nonScientific; + double useScientificAbove; + double useScientificBelow; + + public GeneralDecimalFormat(String scientificString, double useScientificAbove, double useScientificBelow) { + super(scientificString); + this.useScientificAbove = useScientificAbove; + this.useScientificBelow = useScientificBelow; + String nonScientificString = scientificString.replaceAll("E0+",""); + nonScientific = new DecimalFormat(nonScientificString); + } + + public StringBuffer format(double val, StringBuffer buffer, FieldPosition f) { + if (val ==0.0 || (Math.abs(val) <= useScientificAbove && Math.abs(val) > useScientificBelow)) { + return nonScientific.format(val, buffer, f); + } else { + return super.format(val,buffer,f); + } + } + + public StringBuffer format(long val, StringBuffer buffer, FieldPosition f) { + if (val ==0.0 || (Math.abs(val) <= useScientificAbove && Math.abs(val) > useScientificBelow)) { + return nonScientific.format(val, buffer, f); + } else { + return super.format(val,buffer,f); + } + } + +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/JDBCTableReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/JDBCTableReader.java new file mode 100644 index 0000000..a010bfc --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/JDBCTableReader.java @@ -0,0 +1,221 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.IOException; +import java.sql.*; +import java.util.ArrayList; +import java.util.List; +import org.apache.log4j.Logger; + +import com.pb.common.sql.JDBCConnection; +import com.pb.common.sql.SQLExecute; + +/** + * Creates a TableData class from a table in a JDBC data source. + * + * @author Tim Heier + * @version 1.0, 2/07/2004 + * + */ +public class JDBCTableReader extends TableDataReader { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + private JDBCConnection jdbcConn = null; + + private boolean mangleTableNamesForExcel = false; + + + public JDBCTableReader (JDBCConnection jdbcConn) { + if (jdbcConn == null) { + throw new RuntimeException("Database connection is null"); + } + + this.jdbcConn = jdbcConn; + } + + + /** + * Load all columns and rows of table. + */ + public TableDataSet readTable(String tableName) throws IOException { + String mangledTableName = tableName; + if (mangleTableNamesForExcel) { + logger.debug("Mangling table name "+tableName+" to ["+tableName+"$]"); + mangledTableName = "["+tableName+"$]"; + } + TableDataSet theTable = null; + try { + theTable = loadTable(tableName, "SELECT * FROM " + mangledTableName); + theTable.setName(tableName); + } catch (RuntimeException e) { + logger.warn("Table "+tableName+" can not be read by JDBCTableReader, "+e.toString()); + // want to return null object if table doesn't exist, to be consistent with other table readers. + theTable = null; + } + return theTable; + } + + + /** + * Load table using specified query string. + */ + private TableDataSet loadTable(String tableName, String sqlString) throws IOException { + List columnData = new ArrayList(); + String[] columnLabels; + int columnCount; + + logger.debug("JDBCTableReader, table name: " + tableName); + logger.debug("JDBCTableReader, SQL String: " + sqlString); + + if (mangleTableNamesForExcel) { + logger.debug("Mangling table name "+tableName+" to ["+tableName+"$]"); + tableName = "["+tableName+"$]"; + } + + Statement stmt = null; + ResultSet rs = null; + ResultSetMetaData metaData = null; + + SQLExecute sqlExecute = new SQLExecute(jdbcConn); + try { + int rowCount = sqlExecute.getRowCount(tableName); + + //Run main query + rs = sqlExecute.executeQuery(sqlString); + metaData = rs.getMetaData(); + + columnCount = sqlExecute.getColumnCount(); + columnLabels = sqlExecute.getColumnLabels(); + int[] columnType = new int[columnCount]; + + //Set up a vector of arrays to hold the result set. Store the + //column type at the same time. Each vector holds a column of data. + for (int c = 0; c < columnCount; c++) { + int type = metaData.getColumnType(c+1); + + switch(type) { + //Map these types to STRING + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + case Types.DATE: + case Types.TIME: + case Types.TIMESTAMP: + case Types.BIT: + columnData.add(new String[rowCount]); + columnType[c] = DataTypes.STRING; + break; + //Map these types to NUMBER + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + case Types.BIGINT: + case Types.FLOAT: + case Types.REAL: + case Types.DOUBLE: + case Types.DECIMAL: + case Types.NUMERIC: + columnData.add(new float[rowCount]); + columnType[c] = DataTypes.NUMBER; + break; + default: + System.err.println("**error** unknown column data type, column=" + c + + ", type=" + type); + break; + } + } + + //Read result set and store the data into column-wise arrays. + //Column data in a ResultSet starts in 1,2... + int row = 0; + while (rs.next()) { + for (int c=0; c < columnCount; c++) { + int type = columnType[c]; + + switch(type) { + case DataTypes.STRING: + String[] s = (String[]) columnData.get(c); + s[row] = rs.getString(c+1); + break; + case DataTypes.NUMBER: + float[] f = (float[]) columnData.get(c); + f[row] = rs.getFloat(c+1); + break; + default: + System.err.println("**error** unknown column data type - should not be here"); + break; + } + } + row++; + } + } + catch (SQLException e) { + throw new IOException(e.getMessage()); + } +// finally { +// try { +// rs.close(); +// stmt.close(); +// } +// catch (SQLException e) { +// e.printStackTrace(); +// } +// } + + TableDataSet tds = makeTableDataSet(columnData, columnLabels, columnCount); + tds.setName(tableName); + return tds; + } + + + private TableDataSet makeTableDataSet(List columnData, String[] columnLabels, int columnCount) { + + TableDataSet table = new TableDataSet(); + + for (int i=0; i < columnCount; i++) { + table.appendColumn(columnData.get(i), columnLabels[i]); + } + + return table; + } + + + /** + * @return Returns the mangleTableNamesForExcel. + */ + public boolean isMangleTableNamesForExcel() { + return mangleTableNamesForExcel; + } + + /** + * @param mangleTableNamesForExcel The mangleTableNamesForExcel to set. + */ + public void setMangleTableNamesForExcel(boolean mangleTableNamesForExcel) { + this.mangleTableNamesForExcel = mangleTableNamesForExcel; + } + + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataReader#close() + */ + public void close() { + jdbcConn.close(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/JDBCTableWriter.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/JDBCTableWriter.java new file mode 100644 index 0000000..7c4a487 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/JDBCTableWriter.java @@ -0,0 +1,136 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.IOException; +import org.apache.log4j.Logger; + +import com.pb.common.sql.JDBCConnection; +import com.pb.common.sql.SQLExecute; + +/** + * @author jabraham + * + * This class writes TableDataSets to an SQL Database + */ +public class JDBCTableWriter extends TableDataWriter { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile"); + + private JDBCConnection jdbcConn = null; + + private boolean mangleTableNamesForExcel = false; + + + + public void writeTable(TableDataSet tableData, String tableName) + throws IOException { + String insertMangledTableName = tableName; + if (mangleTableNamesForExcel) { + logger.debug("Mangling table name "+tableName+" to ["+tableName+"$]"); + insertMangledTableName = "["+tableName+"$]"; + } + String createMangledTableName = tableName; + if (mangleTableNamesForExcel) { + logger.debug("Mangling table name "+tableName+" to ["+tableName+"]"); + createMangledTableName = "["+tableName+"]"; + } + saveTable(createMangledTableName, insertMangledTableName, tableData); + } + + + /** + * @param mangledTableName + * @param tableData + */ + private void saveTable(String createMangledTableName, String insertMangledTableName, TableDataSet tableData) { + + //TODO: First we need to check to see if the table already exists and then delete it. + + // first create the table + StringBuffer createStatement = new StringBuffer("CREATE TABLE "+createMangledTableName+ " ("); + int[] columnTypes = tableData.getColumnType(); + for (int c =0; c nCols)) { + String msg = "Column number out of range: " + column; + msg += (", number of columns: " + nCols); + + throw new RuntimeException(msg); + } + + if (columnType[column] != type) { + throw new RuntimeException("column " + column + " is type " + + columnType[column] + " not type " + type); + } + } + + /** + * Return the name of the column given a postion. Column numbers are 1-based. + * + * @return The name of the column or an empty string if the requested + * field is out of bounds. + */ + public String getColumnLabel(int column) { + //Data is 0 based so subtract 1 from what the user supplies + column = column - 1; + + if ((columnLabels != null) && (column >= 0) && + (column < columnLabels.size())) { + return (String) columnLabels.get(column); + } else { + return ""; + } + } + + /** + * Return the postion of a column given the name. Column numbers are 1-based. + * + * @return -1 if the requested column name is not found. + * + */ + public int getColumnPosition(String columnName) { + int position = -1; + + for (int col = 0; col < columnLabels.size(); col++) { + String currentColumn = (String) columnLabels.get(col); + if (currentColumn.equalsIgnoreCase(columnName)) { + position = col + 1; + break; + } + } + + return position; + } + + public int checkColumnPosition(String columnName) throws RuntimeException { + int position = getColumnPosition(columnName); + if (position <0) throw new RuntimeException("Column "+columnName+" does not exist in TableDataSet "+getName()); + return position; + } + + /** + * Indicates whether or not the table constains the specified column. + * + * @param columnName Name of the column to check. + * @return boolean indicating if the column is present. + */ + public boolean containsColumn(String columnName) { + int position = getColumnPosition(columnName); + if (position>=0) return true; + else return false; + } + + /** + * Return the values in a specified row as a float[] + * + * @param row row number to retrieve, values are 0-based + * + * @throws RuntimeException when one of the columns is of type STRING + * + */ + public float[] getRowValues(int row) { + //Data is 0 based so subtract 1 from what the user supplies + row = row - 1; + + int startPosition = 0; //position to start in array + + float[] rowValues = new float[nCols + startPosition]; + + for (int c = 0; c < nCols; c++) { + if (columnType[c] == STRING) { + throw new RuntimeException("column " + c + 1 + + " is of type STRING"); + } + + float[] f = (float[]) columnData.get(c); + + rowValues[c + startPosition] = f[row]; + } + + return rowValues; + } + + /** + * Return a values from a specified row using the indexed column. + * + * @param row indexed row number + */ + public float[] getIndexedRowValuesAt(int row) { + if (columnIndex == null) { + throw new RuntimeException("No index defined."); + } + + row = columnIndex[row] + 1; // getRowValues will subtract 1 + + return getRowValues(row); + } + + /** + * Return the row number from the index. + * + * @param index indexed row number + * @return the row number associated with the index + */ + public int getIndexedRowNumber(int index) { + if (columnIndex == null) { + throw new RuntimeException("No index defined."); + } + + return columnIndex[index] + 1; // getRowValues will subtract 1 + } + + + /** + * Return the values in a specified row as a String[] + * + * @param row row number to retrieve, values are 0-based + * + * @throws RuntimeException when one of the columns is of type STRING + * + */ + public String[] getRowValuesAsString(int row) { + //TODO lookup based on indexed column + //Data is 0 based so subtract 1 from what the user supplies + row = row - 1; + + int startPosition = 0; //position to start in array + + String[] rowValues = new String[nCols + startPosition]; + + for (int c = 0; c < nCols; c++) { + switch (columnType[c]) { + case STRING: + String[] s = (String[]) columnData.get(c); + rowValues[c + startPosition] = s[row]; + break; + case NUMBER: + float[] f = (float[]) columnData.get(c); + rowValues[c + startPosition] = valueFormat.format(f[row]); + break; + } + } + + return rowValues; + } + + /** + * Returns a copy of the values in the table as a float[][] + */ + public float[][] getValues() { + float[][] tableValues = new float[nRows][nCols]; + + for (int c = 0; c < nCols; c++) { + if (columnType[c] == STRING) { + throw new RuntimeException("column " + c + 1 + + " is of type STRING"); + } + + float[] f = (float[]) columnData.get(c); + + for (int r = 0; r < nRows; r++) { + tableValues[r][c] = f[r]; + } + } + + return tableValues; + } + + /** + * Return a value from a specified row and column. For speed, the column + * type is not checked. A RuntimeException will be thrown if the column is + * of type NUMBER. + * + */ + public float getValueAt(int row, int column) { + //Data is 0 based so subtract 1 from what the user supplies + row = row - 1; + column = column - 1; + + + //TODO lookup based on indexed column + float[] f = null; + try { + f = (float[]) columnData.get(column); + } catch (ClassCastException e) { + throw new RuntimeException("Column "+column+" in TableDataSet is not float values",e); + } + + return f[row]; + } + + public float getValueAt(int row, String columnName) { + int columnNumber = getColumnPosition(columnName); + + if (columnNumber <= 0) { + logger.error("no column named " + columnName + " in TableDataSet"); + throw new RuntimeException("no column named " + columnName + + " in TableDataSet"); + } + + return getValueAt(row, columnNumber); + } + + /** + * Return a value from a specified row and column. If the column type is + * not STRING then the numeric value will be converted to string before + * it is returned. + * + */ + public String getStringValueAt(int row, int column) { + //Data is 0 based so subtract 1 from what the user supplies + row = row - 1; + column = column - 1; + + String value; + + if (columnType[column] == NUMBER) { + float[] f = (float[]) columnData.get(column); + value = valueFormat.format(f[row]); + } else { + String[] s = (String[]) columnData.get(column); + value = s[row]; + } + + return value; + } + + public boolean getBooleanValueAt(int row, String columnName) { + return getBooleanValueAt(row,checkColumnPosition(columnName)); + } + /** + * Return a value from a specified row and column. + * + */ + public boolean getBooleanValueAt(int row, int column) { + String boolString = getStringValueAt(row,column); + boolString = boolString.trim(); + if (boolString == null) throw new RuntimeException("Boolean value in TableDataSet "+name+" is blank (null)"); + if (use1sAnd0sForTrueFalse ) { + if (boolString.equalsIgnoreCase("1")) return true; + if (boolString.equalsIgnoreCase("0")) return false; + } + /* ABDEL M.:I added boolString.equalsIgnoreCase("t") and boolString.equalsIgnoreCase("f") to the condition below. + The method getStringValueAt(row,column) above returns t or f rather than true or false. It is not the best way to fix the issue but this is a work around + for now till John A. comes and check it. + */ + if (boolString.equalsIgnoreCase("true") || boolString.equalsIgnoreCase("t")) return true; + if (boolString.equalsIgnoreCase("false") || boolString.equalsIgnoreCase("f")) return false; + throw new RuntimeException("Boolean value in table dataset "+name+" column "+ column+ " is neither true nor false, but ('"+boolString+"')."); + } + + public void setBooleanValueAt(int row, String columnName, boolean value) { + setBooleanValueAt(row,checkColumnPosition(columnName), value); + } + + public void setBooleanValueAt(int row, int column, boolean value) { + if (value) setStringValueAt(row,column,"true"); + else setStringValueAt(row,column,"false"); + } + + /** + * Return a value from a specified row and column. For speed, the column + * type is not checked. A RuntimeException will be thrown if the column is + * of type STRING. + * + */ + public String getStringValueAt(int row, String columnName) { + //Data is 0 based so subtract 1 from what the user supplies + row = row - 1; + + int columnNumber = getColumnPosition(columnName); + + if (columnNumber <= 0) { + logger.error("no column named " + columnName + " in TableDataSet"); + + throw new RuntimeException("no column named " + columnName + + " in TableDataSet"); + } + + //Call with 1-based row and column numbers + return getStringValueAt(row + 1, columnNumber); + } + + /** + * Set at a value using the column name. + */ + public void setValueAt(int row, String colName, float newValue) { + int col = getColumnPosition(colName); + setValueAt(row, col, newValue); + } + + /** + * Return a value from a specified row and column. For speed, the column + * type is not checked. A RuntimeException will be thrown if the column is + * of type NUMBER. + * + */ + public void setValueAt(int row, int column, float newValue) { + //Data is 0 based so subtract 1 from what the user supplies + row = row - 1; + column = column - 1; + + float[] f = (float[]) columnData.get(column); + + f[row] = newValue; + + // any TableDataSetIndex that uses this column will have to regenerate its index. + if (indexColumns[column]==true) { + fireIndexValuesChanged(); + } + setDirty(true); + } + + /** + * update the column specified with the int values specified. + * + */ + public void setColumnAsInt ( int column, int[] newValues ) { + //Data is 0 based so subtract 1 from what the user supplies + column = column - 1; + + float[] f = new float[newValues.length]; + for (int i=0; i < newValues.length; i++) + f[i] = (float)newValues[i]; + + columnData.set( column, f ); + if (indexColumns[column]==true) { + fireIndexValuesChanged(); + } + + setDirty(true); + } + + /** + * update the column specified with the float values specified. + * + */ + public void setColumnAsFloat ( int column, float[] newValues ) { + //Data is 0 based so subtract 1 from what the user supplies + column = column - 1; + + columnData.set( column, newValues ); + if (indexColumns[column]==true) { + fireIndexValuesChanged(); + } + + setDirty(true); + } + + /** + * update the column specified with the double values specified. + * + */ + public void setColumnAsDouble ( int column, double[] newValues ) { + //Data is 0 based so subtract 1 from what the user supplies + column = column - 1; + + float[] f = new float[newValues.length]; + for (int i=0; i < newValues.length; i++) + f[i] = (float)newValues[i]; + + columnData.set( column, f ); + if (indexColumns[column]==true) { + fireIndexValuesChanged(); + } + + setDirty(true); + } + + public void setIndexedValueAt(int row, String colName, float newValue) { + if (columnIndex == null) { + throw new RuntimeException("No index defined."); + } + row = columnIndex[row] + 1; + + int col = getColumnPosition(colName); + setValueAt(row, col, newValue); + } + + /** + * Return a value from an indexed row and column. For speed, the column + * type is not checked. A RuntimeException will be thrown if the column is + * of type NUMBER. + * + */ + public void setIndexedValueAt(int row, int column, float newValue) { + if (columnIndex == null) { + throw new RuntimeException("No index defined."); + } + + row = columnIndex[row] + 1; // getRowValues will subtract 1 + setValueAt(row, column, newValue); + } + + /** + * Return a value from a specified row and column. For speed, the column + * type is not checked. A RuntimeException will be thrown if the column is + * of type STRING. + * + */ + public void setStringValueAt(int row, int column, String newValue) { + //Data is 0 based so subtract 1 from what the user supplies + row = row - 1; + column = column - 1; + + //TODO lookup based on indexed column + String[] s = (String[]) columnData.get(column); + + s[row] = newValue; + setDirty(true); + if (indexColumns[column]==true) { + fireIndexValuesChanged(); + } + if (column == stringIndexColumn) + stringIndexDirty = true; + } + + /** + * Set the value of a {@code STRING} column at a specified row. + * + * @param row + * The (1-based) row number. + * + * @param column + * The name of the column. + * + * @param value + * The value to place in {@code column} at {@code row}. + * + * @throws ClassCastException if {@code column} is not a {@code STRING} column. + * @throws RuntimeException if {@code column} is not found in this table. + */ + public void setStringValueAt(int row, String column, String value) { + setStringValueAt(row,checkColumnPosition(column),value); + } + + public void setIndexColumnNames(String[] indexColumnNames) { + for (int i=0;i= 0 ) + continue; + + logger.info("Adding column " + tdsInHeadings[c] + " to TableDataSet due to merge"); + if ( tdsInTypes[c] == NUMBER ) { + float[] newColumn = new float[nRows]; + + for (int r = 0; r < nRows; r++) + newColumn[r] = tdsIn.getValueAt( r+1, c+1 ); + + appendColumn( newColumn, tdsInHeadings[c] ); + } + else if ( tdsInTypes[c] == STRING ) { + String[] newColumn = new String[nRows]; + + for (int r = 0; r < nRows; r++) + newColumn[r] = tdsIn.getStringValueAt( r+1, c+1 ); + + appendColumn( newColumn, tdsInHeadings[c] ); + } + } + setDirty(true); + + } + + /** + * Static method to log the frequency of values in + * a column specified by the user. + * + * @param tableName String identifying contents of TableDataSet + * @param tds containing column for creating frequency table + * @param columnPosition position of desired column + * + */ + public static void logColumnFreqReport(String tableName, TableDataSet tds, + int columnPosition) { + if (tds.getRowCount() == 0) { + logger.info(tableName + " Table is empty - no data to summarize"); + + return; + } + + float[] columnData = new float[tds.getRowCount()]; + int[] sortValues = new int[tds.getRowCount()]; + + for (int r = 1; r <= tds.getRowCount(); r++) { + columnData[r - 1] = tds.getValueAt(r, columnPosition); + sortValues[r - 1] = (int) (columnData[r - 1] * 10000); + } + + // sort the column elements + int[] index = IndexSort.indexSort(sortValues); + + ArrayList bucketValues = new ArrayList(); + ArrayList bucketSizes = new ArrayList(); + + // count the number of identical elements into buckets + float oldValue = columnData[index[0]]; + int count = 1; + + for (int r = 1; r < tds.getRowCount(); r++) { + if (columnData[index[r]] > oldValue) { + bucketValues.add(Float.toString(oldValue)); + bucketSizes.add(Integer.toString(count)); + count = 0; + oldValue = columnData[index[r]]; + } + + count++; + } + + bucketValues.add(Float.toString(oldValue)); + bucketSizes.add(Integer.toString(count)); + + // print a simple summary table + logger.info("Frequency Report table: " + tableName); + logger.info("Frequency for column " + columnPosition + ": " + + (tds.getColumnLabel(columnPosition))); + logger.info(String.format("%8s", "Value") + + String.format("%11s", "Frequency")); + + int total = 0; + + for (int i = 0; i < bucketValues.size(); i++) { + float value = Float.parseFloat((String) (bucketValues.get(i))); + logger.info(String.format("%8.0f", value) + + String.format("%11d", Integer.parseInt((String) (bucketSizes.get(i))))); + total += Integer.parseInt((String) (bucketSizes.get(i))); + } + + logger.info(String.format("%8s", "Total") + + String.format("%11d\n\n\n", total)); + } + + /** + * Logs the frequency of values in a column specified by the user. + * The array list argument can hold descriptions of the values + * if they are known. For example if a column lists alternatives 1-5, you + * might know that alt 1= 0_autos, alt2=1_auto, etc. + * + * @param tableName String identifying contents of TableDataSet + * @param tds containing column for creating frequency table + * @param columnPosition position of desired column + * + */ + public static void logColumnFreqReport(String tableName, TableDataSet tds, + int columnPosition, String[] descriptions) { + if (tds.getRowCount() == 0) { + logger.info(tableName + " Table is empty - no data to summarize"); + + return; + } + + float[] columnData = new float[tds.getRowCount()]; + int[] sortValues = new int[tds.getRowCount()]; + + for (int r = 1; r <= tds.getRowCount(); r++) { + columnData[r - 1] = tds.getValueAt(r, columnPosition); + sortValues[r - 1] = (int) (columnData[r - 1] * 10000); + } + + // sort the column elements + int[] index = IndexSort.indexSort(sortValues); + + ArrayList bucketValues = new ArrayList(); + ArrayList bucketSizes = new ArrayList(); + + // count the number of identical elements into buckets + float oldValue = columnData[index[0]]; + int count = 1; + + for (int r = 1; r < tds.getRowCount(); r++) { + if (columnData[index[r]] > oldValue) { + bucketValues.add(Float.toString(oldValue)); + bucketSizes.add(Integer.toString(count)); + count = 0; + oldValue = columnData[index[r]]; + } + + count++; + } + + bucketValues.add(Float.toString(oldValue)); + bucketSizes.add(Integer.toString(count)); + + // print a simple summary table + logger.info("Frequency Report table: " + tableName); + logger.info("Frequency for column " + columnPosition + ": " + + (tds.getColumnLabel(columnPosition))); + logger.info(String.format("%8s", "Value") + + String.format("%13s", "Description") + + String.format("%11s", "Frequency")); + + if(descriptions!=null) + if(bucketValues.size() != descriptions.length) + logger.fatal("The number of descriptions does not match the number of values in your data"); + + int total = 0; + + for (int i = 0; i < bucketValues.size(); i++) { + float value = Float.parseFloat((String) (bucketValues.get(i))); + String description = ""; //default value as sometime certain columns don't have descriptions + if(descriptions !=null) { + description = descriptions[i]; + } + logger.info(String.format("%8.0f", value) + " " + String.format("%-11s", description) + + String.format("%11d", Integer.parseInt((String) (bucketSizes.get(i))))); + total += Integer.parseInt((String) (bucketSizes.get(i))); + } + + logger.info(String.format("%23s", "Total") + + String.format("%9d\n\n\n", total)); + } + + + /** + * @param index + */ + public void removeChangeListener(ChangeListener index) { + changeListeners.remove(index); + } + + + public void setName(String name) { + this.name = name; + } + + + public String getName() { + return name; + } + + /* (non-Javadoc) + * @see java.lang.Object#toString() + */ + public String toString() { + return "TableDataSet "+name; + } + + + public interface TableDataSetWatcher { + public void isBeingForgotten(TableDataSet s); + public void isDirty(TableDataSet s); + } + + private ArrayList myWatchers = null; + + public void addFinalizingListener(TableDataSetWatcher watcher) { + if (myWatchers ==null) { + myWatchers = new ArrayList(); + } + myWatchers.add(watcher); + } + + + void tellWatchersImBeingForgotten() { + if (myWatchers != null) { + for (int w=0;w stringIndex = null; //map of string index keys to 1-based row numbers + private int stringIndexColumn = -1; + private boolean stringIndexDirty; + + /** + * Build a string index on the specified column. The values in the column must be unique. If the column is + * modified after the index is built, the index must be rebuilt (using this function) before it can be used again. + * + * @param column + * The column to build the index on. + * + * @throws IllegalStateException if the column contains repeated values. + * @throws RuntimeException if the column is not of type {@code STRING}. + */ + public void buildStringIndex(int column) { + checkColumnNumber(column, STRING); + column--; //changed to a zero based index + String[] columnValues = (String[]) columnData.get(column); + + stringIndex = new HashMap(columnValues.length); + Set repeatedValues = new HashSet(); + + for (int i = 0; i < columnValues.length; i++) + if (stringIndex.put(columnValues[i],i+1) != null) + repeatedValues.add(columnValues[i]); + + if (repeatedValues.size() > 0) { + //nulify the index, as it is invalid anyway, in case somebody catches this exception and tries to carry on + stringIndex = null; + stringIndexColumn = -1; + throw new IllegalStateException("String index cannot be built on a column with non-unique values." + + "The following values have been repeated: " + Arrays.toString(repeatedValues.toArray(new String[repeatedValues.size()]))); + } + + stringIndexColumn = column; + stringIndexDirty = false; + } + + private void checkStringIndexValue(String index) { + if (stringIndex == null) + throw new IllegalStateException("No string index exists for this table."); + if (stringIndexDirty) + throw new IllegalStateException("String index column changed, must be rebuilt."); + if (!stringIndex.containsKey(index)) + throw new IllegalArgumentException("String value not found in index: " + index); + } + + /** + * Get the (0-based) row number for the given string index value. + * + * @param index + * The string index value. + * + * @return the row number corresponding to index {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + */ + public int getStringIndexedRowNumber(String index) { + checkStringIndexValue(index); + return stringIndex.get(index)-1; + } + + /** + * Get the value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The (1-based) column number. + * + * @return the value in {@code column} at the row specified by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws IndexOutOfBoundsException if {@code column} is less than 1 or greater than the number of columns in this table. + * @throws RuntimeException if {@code column} does not hold {@code float}s. + */ + public float getStringIndexedValueAt(String index, int column) { + checkStringIndexValue(index); + return getValueAt(stringIndex.get(index),column); + } + + /** + * Get the value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The column name. + * + * @return the value in {@code column} at the row specified by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws RuntimeException if {@code column} is not found in the table, or does not hold {@code float}s. + */ + public float getStringIndexedValueAt(String index, String column) { + checkStringIndexValue(index); + return getValueAt(stringIndex.get(index),column); + } + + /** + * Get the boolean value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The (1-based) column number. + * + * @return the value in {@code column} at the row specified by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws IndexOutOfBoundsException if {@code column} is less than 1 or greater than the number of columns in this table. + * @throws RuntimeException if {@code column} does not hold {@code boolean}s. + */ + public boolean getStringIndexedBooleanValueAt(String index, int column) { + checkStringIndexValue(index); + return getBooleanValueAt(stringIndex.get(index),column); + } + + /** + * Get the boolean value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The column name. + * + * @return the value in {@code column} at the row specified by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws RuntimeException if {@code column} is not found in the table, or does not hold {@code boolean}s. + */ + public boolean getStringIndexedBooleanValueAt(String index, String column) { + checkStringIndexValue(index); + return getBooleanValueAt(stringIndex.get(index),column); + } + + /** + * Get the string value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The (1-based) column number. + * + * @return the value in {@code column} at the row specified by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws IndexOutOfBoundsException if {@code column} is less than 1 or greater than the number of columns in this table. + */ + public String getStringIndexedStringValueAt(String index, int column) { + checkStringIndexValue(index); + return getStringValueAt(stringIndex.get(index),column); + } + + /** + * Get the string value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The column name. + * + * @return the value in {@code column} at the row specified by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws RuntimeException if {@code column} is not found in the table. + */ + public String getStringIndexedStringValueAt(String index, String column) { + checkStringIndexValue(index); + return getStringValueAt(stringIndex.get(index),column); + } + + /** + * Set the value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The (1-based) column number. + * + * @param value + * The value to place in {@code column} at the row indexed by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws IndexOutOfBoundsException if {@code column} is less than 1 or greater than the number of columns in this table. + * @throws ClassCastException if {@code column} does not hold {@code float}s. + */ + public void setStringIndexedValueAt(String index, int column, float value) { + checkStringIndexValue(index); + setValueAt(stringIndex.get(index),column,value); + } + + /** + * Set the value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The column name. + * + * @param value + * The value to place in {@code column} at the row indexed by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws RuntimeException if {@code column} is not found in the table. + * @throws ClassCastException if {@code column} does not hold {@code float}s. + */ + public void setStringIndexedValueAt(String index, String column, float value) { + checkStringIndexValue(index); + setValueAt(stringIndex.get(index),column,value); + } + + /** + * Set the boolean value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The (1-based) column number. + * + * @param value + * The value to place in {@code column} at the row indexed by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws IndexOutOfBoundsException if {@code column} is less than 1 or greater than the number of columns in this table. + * @throws ClassCastException if {@code column} does not hold {@code boolean}s. + */ + public void setStringIndexedBooleanValueAt(String index, int column, boolean value) { + checkStringIndexValue(index); + setBooleanValueAt(stringIndex.get(index),column,value); + } + + /** + * Set the boolean value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The column name. + * + * @param value + * The value to place in {@code column} at the row indexed by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws RuntimeException if {@code column} is not found in the table. + * @throws ClassCastException if {@code column} does not hold {@code boolean}s. + */ + public void setStringIndexedBooleanValueAt(String index, String column, boolean value) { + checkStringIndexValue(index); + setBooleanValueAt(stringIndex.get(index),column,value); + } + + /** + * Set the string value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The (1-based) column number. + * + * @param value + * The value to place in {@code column} at the row indexed by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws IndexOutOfBoundsException if {@code column} is less than 1 or greater than the number of columns in this table. + * @throws ClassCastException if {@code column} does not hold {@code String}s. + */ + public void setStringIndexedStringValueAt(String index, int column, String value) { + checkStringIndexValue(index); + setStringValueAt(stringIndex.get(index),column,value); + } + + /** + * Set the string value for the specified column and row (specified by string index). + * + * @param index + * The index specifying the row. + * + * @param column + * The column name. + * + * @param value + * The value to place in {@code column} at the row indexed by {@code index}. + * + * @throws IllegalStateException if no string index has been built for this table, or if the index needs to be + * rebuilt (because the index column has been modified after the index was built). + * @throws IllegalArgumentException if {@code index} is not found in the index column. + * @throws RuntimeException if {@code column} is not found in the table. + * @throws ClassCastException if {@code column} does not hold {@code String}s. + */ + public void setStringIndexedStringValueAt(String index, String column, String value) { + checkStringIndexValue(index); + setStringValueAt(stringIndex.get(index),column,value); + } + + //The user must ensure that the keys in the HashMap correspond + //to the headers in the table and that each column in the table + //has a value in the HashMap that is of the correct type. This + //method will not do a lot of error checking or handling. + // + // + public void appendRow(HashMap rowData){ + + int type; + String[] headers = getColumnLabels(); + int columnNum = 1; + for(String header : headers){ + System.out.println("Header Value to Append: " + header); + type = getColumnType()[getColumnPosition(header)-1]; + if(type == DataTypes.NUMBER){ + float[] col = getColumnAsFloat(header); + float[] newCol = new float[col.length+1]; + System.arraycopy(col, 0, newCol, 0, col.length); + newCol[newCol.length-1] = (Float) rowData.get(header); + replaceFloatColumn(columnNum, newCol); + }else if(type == DataTypes.STRING){ + String[] col = getColumnAsString(header); + String[] newCol = new String[col.length+1]; + System.arraycopy(col, 0, newCol, 0, col.length); + newCol[newCol.length-1] = (String) rowData.get(header); + replaceStringColumn(columnNum, newCol); + } + columnNum++; + } + nRows++; + + } + + //column positions are 1-number of columns but columnData ArrayList + //is zero-based so subtract 1 from the supplied colNumber + public void replaceFloatColumn(int colNumber, float[] newData){ + columnData.remove(colNumber-1); + columnData.add(colNumber-1, newData); + } + + //column positions are 1-number of columns but columnData ArrayList + //is zero-based so subtract 1 from the supplied colNumber + public void replaceStringColumn(int colNumber, String[] newData){ + columnData.remove(colNumber-1); + columnData.add(colNumber-1, newData); + } + +} + + diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCacheCollection.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCacheCollection.java new file mode 100644 index 0000000..1270832 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCacheCollection.java @@ -0,0 +1,218 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.IOException; +import java.lang.ref.Reference; +import java.lang.ref.ReferenceQueue; +import java.lang.ref.SoftReference; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +import org.apache.log4j.Logger; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to Window - + * Preferences - Java - Code Generation - Code and Comments + */ +public class TableDataSetCacheCollection extends TableDataSetCollection implements TableDataSet.TableDataSetWatcher { + + private static Logger logger = Logger.getLogger(TableDataSetCollection.class); + private HashMap readDataSoftReferences = new HashMap(); + + private HashMap dirtyDataSetMap = new HashMap(); + + ReferenceQueue myReferenceQueue = new ReferenceQueue(); + + public TableDataSetCacheCollection(TableDataReader reader, TableDataWriter writer) { + super(reader,writer); +// Runnable cleanUp = new Runnable() { +// public void run() { +// while (true) { +// try { +// TableDataSetSoftReference fred = (TableDataSetSoftReference) myReferenceQueue.remove(); +// logger.info("TableDataSet "+fred.name+" is gone"); +// readDataSoftReferences.remove(fred.name); +// } catch (InterruptedException e) { +// throw new RuntimeException("TableDataSetCacheCollection cleanup thread is being interrupted",e); +// } +// } +// } +// }; +// Thread cleanUpThread = new Thread(cleanUp); +// cleanUpThread.start(); + } + + + + /** + * @param name + * @return the TableDataSet requested + */ + public synchronized TableDataSet getTableDataSet(String name) { + // first see if we can remove references to datasets that we don't use + TableDataSetSoftReference fred; + fred = (TableDataSetSoftReference) myReferenceQueue.poll(); + while (fred !=null) { + if (logger.isDebugEnabled()) logger.debug("Removing key "+fred.name+" from list of TableDataSets read"); + readDataSoftReferences.remove(fred.name); + fred = (TableDataSetSoftReference) myReferenceQueue.poll(); + } + SoftReference wr = (SoftReference) readDataSoftReferences.get(name); + TableDataSet theTable = null; + if (wr!=null) { + theTable = (TableDataSet) wr.get(); + } + // could be the case that the soft reference was cleared before it became dirty, check + // to see if we can find it in our dirty list. + if (theTable == null) { + theTable = (TableDataSet) dirtyDataSetMap.get(name); + if (theTable!=null) { + addTableToTempStorage(theTable); + } + } + if (theTable == null) { + try { + if (logger.isDebugEnabled()) logger.debug("reading table "+name); + theTable = getMyReader().readTable(name); + double freeMem = Runtime.getRuntime().freeMemory()/1000000.0; + if (logger.isDebugEnabled()) logger.debug("Memory is "+freeMem); + } catch (IOException e) { + e.printStackTrace(); + } + if (theTable == null) + throw new RuntimeException("Can't read in table " + name); + addTableToTempStorage(theTable); + theTable.addFinalizingListener(this); + } + return theTable; + } + + + + private void addTableToTempStorage(TableDataSet theTable) { + if (logger.isDebugEnabled()) logger.debug("Creating temporary references for "+theTable.getName()); + TableDataSetSoftReference fred = new TableDataSetSoftReference(theTable, myReferenceQueue); + readDataSoftReferences.put(theTable.getName(), fred); + } + + public synchronized void flushAndForget(TableDataSet me) { + if (me.isDirty()) { + writeTableToDisk(me); + } + //TODO remove this next line, shouldn't need to manually remove it from the SoftReferences. + readDataSoftReferences.remove(me.getName()); + dirtyDataSetMap.remove(me.getName()); + } + + + private void writeTableToDisk(TableDataSet me) { + try { + if (logger.isDebugEnabled()) logger.debug("writing table "+me.getName() + ". Table has " + me.getRowCount() + " rows"); + getMyWriter().writeTable(me, me.getName()); + me.setDirty(false); + dirtyDataSetMap.remove(me.getName()); + } catch (IOException e1) { + e1.printStackTrace(); + throw new RuntimeException("Can't write out table " + me.getName()); + } + } + + /* + * (non-Javadoc) + * + * @see com.hbaspecto.calibrator.ModelInputsAndOutputs#flush() + */ + public synchronized void flush() { + Iterator it = dirtyDataSetMap.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + TableDataSet t = (TableDataSet) e.getValue(); + if (t.isDirty()) { + writeTableToDisk(t); + } else { + // if (logger.isDebugEnabled()) logger.debug("*don't need to flush* table "+t.getName()+" as it's not dirty"); + } + } + dirtyDataSetMap.clear(); + it = readDataSoftReferences.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + TableDataSet t = (TableDataSet) ((Reference) e.getValue()).get(); + if (t == null) { + if (logger.isDebugEnabled()) logger.debug("soft reference to table "+e.getKey()+" has been cleared"); + } else { + if (t.isDirty()) { + logger.error("Dirty table not in dirtyDataSetMap"); + writeTableToDisk(t); + } else { + // if (logger.isDebugEnabled()) logger.debug("*don't need to flush* table "+t.getName()+" as it's not dirty"); + } + } + } + } + + /* + * Call flush first if any changes need to be written out + * + * @see com.hbaspecto.calibrator.ModelInputsAndOutputs#invalidate() + */ + public synchronized void invalidate() throws IOException { + //TODO should we do something to remove them from the reference queue? + readDataSoftReferences.clear(); + dirtyDataSetMap.clear(); + super.invalidate(); + } + /** + * @param aTable the TableDataSet to add to the colleciton + */ + public synchronized void addTableDataSet(TableDataSet aTable) { + addTableToTempStorage(aTable); + aTable.setDirty(true); + aTable.addFinalizingListener(this); + } + + + public synchronized void isBeingForgotten(TableDataSet t) { + if (logger.isDebugEnabled()) { + double freeMem = Runtime.getRuntime().freeMemory() / 1000000.0; + logger.debug("getting ready to forget about table " + t.getName() + " freeMem=" + + freeMem); + } + } + + public synchronized void isDirty(TableDataSet s) { + if (logger.isDebugEnabled()) logger.debug("Table "+s+" is now dirty, creating a new soft reference to it now"); + dirtyDataSetMap.put(s.getName(),s); + addTableToTempStorage(s); + } + + @Override + protected void finalize() throws Throwable { + // this could be called at the end of the run, before all of the TableDatasets have been finalized + // So we have to write out any dirty datasets. + try { + flush(); + } finally { + super.finalize(); + } + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCollection.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCollection.java new file mode 100644 index 0000000..1c43810 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCollection.java @@ -0,0 +1,200 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import org.apache.log4j.Logger; + +import java.io.IOException; +import java.lang.ref.WeakReference; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.Iterator; +import java.util.Map; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to Window - + * Preferences - Java - Code Generation - Code and Comments + */ +public class TableDataSetCollection { + + private static Logger logger = Logger.getLogger(TableDataSetCollection.class); + + private HashMap readTableDataSets = new HashMap(); + private ArrayList cacheOfCurrentlyUsedIndices = new ArrayList(); + private TableDataReader myReader = null; + private TableDataWriter myWriter = null; + + public TableDataSetCollection(TableDataReader reader, TableDataWriter writer) { + setMyReader(reader); + setMyWriter(writer); + } + + public synchronized TableDataSetIndex getTableDataSetIndex(String tableName, String[] stringKeyColumnNames, String[] intKeyColumnNames) { + TableDataSetIndex theIndex = null; + TableDataSet theTableDataSet = getTableDataSet(tableName); + Iterator it = cacheOfCurrentlyUsedIndices.iterator(); + while (it.hasNext() && theIndex == null) { + WeakReference r = (WeakReference) it.next(); + TableDataSetIndex anIndex = (TableDataSetIndex) r.get(); + if (anIndex != null) { + if (anIndex.getTableName().equals(tableName)) { + theIndex = anIndex; // assume they match then prove + // otherwise + if (anIndex.getStringColumnNumbers().length != stringKeyColumnNames.length + || anIndex.getIntColumnNumbers().length != intKeyColumnNames.length) { + theIndex = null; + } else { + for (int j = 0; j < stringKeyColumnNames.length; j++) { + int column = theTableDataSet.getColumnPosition(stringKeyColumnNames[j]); + if (column != anIndex.getStringColumnNumbers()[j]) { + theIndex = null; + } + } + for (int j = 0; j < intKeyColumnNames.length; j++) { + int column = theTableDataSet.getColumnPosition(intKeyColumnNames[j]); + if (column != anIndex.getIntColumnNumbers()[j]) { + theIndex = null; + } + } + } + + } + } else { + // null weak reference + it.remove(); + } + } + if (theIndex == null) { + theIndex = new TableDataSetIndex(this, tableName); + theIndex.setIndexColumns(stringKeyColumnNames, intKeyColumnNames); + cacheOfCurrentlyUsedIndices.add(new WeakReference(theIndex)); + } + return theIndex; + } + + /** + * @param name + * @return the TableDataSet requested + */ + public synchronized TableDataSet getTableDataSet(String name) { + TableDataSet theTable = (TableDataSet) readTableDataSets.get(name); + if (theTable == null) { + try { + logger.info("reading table "+name); + theTable = getMyReader().readTable(name); + } catch (IOException e) { + e.printStackTrace(); + } + if (theTable == null) { + logger.fatal("Can't read in table " + name); + throw new RuntimeException("Can't read in table " + name); + } + readTableDataSets.put(name, theTable); + } + return theTable; + } + + public synchronized void flushAndForget(TableDataSet me) { + if (me.isDirty()) { + try { + logger.info("writing table "+me.getName() + ". Table has " + me.getRowCount() + " rows"); + getMyWriter().writeTable(me, me.getName()); + } catch (IOException e1) { + e1.printStackTrace(); + throw new RuntimeException("Can't write out table " + me.getName()); + } + + } + readTableDataSets.remove(me.getName()); + } + + /* + * (non-Javadoc) + * + * @see com.hbaspecto.calibrator.ModelInputsAndOutputs#flush() + */ + public synchronized void flush() { + Iterator it = readTableDataSets.entrySet().iterator(); + while (it.hasNext()) { + Map.Entry e = (Map.Entry) it.next(); + TableDataSet t = (TableDataSet) e.getValue(); + if (t.isDirty()) { + try { + logger.info("writing table "+t.getName() + ". Table has " + t.getRowCount() + " rows"); + getMyWriter().writeTable(t, (String) e.getKey()); + } catch (IOException e1) { + e1.printStackTrace(); + throw new RuntimeException("Can't write out table " + e.getKey()); + } + } + } + getMyWriter().close(); + + } + + /* + * Call flush first if any changes need to be written out + * + * @see com.hbaspecto.calibrator.ModelInputsAndOutputs#invalidate() + */ + public synchronized void invalidate() throws IOException { + readTableDataSets.clear(); +// cacheOfCurrentlyUsedIndices.clear(); + Iterator it = cacheOfCurrentlyUsedIndices.iterator(); + while (it.hasNext()) { + TableDataSetIndex x = (TableDataSetIndex) ((WeakReference) it.next()).get(); + if (x!=null) x.tableDataSetShouldBeReloaded(); + else it.remove(); + } + } + + synchronized void setMyReader(TableDataReader myReader) { + this.myReader = myReader; + } + + TableDataReader getMyReader() { + return myReader; + } + + synchronized void setMyWriter(TableDataWriter myWriter) { + this.myWriter = myWriter; + } + + TableDataWriter getMyWriter() { + return myWriter; + } + + /** + * @param landInventoryTable + */ + public synchronized void addTableDataSet(TableDataSet aTable) { + readTableDataSets.put(aTable.getName(),aTable); + aTable.setDirty(true); + } + + /** + * + */ + public synchronized void close() { + myReader.close(); + myWriter.close(); + + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCrosstabber.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCrosstabber.java new file mode 100644 index 0000000..8fbdee9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/TableDataSetCrosstabber.java @@ -0,0 +1,407 @@ +/* + * Created on 13-Oct-2005 + * + * Copyright 2005 JE Abraham and others + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile; + +import java.io.File; +import java.util.Iterator; +import java.util.TreeSet; + +public class TableDataSetCrosstabber { + + + + public TableDataSetCrosstabber() { + super(); + } + + public static void main(String args[]) { + if (args.length!=5) { + System.out.println("usage: java org.sandag.cvm.common.datafile.TableDataSetCrosstabber directory table rows columns, values"); + System.exit(1); + } + CSVFileReader myReader= new CSVFileReader(); + myReader.setMyDirectory(args[0]); + CSVFileWriter myWriter = new CSVFileWriter(); + myWriter.setMyDecimalFormat(new GeneralDecimalFormat("0.#########E0",10000000,.001)); + myWriter.setMyDirectory(new File(args[0])); + TableDataSetCollection myCollection = new TableDataSetCollection(myReader,myWriter); + TableDataSet results = crossTabDataset(myCollection,args[1],args[2],args[3],args[4]); + results.setName(args[1]+"_"+args[2]+args[3]+"_"+args[4]+"_crossTab"); + myCollection.addTableDataSet(results); + myCollection.flush(); + } + +// this will be the new way to avoid code duplication +// public static TableDataSet crossTabDataset(TableDataSetCollection aCollection, String inputTableName, String rowColumnName, String columnColumnName, String valuesColumnName) { +// String[] rowNames = new String[1]; +// rowNames[0] = rowColumnName; +// return crossTabDataset(aCollection, inputTableName, rowNames, columnColumnName, valuesColumnName); +// } + +// this is the method that should be able to handle multiple row headers + // TODO test this + public static TableDataSet crossTabDataset(TableDataSetCollection aCollection, String inputTableName, String[] rowColumnNames, String columnColumnName, String valuesColumnName) { + // preliminaries + TableDataSet inputTable = aCollection.getTableDataSet(inputTableName); + int[] columnTypes = inputTable.getColumnType(); + TableDataSet out = new TableDataSet(); + + // set up rows + TreeSet[] rowHeaders = new TreeSet[rowColumnNames.length]; + int totalOutputRows = 1; + for (int rowColumnId=0;rowColumnId < rowColumnNames.length;rowColumnId++) { + int forRows = inputTable.checkColumnPosition(rowColumnNames[rowColumnId]); + rowHeaders[rowColumnId] = new TreeSet(); + if (columnTypes[forRows-1]==TableDataSet.STRING) { + String[] rowColumn = inputTable.getColumnAsString(forRows); + for (int i=0;ivalueMode controls behaviour when multiple records match the indices + */ + private int valueMode=SINGLE_VALUE_MODE; + /** + * With SUM_MODE the value returned is the sum of all the values + * that match the indices. When a value is put it is divided by the number of + * records that match the indices + */ + public static final int SUM_MODE=1; + /** + * With AVERAGE_MODE the value returned is the average of all the values + * that match the indices. When a value is put the value is put into all of the records + * that match the indices + */ + public static final int AVERAGE_MODE=2; + /** + * With SINGLE_VALUE_MODE a runtime exception is thrown if there is + * more than one record in the table that matches the indices + */ + public static final int SINGLE_VALUE_MODE=3; + + private boolean errorOnMissingValues = false; + + public boolean isErrorOnMissingValues() { + return errorOnMissingValues; + } + + public void setErrorOnMissingValues(boolean errorOnMissingValues) { + this.errorOnMissingValues = errorOnMissingValues; + } + + public TableDataSetIndexedValue( + String tableName, + String[] stringKeyNames, + String[] intKeyNames, + String[][] stringIndexValues, + int[][] intIndexValues, + String columnName) { + + stringKeyNameValues = new String[1+stringIndexValues.length][]; + stringKeyNameValues[0] = stringKeyNames; + for (int i=0;i1 && valueMode == SINGLE_VALUE_MODE) { + throw new MultipleValueException("Multiple matching index values in SINGLE_VALUE_MODE "+this); + } + if (lastRowNumbers.length<1 && isErrorOnMissingValues()) { + throw new MissingValueException("No matching index values for "+this); + } + float sum=0; + float denominator= 0; + for (int r=0;r1 && valueMode == SINGLE_VALUE_MODE) { + throw new RuntimeException("Multiple matching index values in SINGLE_VALUE_MODE "+this); + } + float value= compositeValue; + if (valueMode == SUM_MODE) { + value = compositeValue/lastRowNumbers.length; + } + for (int r=0;r0) { + intKeyValues[r-1][i] = Integer.valueOf(intKeyNameValues[r][i]).intValue(); + } else { + intKeyValues[r-1][i]=0; + } + } catch (java.lang.NumberFormatException e) { + lastExceptionFound = e;; + } + + } + } + } + + public void setMyFieldName(String myFieldName) { + this.myFieldName = myFieldName; + //myLastCollection = null; + //myLastIndex = null; + lastDataColumnNumber = -1; + } + + /** + * To manually set the data column number. You have to know what column number + * has the data you are interested in; if you don't use setMyFieldName instead. + * @param myDataColumnNumber + */ + public void setMyDataColumn(String dataColumnName, int dataColumnNumber) { + myFieldName = dataColumnName; + lastDataColumnNumber = dataColumnNumber; + } + + public String getMyFieldName() { + return myFieldName; + } + + + public String toString() { + StringBuffer myInfo = new StringBuffer(); + myInfo.append(getMyTableName()); + myInfo.append(" "); + myInfo.append(getMyFieldName()); + myInfo.append(" ("); + for (int s=0;s4) myInfo.append("..."+(stringKeyNameValues.length-4)+" more..."); + myInfo.append(" "); + } + for (int i=0;i4) myInfo.append("..."+(intKeyNameValues.length-4)+" more..."); + myInfo.append(" "); + } + myInfo.append(")"); + return myInfo.toString(); + } + /** + * @return Returns the intKeyNameValues. + */ + public String[][] getIntKeyNameValues() { + return intKeyNameValues; + } + + /** + * @param intKeyNameValues The intKeyNameValues to set. + */ + public void setIntKeyNameValues(String[][] intKeyNameValues) { + this.intKeyNameValues = intKeyNameValues; + updateIntKeys(); + myLastCollection= null; + myLastIndex = null; + } + + /** + * @return Returns the stringKeyNameValues. + */ + public String[][] getStringKeyNameValues() { + return stringKeyNameValues; + } + + /** + * @param stringKeyNameValues The stringKeyNameValues to set. + */ + public void setStringKeyNameValues(String[][] stringKeyNameValues) { + this.stringKeyNameValues = stringKeyNameValues; + myLastCollection= null; + myLastIndex = null; + } + + public void setValueMode(int valueMode) { + this.valueMode = valueMode; + } + + public int getValueMode() { + return valueMode; + } + + /* (non-Javadoc) + * @see org.sandag.cvm.common.datafile.TableDataSetIndex.ChangeListener#indexChanged() + */ + public void indexChanged(TableDataSetIndex r) { + lastRowNumbers=null; + } + + /** + * @param newFieldName + * @param newFieldValues + */ + public void addNewStringKey(String newFieldName, String[] newFieldValues) { + if (newFieldValues.length >0) { + String[][] oldKeyValues = stringKeyNameValues; + + // number of permutations and combinations + int numRows = (oldKeyValues.length-1)*newFieldValues.length; + stringKeyNameValues = new String[numRows+1][]; + stringKeyNameValues[0] = new String[oldKeyValues[0].length+1]; + System.arraycopy(oldKeyValues[0],0,stringKeyNameValues[0],0,oldKeyValues[0].length); + stringKeyNameValues[0][oldKeyValues[0].length] = newFieldName; + + //also need to make more int key rows + String[][] oldIntKeyNameValues = intKeyNameValues; + intKeyNameValues = new String[numRows+1][]; + intKeyNameValues[0] = oldIntKeyNameValues[0]; + + for (int originalRow=1;originalRow0) { + String[][] oldKeyValues = intKeyNameValues; + + // number of permutations and combinations + int numRows = (oldKeyValues.length-1)*newFieldValues.length; + intKeyNameValues = new String[numRows+1][]; + intKeyNameValues[0] = new String[oldKeyValues[0].length+1]; + System.arraycopy(oldKeyValues[0],0,intKeyNameValues[0],0,oldKeyValues[0].length); + intKeyNameValues[0][oldKeyValues[0].length] = newFieldName; + + //also need to make more string key rows + String[][] oldStringKeyNameValues = stringKeyNameValues; + stringKeyNameValues = new String[numRows+1][]; + stringKeyNameValues[0] = oldStringKeyNameValues[0]; + + for (int originalRow=1;originalRow1 && valueMode == SINGLE_VALUE_MODE) { + return false; + } + return true; + } catch (RuntimeException e) { + return false; + } + } + + public boolean hasValidLinks() { + return hasValidLinks(myLastCollection); + } + + /** + * @param collection + * @return String indicating the retrieval status + */ + public String retrieveValueStatusString(TableDataSetCollection collection) { + try { + updateLinks(collection); + } catch (RuntimeException e) { + return "Error updating links "+e; + } + if (lastRowNumbers.length==0) { + return "no matching rows"; + } + if (lastRowNumbers.length>1 && valueMode == SINGLE_VALUE_MODE) { + return "Multiple matching index values in SINGLE_VALUE_MODE"; + } + return String.valueOf(retrieveValue(collection)); + } + + /** + * @param e + */ + public void updateIntKeys(TableModelEvent e, String[][] newIntKeyNameValues) { + boolean updateAll = true; + if (e.getType()== e.UPDATE) { + if (e.getFirstRow()>0 && e.getLastRow()<=intKeyValues.length) { + updateAll=false; + for (int i = e.getFirstRow(); i<= e.getLastRow();i++ ) { + for (int c=0;c { + + //Holds end-of-line separator for current platform + public static String EOL; + + //Get end-of-line separator from operating system + static { + EOL = System.getProperty("line.separator"); + } + + String fileName; + + + /** + * Constructor to create a brand new text file. + * + */ + public TextFile() { + + } + + /** + * Basic constructor which reads file line by line. + * + * @param fileName name of file to open and read + */ + public TextFile(String fileName) { + this(fileName, EOL); + } + + /** + * Read a file and split by any regular expression. Default splitter + * is the platform dependent end-of-line character. + * + * @param fileName name of file to open and read + * @param splitter end-of-line separator, default is EOL for system + */ + public TextFile(String fileName, String splitter) { + super(Arrays.asList(readFrom(fileName).split(splitter))); + + //Remember file name for write() method + this.fileName = fileName; + + //Regular expression split() often leaves an empty + //String at the first position: + if (get(0).equals("")) + remove(0); + } + + /** + * Adds a string to the current TextFile object. Wrapper for underlying + * ArrayList.add() method. + * + * @param line string to add to file + */ + public void addLine(String line) { + add(line); + } + + /** + * Returns a line from the current TextFile object given a line number. Line + * numbers start at 0. Wrapper for underlying ArrayList.get() method. + * + * @param lineNumber string to add to file + */ + public String getLine(int lineNumber) { + return get(lineNumber); + } + + /** + * Updates a line in the current TextFile object given a line number. Line + * numbers start at 0. The old line is returned. Wrapper for underlying + * ArrayList.set() method. + * + * @param lineNumber string to add to file + * @param newLine represents the new line character + * @return the old line + */ + public String setLine(int lineNumber, String newLine) { + return set(lineNumber, newLine); + } + + /** + * Read a file as a single string. This method is static and can + * be called directly without creating a TextFile object. + * + * @param fileName name of the file to read from + */ + public static String readFrom(String fileName) { + StringBuilder sb = new StringBuilder(4096); + try { + BufferedReader in = new BufferedReader( + new FileReader( + new File(fileName).getAbsoluteFile())); + try { + String s; + while ((s = in.readLine()) != null) { + sb.append(s); + sb.append(EOL); + } + } finally { + in.close(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + return sb.toString(); + } + + synchronized public void write() { + writeTo(this.fileName, false); + } + + synchronized public void write(boolean append) { + writeTo(this.fileName, append); + } + + /** + * Write a single file in one method call. This method is static and can + * be called directly without creating a TextFile object. + * + * @param fileName name of file to create and write to + * @param text contents of file + */ + synchronized public static void writeTo(String fileName, String text) { + try { + PrintWriter out = new PrintWriter( + new File(fileName).getAbsoluteFile()); + try { + out.print(text); + } finally { + out.close(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + /** + * Writes the contents of a TextFile object to a specified file. The + * destination file can be opened in append mode otherwise it will be + * created if it does not exist. + * + * @param fileName name of file to write to + * @param append flag, true to open file for appending + */ + synchronized public void writeTo(String fileName, boolean append) { + try { + FileWriter fWriter = + new FileWriter(new File(fileName).getAbsoluteFile(), append); + BufferedWriter bWriter = new BufferedWriter(fWriter); + PrintWriter out = new PrintWriter(bWriter); + try { + for (String item : this) + out.println(item); + } finally { + out.close(); + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + + synchronized public void writeTo(String fileName) { + writeTo(fileName, false); + } + + //Used for testing + public static void main(String[] args) { + + //Create a text file in memory and then write it to a file + TextFile newFile = new TextFile(); + newFile.addLine("line #1"); + newFile.addLine("line #2"); + newFile.addLine("line #3"); + newFile.addLine("line #4"); + newFile.setLine(2, "line #3 was replaced with this line"); + newFile.writeTo("testfile.txt"); + + //Example #1: Read previous file into one string + String fileContents = TextFile.readFrom("testfile.txt"); + + //Example #2: Write a string to a new file + TextFile.writeTo("copy of test.txt", fileContents); + + //Example #3: Read a file into an Arraylist based on separator + TextFile txtFile = new TextFile("testfile.txt"); + + System.out.println("number of lines="+ txtFile.size()); + + //Example #3 (cont'd): Change a line by directly accessing it + txtFile.setLine(2, "line #3 has been changed"); + + //Print out to console to check + for (String s : txtFile) { + System.out.println(s); + } + } +} +/*Output: +number of lines=10 +49 35 91 41 82 58 63 46 32 21 +68 33 20 17 43 58 49 89 21 37 +line #2 has been changed +17 30 58 86 83 42 43 50 41 18 +75 20 17 88 49 46 68 60 58 23 +61 31 36 58 42 74 42 72 71 44 +30 47 67 18 94 51 61 78 72 58 +35 84 15 97 98 20 49 61 70 63 +67 39 12 87 34 88 47 47 12 43 +70 15 87 95 77 55 76 55 93 36 +*/ diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/BinaryFileTest.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/BinaryFileTest.java new file mode 100644 index 0000000..fdc8bc1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/BinaryFileTest.java @@ -0,0 +1,105 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile.tests; + +import java.io.File; +import java.io.IOException; + +import org.sandag.cvm.common.datafile.BinaryFileReader; +import org.sandag.cvm.common.datafile.BinaryFileWriter; +import org.sandag.cvm.common.datafile.CSVFileReader; +import org.sandag.cvm.common.datafile.TableDataSet; + + +/** + * Tests the BinaryFileReader and BinaryFile Writer classes. + * + * @author Tim Heier + * @version 1.0, 5/08/2004 + */ +public class BinaryFileTest { + + + public static void main(String[] args) { + + BinaryFileTest.testWrite(); + BinaryFileTest.testRead(); + } + + + public static void testWrite() { + TableDataSet table = null; + + //Read sample file from common-base/src/sql directory + long startTime = System.currentTimeMillis(); + try { + CSVFileReader reader = new CSVFileReader(); + table = reader.readFile(new File("src/sql/zonedata.csv")); + } catch (IOException e) { + e.printStackTrace(); + } + long stopTime = System.currentTimeMillis(); + System.out.println("Time used to read CSV file: " + (stopTime-startTime)); + + //Write the table out to a new file name + BinaryFileWriter writer = new BinaryFileWriter(); + try { + writer.writeFile(table, new File("src/sql/zonedata.bin")); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + public static void testRead() { + TableDataSet table = null; + + //Read sample file from common-base/src/sql directory + long startTime = System.currentTimeMillis(); + try { + BinaryFileReader reader = new BinaryFileReader(); + table = reader.readFile(new File("src/sql/zonedata.bin")); + } catch (IOException e) { + e.printStackTrace(); + } + long stopTime = System.currentTimeMillis(); + System.out.println("Time used to read Binary file: " + (stopTime-startTime)); + + //Display some statistics about the file + System.out.println("Number of columns: " + table.getColumnCount()); + System.out.println("Number of rows: " + table.getRowCount()); + + //Display column titles + String[] labels = table.getColumnLabels(); + for (int i = 0; i < labels.length; i++) { + System.out.print( String.format(" %10s", labels[i]) ); + } + System.out.println(); + + //Print data + for (int i=1; i <= 10; i++) { + //Get a row from table + String row[] = table.getRowValuesAsString(i); + + for (int j=0; j < row.length; j++) { + System.out.print( String.format(" %10s", row[j]) ); + } + System.out.println(); + } + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/CSVFileReaderTest.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/CSVFileReaderTest.java new file mode 100644 index 0000000..cc52aed --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/CSVFileReaderTest.java @@ -0,0 +1,83 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile.tests; + +import java.io.File; +import java.io.IOException; + +import org.sandag.cvm.common.datafile.CSVFileReader; +import org.sandag.cvm.common.datafile.TableDataSet; +import org.sandag.cvm.common.datafile.OLD_CSVFileReader; +import com.pb.common.util.PerformanceTimer; +import com.pb.common.util.PerformanceTimerType; + +/** + * Tests the CSVFileReader class. + * + * @author Tim Heier + * @version 1.0, 2/7/2004 + */ +public class CSVFileReaderTest { + + public static void main(String[] args) { + + CSVFileReaderTest.testRead(); + } + + public static void testRead() { + + CSVFileReader reader = new CSVFileReader(); + // Can set the delimiter set if needed + // reader.setDelimSet(" ,\t\n\r\f\""); + + PerformanceTimer timer = PerformanceTimer.createNewTimer("CsvFileTest", + PerformanceTimerType.CSV_READ); + timer.start(); + + // Read sample file from common-base/src/sql directory + TableDataSet table = null; + try { + table = reader.readFile(new File("test.csv")); + timer.stop(); + } catch (IOException e) { + e.printStackTrace(); + } + + // Display some statistics about the file + System.out.println("Number of columns: " + table.getColumnCount()); + System.out.println("Number of rows: " + table.getRowCount()); + + // Display column titles + String[] labels = table.getColumnLabels(); + for (int i = 0; i < labels.length; i++) { + System.out.print(String.format(" %10s", labels[i])); + } + System.out.println(); + + // Print data + for (int i = 1; i <= 10; i++) { + // Get a row from table + String row[] = table.getRowValuesAsString(i); + + for (int j = 0; j < row.length; j++) { + System.out.print(String.format(" %10s", row[j])); + } + System.out.println(); + } + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/CSVFileWriterTest.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/CSVFileWriterTest.java new file mode 100644 index 0000000..4f20c1f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/CSVFileWriterTest.java @@ -0,0 +1,64 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile.tests; + +import java.io.File; +import java.io.IOException; + +import org.sandag.cvm.common.datafile.CSVFileReader; +import org.sandag.cvm.common.datafile.CSVFileWriter; +import org.sandag.cvm.common.datafile.TableDataSet; + + +/** + * Tests the CSVFileWriter class. + * + * @author Tim Heier + * @version 1.0, 2/7/2004 + */ +public class CSVFileWriterTest { + + + public static void main(String[] args) { + + CSVFileWriterTest.testWrite(); + } + + + public static void testWrite() { + + //Read a CSV file first + TableDataSet table = null; + try { + CSVFileReader reader = new CSVFileReader(); + table = reader.readFile(new File("src/sql/zonedata.csv")); + } catch (IOException e) { + e.printStackTrace(); + } + + //Write the table out to a new file name + CSVFileWriter writer = new CSVFileWriter(); + try { + writer.writeFile(table, new File("src/sql/zonedata_new.csv")); + } catch (IOException e) { + e.printStackTrace(); + } + + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/DataFileTest.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/DataFileTest.java new file mode 100644 index 0000000..722fb0e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/DataFileTest.java @@ -0,0 +1,85 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile.tests; + +import java.io.File; + +import java.util.Date; + +import org.sandag.cvm.common.datafile.DataFile; +import org.sandag.cvm.common.datafile.DataReader; +import org.sandag.cvm.common.datafile.DataWriter; + +/** + * Tests the records package. + * class. + * + * @author Tim Heier + * @version 1.0, 4/15/2000 + * + */ +public class DataFileTest { + + public static void main(String[] args) throws Exception { + int numRecords = 100; + String fileName = "sample.db"; + + //Delete file if it exists as part of the test + File file = new File(fileName); + + if (file.exists()) { + file.delete(); + } + + System.out.println("creating data file: sample.db"); + + DataFile dataFile = new DataFile("sample.db", 100); + + System.out.println("adding data: lastAccessTime"); + + DataWriter dw = new DataWriter("lastAccessTime"); + + dw.writeObject(new Date()); + dataFile.insertRecord(dw); + + DataReader dr = dataFile.readRecord("lastAccessTime"); + Date d = (Date) dr.readObject(); + + System.out.println("lastAccessTime = " + d.toString()); + + System.out.println("updating data: lastAccessTime"); + dw = new DataWriter("lastAccessTime"); + dw.writeObject(new Date()); + dataFile.updateRecord(dw); + + System.out.println("reading data: lastAccessTime"); + dr = dataFile.readRecord("lastAccessTime"); + d = (Date) dr.readObject(); + System.out.println("lastAccessTime = " + d.toString()); + + System.out.println("deleting data: lastAccessTime"); + dataFile.deleteRecord("lastAccessTime"); + + if (dataFile.recordExists("lastAccessTime")) { + throw new Exception("data not deleted"); + } else { + System.out.println("data successfully deleted."); + } + + System.out.println("test completed."); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/DiskObjectArrayTest.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/DiskObjectArrayTest.java new file mode 100644 index 0000000..2d3585f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/DiskObjectArrayTest.java @@ -0,0 +1,193 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile.tests; + +import java.io.IOException; + +import org.sandag.cvm.common.datafile.DiskObjectArray; +import com.pb.common.util.ObjectUtil; + +/** + * + * @author Tim Heier + * @version 1.0, 8/13/2003 + * + */ + +public class DiskObjectArrayTest { + + public static final int ARRAY_SIZE = 500000; + public static final int DATA_SIZE = 1000; + + + public static void main(String[] args) { + + DiskObjectArrayTest test = new DiskObjectArrayTest(); + test.testCreate(); + test.testAddElements(); + test.testFillArray(); + test.testUpdateArray(); + test.testAddLargeElement(); + } + + + public void testCreate() { + + //Create a large object array + DiskObjectArray ba = null; + try { + ba = new DiskObjectArray("test.array", ARRAY_SIZE, DATA_SIZE); + } + catch (IOException e) { + e.printStackTrace(); + } + + System.out.println("testCreate() done. sizeOf DiskObjectArray = " + ObjectUtil.sizeOf(ba) + " bytes"); + + ba.close(); + } + + + public void testAddElements() { + + //Create a large object array + DiskObjectArray ba = null; + try { + ba = new DiskObjectArray("test.array"); + } + catch (IOException e) { + e.printStackTrace(); + } + + //----- Add elements to array + + ba.add( 1, new Integer(1) ); + ba.add( 1, new Integer(2) ); //try adding to same location + + int[] intArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9 }; + ba.add( 2, intArray); + + ba.add( 1000, new Integer(1000) ); + + //----- Read elements from array + + System.out.println("element 1 = " + ba.get( 1 )); + + intArray = (int[]) ba.get( 2 ); + for (int i=0; i < 10; i++) { + System.out.println("element 2["+i+"]" + " = " + intArray[i]); + } + + System.out.println("element 1000 = " + ba.get( 1000 )); + + System.out.println("testAddElements() done. sizeOf DiskObjectArray = " + ObjectUtil.sizeOf(ba) + " bytes"); + + ba.close(); + } + + + public void testFillArray() { + + long startTime=System.currentTimeMillis(), endTime; + + //Create a large object array + DiskObjectArray ba = null; + try { + ba = new DiskObjectArray("test.array"); + } + catch (IOException e) { + e.printStackTrace(); + } + + //----- Add a small object to each location in array + for (int i=0; i < ARRAY_SIZE; i++) { + //for (int i=0; i < 5000; i++) { + if ((i % 500) == 0) { + endTime = System.currentTimeMillis(); + System.out.println("adding="+ i + ", time="+(endTime-startTime)); + startTime = System.currentTimeMillis(); + } + ba.add( i, new Integer(i)); + } + + System.out.println("testFillArray() done. sizeOf DiskObjectArray = " + ObjectUtil.sizeOf(ba) + " bytes"); + + //Close it + ba.close(); + } + + + public void testUpdateArray() { + + long startTime=System.currentTimeMillis(), endTime; + + //Create a large object array + DiskObjectArray ba = null; + try { + ba = new DiskObjectArray("test.array"); + } + catch (IOException e) { + e.printStackTrace(); + } + + //Update an element in the middle of the array + int[] intArray = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19 }; + ba.add( 250000, intArray); + + intArray = (int[]) ba.get( 250000 ); + + System.out.println("element 250000[5]" + " = " + intArray[5]); + + System.out.println("testUpdateArray() done."); + + //Close it + ba.close(); + } + + + public void testAddLargeElement() { + + //Create a large object array + DiskObjectArray ba = null; + try { + ba = new DiskObjectArray("test.array"); + } + catch (IOException e) { + e.printStackTrace(); + } + + //----- Add elements to array + + ba.add( 1, new Integer(1) ); + ba.add( 2, new Integer(2) ); + ba.add( 3, new Integer(3) ); + + int[] intArray = new int[210]; + System.out.println("size of new element 2 = " + ObjectUtil.sizeOf(intArray)); + + ba.add( 2, intArray); + + System.out.println("Trying to read element 3..."); + System.out.println("element 3 = " + ba.get( 3 )); + + System.out.println("testAddLargeElement() done."); + + ba.close(); + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/JDBCTableReaderTest.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/JDBCTableReaderTest.java new file mode 100644 index 0000000..f342d72 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/JDBCTableReaderTest.java @@ -0,0 +1,87 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile.tests; + +import java.io.IOException; + +import org.sandag.cvm.common.datafile.JDBCTableReader; +import org.sandag.cvm.common.datafile.TableDataSet; +import com.pb.common.sql.JDBCConnection; + +/** + * Tests the JDBCTableReader class. + * + * @author Tim Heier + * @version 1.0, 2/7/2004 + */ +public class JDBCTableReaderTest { + + public static String HOST = "localhost"; + public static String DATABASE = "test"; + public static String USER = ""; + public static String PASSWD = ""; + public static String TABLE = "zonedata"; + public static String DRIVER = "com.mysql.jdbc.Driver"; + + + //Database url string - specific to vendor + public static String URL = "jdbc:mysql://" + HOST + "/" + DATABASE + "?user=" + USER + "&password=" + PASSWD; + + + public static void main(String[] args) { + + JDBCTableReaderTest.testLoad(); + } + + + public static void testLoad() { + JDBCConnection jdbcConn = new JDBCConnection(URL, "com.mysql.jdbc.Driver", USER, PASSWD); + + JDBCTableReader reader = new JDBCTableReader(jdbcConn); + + TableDataSet table = null; + try { + table = reader.readTable(TABLE); + } catch (IOException e) { + e.printStackTrace(); + } + jdbcConn.close(); + + //Display some statistics about the file + System.out.println("Number of columns: " + table.getColumnCount()); + System.out.println("Number of rows: " + table.getRowCount()); + + //Display column titles + String[] labels = table.getColumnLabels(); + for (int i = 0; i < labels.length; i++) { + System.out.print( String.format("%10s", labels[i]) ); + } + System.out.println(); + + //Print data + for (int i=1; i <= 10; i++) { + + //Get a row from table + String row[] = table.getRowValuesAsString(i); + + for (int j=0; j < row.length; j++) { + System.out.print( String.format(" %10s", row[j]) ); + } + System.out.println(); + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/TableDataSetTest.java b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/TableDataSetTest.java new file mode 100644 index 0000000..97fe080 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/datafile/tests/TableDataSetTest.java @@ -0,0 +1,322 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.datafile.tests; + +import org.sandag.cvm.common.datafile.CSVFileReader; +import org.sandag.cvm.common.datafile.CSVFileWriter; +import org.sandag.cvm.common.datafile.TableDataSet; + +import java.io.File; +import java.io.IOException; +import org.apache.log4j.Logger; + +/** + * Tests the TableDataSet class. + * + * @author Tim Heier + * @version 1.0, 2/8/2003 + */ +public class TableDataSetTest { + + protected static transient Logger logger = Logger.getLogger("org.sandag.cvm.common.datafile.test"); + + public static void main(String[] args) { + TableDataSet table = TableDataSetTest.readCSVFile(); + TableDataSetTest.testGetRowValues( table ); + TableDataSetTest.testGetValueAt( table ); + TableDataSetTest.testColmnNameRetrieval( table ); + TableDataSetTest.testSetValueAt( table ); + TableDataSetTest.testSaveFile( table ); + TableDataSetTest.testBuildIndex( table ); + TableDataSetTest.readCSVFileNoLabels(); + TableDataSetTest.readCSVFileFilteringColumns(); + //TableDataSetTest.testPerformance(); + } + + +/* TCH - Test method for my machine. + + public static void testPerformance() { + TableDataSetTest.printMemory(); + + TableDataSet[] tables = new TableDataSet[3]; + long startTime, stopTime = 0; + try { + for (int i=0; i < 3; i++) { + startTime = System.currentTimeMillis(); + tables[i] = new TableDataSet(new File("c:/temp/morpc/M5678.csv")); + stopTime = System.currentTimeMillis(); + logger.info("Finished reading " + i + ", " + (stopTime-startTime)); + TableDataSetTest.printMemory(); + } + startTime = System.currentTimeMillis(); + tables[2].saveFile(new File("c:/temp/morpc/M5678_new.csv"), 0, new DecimalFormat("#.000000")); + stopTime = System.currentTimeMillis(); + logger.info("Finished writing " + (stopTime-startTime)); + TableDataSetTest.printMemory(); + } + catch (IOException e) { + e.printStackTrace(); + return; + } + } + + public static void printMemory() { + logger.info("Total memory : " + Runtime.getRuntime().totalMemory()); + logger.info("Max memory : " + Runtime.getRuntime().maxMemory()); + logger.info("Free memory : " + Runtime.getRuntime().freeMemory()); + } +*/ + + /** + * Read a table data set. + * + * @return a fully populated TableDataSet + */ + public static TableDataSet readCSVFile() { + System.out.println("executing readCSVFile()"); + TableDataSet table = null; + + try { + CSVFileReader reader = new CSVFileReader(); + table = reader.readFile(new File("src/sql/bufcrl1.txt")); + } + catch (IOException e) { + e.printStackTrace(); + } + + return table; + } + + + /** + * Tests the getRowValues() method. + * + */ + public static void testGetRowValues(TableDataSet table) { + System.out.println("executing testGetRowValues()"); + + //Display some statistics about the file + System.out.println("Number of columns: " + table.getColumnCount()); + System.out.println("Number of rows: " + table.getRowCount()); + + //Display column titles + String[] titles = table.getColumnLabels(); + for (int i = 0; i < titles.length; i++) { + System.out.print( String.format("%10s", titles[i]) ); + } + System.out.println(); + + try { + //Print the first 10 rows + for (int i=1; i <= 10; i++) { + + //Get a row from table + float row[] = (float[]) table.getRowValues(i); + + for (int j=0; j < row.length; j++) { + System.out.print( String.format(" %9.2f", row[j]) ); + } + System.out.println(); + } + } + catch (Throwable e) { + System.out.println("Exception in testGetRowValues()"); + e.printStackTrace(); + } + } + + + /** + * Tests the getValueAt() and getValues() methods. + * + */ + public static void testGetValueAt(TableDataSet table) { + System.out.println("executing testGetValueAt()"); + + //Get the name of a column + float value1 = table.getValueAt( 1, 10 ); + float value2 = table.getValueAt( 2, 10 ); + String strValue = table.getStringValueAt( 2, 19 ); + + System.out.println( String.format("value at (1,10) =%7.2f", value1) ); + System.out.println( String.format("value at (2,10) =%7.2f", value2) ); + + System.out.println( String.format("value at (2,19) =%s", strValue) ); + System.exit(1); + + //Ask for data as a float[][]. This can be used to create a Matrix + float[][] values = null; + try { + values = table.getValues(); + + for (int i = 0; i < 10; i++) { + + for (int j = 0; j < table.getColumnCount(); j++) { + System.out.print( String.format(" %9.2f", values[i][j]) ); + } + System.out.println(); + } + } + catch (Exception e) { + System.out.println("Exception in testGetRowValues()"); + e.printStackTrace(); + } + } + + + /** + * Test the column look-up features of the table dataset. + * + */ + public static void testColmnNameRetrieval(TableDataSet table) { + System.out.println("executing testColmnNameRetrieval()"); + + //Get the name of a column + String name1 = table.getColumnLabel( 1 ); + String name2 = table.getColumnLabel( 2 ); + + System.out.println( "column 1 = " + name1 ); + System.out.println( "column 2 = " + name2 ); + + //Get the position of a column given it's name - case is ignored + int position1 = table.getColumnPosition("zone"); + int position2 = table.getColumnPosition("totpop"); + + System.out.println( "position of zone = " + position1 ); + System.out.println( "position of totpop = " + position2 ); + + String hhInc = table.getStringValueAt(1, "totpop"); + System.out.println("totpop on row 1 = " + hhInc); + } + + + /** + * Test the column look-up features of the table dataset. + * + */ + public static void testSetValueAt(TableDataSet table) { + System.out.println("executing testSetValueAt()"); + + float value1 = table.getValueAt( 1, 10 ); + System.out.println( String.format("value before update (1,10) =%7.2f", value1) ); + + table.setValueAt(1, 10, (float)300.1); + + System.out.println( String.format("value after update (1,10) =%7.2f", table.getValueAt( 1, 10 )) ); + + } + + + /** + * Test the indexing feature of the table dataset. + * + */ + public static void testSaveFile(TableDataSet table) { + System.out.println("executing testSaveFile()"); + + try { + CSVFileWriter writer = new CSVFileWriter(); + writer.writeFile(table, new File("testtable_new.csv")); + } + catch (IOException e) { + e.printStackTrace(); + } + } + + + /** + * Test the indexing feature of the table dataset. + * + */ + public static void testBuildIndex(TableDataSet table) { + System.out.println("executing testBuildIndex()"); + + //Build an index on column 1 + table.buildIndex(1); + float value1 = table.getIndexedValueAt( 25, 1 ); + + System.out.println( String.format("looking up indexed value=25 in column=1: %7.2f", value1) ); + } + + + /** + * Read a table data set. + */ + public static void readCSVFileNoLabels() { + System.out.println("executing readCSVFileNoLabels()"); + + TableDataSet table = null; + + try { + CSVFileReader reader = new CSVFileReader(); + table = reader.readFile(new File("src/sql/zonedata_nolabels.csv"), false); + } + catch (IOException e) { + e.printStackTrace(); + System.exit(1); + } + + //Display column titles + String[] titles = table.getColumnLabels(); + for (int i = 0; i < titles.length; i++) { + System.out.print( String.format("%10s", titles[i]) ); + } + System.out.println(); + + } + + + /** + * Read a table data set. + */ + public static void readCSVFileFilteringColumns() { + System.out.println("executing readCSVFileFilteringColumns()"); + TableDataSet table = null; + + String[] columnsToRead = { "tothh", "hhinc1" }; + + try { + CSVFileReader reader = new CSVFileReader(); + table = reader.readFile(new File("src/sql/zonedata.csv"), columnsToRead); + + //Display column titles + String[] titles = table.getColumnLabels(); + for (int i = 0; i < titles.length; i++) { + System.out.print( String.format("%10s", titles[i]) ); + } + System.out.println(); + + //Print a couple of values + float value1 = table.getValueAt( 1, 1 ); + float value2 = table.getValueAt( 1, 2 ); + float value3 = table.getValueAt( 2, 1 ); + float value4 = table.getValueAt( 2, 2 ); + + System.out.println( String.format("value at (1,1) =%7.2f", value1) ); + System.out.println( String.format("value at (1,2) =%7.2f", value2) ); + System.out.println( String.format("value at (2,1) =%7.2f", value3) ); + System.out.println( String.format("value at (2,2) =%7.2f", value4) ); + } + catch (Exception e) { + e.printStackTrace(); + } + + } + + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/EventDispatcher.java b/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/EventDispatcher.java new file mode 100644 index 0000000..2441f6c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/EventDispatcher.java @@ -0,0 +1,33 @@ +package org.sandag.cvm.common.discreteEvent; + +import java.util.NoSuchElementException; + +import org.apache.log4j.Logger; + +public class EventDispatcher { + static final Logger logger = Logger.getLogger(EventDispatcher.class); + EventQueue myQueue = new EventQueue(); + + public EventDispatcher() { + + } + + public void dispatchEvents() { + try { + while(true) { + TimedEvent nextEvent = myQueue.popNextEvent(); + nextEvent.handleEvent(this); + } + } catch (NoSuchElementException e) { + logger.info("Event queue is empty"); + } + } + + public EventQueue getMyQueue() { + return myQueue; + } + + public void setMyQueue(EventQueue myQueue) { + this.myQueue = myQueue; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/EventQueue.java b/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/EventQueue.java new file mode 100644 index 0000000..0dba10e --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/EventQueue.java @@ -0,0 +1,34 @@ +package org.sandag.cvm.common.discreteEvent; + +import java.util.NoSuchElementException; +import java.util.TreeSet; + +public class EventQueue { + + //ENHANCEMENT look at using other storage for events. + // For instance we could have 3600*24 buckets, one for + // each second in the day, and then optionally sort the events + // within the buckets. + // Then we could use an array or linked list for each bucket? + TreeSet futureEvents; + + public EventQueue() { + futureEvents = new TreeSet (); + } + + public void enqueue(TimedEvent e) { + futureEvents.add(e); + } + + public TimedEvent popNextEvent() throws NoSuchElementException { + TimedEvent nextEvent = futureEvents.first(); + futureEvents.remove(nextEvent); + return nextEvent; + + } + + public int size() { + return futureEvents.size(); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/TestEventDispatcher.java b/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/TestEventDispatcher.java new file mode 100644 index 0000000..083db80 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/discreteEvent/TestEventDispatcher.java @@ -0,0 +1,65 @@ +package org.sandag.cvm.common.discreteEvent; + +import org.junit.BeforeClass; +import org.junit.Test; + +public class TestEventDispatcher { + + class RequeueEvent extends TimedEvent { + + public RequeueEvent(double myTime) { + super(myTime); + } + + @Override + public void handleEvent(EventDispatcher dispatch) { + numOfEvents++; + if (numOfEvents + averageQueueSize < numberOfEventsToSimulate) { + double selector = (int) (Math.random()*3); + // queue up 0, 1 or 2 new events. + for (int i=0;i ((TimedEvent)arg0).myTime) { + return 2; + } + if (myTime < ((TimedEvent)arg0).myTime) { + return -2; + } + if (arg0==this) return 0; + // ok, our times are identical! + if (myRandomNumber ==0) myRandomNumber = (Math.random()+.001); + TimedEvent other = (TimedEvent) arg0; + if (other.myRandomNumber == 0) other.myRandomNumber = (Math.random()+.001); + if (myRandomNumber > other.myRandomNumber) return 1; + if (myRandomNumber < other.myRandomNumber) return -1; + //TODO maybe do something smarter? + logger.error("randomly generated event sortings are the same"); + return 0; + } + + @Override + public String toString() { + return "Event at "+myTime; + } + + public boolean isProcessEvenIfAfterSimulationTime() { + return processEvenIfAfterSimulationTime; + } + + public void setProcessEvenIfAfterSimulationTime( + boolean processEvenIfAfterSimulationTime) { + this.processEvenIfAfterSimulationTime = processEvenIfAfterSimulationTime; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/emme2/Emme2MatrixHashtableReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/emme2/Emme2MatrixHashtableReader.java new file mode 100644 index 0000000..877efca --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/emme2/Emme2MatrixHashtableReader.java @@ -0,0 +1,65 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.common.emme2; + +import java.io.File; +import java.util.*; + +import com.pb.common.matrix.*; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class Emme2MatrixHashtableReader extends Emme2MatrixReader { + + private Hashtable readMatrices = new Hashtable(); + + /** Reads an entire matrix from an Emme2 databank, but if it's already been + * read once before returns the previously read one hashtable + * + * @param index the short name of the matrix, eg. "mf10" + * @return a complete matrix + * @throws MatrixException + */ + public Matrix readMatrix(String index) throws MatrixException { + + if (readMatrices.containsKey(index)) { + return (Matrix) readMatrices.get(index); + } + Matrix m = super.readMatrix(index ); + readMatrices.put(index,m); + return m; + + } + + + + /** + * Constructor for Emme2MatrixHashtableReader. + * @param file + */ + public Emme2MatrixHashtableReader(File file) { + super(file); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/emme2/IndexConditionFunction.java b/sandag_abm/src/main/java/org/sandag/cvm/common/emme2/IndexConditionFunction.java new file mode 100644 index 0000000..6d05feb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/emme2/IndexConditionFunction.java @@ -0,0 +1,124 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + +package org.sandag.cvm.common.emme2; + +import com.pb.common.matrix.*; + +import java.util.*; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class IndexConditionFunction { + + public void readMatrices(MatrixCacheReader mr) { + coefficients = new double[coefficientValues.size()]; + matrices = new Matrix[matrixNames.size()]; +// conditions = new int[conditionValues.size()]; + for (int i=0;i + * MSValue * MFValue + *
Where MSValue is constant and MFValue is the value from the MF matrix + * @param matrix the MF matrix where the value is looked up based on the indices + * @param coeffMSMatrix the MS matrix where the coefficient value comes from + */ + public void addCoefficient(String matrix, String coeffMSMatrix) { + matrixNames.add(matrix); + coefficientValues.add(coeffMSMatrix); + coefficients = null; + matrices = null; + } + + /** + * Method addCoefficient, adds a term into the utility function
+ * coeffValue * MFValue + * @param matrix the emme/2 name of the matrix to be used (if + * blank or "none" the coefficient will be taken as part of the constant term) + * @param coeffValue value of the coefficient to be multiplied by the emme/2 matrix term + */ + public void addCoefficient(String matrix, double coeffValue) { + if (matrix.length() ==0 || matrix.equalsIgnoreCase("none")) addConstant(coeffValue); + else { + matrixNames.add(matrix); + coefficientValues.add(new Double(coeffValue)); + coefficients = null; + matrices = null; + } + } + + /** Changes the value of a specific coefficient (normally use addCoefficient instead) + * @param coeffIndex the previously added coefficient to change the value of + * @param matrix the matrix that is multiplied by the coefficient value + * @param coeffValue the coefficient value + */ + void setCoefficient(int coeffIndex,String matrix,double coeffValue) { + coefficientValues.set(coeffIndex,new Double(coeffValue)); + matrixNames.set(coeffIndex,matrix); + coefficients = null; + matrices = null; + } + + /** + * Reads in the emme2matrices into memory, also initializes some internal data. Call this method after the + * terms have been added to the utility function but before the utility function is evaluated. + * @param matrixReader the matrix reader to use to read in the matrices from the emme2 databank + */ + public void readMatrices(MatrixCacheReader matrixReader) { + coefficients = new double[coefficientValues.size()]; + matrices = new Matrix[matrixNames.size()]; + for (int i=0;i=4.712999999 || m.getValueAt(1619,1610)<=4.7130000001); + assertTrue("name should be mf22 but is "+m.getName(),m.getName().equals("mf22")); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/AggregateAlternative.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/AggregateAlternative.java new file mode 100644 index 0000000..45d4549 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/AggregateAlternative.java @@ -0,0 +1,26 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 John Abraham jabraham@ucalgary.ca and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + +package org.sandag.cvm.common.model; + +public interface AggregateAlternative extends Alternative { + void setAggregateQuantity(double amount, double derivative); +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/Alternative.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/Alternative.java new file mode 100644 index 0000000..3d6712b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/Alternative.java @@ -0,0 +1,26 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + +package org.sandag.cvm.common.model; + +public interface Alternative { + double getUtility(); +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/ChoiceModelOverflowException.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/ChoiceModelOverflowException.java new file mode 100644 index 0000000..3f36357 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/ChoiceModelOverflowException.java @@ -0,0 +1,20 @@ +package org.sandag.cvm.common.model; + +public class ChoiceModelOverflowException extends RuntimeException { + + public ChoiceModelOverflowException() { + } + + public ChoiceModelOverflowException(String message) { + super(message); + } + + public ChoiceModelOverflowException(Throwable cause) { + super(cause); + } + + public ChoiceModelOverflowException(String message, Throwable cause) { + super(message, cause); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/DiscreteChoiceModel.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/DiscreteChoiceModel.java new file mode 100644 index 0000000..ddd447c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/DiscreteChoiceModel.java @@ -0,0 +1,63 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + + +package org.sandag.cvm.common.model; + +import java.util.Random; + +public abstract class DiscreteChoiceModel implements DiscreteChoiceModelInterface { + /** Picks one of the alternatives based on the logit model probabilities + * @throws ChoiceModelOverflowException */ + public abstract Alternative monteCarloChoice() throws NoAlternativeAvailable, ChoiceModelOverflowException ; + + /** Picks one of the alternatives based on the logit model probabilities and random number given*/ + public abstract Alternative monteCarloChoice(double r) throws NoAlternativeAvailable ; + + public Alternative monteCarloElementalChoice() throws NoAlternativeAvailable, ChoiceModelOverflowException { + Alternative a = monteCarloChoice(); + while (a instanceof DiscreteChoiceModel) { + a = ((DiscreteChoiceModel) a).monteCarloChoice(); + } + return a; + } + /** Use this method if you want to give a random number */ + public Alternative monteCarloElementalChoice(double r) throws NoAlternativeAvailable { + Alternative a = monteCarloChoice(r ); + Random newRandom = new Random(new Double(r*1000).longValue()); + while (a instanceof DiscreteChoiceModel) { + a = ((DiscreteChoiceModel) a).monteCarloChoice(newRandom.nextDouble()); + } + return a; + } + + /** @param a the alternative to add into the choice set */ + public abstract void addAlternative(Alternative a); + + public abstract Alternative alternativeAt(int i); + + public abstract double[] getChoiceProbabilities(); + + abstract public void allocateQuantity(double amount); + + +} + diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/DiscreteChoiceModelInterface.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/DiscreteChoiceModelInterface.java new file mode 100644 index 0000000..24c59ed --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/DiscreteChoiceModelInterface.java @@ -0,0 +1,47 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.common.model; + +/** + * @author jabraham + * + * To change the template for this generated type comment go to + * Window - Preferences - Java - Code Generation - Code and Comments + */ +public interface DiscreteChoiceModelInterface { + /** Picks one of the alternatives based on the logit model probabilities + * @throws ChoiceModelOverflowException */ + public abstract Alternative monteCarloChoice() + throws NoAlternativeAvailable, ChoiceModelOverflowException; + /** Picks one of the alternatives based on the logit model probabilities and random number given*/ + public abstract Alternative monteCarloChoice(double r) + throws NoAlternativeAvailable; + public abstract Alternative monteCarloElementalChoice() + throws NoAlternativeAvailable, ChoiceModelOverflowException; + /** Use this method if you want to give a random number */ + public abstract Alternative monteCarloElementalChoice(double r) + throws NoAlternativeAvailable; + /** @param a the alternative to add into the choice set */ + public abstract void addAlternative(Alternative a); + public abstract Alternative alternativeAt(int i); + public abstract double[] getChoiceProbabilities(); + public abstract void allocateQuantity(double amount); +} \ No newline at end of file diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/FixedUtilityAlternative.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/FixedUtilityAlternative.java new file mode 100644 index 0000000..b772896 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/FixedUtilityAlternative.java @@ -0,0 +1,37 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + +package org.sandag.cvm.common.model; + +public class FixedUtilityAlternative implements Alternative { + public FixedUtilityAlternative(double utilityValue) { + this.utilityValue=utilityValue; + } + + public double getUtility() {return utilityValue;} + + public double getUtilityValue(){ return utilityValue; } + + public void setUtilityValue(double utilityValue){ this.utilityValue = utilityValue; } + + private double utilityValue; + public String toString() {return "FixedUtility - "+utilityValue;}; +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/GumbelErrorTerm.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/GumbelErrorTerm.java new file mode 100644 index 0000000..eb38dfa --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/GumbelErrorTerm.java @@ -0,0 +1,77 @@ +/** + * + */ +package org.sandag.cvm.common.model; + +import java.util.Random; + +/** + * This class is used to sample and store Weibull distributed values + * @author John Abraham + * + */ +public class GumbelErrorTerm extends RandomVariable { + + static final double eulersConstant = 0.5772156649015328606; + + /** + * Static method to sample and return + * @param dispersionParameter + * @return a sample value from the Gumbel distribution with mean 0. + */ + public static double sample(double dispersionParameter) { + double sample = Math.random(); + return eulersConstant-dispersionParameter*Math.log(-Math.log(sample)); + } + + /** + * Static method to sample and return + * @param dispersionParameter + * @param r The random number generator to use + * @return a sample value from the Gumbel distribution with mean 0. + */ + public static double sample(double dispersionParameter, Random r) { + double sample = r.nextDouble(); + return eulersConstant-dispersionParameter*Math.log(-Math.log(sample)); + } + + private double dispersionParameter; + + /** + * Constructor + */ + public GumbelErrorTerm(double dispersionParameter) { + value = 0; + this.dispersionParameter = dispersionParameter; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + public double getDispersionParameter() { + return dispersionParameter; + } + + /** (non-Javadoc) + * @see org.sandag.cvm.common.model.RandomVariable#sample() + * Changes the value to a new random term by sampling from the Probability + * Density Function z*exp(-z)/beta where z=exp(-(x)/beta)) + */ + @Override + public double sample() { + double sample = Math.random(); + value = eulersConstant-dispersionParameter*Math.log(-Math.log(sample)); + return value; + } + + public static double transformUniformToGumble(double uniform, double dispersionParameter) { + return eulersConstant - dispersionParameter*Math.log(-Math.log(uniform)); + } + + public void setDispersionParameter(double dispersionParameter) { + this.dispersionParameter = dispersionParameter; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/LinearInParametersFunction.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/LinearInParametersFunction.java new file mode 100644 index 0000000..9091d4c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/LinearInParametersFunction.java @@ -0,0 +1,72 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + +package org.sandag.cvm.common.model; + +/** + * @author John Abraham + * + * A cool class created by John Abraham (c) 2003 + */ +public class LinearInParametersFunction { + + /** + * Constructor for LinearInParametersFunction. + */ + public LinearInParametersFunction() { + new LinearInParametersFunction(0); + } + + public LinearInParametersFunction(int size) { + coefficients = new double[size]; + } + + private double[] coefficients; + + public void addCoefficient(double coeffValue) { + double[] oldCoefficients = coefficients; + coefficients = new double[oldCoefficients.length+1]; + System.arraycopy(oldCoefficients,0,coefficients,0,oldCoefficients.length); + coefficients[coefficients.length-1]=coeffValue; + } + + public void setCoefficient(int coeffIndex,double coeffValue) { + if (coefficients.length <= coeffIndex) { + double[] oldCoefficients = coefficients; + coefficients = new double[coeffIndex+1]; + System.arraycopy(oldCoefficients,0,coefficients,0,oldCoefficients.length); + } + coefficients[coeffIndex]=coeffValue; + } + + public double getCoefficient(int coeffIndex) { + return coefficients[coeffIndex]; + } + + public double calcProduct(double[] values) { + double value = 0; + for (int i=0; i(); + dispersionParameter = 1.0; + } + //use this constructor if you know how many alternatives + public LogitModel(int numberOfAlternatives) { + alternatives = new ArrayList(numberOfAlternatives); + dispersionParameter = 1.0; + } + + + /** @return the composite utility (log sum value) of all the alternatives */ + public double getUtility() { + double sum = 0; + int i = 0; + while (i it = alternatives.listIterator(); + int i = 0; + while (it.hasNext()) { + Alternative a = (Alternative) it.next(); + double utility = a.getUtility(); + weights[i] = Math.exp(dispersionParameter * utility); + if (Double.isNaN(weights[i])) { + System.out.println("hmm, alternative "+a+" was such that LogitModel weight was NaN"); + System.out.println("dispersionParameter ="+dispersionParameter+", utility ="+utility); + throw new Error("NAN in weight for alternative "+a); + } + sum += weights[i]; + i++; + } + if (sum!=0) { + for (i = 0; i < weights.length; i++) { + weights[i] /= sum; + } + } + return weights; + } + } + + public Alternative alternativeAt(int i) { return (Alternative) alternatives.get(i);}// should throw an error if out of range + + + /** Picks one of the alternatives based on the logit model probabilities + * @throws ChoiceModelOverflowException */ + public Alternative monteCarloChoice() throws NoAlternativeAvailable, ChoiceModelOverflowException { + // synchronized(alternatives) { + double[] weights = new double[alternatives.size()]; + double sum = 0; + Iterator it = alternatives.listIterator(); + int i = 0; + while (it.hasNext()) { + Alternative a = it.next(); + double utility = a.getUtility(); + weights[i] = Math.exp(dispersionParameter * utility); + if (Double.isNaN(weights[i])) { + System.out.println("hmm, alternative "+a+" was such that LogitModel weight was NaN"); + System.out.println("dispersionParameter ="+dispersionParameter+", utility ="+utility); + } + sum += weights[i]; + i++; + } + if (Double.isInfinite(sum)) { + logger .fatal("Overflow error in choice model, list of alternatives follows"); + it = alternatives.listIterator(); + while (it.hasNext()) { + Alternative a = (Alternative) it.next(); + double utility = a.getUtility(); + System.out.println(" U:"+utility+", W:"+Math.exp(dispersionParameter * utility)+" for "+a); + } + + throw new ChoiceModelOverflowException("Infinite weight(s) in logit model choice function"); + } + if (sum==0) throw new NoAlternativeAvailable(); + double selector = myRandom.nextDouble() * sum; + sum = 0; + for (i = 0; i < weights.length; i++) { + sum += weights[i]; + if (selector <= sum) return (Alternative)alternatives.get(i); + } + //yikes! + System.out.println("Error: problem with logit model. sum is "+sum+", rand is "+selector); + System.out.println("Alternative,weight"); + for (i=0; i < weights.length; i++){ + System.out.println((Alternative)alternatives.get(i)+","+weights[i]); + } + throw new Error("Random Number Generator in Logit Model didn't return value between 0 and 1"); + // } + } + + /** Picks one of the alternatives based on the logit model probabilities; + use this if you want to give method random number */ + public Alternative monteCarloChoice(double randomNumber) throws NoAlternativeAvailable { + synchronized(alternatives) { + double[] weights = new double[alternatives.size()]; + double sum = 0; + Iterator it = alternatives.listIterator(); + int i = 0; + while (it.hasNext()) { + double utility = ((Alternative)it.next()).getUtility(); + weights[i] = Math.exp(dispersionParameter * utility); + if (Double.isNaN(weights[i])) { + System.out.println("hmm, alternative was such that LogitModel weight was NaN"); + } + sum += weights[i]; + i++; + } + if (sum==0) throw new NoAlternativeAvailable(); + double selector = randomNumber * sum; + sum = 0; + for (i = 0; i < weights.length; i++) { + sum += weights[i]; + if (selector <= sum) return (Alternative)alternatives.get(i); + } + //yikes! + System.out.println("Error: problem with logit model. sum is "+sum+", rand is "+randomNumber); + System.out.println("Alternative,weight"); + for (i=0; i < weights.length; i++){ + System.out.println((Alternative)alternatives.get(i)+","+weights[i]); + } + throw new Error("Random Number Generator in Logit Model didn't return value between 0 and 1"); + } + } + + + private double dispersionParameter; + private double constantUtility=0; + protected ArrayList alternatives; + + public String toString() { + StringBuffer altsString = new StringBuffer(); + int alternativeCounter = 0; + if (alternatives.size() > 5) { altsString.append("LogitModel with " + alternatives.size() + "alternatives {"); } + else altsString.append("LogitModel, choice between "); + Iterator it = alternatives.iterator(); + while (it.hasNext() && alternativeCounter < 5) { + altsString.append(it.next()); + altsString.append(","); + alternativeCounter ++; + } + if (it.hasNext()) altsString.append("...}"); else altsString.append("}"); + return new String(altsString); + } + + public double getConstantUtility(){ return constantUtility; } + + public void setConstantUtility(double constantUtility){ this.constantUtility = constantUtility; } + + /** + * Method arrayCoefficientSimplifiedChoice. + * @param theCoefficients + * @param theAttributes + * @return int + */ + public static int arrayCoefficientSimplifiedChoice( + double[][] theCoefficients, + double[] theAttributes) { + + double[] utilities = new double[theCoefficients.length]; + int alt; + for (alt =0; alt < theCoefficients.length; alt++){ + utilities[alt] = 0; + for (int c=0;c getAlternativesIterator() { + return alternatives.iterator(); + } + +} + + diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/NoAlternativeAvailable.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/NoAlternativeAvailable.java new file mode 100644 index 0000000..3e377ed --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/NoAlternativeAvailable.java @@ -0,0 +1,28 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + +package org.sandag.cvm.common.model; + +public class NoAlternativeAvailable extends Exception { + + public NoAlternativeAvailable() { + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/NumericalDerivativeSingleParameterFunction.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/NumericalDerivativeSingleParameterFunction.java new file mode 100644 index 0000000..3962bbe --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/NumericalDerivativeSingleParameterFunction.java @@ -0,0 +1,34 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + +package org.sandag.cvm.common.model; + +public abstract class NumericalDerivativeSingleParameterFunction implements SingleParameterFunction { + double delta; + public NumericalDerivativeSingleParameterFunction(double delta) { + this.delta=delta; + } + + public double derivative(double point){ + double perturbed = evaluate(point+delta); + return (perturbed-evaluate(point))/delta; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/RandomVariable.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/RandomVariable.java new file mode 100644 index 0000000..b5d0f59 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/RandomVariable.java @@ -0,0 +1,35 @@ +package org.sandag.cvm.common.model; + +public abstract class RandomVariable implements Cloneable { + + double value; + + private boolean validValue; + + public RandomVariable() { + super(); + value = 0; + validValue = false; + } + + @Override + public Object clone() throws CloneNotSupportedException { + return super.clone(); + } + + abstract public double sample(); + + public double sampleIfNecessaryAndSave() { + if (validValue) { + return value; + } + value = sample(); + validValue = true; + return value; + } + + public void setInvalid() { + validValue = false; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/SingleParameterFunction.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/SingleParameterFunction.java new file mode 100644 index 0000000..9063198 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/SingleParameterFunction.java @@ -0,0 +1,28 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + +package org.sandag.cvm.common.model; + +public interface SingleParameterFunction { + double evaluate(double point); + + double derivative(double point); +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/TestLogitModel.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/TestLogitModel.java new file mode 100644 index 0000000..9476ff7 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/TestLogitModel.java @@ -0,0 +1,63 @@ +/* + Travel Model Microsimulation library + Copyright (C) 2005 PbConsult, JE Abraham and others + + + Licensed under the Apache License, Version 2.0 (the "License"); + you may not use this file except in compliance with the License. + You may obtain a copy of the License at + + http://www.apache.org/licenses/LICENSE-2.0 + + Unless required by applicable law or agreed to in writing, software + distributed under the License is distributed on an "AS IS" BASIS, + WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + See the License for the specific language governing permissions and + limitations under the License. + +*/ + + + + +package org.sandag.cvm.common.model; + +public class TestLogitModel { + public static void main(String[] args) throws ChoiceModelOverflowException { + try { + LogitModel lm = new LogitModel(); + Alternative a = new FixedUtilityAlternative(1.0); + Alternative b = new FixedUtilityAlternative(2.0); + lm.addAlternative(a); + lm.addAlternative(b); + for (double dp=.001;dp<100000 ;dp*=2 ) + { + lm.setDispersionParameter(dp); + int acount=0; + int bcount=0; + for (int i=0;i<1000 ;i++ ) + { + if (lm.monteCarloChoice()==a) acount++; else bcount++; + } + System.out.println("DispersionParameter="+dp+" acount="+acount+" bcount"+bcount); + } + lm=new LogitModel(); + lm.addAlternative(new FixedUtilityAlternative(Math.exp(50000))); + System.out.println("Composite utility of one infinite utility alternative is "+lm.getUtility()); + lm.monteCarloChoice(); + lm=new LogitModel(); + lm.addAlternative(new FixedUtilityAlternative(Math.log(0))); + lm.addAlternative(new FixedUtilityAlternative(5.0)); + + System.out.println("Composite utility of one negative infinite utility alternative and a '5' alt is "+lm.getUtility()); + lm.monteCarloChoice(); + + lm.addAlternative(new FixedUtilityAlternative(Math.log(0))); + System.out.println("Composite utility of one negative infinite utility alternative and a '5' alt and an alternative with zero size is "+lm.getUtility()); + lm.monteCarloChoice(); + } catch (NoAlternativeAvailable e) { + System.out.println("No alternative available somewhere here..."); + } + + } +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/UtilityMaximizingChoiceModel.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/UtilityMaximizingChoiceModel.java new file mode 100644 index 0000000..8d312b8 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/UtilityMaximizingChoiceModel.java @@ -0,0 +1,64 @@ +package org.sandag.cvm.common.model; + +import java.util.ArrayList; + +import org.apache.log4j.Logger; + + +public class UtilityMaximizingChoiceModel extends + DiscreteChoiceModel { + + ArrayList alternatives = new ArrayList(); + + private static Logger logger = Logger.getLogger(UtilityMaximizingChoiceModel.class); + + public UtilityMaximizingChoiceModel(RandomVariable myRandomVariable) { + super(); + } + + @Override + public void addAlternative(Alternative a) { + alternatives.add(a); + } + + @Override + public void allocateQuantity(double amount) { + String msg = this.getClass().toString()+" can't allocate quantity amongst alternatives -- it is only for simulation"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + @Override + public Alternative alternativeAt(int i) { + return alternatives.get(i); + } + + @Override + public double[] getChoiceProbabilities() { + String msg = this.getClass().toString()+" can't allocate quantity amongst alternatives -- it is only for simulation"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + + public Alternative monteCarloChoice() { + int maxAlternative = 0; + double maxUtility = Double.NEGATIVE_INFINITY; + for (int i=0;imaxUtility) { + maxUtility = utility; + maxAlternative=i; + } + } + return alternatives.get(maxAlternative); + } + + @Override + public Alternative monteCarloChoice(double r) throws NoAlternativeAvailable { + String msg = this.getClass().toString()+" can't take a random number parameter"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/model/UtilityMaximizingChoiceModelWithErrorTermVector.java b/sandag_abm/src/main/java/org/sandag/cvm/common/model/UtilityMaximizingChoiceModelWithErrorTermVector.java new file mode 100644 index 0000000..59f15f1 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/model/UtilityMaximizingChoiceModelWithErrorTermVector.java @@ -0,0 +1,84 @@ +package org.sandag.cvm.common.model; + +import java.util.ArrayList; + +import org.apache.log4j.Logger; + + +public class UtilityMaximizingChoiceModelWithErrorTermVector extends + DiscreteChoiceModel { + + ArrayList alternatives = new ArrayList(); + double[] errorTerms = null; + RandomVariable myRandomVariable; + + private static Logger logger = Logger.getLogger(UtilityMaximizingChoiceModelWithErrorTermVector.class); + + public UtilityMaximizingChoiceModelWithErrorTermVector(RandomVariable myRandomVariable) { + super(); + this.myRandomVariable = myRandomVariable; + } + + @Override + public void addAlternative(Alternative a) { + alternatives.add(a); + errorTerms = null; + } + + @Override + public void allocateQuantity(double amount) { + String msg = this.getClass().toString()+" can't allocate quantity amongst alternatives -- it is only for simulation"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + @Override + public Alternative alternativeAt(int i) { + return alternatives.get(i); + } + + @Override + public double[] getChoiceProbabilities() { + String msg = this.getClass().toString()+" can't allocate quantity amongst alternatives -- it is only for simulation"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + @Override + public Alternative monteCarloChoice() throws NoAlternativeAvailable { + if (errorTerms !=null) { + if (errorTerms.length != alternatives.size()) { + errorTerms = null; + } + } + if (errorTerms ==null) { + errorTerms = new double[alternatives.size()]; + for (int i =0;imaxUtility) { + maxUtility = utility; + maxAlternative=i; + } + } + return alternatives.get(maxAlternative); + } + + @Override + public Alternative monteCarloChoice(double r) throws NoAlternativeAvailable { + String msg = this.getClass().toString()+" can't take a random number parameter"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/skims/HDF5MatrixReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/HDF5MatrixReader.java new file mode 100644 index 0000000..7edb73f --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/HDF5MatrixReader.java @@ -0,0 +1,395 @@ +package org.sandag.cvm.common.skims; + +import java.io.File; +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.TreeSet; + +import javax.swing.tree.DefaultMutableTreeNode; + +import ncsa.hdf.object.CompoundDS; +import ncsa.hdf.object.FileFormat; +import ncsa.hdf.object.HObject; +import ncsa.hdf.object.h5.H5File; + +import org.apache.log4j.Logger; + +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixException; +import com.pb.common.matrix.MatrixReader; + + +public class HDF5MatrixReader extends MatrixReader { + + public static void main(String args[]) { + String[] skimsToGet = new String[] {"Light_Off","Light_AM","Light_Mid","Light_PM","Medium_Off", + "Medium_AM","Medium_Mid","Medium_PM","Heavy_Off","Heavy_AM","Heavy_Mid","Heavy_PM"}; + String[] nodes = new String[] {"cvm"}; + HDF5MatrixReader r = new HDF5MatrixReader(new File("/ProjectWork/CSTDM2009 105073x4/Technical/Skims and OD/skims.h5"), nodes, skimsToGet); + +// r.testMatrixFile(); + r.readMatrices(); + } + + static Logger logger = Logger.getLogger(HDF5MatrixReader.class); + + File hdf5File; + + private List nodeNames; + + private String[] initialMatrixNames; + + public HDF5MatrixReader(File hdf5File, String[] nodeNames, String[] matrixNames) { + this.nodeNames = Arrays.asList(nodeNames); + this.hdf5File = hdf5File; + this.initialMatrixNames = matrixNames; + } + + public HDF5MatrixReader(File file, String node) { + throw new RuntimeException("Not implemented yet"); + //FIXME implement read all skims from node + } + + /** + * Builds the user to sequential lookup table and the sequential to user lookup table + * @param origins + * @param destinations + * @return [0] is sequentialToUser, to lookup user zone numbers, [1] is userToSequential to lookup index. + */ + private static int[][] buildCrossLookups(int[] origins, int[] destinations) { + TreeSet zoneSet = new TreeSet(); + int mod = 0; + for (int o : origins) { + zoneSet.add(o); + if (++mod % 250000 == 0) logger.info(" Processed line "+mod+" origin "+o); + } + mod = 0; + for (int d : destinations) { + zoneSet.add(d); + if (++mod % 250000 == 0) logger.info(" Processed line "+mod+" destination "+d); + } + int maxZone = Collections.max(zoneSet); + int[][] userSequentialCrossLookup= new int[2][]; + int[] sequentialToUserLookup = new int[zoneSet.size()]; + userSequentialCrossLookup[0] = sequentialToUserLookup; + int[] userToSequentialLookup = new int[maxZone+1]; + userSequentialCrossLookup[1] = userToSequentialLookup; + int z=0; + for (int z1 : userToSequentialLookup) { + userToSequentialLookup[z++] = -1; + } + z=0; + for (int z2 : zoneSet) { + sequentialToUserLookup[z] = z2; + userToSequentialLookup[z2] = z++; + } + return userSequentialCrossLookup; + } + + + /** + * Check if the dataset contains a column with the correct name + * If it does return the index number, else return -1 + * Also if it does contain the column, select the column for retrieval + * @param hdfDataset the dataset to be checked + * @param name the name of the column to be checked and marked for retrieval + * @return the index of the column, -1 if the column was not present + */ + static int selectHDFFieldByName(CompoundDS hdfDataset, String name) { + List nameList = Arrays.asList(hdfDataset.getMemberNames()); + int index = nameList.indexOf(name); + if (index != -1) { + hdfDataset.selectMember(index); + } + return index; + } + + + static class intKeyString implements Comparable { + int myInt; + String myString; + boolean found = false; + + intKeyString(int i, String s) { + myInt = i; + myString = s; + } + + @Override + public int compareTo(Object o) { + int otherInt = ((intKeyString) o).myInt; + if (otherInt > myInt) return -1; + if (otherInt < myInt) return 1; + if (otherInt == myInt) return 0; + assert false; + return 0; + } + } + + + @Override + public Matrix[] readMatrices() throws MatrixException { + return readMatrices(initialMatrixNames); + } + + public Matrix[] readMatrices(String[] matrixNames) { + ArrayList matrixList = new ArrayList(); + FileFormat f = null; + + intKeyString[] skimIndices = new intKeyString[matrixNames.length]; + int j=0; + for (String skimName : matrixNames) { + skimIndices[j] = new intKeyString(-1, skimName); + j++; + } + + try { + f = new H5File(hdf5File.getAbsolutePath(), H5File.READ); + f.open(); + DefaultMutableTreeNode theRoot = (DefaultMutableTreeNode) f.getRootNode(); + if (theRoot == null) { + String msg= "Null root in HDF5 skim file "+hdf5File; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + + Enumeration local_enum = ((DefaultMutableTreeNode) theRoot).breadthFirstEnumeration(); + while (local_enum.hasMoreElements()) { + DefaultMutableTreeNode theNode = (DefaultMutableTreeNode) local_enum.nextElement(); + HObject theObj = (HObject) theNode.getUserObject(); + String theName = theObj.getName(); + if (nodeNames.contains(theName)){ + logger.info("Found object \""+theName+"\" in HDF5File "+hdf5File+", reading skims"); + if (!(theObj instanceof CompoundDS)) { + String msg = "object \""+theName+"\" in HDF5File "+hdf5File+" is not a compound dataset, can't read skims"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + theObj.getMetadata(); + CompoundDS skims = (CompoundDS) theObj; + assert skims.getRank() ==1 : "Skim object in HDF5 file should only be of rank 1"; + skims.setMemberSelection(false); + int originFieldIndex = selectHDFFieldByName(skims, "origin"); + assert originFieldIndex == 0 : "Origin needs to be first member in HDF skim dataset"; + int destinationFieldIndex = selectHDFFieldByName(skims, "destination"); + assert destinationFieldIndex == 1 : "Destination needs to be second member in HDF skim dataset"; + + // get origin and destination zones, get all rows from file but no content yet. + long[] selected = skims.getSelectedDims(); + logger.info("getting zone numbers from "+selected[0]+" rows of origins and destinations"); + + List odNumbers = (List) skims.read(); + assert odNumbers.get(0) instanceof int[] : "Skim origins are not integer in HDF skim dataset"; + int[] origins = (int[]) odNumbers.get(0); + assert odNumbers.get(1) instanceof int[] : "Skim destinations are not integer in HDF skim dataset"; + int[] destinations = (int[]) odNumbers.get(1); + int[][] userSequentialCrossLookup = buildCrossLookups( + origins, destinations); + + odNumbers = null; // forget it so we can collect the memory with garbage collection + + int count = 0; + for (intKeyString identifier : skimIndices) { + int index = selectHDFFieldByName(skims,identifier.myString); + if (index >=0 ) { + // found + if (identifier.found) { + String msg = "found "+identifier.myString+" in more than one node in skim file, not sure which one to use"; + logger.fatal(msg); + throw new RuntimeException(msg); + } else { + logger.info("Reading "+identifier.myString+" from node "+theName); + identifier.myInt = index; + identifier.found = true; + count ++; + } + } else { + identifier.myInt = -1; + } + } + Arrays.sort(skimIndices); // important to sort them so we get them in the correct order below, -1 should be first; + + if (count ==0) { + logger.warn("No relevant skims in node "+theName+" skipping"); + } else { + + // allocate the storage for the arrays based on the number of skims and the number of zones + float[][][] matrixArrays = new float[count][userSequentialCrossLookup[0].length][userSequentialCrossLookup[0].length]; + + // now get content 100 rows at a time + final long HOWMANY = 250000; + long[] start = skims.getStartDims(); + selected[0] = HOWMANY; + long size = skims.getDims()[0]; + boolean verbose = false; + int startingCol = 0; + while (skimIndices[startingCol].myInt<0) startingCol++; + assert skimIndices.length-startingCol == count; + + for (long beginAt = 0; beginAt <= size; beginAt += HOWMANY) { + logger.info("Processing line "+beginAt+" from skims"); + start[0] = beginAt; + if (beginAt+HOWMANY >= size) // should be >=? + { + //verbose = true; + selected[0] = size - beginAt; + } + List skimData = (List) skims.read(); + assert skimData.size() == count+2; + assert skimData.get(0) instanceof int[] : "Skim origins are not integer in HDF skim dataset"; + origins = (int[]) skimData.get(0); + assert skimData.get(1) instanceof int[] : "Skim destinations are not integer in HDF skim dataset"; + destinations = (int[]) skimData.get(1); + for (int r = 0; r < origins.length; r++ ) { + int originArrayIndex = userSequentialCrossLookup[1][origins[r]]; + int destinationArrayIndex = userSequentialCrossLookup[1][destinations[r]]; + if (verbose) System.out.println("processing origin "+origins[r]+","+destinations[r]+" (index "+originArrayIndex+","+destinationArrayIndex); + for (int col = 0; col + 2 < skimData.size(); col ++) { + matrixArrays[col][originArrayIndex][destinationArrayIndex] = ((float[]) skimData.get(col+2))[r]; + } + } + verbose = false; + + } + + + int[] externalZoneNumbers = new int[userSequentialCrossLookup[0].length+1]; + for(int k=1;k99999)) + matrixValue=0; + utility += coefficients[i]*matrixValue; + } + return utility; + } + if (travelConditions instanceof SomeSkims) { + lastSkims = (SomeSkims) travelConditions; + matrixIndices = new int[namesList.size()]; + for (int i=0;i99999)) + matrixValue=0; + components[i] = coefficients[i]*matrixValue; + } + return components; + } + if (travelConditions instanceof SomeSkims) { + lastSkims = (SomeSkims) travelConditions; + matrixIndices = new int[namesList.size()]; + for (int i=0;i2) { + String msg = "Matrix name "+name+" has more than 1 part"; + } + OMXMatrixReader r = new OMXMatrixReader(new File(directoryOfMatrices,split[0]+".omx")); + // if (split.length == 1) return r.readMatrix(0); + return r.readMatrix(split[1]); + } + + /* (non-Javadoc) + * @see com.pb.common.matrix.MatrixReader#readMatrix() + */ + @Override + public Matrix readMatrix() throws MatrixException { + throw new RuntimeException("Can't read OMX Matrix without specifying file_name:matrix_name"); + } + + /* (non-Javadoc) + * @see com.pb.common.matrix.MatrixReader#readMatrices() + */ + @Override + public Matrix[] readMatrices() throws MatrixException { + throw new RuntimeException("Can't read OMX Matrices without specifying the file name, this java class is to be used for an entire directory of files."); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/skims/SomeSkims.java b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/SomeSkims.java new file mode 100644 index 0000000..206e589 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/SomeSkims.java @@ -0,0 +1,437 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +package org.sandag.cvm.common.skims; + +import org.sandag.cvm.common.datafile.TableDataSet; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; +import com.pb.common.matrix.MatrixType; +import com.pb.common.matrix.ZipMatrixReader; + +import drasys.or.util.Array; + +import ncsa.hdf.object.h5.H5CompoundDS; +import ncsa.hdf.object.FileFormat; +import ncsa.hdf.object.HObject; +import ncsa.hdf.object.h5.H5File; + +import org.apache.log4j.Logger; + +import java.io.File; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collections; +import java.util.Enumeration; +import java.util.List; +import java.util.TreeSet; + +import javax.swing.tree.DefaultMutableTreeNode; + +/** + * A class that reads in peak auto skims and facilitates zone pair disutility calculations + * @author John Abraham, Joel Freedman + * + */ +public class SomeSkims implements TravelAttributesInterface { + protected static Logger logger = Logger.getLogger("com.pb.models.pecas"); + + private ArrayList matrixList = new ArrayList(); + public Matrix[] matrices = new Matrix[0]; + private ArrayList matrixNameList = new ArrayList(); + + String my1stPath; + String my2ndPath; + + + public SomeSkims() { + my1stPath = System.getProperty("user.dir"); + } + + public SomeSkims(String firstPath, String secondPath) { + my1stPath = firstPath; + my2ndPath =secondPath; + }; + + public Matrix getMatrix(String name) { + int place = matrixNameList.indexOf(name); + if (place >=0) return matrices[place]; + return null; + } + + public void addZipMatrix(String matrixName) { + if (matrixNameList.contains(matrixName)) { + logger.info("SomeSkims already contains matrix named "+matrixName+", not reading it in again"); + } else { + File skim = new File(my1stPath+matrixName+".zip"); + if (!skim.exists()) skim = new File(my1stPath+matrixName+".zipMatrix"); + if(!skim.exists()) skim = new File(my1stPath+matrixName+".zmx"); + if(!skim.exists()){ + skim = new File(my2ndPath+matrixName+".zip"); + if(!skim.exists()) skim = new File(my2ndPath+matrixName+".zipMatrix"); + if(!skim.exists()) skim = new File(my2ndPath+matrixName+".zmx"); + if (!skim.exists()) { + logger.fatal("Could not find "+ matrixName+".zip, .zipMatrix or .zmx in either directory"); + throw new RuntimeException("Could not find "+ matrixName+".zip, .zipMatrix or .zmx in either directory"); + } + } + matrixList.add(new ZipMatrixReader(skim).readMatrix()); + matrixNameList.add(matrixName); + matrices = (Matrix[]) matrixList.toArray(matrices); + } + + if(logger.isDebugEnabled()) logger.debug("finished reading zipmatrix of skims "+matrixName+" into memory"); + } + + public void addTableDataSetSkims(TableDataSet s, String[] fieldsToAdd, int maxZoneNumber) { + addTableDataSetSkims(s, fieldsToAdd, maxZoneNumber, "origin", "destination"); + + } + + public void addMatrixFromFile(String fileName, String matrixName) { + File f = new File(fileName); + MatrixType type = MatrixReader.determineMatrixType(f); + if (type == null) { + logger.error("Can't determine matrix type for "+fileName); + } else { + MatrixReader r = MatrixReader.createReader(type,f); + Matrix m = r.readMatrix(); + matrixNameList.add(matrixName); + matrixList.add(m); + m.setName(matrixName); + matrices = (Matrix[]) matrixList.toArray(matrices); + } + + } + + public void addMatrix(Matrix m, String name) { + matrixNameList.add(name); + matrixList.add(m); + m.setName(name); + matrices = (Matrix[]) matrixList.toArray(matrices); + } + + public void addMatrixCSVSkims(TableDataSet s, String name) { + int rows = s.getRowCount(); + int columns = s.getColumnCount()-1; + if (rows!=columns) { + logger.fatal("Trying to add CSV Matrix Skims and number of columns does not equal number of rows"); + throw new RuntimeException("Trying to add CSV Matrix Skims and number of columns does not equal number of rows"); + } + float[][] tempArray = new float[rows][columns]; + int[] userToSequentialLookup = new int[rows+1]; + // check order of rows and columns + for (int check = 1;check < s.getRowCount();check++) { + if (!(s.getColumnLabel(check+1).equals(String.valueOf((int) (s.getValueAt(check,1)))))) { + logger.fatal("CSVMatrixSkims have columns out of order (needs to be the same as rows)"); + throw new RuntimeException("CSVMatrixSkims have columns out of order (needs to be the same as rows)"); + } + } + // TODO check for missing skims when using CSV format + for (int tdsRow = 1;tdsRow <= s.getRowCount();tdsRow++) { + userToSequentialLookup[tdsRow]=(int) s.getValueAt(tdsRow,1); + for (int tdsCol=2;tdsCol<=s.getColumnCount();tdsCol++) { + tempArray[tdsRow-1][tdsCol-2]=s.getValueAt(tdsRow,tdsCol); + } + } + Matrix m = new Matrix(name,"",tempArray); + matrixNameList.add(name); + m.setExternalNumbers(userToSequentialLookup); + this.matrixList.add(m); + matrices = (Matrix[]) matrixList.toArray(matrices); + } + + /** Adds a table data set of skims into the set of skims that are available + * + * @param s the table dataset of skims. There must be a column called "origin" + * and another column called "destination" + * @param fieldsToAdd the names of the fields from which to create matrices from, all other fields + * will be ignored. + */ + public void addTableDataSetSkims(TableDataSet s, String[] fieldsToAdd, int maxZoneNumber, String originFieldName, String destinationFieldName) { + int originField = s.checkColumnPosition(originFieldName); + int destinationField = s.checkColumnPosition(destinationFieldName); + int[] userToSequentialLookup = new int[maxZoneNumber]; + int[] sequentialToUserLookup = new int[maxZoneNumber]; + for (int i =0; i0) { + matrixArrays[entry][userToSequentialLookup[origin]][userToSequentialLookup[destination]] = s.getValueAt(row,fieldIds[entry]); + } + } + } + + for (int matrixToBeAdded =0; matrixToBeAdded < fieldsToAdd.length; matrixToBeAdded++) { + if (fieldIds[matrixToBeAdded]>0) { + matrixNameList.add(fieldsToAdd[matrixToBeAdded]); + Matrix m = new Matrix(fieldsToAdd[matrixToBeAdded],"",matrixArrays[matrixToBeAdded]); + m.setExternalNumbers(externalZoneNumbers); + this.matrixList.add(m); + } + } + + matrices = (Matrix[]) matrixList.toArray(matrices); + + logger.info("Finished reading TableDataSet skims "+s+" into memory"); + } + + + static int selectHDFFieldByName(H5CompoundDS hdfDataset, String name) { + List nameList = Arrays.asList(hdfDataset.getMemberNames()); + int index = nameList.indexOf(name); + if (index == -1) { + String msg = "No field of name "+name+" in HDF5 file node"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + hdfDataset.selectMember(index); + return index; + } + + + static class intKeyString implements Comparable { + int myInt; + String myString; + + intKeyString(int i, String s) { + myInt = i; + myString = s; + } + + @Override + public int compareTo(Object o) { + int otherInt = ((intKeyString) o).myInt; + if (otherInt > myInt) return -1; + if (otherInt < myInt) return 1; + if (otherInt == myInt) return 0; + assert false; + return 0; + } + } + + /** + * Adds some skims from an HDF5 file of skims into the set of skims that are available + * @param hdf5File + * @param nodeName + * @param fieldsToAdd + * @param maxZoneNumber + * @param originFieldName + * @param destinationFieldName + */ + public void addHDF5Skims(File hdf5File, String nodeName, String[] fieldsToAdd, int maxZoneNumber, String originFieldName, String destinationFieldName) { + logger.error("HDF5 Skims have not been tested yet, test SomeSkims.addHDF5Skims before using it"); + FileFormat f = null; + try { + f = new H5File(hdf5File.getAbsolutePath(), H5File.READ); + f.open(); + DefaultMutableTreeNode theRoot = (DefaultMutableTreeNode) f.getRootNode(); + if (theRoot == null) { + String msg= "Null root in HDF5 skim file "+hdf5File; + logger.fatal(msg); + throw new RuntimeException(msg); + } + + Enumeration local_enum = ((DefaultMutableTreeNode) theRoot).breadthFirstEnumeration(); + while (local_enum.hasMoreElements()) { + DefaultMutableTreeNode theNode = (DefaultMutableTreeNode) local_enum.nextElement(); + HObject theObj = (HObject) theNode.getUserObject(); + String theName = theObj.getName(); + if (theName.equals(nodeName)){ + logger.info("Found object \""+theName+"\" in HDF5File "+hdf5File+", reading skims"); + if (!(theObj instanceof H5CompoundDS)) { + String msg = "object \""+theName+"\" in HDF5File "+hdf5File+" is not a compound dataset, can't read skims"; + logger.fatal(msg); + throw new RuntimeException(msg); + } + H5CompoundDS skims = (H5CompoundDS) theObj; + assert skims.getRank() ==1 : "Skim object in HDF5 file should only be of rank 1"; + skims.setMemberSelection(false); + int originFieldIndex = selectHDFFieldByName(skims, originFieldName); + assert originFieldIndex == 0 : "Origin needs to be first member in HDF skim dataset"; + int destinationFieldIndex = selectHDFFieldByName(skims, destinationFieldName); + assert destinationFieldIndex == 1 : "Destination needs to be second member in HDF skim dataset"; + + // get origin and destination zones, get all rows from file but no content yet. + long[] selected = skims.getSelectedDims(); + logger.info("getting zone numbers from "+selected[0]+" rows of origins and destinations"); + + List odNumbers = (List) skims.read(); + assert odNumbers.get(0) instanceof int[] : "Skim origins are not integer in HDF skim dataset"; + int[] origins = (int[]) odNumbers.get(0); + assert odNumbers.get(1) instanceof int[] : "Skim destinations are not integer in HDF skim dataset"; + int[] destinations = (int[]) odNumbers.get(1); + int[][] userSequentialCrossLookup = buildCrossLookups( + origins, destinations); + + odNumbers = null; // forget it so we can collect the memory with garbage collection + + intKeyString[] skimIndices = new intKeyString[fieldsToAdd.length]; + int i = 0; + for (String skimName : fieldsToAdd) { + skimIndices[i] = new intKeyString(selectHDFFieldByName(skims,skimName), skimName); + i++; + } + Arrays.sort(skimIndices); // important to sort them so we get them in the correct order below. + + float[][][] matrixArrays = new float[skimIndices.length][userSequentialCrossLookup[0].length][userSequentialCrossLookup[0].length]; + + // now get content 100 rows at a time + final long HOWMANY = 100; + long[] start = skims.getStartDims(); + selected[0] = HOWMANY; + long size = skims.getDims()[0]; + for (long beginAt = 0; beginAt <= size; beginAt += HOWMANY) { + if (beginAt+HOWMANY >= size) // should be >=? + { + selected[0] = size - beginAt; + } + List skimData = (List) skims.read(); + assert skimData.get(0) instanceof int[] : "Skim origins are not integer in HDF skim dataset"; + origins = (int[]) skimData.get(0); + assert skimData.get(1) instanceof int[] : "Skim destinations are not integer in HDF skim dataset"; + destinations = (int[]) skimData.get(1); + for (int r = 0; r < origins.length; r++ ) { + int originArrayIndex = userSequentialCrossLookup[0][origins[r]]; + int destinationArrayIndex = userSequentialCrossLookup[0][destinations[r]]; + for (int col = 0; col + 2 < skimData.size(); col ++) { + matrixArrays[col][originArrayIndex][destinationArrayIndex] = ((float[]) skimData.get(col+2))[r]; + } + } + + } + + + int[] externalZoneNumbers = new int[userSequentialCrossLookup[0].length+1]; + for(int k=1;k zoneSet = new TreeSet(); + for (int o : origins) { + zoneSet.add(o); + } + for (int d : destinations) { + zoneSet.add(d); + } + int maxZone = Collections.max(zoneSet); + int[][] userSequentialCrossLookup= new int[2][]; + int[] sequentialToUserLookup = new int[zoneSet.size()]; + userSequentialCrossLookup[0] = sequentialToUserLookup; + int[] userToSequentialLookup = new int[maxZone+1]; + userSequentialCrossLookup[1] = userToSequentialLookup; + int z=0; + for (int z1 : userToSequentialLookup) { + userToSequentialLookup[z++] = -1; + } + z=0; + for (int z2 : zoneSet) { + sequentialToUserLookup[z] = z2; + userToSequentialLookup[z2] = z++; + } + return userSequentialCrossLookup; + } + + + public int getMatrixId(String string) { + + return matrixNameList.indexOf(string); + } + + + /** + * @param my1stPath The my1stPath to set. + */ + public void setMy1stPath(String my1stPath) { + this.my1stPath = my1stPath; + } + + /** + * @param my2ndPath The my2ndPath to set. + */ + public void setMy2ndPath(String my2ndPath) { + this.my2ndPath = my2ndPath; + } + +}; diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TranscadMatrixCollectionReader.java b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TranscadMatrixCollectionReader.java new file mode 100644 index 0000000..64611ab --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TranscadMatrixCollectionReader.java @@ -0,0 +1,67 @@ +/** + * + */ +package org.sandag.cvm.common.skims; + +import java.io.File; + +import org.apache.log4j.Logger; + +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixException; +import com.pb.common.matrix.MatrixReader; +import com.pb.common.matrix.TranscadMatrixReader; + +/** + * Reads a matrix by name with two parts separated by a colon. The first part is the file + * name (without the .mtx extension), the second part is the "core" name within the file. + * + * Transcad creates matrix files, but they are three dimensional matrices, with the z dimension being + * referred to as "cores". This allows treating these files as a list of two dimensional matrices + * @author johna + * + */ +public class TranscadMatrixCollectionReader extends MatrixReader { + + protected static Logger logger = Logger.getLogger(TranscadMatrixCollectionReader.class); + + protected File directoryOfMatrices; + + /** + * + */ + public TranscadMatrixCollectionReader(File directory) { + directoryOfMatrices = directory; + } + + /* (non-Javadoc) + * @see com.pb.common.matrix.MatrixReader#readMatrix(java.lang.String) + */ + @Override + public Matrix readMatrix(String name) throws MatrixException { + String[] split = name.split(":"); + if (split.length>2) { + String msg = "Matrix name "+name+" has more than 1 part"; + } + TranscadMatrixReader r = new TranscadMatrixReader(new File(directoryOfMatrices,split[0]+".mtx")); + if (split.length == 1) return r.readMatrix(0); + return r.readMatrix(split[1]); + } + + /* (non-Javadoc) + * @see com.pb.common.matrix.MatrixReader#readMatrix() + */ + @Override + public Matrix readMatrix() throws MatrixException { + throw new RuntimeException("Can't read Transcad Matrix without specifying file_name:matrix_name"); + } + + /* (non-Javadoc) + * @see com.pb.common.matrix.MatrixReader#readMatrices() + */ + @Override + public Matrix[] readMatrices() throws MatrixException { + throw new RuntimeException("Can't read Transcad Matrices without specifying the file name, this java class is to be used for an entire directory of files."); + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TravelAttributesInterface.java b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TravelAttributesInterface.java new file mode 100644 index 0000000..208960a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TravelAttributesInterface.java @@ -0,0 +1,23 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ +/* Generated by Together */ + +package org.sandag.cvm.common.skims; + +public interface TravelAttributesInterface { + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TravelUtilityCalculatorInterface.java b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TravelUtilityCalculatorInterface.java new file mode 100644 index 0000000..15d787b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/common/skims/TravelUtilityCalculatorInterface.java @@ -0,0 +1,28 @@ +/* + * Copyright 2005 PB Consult Inc. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + * + */ + +package org.sandag.cvm.common.skims; + + +/** A class that represents how the preferences for travel by different modes and different times of day + * + * @author J. Abraham + */ +public interface TravelUtilityCalculatorInterface { + public double getUtility(Location origin, Location destination, TravelAttributesInterface travelConditions); + +} diff --git a/sandag_abm/src/main/java/org/sandag/cvm/model/patternDetail/DestinationRandomTerms.java b/sandag_abm/src/main/java/org/sandag/cvm/model/patternDetail/DestinationRandomTerms.java new file mode 100644 index 0000000..625e869 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/cvm/model/patternDetail/DestinationRandomTerms.java @@ -0,0 +1,121 @@ +package org.sandag.cvm.model.patternDetail; + +import java.util.Random; + +import org.apache.log4j.Logger; + +import org.sandag.cvm.common.model.GumbelErrorTerm; + +public class DestinationRandomTerms { + + protected static Logger logger = Logger.getLogger(DestinationRandomTerms.class); + + + static final Random random = new Random(); + static final double log4pi = Math.log(4*Math.PI); + + final int normalPoolSize = 100000; + /** + * This is the pool of standard normals, used for zones with size < useGumbel + */ + double[] normalPool = null; + + final int uniformPoolSize = 100000; + /** + * This is the pool of uniform distributed numbers, used with size > useGumbel + */ + double[] uniformPool = null; + + // TODO set useGumbel to something > 1 + /** + * if n > useGumbel, we'll use the Hall approximation to the Gumbel Distribution + */ + int useGumbel = 200; + + /** + * Gets a extreme normal random variable for a zone. If zone, poolOffset, poolSkip and n + * are the same it will return the same value. + * @param zone the destination zone under consideration + * @param poolOffset something stored in Preferences to distinguish decision makers + * @param poolSkip something stored in Preferences to distinguish decision makers + * @param n how large the population is in the zone + * @param stdDev the variance of the underlying normal distribution + * @return the sample from the extreme normal distribution + */ + public double getExtremeNormal(int zone, int poolOffset, int poolSkip, int n, double stdDev) { + if (poolSkip ==0) { + logger.warn("poolSkip is zero, setting it to 1"); + poolSkip = 1; + } + checkPools(); + if (stdDev == 0) return 0; + if (n 1.9999); + } + // let's check for n=20, see if we get expected within a certain tolerance + // these are the expected histograms from another experiment, with 4777 maximum random draws + // they are 0.1 apart and the first upper bound is 0.2 + int[] expectedHistograms = new int[]{ + 0, + 0, + 1, + 0, + 5, + 13, + 26, + 38, + 74, + 91, + 155, + 217, + 254, + 327, + 355, + 350, + 370, + 394, + 330, + 330, + 305, + 229, + 205, + 163, + 116, + 114, + 97, + 61, + 47, + 31, + 17, + 22, + 15, + 3, + 10, + 2, + 3, + 4, + 1, + 0, + 0, + 0, + 0, + 0, + 2, + 0, + 0, + 0, + 0}; + int offSet = (int) (Math.random()*10000); + int skip = (int) (Math.random()*10); + for (int i=0;i<4777;i++) { + int fakeZone = (int) (Math.random()*15000); + double sample1 = sampler.getExtremeNormal(fakeZone, offSet, skip, 20, 1); + int bin = (int) ((sample1-0.1)/0.1); + if (bin <0) bin =0; + if (bin >= expectedHistograms.length) bin = expectedHistograms.length-1; + expectedHistograms[bin]--; + } + // now check to see if maximum diff < 70; + int maximumDiff = 0; + for (int i=0;i= expectedHistograms.length) bin = expectedHistograms.length-1; + expectedHistograms[bin]--; + } + // now check to see if maximum diff < 100; + maximumDiff = 0; + for (int i=0;i= expectedHistograms.length) bin = expectedHistograms.length-1; + expectedHistograms[bin]--; + } + // now check to see if maximum diff < 5; + maximumDiff = 0; + for (int i=0;i cntFlows; + private Matrix[] truckFlowsSUT; + private Matrix[] truckFlowsMUT; + private Matrix emptySUT; + private Matrix emptyMUT; + + + public SandagCountyModel(ReadFAF4 faf4, disaggregateFlows df) { + // constructor + this.faf4 = faf4; + this.df = df; + + } + + + public void runSandagCountyModel () { + // run model to disaggregate flows from FAF zones to counties + + logger.info("Model to disaggregate flows from FAF zones to counties"); + + df.getUScountyEmploymentByIndustry(utilities.getRb()); + utilities.createZoneList(); + faf4.readAllData(utilities.getRb(), utilities.getYear(), "tons"); + + faf4.definePortsOfEntry(utilities.getRb()); + if (utilities.getBooleanProperty("read.in.raw.faf.data", true)) extractTruckData(); + disaggregateFromFafToCounties(); + + convertTonsToTrucks cttt = new convertTonsToTrucks(utilities.getRb()); + cttt.readData(); + convertTonsToTrucks(cttt); + addEmptyTrucks(); + writeCountyTripTables(); + } + + + private void extractTruckData() { + // extract truck data and write flows to file + logger.info("Extracting FAF truck data"); + String[] scaleTokens = ResourceUtil.getArray(utilities.getRb(), "scaling.truck.trips.tokens"); + double[] scaleValues = ResourceUtil.getDoubleArray(utilities.getRb(), "scaling.truck.trips.values"); + HashMap scaler = fafUtils.createScalerHashMap(scaleTokens, scaleValues); + String truckFileNameT = ResourceUtil.getProperty(utilities.getRb(), "processed.truck.faf.data") + "_" + + utilities.getYear(); + + // create output directory if it does not exist yet + File file = new File ("output/temp"); + if (!file.exists()) { + boolean outputDirectorySuccessfullyCreated = file.mkdir(); + if (!outputDirectorySuccessfullyCreated) logger.warn("Could not create scenario directory output/temp/"); + } + faf4.writeFlowsByModeAndCommodity(truckFileNameT, ModesFAF.Truck, reportFormat.internat_domesticPart, scaler); + } + + + private void disaggregateFromFafToCounties() { + // disaggregates freight flows from FAF zoneArray to counties + + logger.info(" Disaggregating FAF data from FAF zones to counties for year " + utilities.getYear() + "."); + + int matrixSize = utilities.countyFips.length; + cntFlows = new HashMap<>(); + + float globalScale = (float) ResourceUtil.getDoubleProperty(utilities.getRb(), "overall.scaling.factor.truck"); + + // regular method + for (String com: ReadFAF4.sctgStringCommodities) { + float[][] dummy = new float[matrixSize][matrixSize]; + cntFlows.put(com, dummy); + } + df.prepareCountyDataForFAFwithDetailedEmployment(utilities.getRb(), utilities.getYear(), false); + df.scaleSelectedCounties(utilities.getRb()); + + java.util.concurrent.ForkJoinPool pool = new java.util.concurrent.ForkJoinPool(); + DnCRecursiveAction action = new DissaggregateFafAction(globalScale); + pool.execute(action); + action.getResult(); + } + + + private class DissaggregateFafAction extends DnCRecursiveAction { + private final float globalScale; + + private DissaggregateFafAction(float globalScale) { + super(0,ReadFAF4.sctgStringCommodities.length); + this.globalScale = globalScale; + } + + private DissaggregateFafAction(float globalScale, long start, long length, DnCRecursiveAction next) { + super(start,length,next); + this.globalScale = globalScale; + } + + @Override + protected void computeAction(long start, long length) { + long end = start + length; + for (int comm = (int) start; comm < end; comm++) { + int cm = ReadFAF4.sctgCommodities[comm]; + + String fileName = ResourceUtil.getProperty(utilities.getRb(), "processed.truck.faf.data") + "_" + utilities.getYear(); + if (cm < 10) fileName = fileName + "_SCTG0" + cm + ".csv"; + else fileName = fileName + "_SCTG" + cm + ".csv"; + logger.info(" Working on " + fileName); + String sctg = ReadFAF4.getSCTGname(cm); + float[][] values = cntFlows.get(sctg); + TableDataSet tblFlows = fafUtils.importTable(fileName); + for (int row = 1; row <= tblFlows.getRowCount(); row++) { + float shortTons = tblFlows.getValueAt(row, "shortTons"); + if (shortTons == 0) continue; + String dir = tblFlows.getStringValueAt(row, "flowDirection"); + int orig = (int) tblFlows.getValueAt(row, "originFAF"); + int dest = (int) tblFlows.getValueAt(row, "destinationFAF"); + TableDataSet singleFlow; + if (dir.startsWith("import") || dir.startsWith("export")) { + TableDataSet poe = null; + // Entry through land border + switch (dir) { + case "import": + poe = ReadFAF4.getPortsOfEntry(orig); + break; + // Entry through marine port + case "import_port": + poe = ReadFAF4.getMarinePortsOfEntry(orig); + break; + // Entry through airport + case "import_airport": + poe = ReadFAF4.getAirPortsOfEntry(orig); + break; + // Exit through land border + case "export": + poe = ReadFAF4.getPortsOfEntry(dest); + break; + // Exit through marine port + case "export_port": + poe = ReadFAF4.getMarinePortsOfEntry(dest); + break; + // Exit through airport + case "export_airport": + poe = ReadFAF4.getAirPortsOfEntry(dest); + break; + } + singleFlow = df.disaggregateSingleFAFFlowThroughPOE(dir, poe, orig, dest, sctg, shortTons, 1); + } else singleFlow = df.disaggregateSingleFAFFlow(orig, dest, sctg, shortTons, 1); + for (int i = 1; i <= singleFlow.getRowCount(); i++) { + int oFips = (int) singleFlow.getValueAt(i, "oFips"); + int oZone = utilities.countyFipsIndex[oFips]; + int dFips = (int) singleFlow.getValueAt(i, "dFips"); + int dZone = utilities.countyFipsIndex[dFips]; + float thisFlow = singleFlow.getValueAt(i, "Tons") * globalScale; + values[oZone][dZone] += thisFlow; + } + } + } + } + + @Override + protected DnCRecursiveAction getNextAction(long start, long length, DnCRecursiveAction next) { + return new DissaggregateFafAction(globalScale,start,length,next); + } + + @Override + protected boolean continueDividing(long length) { + return getSurplusQueuedTaskCount() < 3 && length > 1; + } + } + + + private void convertTonsToTrucks (convertTonsToTrucks cttt) { + // convert flows in tons into flows in trucks using average payload factors + + logger.info(" Converting tons into trucks"); + + int highestGroupCode = utilities.getHighestVal(utilities.getCommodityGroupOfSCTG()); + truckFlowsSUT = new Matrix[highestGroupCode + 1]; + truckFlowsMUT = new Matrix[highestGroupCode + 1]; + float aawdtFactor = (float) ResourceUtil.getDoubleProperty(utilities.getRb(), "AADT.to.AAWDT.factor"); + for (int i = 0; i <= highestGroupCode; i++) { + truckFlowsSUT[i] = createCountyMatrix(); + truckFlowsMUT[i] = createCountyMatrix(); + } + + for (String com: ReadFAF4.sctgStringCommodities) { + int comGroup = utilities.getCommodityGroupOfSCTG()[Integer.parseInt(com.substring(4))]; + float[][] flowsThisCommodity = cntFlows.get(com); + for (int oFips: utilities.countyFips) { + for (int dFips: utilities.countyFips) { + int oZone = utilities.countyFipsIndex[oFips]; + int dZone = utilities.countyFipsIndex[dFips]; + float distance = df.getCountyDistance(oFips, dFips); + float truckByType[] = cttt.convertThisFlowFromTonsToTrucks(com, distance, flowsThisCommodity[oZone][dZone]); + float oldValueSUT = truckFlowsSUT[comGroup].getValueAt(oFips, dFips); + float newValueSut = truckByType[0] / 365.25f * aawdtFactor; + truckFlowsSUT[comGroup].setValueAt(oFips, dFips, oldValueSUT + newValueSut); + float oldValueMUT = truckFlowsMUT[comGroup].getValueAt(oFips, dFips); + float newValueMUT = (truckByType[1] + truckByType[2] + truckByType[3]) / 365.25f * aawdtFactor; + truckFlowsMUT[comGroup].setValueAt(oFips, dFips, oldValueMUT + newValueMUT); + } + } + } + } + + + private Matrix createCountyMatrix() { + Matrix mat = new Matrix(utilities.countyFips.length, utilities.countyFips.length); + mat.setExternalNumbersZeroBased(utilities.countyFips); + return mat; + } + + private void addEmptyTrucks() { + // Empty truck model to ensure balanced truck volumes entering and leaving every zone + + double emptyRate = 1f - ResourceUtil.getDoubleProperty(utilities.getRb(), "empty.truck.rate"); + + int highestGroupCode = utilities.getHighestVal(utilities.getCommodityGroupOfSCTG()); + double[] balSut = new double[utilities.countyFips.length]; + double[] balMut = new double[utilities.countyFips.length]; + Matrix loadedSutTot = createCountyMatrix(); + Matrix loadedMutTot = createCountyMatrix(); + for (int orig = 0; orig < utilities.countyFips.length; orig++) { + for (int dest = 0; dest < utilities.countyFips.length; dest++) { + for (int comGroup = 0; comGroup <= highestGroupCode; comGroup++) { + float sut = truckFlowsSUT[comGroup].getValueAt(utilities.countyFips[orig], utilities.countyFips[dest]); + float mut = truckFlowsMUT[comGroup].getValueAt(utilities.countyFips[orig], utilities.countyFips[dest]); + balSut[orig] -= sut; + balSut[dest] += sut; + balMut[orig] -= mut; + balMut[dest] += mut; + loadedSutTot.setValueAt(utilities.countyFips[orig], utilities.countyFips[dest], + (loadedSutTot.getValueAt(utilities.countyFips[orig], utilities.countyFips[dest]) + sut)); + loadedMutTot.setValueAt(utilities.countyFips[orig], utilities.countyFips[dest], + (loadedMutTot.getValueAt(utilities.countyFips[orig], utilities.countyFips[dest]) + mut)); + } + } + } + Matrix emptyBalancedSut = balanceEmpties(balSut); + Matrix emptyBalancedMut = balanceEmpties(balMut); + double targetSut = loadedSutTot.getSum() / emptyRate; + double targetMut = loadedMutTot.getSum() / emptyRate; + double emptySutRetTot = emptyBalancedSut.getSum(); + double emptyMutRetTot = emptyBalancedMut.getSum(); + + logger.info(" Trucks generated by commodity flows: " + Math.round(loadedSutTot.getSum()) + " SUT and " + + Math.round(loadedMutTot.getSum()) + " MUT."); + logger.info(" Empty trucks generated by balancing: " + Math.round((float) emptySutRetTot) + " SUT and " + + Math.round((float) emptyMutRetTot) + " MUT."); + double correctedEmptyTruckRate = emptyRate + (emptySutRetTot + emptyMutRetTot) / (targetSut + targetMut); + if (correctedEmptyTruckRate < 0) logger.warn("Empty truck rate for returning trucks is with " + + utilities.rounder(((emptySutRetTot + emptyMutRetTot) / (targetSut + targetMut)), 2) + + " greater than global empty-truck rate of " + utilities.rounder(emptyRate, 2)); + logger.info(" Empty trucks added by statistics: " + Math.round((float) ((1 - correctedEmptyTruckRate) * targetSut)) + + " SUT and " + Math.round((float) ((1 - correctedEmptyTruckRate) * targetMut)) + " MUT."); + + emptySUT = createCountyMatrix(); + emptyMUT = createCountyMatrix(); + for (int origin : utilities.countyFips) { + for (int destination : utilities.countyFips) { + float emptySutReturn = emptyBalancedSut.getValueAt(destination, origin); // note: orig and dest are switched to get return trip + float emptyMutReturn = emptyBalancedMut.getValueAt(destination, origin); // note: orig and dest are switched to get return trip + double emptySutStat = (loadedSutTot.getValueAt(origin, destination) + emptySutReturn) / correctedEmptyTruckRate - + (loadedSutTot.getValueAt(origin, destination) + emptySutReturn); + double emptyMutStat = (loadedMutTot.getValueAt(origin, destination) + emptyMutReturn) / correctedEmptyTruckRate - + (loadedMutTot.getValueAt(origin, destination) + emptyMutReturn); + + emptySUT.setValueAt(origin, destination, (float) (emptySutReturn + emptySutStat)); + emptyMUT.setValueAt(origin, destination, (float) (emptyMutReturn + emptyMutStat)); + } + } + } + + + private Matrix balanceEmpties(double[] trucks) { + // generate empty truck trips + + RowVector emptyTruckDest = new RowVector(utilities.countyFips.length); + emptyTruckDest.setExternalNumbersZeroBased(utilities.countyFips); + ColumnVector emptyTruckOrig = new ColumnVector(utilities.countyFips.length); + emptyTruckOrig.setExternalNumbersZeroBased(utilities.countyFips); + for (int zn = 0; zn < utilities.countyFips.length; zn++) { + if (trucks[zn] > 0) { + emptyTruckDest.setValueAt(utilities.countyFips[zn], (float) trucks[zn]); + emptyTruckOrig.setValueAt(utilities.countyFips[zn], 0f); + } + else { + emptyTruckOrig.setValueAt(utilities.countyFips[zn], (float) trucks[zn]); + emptyTruckDest.setValueAt(utilities.countyFips[zn], 0f); + } + } + Matrix seed = createCountyMatrix(); + for (int o: utilities.countyFips) { + for (int d: utilities.countyFips) { + float friction = (float) Math.exp(-0.001 * df.getCountyDistance(o, d)); + seed.setValueAt(o, d, friction); + } + } + MatrixBalancerRM mb = new MatrixBalancerRM(seed, emptyTruckOrig, emptyTruckDest, 0.001, 10, MatrixBalancerRM.ADJUST.BOTH_USING_AVERAGE); + return mb.balance(); + } + + + private void writeCountyTripTables() { + // write out county-to-county trip tables + + logger.info(" Writing county-to-county truck trip table"); + String fileName = utilities.getRb().getString("county.to.county.trip.table") + "_" + utilities.getYear() + ".csv"; + PrintWriter pw = fafUtils.openFileForSequentialWriting(fileName); + pw.println("origFips,destFips,sut1,sut2,sut3,sut4,sut5,sut6,emptySut,mut1,mut2,mut3,mut4,mut5,mut6,emptyMut"); + for (int oFips: utilities.countyFips) { + for (int dFips: utilities.countyFips) { + pw.print(oFips+","+dFips); + for (int i = 1; i < truckFlowsSUT.length; i++) pw.print("," + truckFlowsSUT[i].getValueAt(oFips,dFips)); + pw.print("," + emptySUT.getValueAt(oFips, dFips)); + for (int i = 1; i < truckFlowsMUT.length; i++) pw.print("," + truckFlowsMUT[i].getValueAt(oFips,dFips)); + pw.println("," + emptyMUT.getValueAt(oFips, dFips)); + } + } + pw.close(); + } + + + +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/applications/ohio.java b/sandag_abm/src/main/java/org/sandag/htm/applications/ohio.java new file mode 100644 index 0000000..0cd3513 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/applications/ohio.java @@ -0,0 +1,118 @@ +package org.sandag.htm.applications; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; +import org.sandag.htm.processFAF.countyTruckModel; +import org.sandag.htm.processFAF.fafUtils; +import org.sandag.htm.processFAF.readFAF3; + +import org.apache.log4j.Logger; + +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; + +/** + * Application of countyTruckModel for Ohio State + * Author: Rolf Moeckel, PB Albuquerque + * Date: June 15, 2012 (Chicago IL) + + */ +public class ohio { + + private static Logger logger = Logger.getLogger(ohio.class); + private static String[] listOfRailRegions; + private static String[] railRegionReference; + private static boolean[] relevantCommodities; + + public static void summarizeFAFData (ResourceBundle appRb, int[] countyFips) { + // Summarize commodity flows of FAF data + +// if (!ResourceUtil.getBooleanProperty(appRb, "read.in.raw.faf.data")) { +// logger.error("Cannot summarize data for Ohio, set \"read.in.raw.faf.data\" to true."); +// return; +// } + if (ResourceUtil.getBooleanProperty(appRb, "summarize.by.ohio.rail.zones")) { + readOhioRailRegions(appRb, countyFips); + readRelevantCommodities(appRb); + } + + } + + + private static void readOhioRailRegions (ResourceBundle appRb, int[] countyFips) { + // create reference between fips code and Ohio Rail Region + + logger.info("Reading Ohio Rail Regions"); + TableDataSet railRegions = fafUtils.importTable(appRb.getString("rail.zone.definition")); + int highestFips = fafUtils.getHighestVal(countyFips); + + railRegionReference = new String[highestFips + 1]; + for (int row = 1; row <= railRegions.getRowCount(); row++) { + int fips = (int) railRegions.getValueAt(row, "fips"); + String reg = railRegions.getStringValueAt(row, "ohioRailRegion"); + railRegionReference[fips] = reg; + } + listOfRailRegions = fafUtils.getUniqueListOfValues(railRegionReference); + } + + + private static void readRelevantCommodities (ResourceBundle appRb) { + // Read how commodities are grouped by SCTG cagegory + + TableDataSet comGroups = fafUtils.importTable(appRb.getString("commodity.grouping")); + relevantCommodities = new boolean[fafUtils.getHighestVal(readFAF3.sctgCommodities) + 1]; + for (int i = 0; i < relevantCommodities.length; i++) relevantCommodities[i] = false; + for (int row = 1; row <= comGroups.getRowCount(); row++) { + int sctg = (int) comGroups.getValueAt(row, "SCTG"); + String truckType = comGroups.getStringValueAt(row, "MainTruckType"); + relevantCommodities[sctg] = truckType.equals("Van"); // set relevantCommodities to true if truckType equals Van + } + } + + + public static void sumFlowByRailZone(ResourceBundle appRb, int year, int[] countyFips, int[] countyIndex, HashMap cntFlows) { + // summarize flows by rail regions + + // Step 1: Initialize counter + HashMap railRegionIndex = new HashMap<>(); + int regionCounter = 0; + for (String txt: listOfRailRegions) { + railRegionIndex.put(txt,regionCounter); + regionCounter++; + } + double[][] summaryRailRegions = new double[listOfRailRegions.length][listOfRailRegions.length]; + + // Step 2: Summarize flows + String[] commodities = readFAF3.sctgStringCommodities; + for (String com: commodities) { + if (!relevantCommodities[Integer.parseInt(com.substring(4))]) continue; + float[][] flows = cntFlows.get(com); + for (int oFips: countyFips) { + if (railRegionReference[oFips] != null) { + int origRailRegion = railRegionIndex.get(railRegionReference[oFips]); + for (int dFips: countyFips) { + if (railRegionReference[dFips] != null) { + int destRailRegion = railRegionIndex.get(railRegionReference[dFips]); + summaryRailRegions[origRailRegion][destRailRegion] += flows[countyIndex[oFips]][countyIndex[dFips]]; + } + } + } + } + } + + PrintWriter pw = fafUtils.openFileForSequentialWriting(appRb.getString("rail.zone.output") + "_" + year + ".csv"); + + pw.print("Region"); + for (String txt: listOfRailRegions) pw.print("," + txt); + pw.println(); + for (String orig: listOfRailRegions) { + pw.print(orig); + for (String dest: listOfRailRegions) { + pw.print("," + summaryRailRegions[railRegionIndex.get(orig)][railRegionIndex.get(dest)]); + } + pw.println(); + } + pw.close(); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/applications/sandagZonalModel.java b/sandag_abm/src/main/java/org/sandag/htm/applications/sandagZonalModel.java new file mode 100644 index 0000000..1e5e07d --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/applications/sandagZonalModel.java @@ -0,0 +1,338 @@ +package org.sandag.htm.applications; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; +import org.sandag.htm.processFAF.disaggregateFlows; +import org.sandag.htm.processFAF.fafUtils; +import com.pb.sawdust.calculator.Function1; +import com.pb.sawdust.util.array.ArrayUtil; +import com.pb.sawdust.util.concurrent.ForkJoinPoolFactory; +import com.pb.sawdust.util.concurrent.IteratorAction; +import org.apache.log4j.Logger; + +import java.io.PrintWriter; +import java.util.*; +import java.util.concurrent.ForkJoinPool; + +/** + * SANDAG external truck model + * Class to disaggregate FAF flows from counties to SANDAG zones + * Author: Rolf Moeckel, PB Albuquerque + * Date: 6 March 2013 (Santa Fe, NM) + * Version 1.0 + */ + +public class sandagZonalModel { + + private static Logger logger = Logger.getLogger(sandagZonalModel.class); + private int[] zones; + private HashMap useHshLocal; + private HashMap makeHshLocal; + private String[] industries; + private float[][] zonalEmployment; + private TableDataSet countyFlows; + private int[] sandagExtStatID; + private boolean[] sandagExtStat_border; + private int[] sanDiegoNodes; + private final HashMap disaggregatedFlows = new HashMap<>(); + private String[] todNames; + private float[][] todSutShare; + private float[][] todMutShare; + + + public sandagZonalModel() { + // constructor + } + + + public void runSandagZonalModel () { + // run model to disaggregate flows from counties to SANDAG zones + + logger.info("Model to disaggregate flows from counties to zones"); + + readInputData(); + disaggregateFlowsFromCountiesToZones(); + writeOutDisaggregatedFlows(); + } + + + private void readInputData() { + // read input data + + logger.info(" Reading input data"); + // define TAZ and MGRA system + TableDataSet zonesTbl = fafUtils.importTable(utilities.getRb().getString("local.zones")); + zones = zonesTbl.getColumnAsInt("TAZ"); + TableDataSet mgraZones = fafUtils.importTable(utilities.getRb().getString("local.mgra.zones")); + int[] mgras = mgraZones.getColumnAsInt("mgra13"); + int[] mgraTazReference = new int[fafUtils.getHighestVal(mgras) + 1]; + for (int row = 1; row <= mgraZones.getRowCount(); row++) { + mgraTazReference[(int) mgraZones.getValueAt(row, "mgra13")] = (int) mgraZones.getValueAt(row, "taz13"); + } + + // process local make/use coefficients + String useToken = "faf.use.coefficients.local"; + String makeToken = "faf.make.coefficients.local"; + useHshLocal = disaggregateFlows.createMakeUseHashMap(utilities.getRb(), useToken); + makeHshLocal = disaggregateFlows.createMakeUseHashMap(utilities.getRb(), makeToken); + TableDataSet useCoeff = fafUtils.importTable(utilities.getRb().getString(useToken)); + industries = useCoeff.getColumnAsString("Industry"); + + // read local employment data + TableDataSet employmentMGRA = fafUtils.importTable(utilities.getRb().getString("local.employment.data") + + utilities.getYear() + ".csv"); + zonalEmployment = new float[utilities.getHighestVal(zones)+1][industries.length]; + for (int row = 1; row <= employmentMGRA.getRowCount(); row++) { + int mgra = (int) employmentMGRA.getValueAt(row, "mgra"); + int taz = mgraTazReference[mgra]; + for (int ind = 0; ind < industries.length; ind++) { + zonalEmployment[taz][ind] += employmentMGRA.getValueAt(row, industries[ind]); + } + } + + // read external station IDs + TableDataSet extStations = fafUtils.importTable(utilities.getRb().getString("external.station.definition")); + sandagExtStatID = new int[utilities.getHighestVal(extStations.getColumnAsInt("natExtStat")) + 1]; + sandagExtStat_border = new boolean[utilities.getHighestVal(zones) + 1]; + for (int row = 1; row <= extStations.getRowCount(); row++) { + sandagExtStatID[(int) extStations.getValueAt(row, "natExtStat")] = + (int) extStations.getValueAt(row, "sandagExtStat"); + sandagExtStat_border[(int) extStations.getValueAt(row, "sandagExtStat")] = + extStations.getBooleanValueAt(row, "borderCrossing"); + } + + // read flows at external stations + String fileName = utilities.getRb().getString("external.station.flows"); + countyFlows = utilities.importTableFromDBF(fileName); + if (countyFlows.getColumnCount() != 16) logger.error("Excepted 16 but found " + countyFlows.getColumnCount() + + " columns in " + fileName); + String[] expectedLabels = {"SUBAREA_NO","SUBAREA_N1","DEMAND_SUT","DEMAND_SU1","DEMAND_SU2","DEMAND_SU3","DEMAND_SU4","DEMAND_SU5","DEMAND_EMP","DEMAND_MUT","DEMAND_MU1","DEMAND_MU2","DEMAND_MU3","DEMAND_MU4","DEMAND_MU5","DEMAND_EM1"}; + String[] actualLabels = countyFlows.getColumnLabels(); + boolean wrongHeader = false; + for (int col = 0; col < countyFlows.getColumnCount(); col++) { + if (!actualLabels[col].equalsIgnoreCase(expectedLabels[col])) + wrongHeader = true; + } + if (wrongHeader) { + logger.error("File " + fileName + " has unexpected headers:"); + logger.info("Column,ExpectedLabel,ActualLabel"); + for (int col = 0; col < countyFlows.getColumnCount(); col++) + logger.info(col+1 + "," + expectedLabels[col] + "," + actualLabels[col] + "," + (expectedLabels[col].equals(actualLabels[col]))); + System.exit(1); + } + countyFlows.setColumnLabels(new String[]{"orig","dest","sut1","sut2","sut3","sut4","sut5","sut6","sutEmpty", + "mut1","mut2","mut3","mut4","mut5","mut6","mutEmpty"}); + + sanDiegoNodes = ResourceUtil.getIntegerArray(utilities.getRb(), "internal.nodes.san.diego"); + + // read time-of-day shares + TableDataSet TODValuesGeneral = fafUtils.importTable(utilities.getRb().getString("time.of.day.shares.general")); + TableDataSet TODValuesBorder = fafUtils.importTable(utilities.getRb().getString("time.of.day.shares.border")); + todNames = TODValuesGeneral.getColumnAsString("DESCRIPTION"); + todSutShare = new float[2][TODValuesGeneral.getRowCount()]; + todMutShare = new float[2][TODValuesGeneral.getRowCount()]; + float[] checkSum = new float[4] ; + for (int row = 1; row <= TODValuesGeneral.getRowCount(); row++) { + todSutShare[0][row-1] = TODValuesGeneral.getValueAt(row, "ShareSUT"); + todMutShare[0][row-1] = TODValuesGeneral.getValueAt(row, "ShareMUT"); + todSutShare[1][row-1] = TODValuesBorder.getValueAt(row, "ShareSUT"); + todMutShare[1][row-1] = TODValuesBorder.getValueAt(row, "ShareMUT"); + checkSum[0] += todSutShare[0][row-1]; + checkSum[1] += todMutShare[0][row-1]; + checkSum[2] += todSutShare[1][row-1]; + checkSum[3] += todMutShare[1][row-1]; + } + if (checkSum[0] > 1.001 || checkSum[0] < 0.999) logger.warn("Time of day share for SUT (general) does not add up to 1 but " + checkSum[0]); + if (checkSum[1] > 1.001 || checkSum[1] < 0.999) logger.warn("Time of day share for MUT (general) does not add up to 1 but " + checkSum[1]); + if (checkSum[2] > 1.001 || checkSum[2] < 0.999) logger.warn("Time of day share for SUT (border) does not add up to 1 but " + checkSum[2]); + if (checkSum[3] > 1.001 || checkSum[3] < 0.999) logger.warn("Time of day share for MUT (border) does not add up to 1 but " + checkSum[3]); + } + + + private void disaggregateFlowsFromCountiesToZones() { + // calculate local weights and disaggregate flows from counties/external stations to zones/external stations + + final HashMap weights = prepareZonalWeights(); + logger.info(" Disaggregating flows to zones"); + + int[] listOfCommodityGroupsPlusEmpties = new int[utilities.getListOfCommodityGroups().length + 1]; + listOfCommodityGroupsPlusEmpties[0] = 0; // category for empty trucks + System.arraycopy(utilities.getListOfCommodityGroups(), 0, listOfCommodityGroupsPlusEmpties, 1, utilities.getListOfCommodityGroups().length); + Integer[] list = new Integer[listOfCommodityGroupsPlusEmpties.length]; + for (int i = 0; i < listOfCommodityGroupsPlusEmpties.length; i++) list[i] = listOfCommodityGroupsPlusEmpties[i]; + Function1 commodityDisaggregationFunctionFAF = new Function1() { + public Void apply(Integer com) { + processCommodityDisaggregation(com, weights); + return null; + } + }; + + Iterator commodityIterator = ArrayUtil.getIterator(list); + IteratorAction itTask = new IteratorAction<>(commodityIterator, commodityDisaggregationFunctionFAF); + ForkJoinPool pool = ForkJoinPoolFactory.getForkJoinPool(); + pool.execute(itTask); + itTask.waitForCompletion(); + } + + + + + private HashMap prepareZonalWeights() { + // prepare zonal weights based on employment by industry + + logger.info(" Calculating zonal weights"); + HashMap weights = new HashMap<>(); + + double[] makeEmpty = new double[zones.length]; + double[] useEmpty = new double[zones.length]; + + for (int comGrp: utilities.getListOfCommodityGroups()) { + double[] makeWeight = new double[zones.length]; + double[] useWeight = new double[zones.length]; + for (int com: utilities.getComGroupDefinition().get(comGrp)) { + for (int iz = 0; iz < zones.length; iz++) { + int zn = zones[iz]; + for (int ind = 0; ind < industries.length; ind++) { + String industry = industries[ind]; + String code; + if (com <= 9) code = industry + "_SCTG0" + com; + else code = industry + "_SCTG" + com; + makeWeight[iz] += zonalEmployment[zn][ind] * makeHshLocal.get(code); + useWeight[iz] += zonalEmployment[zn][ind] * useHshLocal.get(code); + makeEmpty[iz] += zonalEmployment[zn][ind] * makeHshLocal.get(code); + useEmpty[iz] += zonalEmployment[zn][ind] * useHshLocal.get(code); + } + } + } + String mCode = comGrp + "_make"; + weights.put(mCode, makeWeight); + String uCode = comGrp + "_use"; + weights.put(uCode, useWeight); + } + weights.put("0_make", makeEmpty); + weights.put("0_use", useEmpty); + return weights; + } + + + + private boolean checkIfCountyInSanDiego(int node) { + // check if county is either San Diego County of San Diego Phantom County + + boolean insideSandag = false; + for (int i: sanDiegoNodes) if (i == node) insideSandag = true; + return insideSandag; + } + + + private void processCommodityDisaggregation(Integer comGroup, Map weights) { + // Disaggregate a single commodity from county-to-county flows to zone-to-zone flows + logger.info(" Processing commodity group " + comGroup); + + ArrayList origAL = new ArrayList<>(); + ArrayList destAL = new ArrayList<>(); + ArrayList flowSutAL = new ArrayList<>(); + ArrayList flowMutAL = new ArrayList<>(); + for (int row = 1; row <= countyFlows.getRowCount(); row ++) { + int orig = (int) countyFlows.getValueAt(row, "orig"); + int dest = (int) countyFlows.getValueAt(row, "dest"); + String sutLabel; + if (comGroup == 0) sutLabel = "sutEmpty"; + else sutLabel = "sut" + comGroup; + float sutTrk = countyFlows.getValueAt(row, sutLabel); + String mutLabel; + if (comGroup == 0) mutLabel = "mutEmpty"; + else mutLabel = "mut" + comGroup; + float mutTrk = countyFlows.getValueAt(row, mutLabel); + + if (checkIfCountyInSanDiego(orig) && checkIfCountyInSanDiego(dest)) { + // flows from San Diego County to San Diego Phantom County or vice versa + // ignore as these flows are internal to SANDAG and known to be underestimated + } else if (checkIfCountyInSanDiego(orig)) { + // flows from San Diego to elsewhere + double[] makeShare = weights.get(comGroup + "_make"); + double makeShareSum = utilities.getSum(makeShare); + for (int zone = 0; zone < zones.length; zone++) { + origAL.add(zones[zone]); + destAL.add(sandagExtStatID[dest]); + flowSutAL.add((float) (sutTrk * makeShare[zone] / makeShareSum)); + flowMutAL.add((float) (mutTrk * makeShare[zone] / makeShareSum)); + } + } else if (checkIfCountyInSanDiego(dest)) { + // flows from elsewhere to San Diego + double[] useShare = weights.get(comGroup + "_use"); + double useShareSum = utilities.getSum(useShare); + for (int zone = 0; zone < zones.length; zone++) { + origAL.add(sandagExtStatID[orig]); + destAL.add(zones[zone]); + flowSutAL.add((float) (sutTrk * useShare[zone] / useShareSum)); + flowMutAL.add((float) (mutTrk * useShare[zone] / useShareSum)); + } + } else { + // through flows through San Diego + origAL.add(sandagExtStatID[orig]); + destAL.add(sandagExtStatID[dest]); + flowSutAL.add(sutTrk); + flowMutAL.add(mutTrk); + } + + TableDataSet disFlows = new TableDataSet(); + disFlows.appendColumn(utilities.convertIntArrayListToArray(origAL), "orig"); + disFlows.appendColumn(utilities.convertIntArrayListToArray(destAL), "dest"); + disFlows.appendColumn(utilities.convertFloatArrayListToArray(flowSutAL), "sut"); + disFlows.appendColumn(utilities.convertFloatArrayListToArray(flowMutAL), "mut"); + + synchronized (disaggregatedFlows) { + disaggregatedFlows.put(comGroup, disFlows); + } + } + } + + + private void writeOutDisaggregatedFlows () { + // write out disaggregated flows to csv file + + logger.info(" Writing zone-to-external station truck trip table"); + String fileName = utilities.getRb().getString("zone.to.ext.stat.trip.table") + "_" + utilities.getYear() + ".csv"; + PrintWriter pw = fafUtils.openFileForSequentialWriting(fileName); + pw.print("orig,dest"); + for (String tod: todNames) pw.print(",SUT " + tod); + for (String tod: todNames) pw.print(",MUT " + tod); + pw.println(); + + HashMap summarizedFlows = new HashMap<>(); + + for (int comGrp = 0; comGrp <= utilities.getHighestVal(utilities.getListOfCommodityGroups()); comGrp++) { + TableDataSet flows = disaggregatedFlows.get(comGrp); + + for (int row = 1; row <= flows.getRowCount(); row++) { + String key = (int) flows.getValueAt(row, "orig") + "," + (int) flows.getValueAt(row, "dest"); + float[] values; + if (summarizedFlows.containsKey(key)) { + values = summarizedFlows.get(key); + } else { + values = new float[]{0,0}; + } + values[0] += flows.getValueAt(row, "sut"); + values[1] += flows.getValueAt(row, "mut"); + summarizedFlows.put(key, values); + } + } + + for (String key: summarizedFlows.keySet()) { + float[] values = summarizedFlows.get(key); + pw.print(key); + + // check if flow crosses border with Mexico, in which case different time-of-day split is used + String[] odPair = key.split(","); + int border = 0; + if (sandagExtStat_border[Integer.parseInt(odPair[0])] || + sandagExtStat_border[Integer.parseInt(odPair[1])]) border = 1; + + for (int tod = 0; tod < todNames.length; tod++) pw.print("," + values[0] * todSutShare[border][tod]); + for (int tod = 0; tod < todNames.length; tod++) pw.print("," + values[1] * todMutShare[border][tod]); + pw.println(); + } + pw.close(); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/applications/sandag_tm.java b/sandag_abm/src/main/java/org/sandag/htm/applications/sandag_tm.java new file mode 100644 index 0000000..fcd4ed9 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/applications/sandag_tm.java @@ -0,0 +1,45 @@ +package org.sandag.htm.applications; + +import org.sandag.htm.processFAF.disaggregateFlows; +import org.sandag.htm.processFAF.readFAF3; +import org.sandag.htm.processFAF.ReadFAF4; + +import org.apache.log4j.Logger; + +/** + * Program to model SANDAG external truck flows based on FAF3 data + * Author: Rolf Moeckel, PB Albuquerque + * Date: 6 March 2013 (Santa Fe, NM) + * Version 1.0 + * + * Modified 2017-12-28 to use FAF4 data by JEF, RSG + */ + +public class sandag_tm { + + private static Logger logger = Logger.getLogger(sandag_tm.class); + + + public static void main(String[] args) { + + long startTime = System.currentTimeMillis(); + + ReadFAF4 faf4 = new ReadFAF4(); + disaggregateFlows df = new disaggregateFlows(); + utilities.truckModelInitialization(args, faf4, df); + + if (utilities.getModel().equalsIgnoreCase("counties")) { + SandagCountyModel scm = new SandagCountyModel(faf4, df); + scm.runSandagCountyModel(); + } else { + sandagZonalModel szm = new sandagZonalModel(); + szm.runSandagZonalModel(); + } + + logger.info("Finished SANDAG Truck Model for year " + utilities.getYear()); + float endTime = utilities.rounder(((System.currentTimeMillis() - startTime) / 60000), 1); + int hours = (int) (endTime / 60); + int min = (int) (endTime - 60 * hours); + logger.info("Runtime: " + hours + " hours and " + min + " minutes."); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/applications/utilities.java b/sandag_abm/src/main/java/org/sandag/htm/applications/utilities.java new file mode 100644 index 0000000..330aca4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/applications/utilities.java @@ -0,0 +1,217 @@ +package org.sandag.htm.applications; + +import com.pb.common.datafile.DBFFileReader; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; +import org.sandag.htm.processFAF.disaggregateFlows; +import org.sandag.htm.processFAF.fafUtils; +import org.sandag.htm.processFAF.readFAF3; +import org.sandag.htm.processFAF.ReadFAF4; + +import org.apache.log4j.Logger; + +import java.io.File; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.ResourceBundle; + +/** + * Utility methods for SANDAG external truck model + * Author: Rolf Moeckel, PB Albuquerque + * Date: 6 March 2013 (Santa Fe, NM) + * Version 1.0 + */ + +public class utilities { + + + private static ResourceBundle rb; + private static String model; + private static int year; + public static int[] countyFips; + public static int[] countyFipsIndex; + private static int[] commodityGroupOfSCTG; + private static HashMap comGroupDefinition; + private static int[] listOfCommodityGroups; + private static Logger logger = Logger.getLogger(utilities.class); + + + public static void truckModelInitialization(String[] args, readFAF3 faf3, disaggregateFlows df) { + // read in properties file and define basic variables, such as model year + + String rbName = args[0]; + File propFile = new File(rbName); + rb = ResourceUtil.getPropertyBundle(propFile); + model = args[1]; + if (!model.equalsIgnoreCase("counties") && !model.equalsIgnoreCase("zones")) { + logger.error("Call program with parameters "); + logger.error("Geography " + args[1] + " not understood. Choose \"counties\" or \"zones\""); + System.exit(1); + } + year = Integer.parseInt(args[2]); + logger.info("Starting SANDAG Truck Model for year " + utilities.getYear()); + readCommodityGrouping(); + } + + + public static void truckModelInitialization(String[] args, ReadFAF4 faf4, disaggregateFlows df) { + // read in properties file and define basic variables, such as model year + + String rbName = args[0]; + File propFile = new File(rbName); + rb = ResourceUtil.getPropertyBundle(propFile); + model = args[1]; + if (!model.equalsIgnoreCase("counties") && !model.equalsIgnoreCase("zones")) { + logger.error("Call program with parameters "); + logger.error("Geography " + args[1] + " not understood. Choose \"counties\" or \"zones\""); + System.exit(1); + } + year = Integer.parseInt(args[2]); + logger.info("Starting SANDAG Truck Model for year " + utilities.getYear()); + readCommodityGrouping(); + } + + private static void readCommodityGrouping () { + // read in commodity grouping + + TableDataSet commodityGrouping = fafUtils.importTable(utilities.getRb().getString("commodity.grouping")); + int highestValue = utilities.getHighestVal(commodityGrouping.getColumnAsInt("SCTG")); + commodityGroupOfSCTG = new int[highestValue + 1]; + comGroupDefinition = new HashMap<>(); + for (int row = 1; row <= commodityGrouping.getRowCount(); row++) { + int sctg = (int) commodityGrouping.getValueAt(row, "SCTG"); + int grp = (int) commodityGrouping.getValueAt(row, "CommodityGroup"); + commodityGroupOfSCTG[sctg] = grp; + if (comGroupDefinition.containsKey(grp)) { + int[] commodities = comGroupDefinition.get(grp); + comGroupDefinition.put(grp, expandArrayByOneElement(commodities, sctg)); + } else { + comGroupDefinition.put(grp, new int[]{sctg}); + } + } + listOfCommodityGroups = new int[comGroupDefinition.size()]; + int count = 0; + for (int comGrp: comGroupDefinition.keySet()) { + listOfCommodityGroups[count] = comGrp; + count++; + } + } + + + public static int[] getCommodityGroupOfSCTG() { + return commodityGroupOfSCTG; + } + + + public static HashMap getComGroupDefinition() { + return comGroupDefinition; + } + + + public static int[] getListOfCommodityGroups() { + return listOfCommodityGroups; + } + + + public static float rounder(float value, int digits) { + // rounds value to digits behind the decimal point + return Math.round(value * Math.pow(10, digits) + 0.5)/(float) Math.pow(10, digits); + } + + + public static int getYear() { + return year; + } + + public static ResourceBundle getRb() { + return rb; + } + + public static String getModel() { + return model; + } + + public static boolean getBooleanProperty (String token, boolean defaultIfNotAvailable) { + return ResourceUtil.getBooleanProperty(rb, token, defaultIfNotAvailable); + } + + + public static int getHighestVal(int[] array) { + // return highest number in array + + int high = Integer.MIN_VALUE; + for (int num: array) high = Math.max(high, num); + return high; + } + + + public static float rounder(double value, int digits) { + // rounds value to digits behind the decimal point + return Math.round(value * Math.pow(10, digits) + 0.5)/(float) Math.pow(10, digits); + } + + + public static int[] expandArrayByOneElement (int[] existing, int addElement) { + // create new array that has length of existing.length + 1 and copy values into new array + int[] expanded = new int[existing.length + 1]; + System.arraycopy(existing, 0, expanded, 0, existing.length); + expanded[expanded.length - 1] = addElement; + return expanded; + } + + + public static void createZoneList() { + // Create array with specialRegions that serve as port of entry/exit + + int[] poeLand = fafUtils.importTable(rb.getString("ports.of.entry")).getColumnAsInt("pointOfEntry"); + int[] poeSea = fafUtils.importTable(rb.getString("marine.ports.of.entry")).getColumnAsInt("pointOfEntry"); + int[] poeAir = fafUtils.importTable(rb.getString("air.ports.of.entry")).getColumnAsInt("pointOfEntry"); + int[] list = new int[poeLand.length + poeSea.length + poeAir.length]; + System.arraycopy(poeLand, 0, list, 0, poeLand.length); + System.arraycopy(poeSea, 0, list, poeLand.length, poeSea.length); + System.arraycopy(poeAir, 0, list, poeLand.length + poeSea.length, poeAir.length); + countyFips = fafUtils.createCountyFipsArray(list); + countyFipsIndex = new int[fafUtils.getHighestVal(countyFips) + 1]; + for (int i = 0; i < countyFips.length; i++) { + countyFipsIndex[countyFips[i]] = i; + } + } + + + public static TableDataSet importTableFromDBF(String filePath) { + // read a dbf file into a TableDataSet + + TableDataSet tblData; + DBFFileReader dbfReader = new DBFFileReader(); + try { + tblData = dbfReader.readFile(new File( filePath )); + } catch (Exception e) { + throw new RuntimeException("File not found: <" + filePath + ">.", e); + } + dbfReader.close(); + return tblData; + } + + + public static double getSum (double[] array) { + // return sum of all elements in array + double sum = 0; + for (double val: array) sum += val; + return sum; + } + + + public static float[] convertIntArrayListToArray(ArrayList al) { + float[] array = new float[al.size()]; + for (int i = 0; i < al.size(); i++) array[i] = al.get(i); + return array; + } + + + public static float[] convertFloatArrayListToArray(ArrayList al) { + float[] array = new float[al.size()]; + for (int i = 0; i < al.size(); i++) array[i] = al.get(i); + return array; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/applications/yumaMPO.java b/sandag_abm/src/main/java/org/sandag/htm/applications/yumaMPO.java new file mode 100644 index 0000000..72a67eb --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/applications/yumaMPO.java @@ -0,0 +1,180 @@ +package org.sandag.htm.applications; + +import com.pb.common.datafile.TableDataSet; +import org.sandag.htm.processFAF.fafUtils; +import org.sandag.htm.processFAF.readFAF3; + +import java.io.PrintWriter; +import java.util.ResourceBundle; + +/** + * Application of countyTruckModel for Yuma, AZ MPO + * Author: Rolf Moeckel, PB Albuquerque + * Date: April 5, 2012 (Santa Fe NM) + + */ +public class yumaMPO { + + private static float[][][] tons_yuma_border; + private static float[][][] tons_yuma_fafzones; + private static float[][][] tons_yuma_counties; + private static float[][] tons_yuma_mex; + private static TableDataSet counties; + private static int[] countyIndex; + + + public static void initializeVariables(ResourceBundle appRb) { + // set up variables for summaries + int maxCom = fafUtils.getHighestVal(readFAF3.sctgCommodities); + tons_yuma_border = new float[2][560 + 1][maxCom + 1]; // by direction, FAF zone and commodity + tons_yuma_fafzones = new float[2][560 + 1][maxCom + 1]; // by direction, FAF zone and commodity + tons_yuma_counties = new float[2][15 + 1][maxCom + 1]; // by direction, county and commodity + counties = fafUtils.importTable(appRb.getString("county.ID")); + counties.buildIndex(counties.getColumnPosition("COUNTYFIPS")); + countyIndex = new int[fafUtils.getHighestVal(counties.getColumnAsInt("COUNTYFIPS")) + 1]; + for (int i = 0; i < countyIndex.length; i++) countyIndex[i] = -1; + countyIndex[4001] = 0; // index counties within Arizona + countyIndex[4003] = 1; + countyIndex[4005] = 2; + countyIndex[4007] = 3; + countyIndex[4009] = 4; + countyIndex[4011] = 5; + countyIndex[4012] = 6; + countyIndex[4013] = 7; + countyIndex[4015] = 8; + countyIndex[4017] = 9; + countyIndex[4019] = 10; + countyIndex[4021] = 11; + countyIndex[4023] = 12; + countyIndex[4025] = 13; + countyIndex[4027] = 14; + countyIndex[6025] = 15; // index Imperial County in California + tons_yuma_mex = new float[2][2]; + } + + + public static void saveForYuma(int com, int oFips, int dFips, float tons) { + // save relevant data for Yuma-specific summaries + +// try { + int oFAF = 0; + if (oFips < 60000) oFAF = (int) counties.getIndexedValueAt(oFips, "FAF3region"); + int dFAF = 0; + if (dFips < 60000) dFAF = (int) counties.getIndexedValueAt(dFips, "FAF3region"); + + // Flows through Yuma border crossing + if (oFips == 61934 && dFAF != 0) { + tons_yuma_border[0][dFAF][com] += tons; + } else if (dFips == 61934 && oFAF != 0) { + tons_yuma_border[1][oFAF][com] += tons; + } + // Flows to/from Yuma + if (oFips == 4027 && dFAF != 0) { + tons_yuma_fafzones[0][dFAF][com] += tons; + if (countyIndex[dFips] >= 0) tons_yuma_counties[0][countyIndex[dFips]][com] += tons; + } else if (dFips == 4027 && oFAF != 0) { + tons_yuma_fafzones[1][oFAF][com] += tons; + if (countyIndex[oFips] >= 0) tons_yuma_counties[1][countyIndex[oFips]][com] += tons; + } + // Flows between Yuma and Mexico + if (oFips == 4027) tons_yuma_mex[0][0] += tons; + if (oFips == 4027 && dFips > 60000) tons_yuma_mex[0][1] += tons; + if (dFips == 4027) tons_yuma_mex[1][0] += tons; + if (dFips == 4027 && oFips > 60000) tons_yuma_mex[1][1] += tons; + +// } catch (Exception e) { +// System.out.println("Error: " + com+" "+oFips+" "+dFips); +// } + } + + + public static void writeOutResults(ResourceBundle appRb, int year) { + // write results to summary file + + PrintWriter pw = fafUtils.openFileForSequentialWriting(appRb.getString("yuma.summary") + year + ".csv"); + + pw.println("Total tons leaving Yuma : " + tons_yuma_mex[0][0]); + pw.println("Tons from Yuma to Mexico: " + tons_yuma_mex[0][1]); + pw.println("Total tons entering Yuma: " + tons_yuma_mex[1][0]); + pw.println("Tons from Mexico to Yuma: " + tons_yuma_mex[1][1]); + pw.println(); + + pw.println("SUMMARY BY FAF ZONE"); + pw.print("FlowsFromYumaToFAFZone"); + for (int i: readFAF3.sctgCommodities) pw.print(",SCTG" + i); + pw.println(); + for (int faf = 1; faf <= 560; faf++) { + float sum = 0; + for (int i: readFAF3.sctgCommodities) sum += tons_yuma_fafzones[0][faf][i]; + if (sum > 0) { + pw.print(faf); + for (int i: readFAF3.sctgCommodities) pw.print("," + tons_yuma_fafzones[0][faf][i]); + pw.println(); + } + } + pw.println(); + pw.print("FlowsToYumaFromFAFZone"); + for (int i: readFAF3.sctgCommodities) pw.print(",SCTG" + i); + pw.println(); + for (int faf = 1; faf <= 560; faf++) { + float sum = 0; + for (int i: readFAF3.sctgCommodities) sum += tons_yuma_fafzones[1][faf][i]; + if (sum > 0) { + pw.print(faf); + for (int i: readFAF3.sctgCommodities) pw.print("," + tons_yuma_fafzones[1][faf][i]); + pw.println(); + } + } + pw.println(); + + pw.println("SUMMARY BY COUNTY"); + pw.print("FlowsFromYumaToCounty"); + for (int i: readFAF3.sctgCommodities) pw.print(",SCTG" + i); + pw.println(); + for (int county: counties.getColumnAsInt("COUNTYFIPS")) { + if (countyIndex[county] == -1) continue; + pw.print(county); + for (int i: readFAF3.sctgCommodities) pw.print("," + tons_yuma_counties[0][countyIndex[county]][i]); + pw.println(); + } + pw.println(); + pw.print("FlowsToYumaFromCounty"); + for (int i: readFAF3.sctgCommodities) pw.print(",SCTG" + i); + pw.println(); + for (int county: counties.getColumnAsInt("COUNTYFIPS")) { + if (countyIndex[county] == -1) continue; + pw.print(county); + for (int i: readFAF3.sctgCommodities) pw.print("," + tons_yuma_counties[1][countyIndex[county]][i]); + pw.println(); + } + pw.println(); + + pw.println("SUMMARY BY BORDER ZONE"); + pw.print("FlowsFromYumaBorderToFAFZone"); + for (int i: readFAF3.sctgCommodities) pw.print(",SCTG" + i); + pw.println(); + for (int faf = 1; faf <= 560; faf++) { + float sum = 0; + for (int i: readFAF3.sctgCommodities) sum += tons_yuma_border[0][faf][i]; + if (sum > 0) { + pw.print(faf); + for (int i: readFAF3.sctgCommodities) pw.print("," + tons_yuma_border[0][faf][i]); + pw.println(); + } + } + pw.println(); + pw.print("FlowsToYumaBorderFromFAFZone"); + for (int i: readFAF3.sctgCommodities) pw.print(",SCTG" + i); + pw.println(); + for (int faf = 1; faf <= 560; faf++) { + float sum = 0; + for (int i: readFAF3.sctgCommodities) sum += tons_yuma_border[1][faf][i]; + if (sum > 0) { + pw.print(faf); + for (int i: readFAF3.sctgCommodities) pw.print("," + tons_yuma_border[1][faf][i]); + pw.println(); + } + } + pw.close(); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/ModesFAF.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/ModesFAF.java new file mode 100644 index 0000000..ef5e308 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/ModesFAF.java @@ -0,0 +1,19 @@ +package org.sandag.htm.processFAF; + +/** + * Defines modes available in FAF + * Author: Rolf Moeckel (PB Albuquerque) + * Date: September 9, 2010 + * Edited jef 2017-12-28 to remove reference to FAF3 since FAF3 modes are same as FAF4 + */ + +public enum ModesFAF { + + Truck, + Rail, + Water, + Air, + MultipleModesAndMail, + Pipeline, + OtherAndUnknown +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/ReadFAF4.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/ReadFAF4.java new file mode 100644 index 0000000..8984f5c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/ReadFAF4.java @@ -0,0 +1,522 @@ +package org.sandag.htm.processFAF; + +import org.apache.log4j.Logger; + +import java.util.ResourceBundle; +import java.util.HashMap; +import java.io.PrintWriter; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +/** + * This class reads FAF4 data and stores data in a TableDataSet + * Author: Joel Freedman, RSG - based on readFAF3 by Rolf Moeckel, PB + * Date: Dec 27, 2017 + */ + +public class ReadFAF4 { + Logger logger = Logger.getLogger(ReadFAF4.class); + private int factor; + private String[] valueColumnName; + private TableDataSet faf4commodityFlows; + public static TableDataSet fafRegionList; + private String[] regionState; + private static int[] domRegionIndex; + static public int[] sctgCommodities; + static public String[] sctgStringCommodities; + static private int[] sctgStringIndex; + private static HashMap portsOfEntry; + private static HashMap marinePortsOfEntry; + private static HashMap railPortsOfEntry; + private static HashMap airPortsOfEntry; + private static int[] listOfBorderPortOfEntries; + + + public void readAllData (ResourceBundle appRb, int year, String unit) { + // read input data + + if (ResourceUtil.getBooleanProperty(appRb, "read.in.raw.faf.data", true)) + readAllFAF4DataSets(appRb, unit, year); + readCommodityList(appRb); + readFAF4ReferenceLists(appRb); + } + + + public void readCommodityList(ResourceBundle appRb) { + // read commodity names + TableDataSet sctgComList = fafUtils.importTable(ResourceUtil.getProperty(appRb, "faf4.sctg.commodity.list")); + sctgCommodities = new int[sctgComList.getRowCount()]; + sctgStringCommodities = new String[sctgCommodities.length]; + for (int i = 1; i <= sctgComList.getRowCount(); i++) { + sctgCommodities[i-1] = (int) sctgComList.getValueAt(i, "SCTG"); + if (sctgCommodities[i-1] < 10) sctgStringCommodities[i-1] = "SCTG0" + sctgCommodities[i-1]; + else sctgStringCommodities[i-1] = "SCTG" + sctgCommodities[i-1]; + } + sctgStringIndex = new int[fafUtils.getHighestVal(sctgCommodities) + 1]; + for (int num = 0; num < sctgCommodities.length; num++) sctgStringIndex[sctgCommodities[num]] = num; + } + + + public int getIndexOfCommodity (int commodity) { + return sctgStringIndex[commodity]; + } + + + public static String getSCTGname(int sctgInt) { + // get String name from sctg number + return sctgStringCommodities[sctgStringIndex[sctgInt]]; + } + + + public static String getFAFzoneName(int fafInt) { + // get String name from int FAF zone code number + return fafRegionList.getStringValueAt(domRegionIndex[fafInt], "FAF4 Zones -Short Description"); + } + + + public static String getFAFzoneState(int fafInt) { + // get String two-letter abbreviation of state of fafInt + return fafRegionList.getStringValueAt(domRegionIndex[fafInt], "State"); + } + + + public void definePortsOfEntry(ResourceBundle appRb) { + // read data to translate ports of entry in network links + + // Border crossings + portsOfEntry = new HashMap<>(); + TableDataSet poe = fafUtils.importTable(appRb.getString("ports.of.entry")); + for (int row = 1; row <= poe.getRowCount(); row++) { + int fafID = (int) poe.getValueAt(row, "faf4id"); + int node = (int) poe.getValueAt(row, "pointOfEntry"); + float weight = poe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (portsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = portsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + portsOfEntry.put(fafID, newPortsOfEntry); + } + listOfBorderPortOfEntries = poe.getColumnAsInt("pointOfEntry"); + + // Marine ports + marinePortsOfEntry = new HashMap<>(); + if (appRb.containsKey("marine.ports.of.entry")) { + TableDataSet mpoe = fafUtils.importTable(appRb.getString("marine.ports.of.entry")); + for (int row = 1; row <= mpoe.getRowCount(); row++) { + int fafID = (int) mpoe.getValueAt(row, "faf4id"); + int node = (int) mpoe.getValueAt(row, "pointOfEntry"); + float weight = mpoe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (marinePortsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = marinePortsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + marinePortsOfEntry.put(fafID, newPortsOfEntry); + } + } + // Rail ports (railyards) + railPortsOfEntry = new HashMap<>(); + if (appRb.containsKey("rail.ports.of.entry")) { + TableDataSet rpoe = fafUtils.importTable(appRb.getString("rail.ports.of.entry")); + for (int row = 1; row <= rpoe.getRowCount(); row++) { + int fafID = (int) rpoe.getValueAt(row, "faf4id"); + int node = (int) rpoe.getValueAt(row, "pointOfEntry"); + float weight = rpoe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (railPortsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = railPortsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + railPortsOfEntry.put(fafID, newPortsOfEntry); + } + } + // Airports + airPortsOfEntry = new HashMap<>(); + if (appRb.containsKey("air.ports.of.entry")) { + TableDataSet apoe = fafUtils.importTable(appRb.getString("air.ports.of.entry")); + for (int row = 1; row <= apoe.getRowCount(); row++) { + int fafID = (int) apoe.getValueAt(row, "faf4id"); + int node = (int) apoe.getValueAt(row, "pointOfEntry"); + float weight = apoe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (airPortsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = airPortsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + airPortsOfEntry.put(fafID, newPortsOfEntry); + } + } + } + + + public static int[] getListOfBorderPortOfEntries() { + return listOfBorderPortOfEntries; + } + + + + public static TableDataSet getPortsOfEntry (int fafZone) { + // return list of ports of entry if available, otherwise return fafZone + if (portsOfEntry.containsKey(fafZone)) return portsOfEntry.get(fafZone); + else return null; + } + + + public static TableDataSet getMarinePortsOfEntry (int fafZone) { + // return list of ports of entry if available, otherwise return fafZone + if (marinePortsOfEntry.containsKey(fafZone)) return marinePortsOfEntry.get(fafZone); + else return null; + } + + + public static TableDataSet getAirPortsOfEntry (int fafZone) { + // return list of ports of entry if available, otherwise return fafZone + if (airPortsOfEntry.containsKey(fafZone)) return airPortsOfEntry.get(fafZone); + else return null; + } + + + public void readAllFAF4dataSets2015(ResourceBundle appRb, String unit) { + // read all FAF4 data into TableDataSets in unit (= tons or dollars) + + logger.info ("Reading domestic FAF4 data in " + unit); + if (unit.equals("tons")) { + factor = 1000; // tons are in 1,000s + valueColumnName = new String[]{"tons_2015"}; + } else if (unit.equals("dollars")) { + factor = 1000000; // dollars are in 1,000,000s + valueColumnName = new String[]{"value_2015"}; + } else { + logger.fatal ("Wrong token " + unit + " in method readAllFAF4dataSets2015. Use tons or dollars."); + } + faf4commodityFlows = readFAF4CommodityFlows(appRb, unit); + } + + + public double[] summarizeFlowByCommodity (ModesFAF fafMode) { + // sum commodity flows by commodity and return array with total tons + + double[] totalFlows = new double[sctgCommodities.length]; + int modeNum = fafUtils.getEnumOrderNumber(fafMode); + for (int row = 1; row <= faf4commodityFlows.getRowCount(); row++) { + if (faf4commodityFlows.getValueAt(row, "dms_mode") != modeNum) continue; + int com = sctgStringIndex[(int) faf4commodityFlows.getValueAt(row, "sctg2")]; + if (valueColumnName.length == 1) { + // use year provided by user + totalFlows[com] += faf4commodityFlows.getValueAt(row, valueColumnName[0]); + } else { + // interpolate between two years + float val1 = faf4commodityFlows.getValueAt(row, valueColumnName[0]); + float val2 = faf4commodityFlows.getValueAt(row, valueColumnName[1]); + totalFlows[com] += val1 + (val2 - val1) * Float.parseFloat(valueColumnName[2]); + } + } + return totalFlows; + } + + + public void readAllFAF4DataSets(ResourceBundle appRb, String unit, int year) { + // read all FAF4 data into TableDataSets in unit (= tons or dollars) + + logger.info (" Reading FAF4 data in " + unit); + switch (unit) { + case "tons": + factor = 1000; // tons are provided in 1,000s + break; + case "dollars": + factor = 1000000; // dollars are provided in 1,000,000s + break; + default: + logger.fatal("Wrong token " + unit + " in method readAllFAF4DataSets. Use tons or dollars."); + throw new RuntimeException(); + } + int[] availYears = {2012, 2013, 2014, 2015, 2020, 2025, 2030, 2035, 2040, 2045}; + boolean yearInFaf = false; + for (int y: availYears) if (year == y) yearInFaf = true; + if (!yearInFaf) { // interpolate between two years + logger.info(" Year " + year + " does not exist in FAF4 data."); + int year1 = availYears[0]; + int year2 = availYears[availYears.length-1]; + for (int availYear : availYears) if (availYear < year) year1 = availYear; + for (int i = availYears.length - 1; i >= 0; i--) if (availYears[i] > year) year2 = availYears[i]; + logger.info(" FAF4 data are interpolated between " + year1 + " and " + year2 + "."); + // first position: lower year, second position: higher year, third position: steps away from lower year + valueColumnName = new String[]{unit + "_" + year1, unit + "_" + year2, String.valueOf((1f * (year - year1)) / (1f * (year2 - year1)))}; + } else { // use year provided by user + valueColumnName = new String[]{unit + "_" + year}; + } + faf4commodityFlows = readFAF4CommodityFlows(appRb, unit); + } + + + private TableDataSet readFAF4CommodityFlows(ResourceBundle appRb, String unit) { + // read FAF4 data and return TableDataSet with flow data + String fileName = ResourceUtil.getProperty(appRb, ("faf4.data")); + return fafUtils.importTable(fileName); + } + + + public HashMap createScaler(String[] tokens, double[] values) { + // create HashMap with state O-D pairs that need to be scaled + + HashMap scaler = new HashMap(); + if (tokens.length != values.length) { + throw new RuntimeException("Error. scaling.truck.trips.tokens must be same length as scaling.truck.trips.values"); + } + for (int i=0; i scaler) { + // extract truck flows for year yr and scale flows according to scaler HashMap (no special regions specified) + + PrintWriter outFile = fafUtils.openFileForSequentialWriting(outFileName); + outFile.println("originFAF,destinationFAF,flowDirection," + commodityClassType.SCTG + "_commodity,shortTons"); + int modeNum = fafUtils.getEnumOrderNumber(mode); + for (int row = 1; row <= faf4commodityFlows.getRowCount(); row++) { + int type = (int) faf4commodityFlows.getValueAt(row, "trade_type"); + double val; + if (valueColumnName.length == 1) { + // use year provided by user + val = faf4commodityFlows.getValueAt(row, valueColumnName[0]); + } else { + // interpolate between two years + float val1 = faf4commodityFlows.getValueAt(row, valueColumnName[0]); + float val2 = faf4commodityFlows.getValueAt(row, valueColumnName[1]); + val = val1 + (val2 - val1) * Float.parseFloat(valueColumnName[2]); + } + val *= factor * odScaler(row, type, scaler); + if (val == 0) continue; + if (type == 1) writeDomesticFlow(modeNum, val, row, outFile); + else if (type == 2) writeImportFlow(modeNum, val, row, outFile, repF); + else if (type == 3) writeExportFlow(modeNum, val, row, outFile, repF); + else if (type == 4) writeThroughFlow(modeNum, val, row, outFile, repF); + else{ + logger.info("Invalid trade_type in FAF4 dataset in row " + row + ": " + type); + } + } + outFile.close(); + } + + + public void writeFlowsByModeAndCommodity (String outFileName, ModesFAF mode, reportFormat repF, + HashMap scaler) { + // extract truck flows for year yr and scale flows according to scaler HashMap, including special regions + + PrintWriter outFile[] = new PrintWriter[sctgCommodities.length]; + for (int com: sctgCommodities) { + String fileName; + if (com < 10) fileName = outFileName + "_SCTG0" + com + ".csv"; + else fileName = outFileName + "_SCTG" + com + ".csv"; + outFile[sctgStringIndex[com]] = fafUtils.openFileForSequentialWriting(fileName); + outFile[sctgStringIndex[com]].println("originFAF,destinationFAF,flowDirection,SCTG_commodity,shortTons"); + } + int modeNum = fafUtils.getEnumOrderNumber(mode); + for (int row = 1; row <= faf4commodityFlows.getRowCount(); row++) { + int type = (int) faf4commodityFlows.getValueAt(row, "trade_type"); + double val; + if (valueColumnName.length == 1) { + // use year provided by user + val = faf4commodityFlows.getValueAt(row, valueColumnName[0]); + } else { + // interpolate between two years + float val1 = faf4commodityFlows.getValueAt(row, valueColumnName[0]); + float val2 = faf4commodityFlows.getValueAt(row, valueColumnName[1]); + val = val1 + (val2 - val1) * Float.parseFloat(valueColumnName[2]); + } + val *= factor * odScaler(row, type, scaler); + if (val == 0) continue; + int comIndex = getIndexOfCommodity((int) faf4commodityFlows.getValueAt(row, "sctg2")); + if (type == 1) writeDomesticFlow(modeNum, val, row, outFile[comIndex]); + else if (type == 2) writeImportFlow(modeNum, val, row, outFile[comIndex], repF); + else if (type == 3) writeExportFlow(modeNum, val, row, outFile[comIndex], repF); + else if (type == 4) writeThroughFlow(modeNum, val, row, outFile[comIndex], repF); + else logger.info("Invalid trade_type in FAF4 dataset in row " + row + ": " + type); + } + for (int com: sctgCommodities) outFile[sctgStringIndex[com]].close(); + } + + + public float odScaler (int row, int type, HashMap scaler) { + // find scaler for origin destination pair in row + + int orig; + int dest; + if (type == 1) { + orig = (int) faf4commodityFlows.getValueAt(row, "dms_orig"); + dest = (int) faf4commodityFlows.getValueAt(row, "dms_dest"); + } else if (type == 2) { + orig = (int) faf4commodityFlows.getValueAt(row, "fr_orig"); + dest = (int) faf4commodityFlows.getValueAt(row, "dms_dest"); + } else if (type == 3) { + orig = (int) faf4commodityFlows.getValueAt(row, "dms_orig"); + dest = (int) faf4commodityFlows.getValueAt(row, "fr_dest"); + } else { + orig = (int) faf4commodityFlows.getValueAt(row, "fr_orig"); + dest = (int) faf4commodityFlows.getValueAt(row, "fr_dest"); + } + String stateLevelToken = regionState[orig] + "_" + regionState[dest]; + String combo1Token = orig + "_" + regionState[dest]; + String combo2Token = regionState[orig] + "_" + dest; + String fafLevelToken = orig + "_" + dest; + float adj = 1; + if (scaler.containsKey(stateLevelToken)) adj = scaler.get(stateLevelToken); + if (scaler.containsKey(combo1Token)) adj = scaler.get(combo1Token); + if (scaler.containsKey(combo2Token)) adj = scaler.get(combo2Token); + if (scaler.containsKey(fafLevelToken)) adj = scaler.get(fafLevelToken); + return adj; + } + + + private int tryGettingThisValue(int row, String token) { + // for some flows, international zones/modes are empty -> catch this case and set zone to 0 + + int region; + try { + region = (int) faf4commodityFlows.getValueAt(row, token); + } catch (Exception e) { + region = 0; + } + return region; + } + + + public void writeDomesticFlow (int modeNum, double val, int row, PrintWriter outFile) { + // internal US flow + if (faf4commodityFlows.getValueAt(row, "dms_mode") == modeNum) { + int orig = (int) faf4commodityFlows.getValueAt(row, "dms_orig"); + int dest = (int) faf4commodityFlows.getValueAt(row, "dms_dest"); + int comm = (int) faf4commodityFlows.getValueAt(row, "sctg2"); + outFile.println(orig + "," + dest + ",domestic," + comm + "," + val); + } + } + + + public void writeImportFlow (int modeNum, double val, int row, PrintWriter outFile, reportFormat repF) { + // from abroad to US + + int frInMode = (int) faf4commodityFlows.getValueAt(row, "fr_inmode"); + int borderZone = (int) faf4commodityFlows.getValueAt(row, "dms_orig"); + int comm = (int) faf4commodityFlows.getValueAt(row, "sctg2"); + if (frInMode == modeNum && repF != reportFormat.internat_domesticPart) { + int orig = tryGettingThisValue(row, "fr_orig"); + outFile.println(orig + "," + borderZone + ",import," + comm + "," + val); + } + if (faf4commodityFlows.getValueAt(row, "dms_mode") == modeNum) { + int dest = (int) faf4commodityFlows.getValueAt(row, "dms_dest"); + String txt; + if (frInMode == fafUtils.getEnumOrderNumber(ModesFAF.Water)) txt = ",import_port,"; + else if (frInMode == fafUtils.getEnumOrderNumber(ModesFAF.Rail)) txt = ",import_rail,"; + else if (frInMode == fafUtils.getEnumOrderNumber(ModesFAF.Air)) txt = ",import_airport,"; + else txt = ",import,"; + outFile.println(borderZone + "," + dest + txt + comm + "," + val); + } + } + + + public void writeExportFlow (int modeNum, double val, int row, PrintWriter outFile, reportFormat repF) { + // from US to abroad + int frOutMode = tryGettingThisValue(row, "fr_outmode"); + int borderZone = (int) faf4commodityFlows.getValueAt(row, "dms_dest"); + int comm = (int) faf4commodityFlows.getValueAt(row, "sctg2"); + if (frOutMode == modeNum && repF != reportFormat.internat_domesticPart) { + int dest = tryGettingThisValue(row, "fr_dest"); + outFile.println(borderZone + "," + dest + ",export," + comm + "," + val); + } + if (faf4commodityFlows.getValueAt(row, "dms_mode") == modeNum) { + int orig = (int) faf4commodityFlows.getValueAt(row, "dms_orig"); + String txt = ",export,"; + if (frOutMode == fafUtils.getEnumOrderNumber(ModesFAF.Water)) txt = ",export_port,"; + if (frOutMode == fafUtils.getEnumOrderNumber(ModesFAF.Rail)) txt = ",export_rail,"; + if (frOutMode == fafUtils.getEnumOrderNumber(ModesFAF.Air)) txt = ",export_airport,"; + outFile.println(orig + "," + borderZone + txt + comm + "," + val); + } + } + + + public void writeThroughFlow(int modeNum, double val, int row, PrintWriter outFile, reportFormat repF) { + // flows in transit through US + if ((int) faf4commodityFlows.getValueAt(row, "dms_mode") != modeNum) return; + int borderInZone = (int) faf4commodityFlows.getValueAt(row, "dms_orig"); + int borderOutZone = (int) faf4commodityFlows.getValueAt(row, "dms_dest"); + logger.warn("Through flows not yet implemented. This flow from " + borderInZone + " to " + borderOutZone + " is lost."); + } + + + public void readFAF4ReferenceLists(ResourceBundle rb) { + // read list of regions for FAF4 + String regFileName = rb.getString("faf4.region.list"); + fafRegionList = fafUtils.importTable(regFileName); + int[] reg = fafRegionList.getColumnAsInt(fafRegionList.getColumnPosition("ZoneID")); + domRegionIndex = new int[fafUtils.getHighestVal(reg) + 1]; + for (int num = 0; num < reg.length; num++) domRegionIndex[reg[num]] = num + 1; + regionState = new String[fafUtils.getHighestVal(reg) + 1]; + for (int row = 1; row <= fafRegionList.getRowCount(); row++) { + int zone = (int) fafRegionList.getValueAt(row, "ZoneID"); + regionState[zone] = fafRegionList.getStringValueAt(row, "State"); + } + } + + + public int[] getFAFzoneIDs () { + return fafRegionList.getColumnAsInt("ZoneID"); + } + + + public TableDataSet getFAF4Flows() { + return faf4commodityFlows; + } + + + public int getFactor() { + return factor; + } + + + public TableDataSet getFAF4CommodityFlows() { + return faf4commodityFlows; + } + + + public String[] getValueColumnName() { + return valueColumnName; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/commodityClassType.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/commodityClassType.java new file mode 100644 index 0000000..17e8314 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/commodityClassType.java @@ -0,0 +1,13 @@ +package org.sandag.htm.processFAF; + +/** + * Defines commodity classification + * STCC + * SCTG + * User: Moeckel + * Date: May 7, 2009 + */ + +public enum commodityClassType { + STCC, SCTG +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/convertTonsToTrucks.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/convertTonsToTrucks.java new file mode 100644 index 0000000..3d578cd --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/convertTonsToTrucks.java @@ -0,0 +1,113 @@ +package org.sandag.htm.processFAF; + +import com.pb.common.datafile.TableDataSet; +import org.apache.log4j.Logger; + +import java.util.ResourceBundle; + +/** + * Class to convert flows from tons into trucks by type + * Author: Rolf Moeckel, PB Albuquerque + * Data: 11 March 2013 (Santa Fe) + */ + +public class convertTonsToTrucks { + + private static Logger logger = Logger.getLogger(convertTonsToTrucks.class); + private String[] truckTypes = new String[] {"SingleUnit","TruckTrailer","CombinationSemitrailer","CombinationDoubleTriple"}; + private int[] fromMiles; + private float[][] truckShareByDistance; + private TableDataSet[] payloadByTruckType; + private ResourceBundle appRb; + + public convertTonsToTrucks(ResourceBundle appRb) { + this.appRb = appRb; + } + + + public void readData () { + // read data to convert tons into trucks + + logger.info(" Reading FAF3 payload factors"); + // truck types by distance class + TableDataSet truckTypeByDist = fafUtils.importTable(appRb.getString("truck.type.share.by.distance")); + fromMiles = truckTypeByDist.getColumnAsInt("fromMiles"); + truckShareByDistance = new float[fromMiles.length][truckTypes.length]; + // todo: allow adjustment of SUT/MUT share + for (int row = 1; row <= truckTypeByDist.getRowCount(); row++) { + for (int col = 0; col < truckTypes.length; col++) { + truckShareByDistance[row-1][col] = truckTypeByDist.getValueAt(row, truckTypes[col]); + } + } + + // truck body type by commodity + payloadByTruckType = new TableDataSet[4]; + payloadByTruckType[0] = fafUtils.importTable(appRb.getString("truck.body.share.single.unit")); + payloadByTruckType[0].buildIndex(payloadByTruckType[0].getColumnPosition("sctg")); + payloadByTruckType[1] = fafUtils.importTable(appRb.getString("truck.body.share.tractor.trl")); + payloadByTruckType[1].buildIndex(payloadByTruckType[1].getColumnPosition("sctg")); + payloadByTruckType[2] = fafUtils.importTable(appRb.getString("truck.body.share.comb.semi.t")); + payloadByTruckType[2].buildIndex(payloadByTruckType[2].getColumnPosition("sctg")); + payloadByTruckType[3] = fafUtils.importTable(appRb.getString("truck.body.share.comb.dbl.tr")); + payloadByTruckType[3].buildIndex(payloadByTruckType[3].getColumnPosition("sctg")); + } + + + public float[] convertThisFlowFromTonsToTrucks (String commodity, float distance, float flowInTons) { + // convert commodity flow in tons into number of trucks by truck type + + // find correct distance class + int distClass = 0; + for (int i = 0; i < fromMiles.length; i++) if (distance > fromMiles[i]) distClass = i; + + // calculate trucks by truck type + float[] trucksByType = new float[truckTypes.length]; + for (int i = 0; i < truckTypes.length; i++) trucksByType[i] = loadTruckShare(i, distClass, commodity, flowInTons); + + return trucksByType; + } + + + private float loadTruckShare (int truckType, int distClass, String commodity, float flowInTons) { + // calculate payload for with for + + int com = Integer.parseInt(commodity.substring(4)); + float tonsOnThisTruckType = flowInTons * truckShareByDistance[distClass][truckType]; + + float trucks = 0; + for (int col = 2; col <= payloadByTruckType[truckType].getColumnCount(); col++) { + trucks += tonsOnThisTruckType * payloadByTruckType[truckType].getIndexedValueAt(com, col); + } + return trucks; + } + + + public double[] convertThisFlowFromTonsToTrucks (String commodity, float distance, double flowInTons) { + // convert commodity flow in tons into number of trucks by truck type + + // find correct distance class + int distClass = 0; + for (int i = 0; i < fromMiles.length; i++) if (distance > fromMiles[i]) distClass = i; + + // calculate trucks by truck type + double[] trucksByType = new double[truckTypes.length]; + for (int i = 0; i < truckTypes.length; i++) trucksByType[i] = loadTruckShare(i, distClass, commodity, flowInTons); + + return trucksByType; + } + + + private double loadTruckShare (int truckType, int distClass, String commodity, double flowInTons) { + // calculate payload for with for + + int com = Integer.parseInt(commodity.substring(4)); + double tonsOnThisTruckType = flowInTons * truckShareByDistance[distClass][truckType]; + + double trucks = 0; + for (int col = 2; col <= payloadByTruckType[truckType].getColumnCount(); col++) { + trucks += tonsOnThisTruckType * payloadByTruckType[truckType].getIndexedValueAt(com, col); + } + return trucks; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/countyTruckModel.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/countyTruckModel.java new file mode 100644 index 0000000..0be8116 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/countyTruckModel.java @@ -0,0 +1,597 @@ +package org.sandag.htm.processFAF; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; +import org.sandag.htm.applications.ohio; +import org.sandag.htm.applications.yumaMPO; +import org.apache.log4j.Logger; +import com.pb.sawdust.util.concurrent.DnCRecursiveAction; + +import java.io.File; +import java.io.PrintWriter; +import java.util.HashMap; +import java.util.ResourceBundle; + +/** + * Reads FAF3 data, disaggregates them to county-to-county flows and converts them into truck trips + * Author: Rolf Moeckel, PB Albuquerque + * Date: August 22, 2011 (Santa Fe NM) + * Revised for Yuma County: March 29, 2012 (Albuquerque, NM) + */ + +public class countyTruckModel { + + private static Logger logger = Logger.getLogger(countyTruckModel.class); + private ResourceBundle appRb; + private int year; + private disaggregateFlows df; + private HashMap cntFlows; + private int[] countyFips; + private int[] countyFipsIndex; + private int[] commodityGrouping; + private int numCommodityGroups; + private boolean yumaSummary; + + + public countyTruckModel(ResourceBundle rb, int yr) { + this.appRb = rb; + this.year = yr; + } + + + public static void main(String[] args) { + // construct main model + + long startTime = System.currentTimeMillis(); + ResourceBundle appRb = fafUtils.getResourceBundle(args[0]); + int year = Integer.parseInt(args[1]); + countyTruckModel ctm = new countyTruckModel(appRb, year); + ctm.run(); + logger.info("County Truck Model completed."); + float endTime = fafUtils.rounder(((System.currentTimeMillis() - startTime) / 60000), 1); + logger.info("Runtime: " + endTime + " minutes."); + } + + + private void run() { + // main run method + + logger.info("Started FAF4 model to generate county-to-county truck flows for " + year); + ReadFAF4 faf4 = new ReadFAF4(); + df = new disaggregateFlows(); + df.getUScountyEmploymentByIndustry(appRb); + faf4.readAllData(appRb, year, "tons"); + faf4.definePortsOfEntry(appRb); + if (ResourceUtil.getBooleanProperty(appRb, "read.in.raw.faf.data", true)) extractTruckData(faf4); + createZoneList(); + String truckTypeDefinition = "sut_mut"; + df.defineTruckTypes(truckTypeDefinition, appRb); + if (ResourceUtil.getBooleanProperty(appRb, "save.results.for.ohio", false)) ohio.summarizeFAFData(appRb, countyFips); + yumaSummary = ResourceUtil.getBooleanProperty(appRb, "save.results.for.yuma", false); + if (yumaSummary) yumaMPO.initializeVariables(appRb); + disaggregateFromFafToCounties(); + if (yumaSummary) yumaMPO.writeOutResults(appRb, year); + if (ResourceUtil.getBooleanProperty(appRb, "report.by.employment")) { + convertFromCommoditiesToTrucksByEmpType(); + } else { + convertFromCommoditiesToTrucks(); + } + if (ResourceUtil.getBooleanProperty(appRb, "analyze.commodity.groups", false)) { + readCommodityGrouping(); + convertFromCommoditiesToTrucksByComGroup(); + } + } + + private void extractTruckData(readFAF3 faf3) { + // extract truck data and write flows to file + logger.info("Extracting FAF3 truck data"); + String[] scaleTokens = ResourceUtil.getArray(appRb, "scaling.truck.trips.tokens"); + double[] scaleValues = ResourceUtil.getDoubleArray(appRb, "scaling.truck.trips.values"); + HashMap scaler = fafUtils.createScalerHashMap(scaleTokens, scaleValues); + String truckFileNameT = ResourceUtil.getProperty(appRb, "temp.truck.flows.faf.zones") + "_" + year; + + // create output directory if it does not exist yet + File file = new File ("output/temp"); + if (!file.exists()) { + boolean outputDirectorySuccessfullyCreated = file.mkdir(); + if (!outputDirectorySuccessfullyCreated) logger.warn("Could not create scenario directory output/temp/"); + } + + faf3.writeFlowsByModeAndCommodity(truckFileNameT, ModesFAF.Truck, reportFormat.internat_domesticPart, scaler); + } + + private void extractTruckData(ReadFAF4 faf4) { + // extract truck data and write flows to file + logger.info("Extracting FAF4 truck data"); + String[] scaleTokens = ResourceUtil.getArray(appRb, "scaling.truck.trips.tokens"); + double[] scaleValues = ResourceUtil.getDoubleArray(appRb, "scaling.truck.trips.values"); + HashMap scaler = fafUtils.createScalerHashMap(scaleTokens, scaleValues); + String truckFileNameT = ResourceUtil.getProperty(appRb, "temp.truck.flows.faf.zones") + "_" + year; + + // create output directory if it does not exist yet + File file = new File ("output/temp"); + if (!file.exists()) { + boolean outputDirectorySuccessfullyCreated = file.mkdir(); + if (!outputDirectorySuccessfullyCreated) logger.warn("Could not create scenario directory output/temp/"); + } + + faf4.writeFlowsByModeAndCommodity(truckFileNameT, ModesFAF.Truck, reportFormat.internat_domesticPart, scaler); + } + + private void createZoneList() { + // Create array with specialRegions that serve as port of entry/exit + + TableDataSet poe = fafUtils.importTable(appRb.getString("ports.of.entry")); + countyFips = fafUtils.createCountyFipsArray(poe.getColumnAsInt("pointOfEntry")); + countyFipsIndex = new int[fafUtils.getHighestVal(countyFips) + 1]; + for (int i = 0; i < countyFips.length; i++) { + countyFipsIndex[countyFips[i]] = i; + } + } + + + private void disaggregateFromFafToCounties() { + // disaggregates freight flows from FAF zoneArray to counties + + logger.info("Disaggregating FAF3 data from FAF zones to counties for year " + year + "."); + + cntFlows = new HashMap<>(); + + String[] commodities; + commodities = readFAF3.sctgStringCommodities; + int matrixSize = countyFips.length; + cntFlows = new HashMap<>(); + + float globalScale = (float) ResourceUtil.getDoubleProperty(appRb, "overall.scaling.factor.truck"); + + // regular method + for (String com: commodities) { + float[][] dummy = new float[matrixSize][matrixSize]; + cntFlows.put(com, dummy); + } + boolean keepTrackOfEmplType = ResourceUtil.getBooleanProperty(appRb, "report.by.employment", false); + df.prepareCountyDataForFAFwithDetailedEmployment(appRb, year, keepTrackOfEmplType); + + java.util.concurrent.ForkJoinPool pool = new java.util.concurrent.ForkJoinPool(); + DnCRecursiveAction action = new DissaggregateFafAction(globalScale); + pool.execute(action); + action.getResult(); + + if (ResourceUtil.getBooleanProperty(appRb, "summarize.by.ohio.rail.zones", false)) + ohio.sumFlowByRailZone(appRb, year, countyFips, countyFipsIndex, cntFlows); + } + + + private class DissaggregateFafAction extends DnCRecursiveAction { + private final float globalScale; + + private DissaggregateFafAction(float globalScale) { + super(0,readFAF3.sctgStringCommodities.length); + this.globalScale = globalScale; + } + + private DissaggregateFafAction(float globalScale, long start, long length, DnCRecursiveAction next) { + super(start,length,next); + this.globalScale = globalScale; + } + + @Override + protected void computeAction(long start, long length) { + long end = start + length; + for (int comm = (int) start; comm < end; comm++) { + int cm = readFAF3.sctgCommodities[comm]; + String fileName = ResourceUtil.getProperty(appRb, "temp.truck.flows.faf.zones") + "_" + year; + if (cm < 10) fileName = fileName + "_SCTG0" + cm + ".csv"; + else fileName = fileName + "_SCTG" + cm + ".csv"; + logger.info(" Working on " + fileName); + String sctg = readFAF3.getSCTGname(cm); + float[][] values = cntFlows.get(sctg); + TableDataSet tblFlows = fafUtils.importTable(fileName); + for (int row = 1; row <= tblFlows.getRowCount(); row++) { + float shortTons = tblFlows.getValueAt(row, "shortTons"); + if (shortTons == 0) continue; + String dir = tblFlows.getStringValueAt(row, "flowDirection"); + int orig = (int) tblFlows.getValueAt(row, "originFAF"); + int dest = (int) tblFlows.getValueAt(row, "destinationFAF"); + TableDataSet singleFlow; + if (dir.equals("import") || dir.equals("export")) { + TableDataSet poe; + if (dir.equals("import")) poe = readFAF3.getPortsOfEntry(orig); + else poe = readFAF3.getPortsOfEntry(dest); + singleFlow = df.disaggregateSingleFAFFlowThroughPOE(dir, poe, orig, dest, sctg, shortTons, 1); + } else singleFlow = df.disaggregateSingleFAFFlow(orig, dest, sctg, shortTons, 1); + for (int i = 1; i <= singleFlow.getRowCount(); i++) { + int oFips = (int) singleFlow.getValueAt(i, "oFips"); + int oZone = getCountyId(oFips); + int dFips = (int) singleFlow.getValueAt(i, "dFips"); + int dZone = getCountyId(dFips); + float thisFlow = singleFlow.getValueAt(i, "Tons") * globalScale; + values[oZone][dZone] += thisFlow; + if (yumaSummary) yumaMPO.saveForYuma(cm, oFips, dFips, thisFlow); + } + } + } + } + + @Override + protected DnCRecursiveAction getNextAction(long start, long length, DnCRecursiveAction next) { + return new DissaggregateFafAction(globalScale,start,length,next); + } + + @Override + protected boolean continueDividing(long length) { + return getSurplusQueuedTaskCount() < 3 && length > 1; + } + } + + + private int getCountyId(int fips) { + // Return region code of regName + return countyFipsIndex[fips]; + } + + + private void readCommodityGrouping () { + // Read how commodities are grouped by SCTG cagegory + + TableDataSet comGroups = fafUtils.importTable(appRb.getString("commodity.grouping")); + commodityGrouping = new int[fafUtils.getHighestVal(readFAF3.sctgCommodities) + 1]; + for (int row = 1; row <= comGroups.getRowCount(); row++) { + int sctg = (int) comGroups.getValueAt(row, "SCTG"); + int group = (int) comGroups.getValueAt(row, "Group"); + commodityGrouping[sctg] = group; + } + numCommodityGroups = 0; + for (int i = 0; i < commodityGrouping.length; i++) { + if (commodityGrouping[i] == 0) continue; + boolean alreadyExists = false; + for (int j = 0; j < i; j++) { + if (j == i) continue; + if (commodityGrouping[j] == commodityGrouping[i]) alreadyExists = true; + } + if (!alreadyExists) numCommodityGroups++; + } + } + + + private void convertFromCommoditiesToTrucks() { + // generate truck flows based on commodity flows + logger.info("Converting flows in tons into truck trips"); + float emptyTruckRate = (float) ResourceUtil.getDoubleProperty(appRb, "empty.truck.rate"); + float aawdtFactor = (float) ResourceUtil.getDoubleProperty(appRb, "AADT.to.AAWDT.factor"); + double[][]sluTrucks = new double[countyFips.length][countyFips.length]; + double[][]mtuTrucks = new double[countyFips.length][countyFips.length]; + for (String com: readFAF3.sctgStringCommodities) { + double avPayload = fafUtils.findAveragePayload(com, "SCTG"); + double sutPL = ResourceUtil.getDoubleProperty(appRb, "multiplier.SUT.payload") * avPayload; + double mutPL = ResourceUtil.getDoubleProperty(appRb, "multiplier.MUT.payload") * avPayload; + float[][] tonFlows = cntFlows.get(com); + for (int i: countyFips) { + for (int j: countyFips) { + float dist = df.getCountyDistance(i, j); + if (dist < 0) continue; // skip flows to Guam, Puerto Rico, Hawaii, Alaskan Islands etc. + int orig = getCountyId(i); + int dest = getCountyId(j); + if (tonFlows[orig][dest] == 0) continue; + double[] trucksByType = df.getTrucksByType(dist, sutPL, mutPL, tonFlows[orig][dest]); + // add empty trucks + trucksByType[0] += trucksByType[0] * (emptyTruckRate/100.0); + trucksByType[1] += trucksByType[1] * (emptyTruckRate/100.0); + // Annual cntFlows divided by 365.25 days plus AAWDT-over-AADT factor + trucksByType[0] = trucksByType[0] / 365.25f * (1 + (aawdtFactor / 100)); + trucksByType[1] = trucksByType[1] / 365.25f * (1 + (aawdtFactor / 100)); + sluTrucks[orig][dest] += trucksByType[0]; + mtuTrucks[orig][dest] += trucksByType[1]; + } + } + } + if (ResourceUtil.getBooleanProperty(appRb, "write.cnty.to.cnty.truck.trps", false)) + writeOutDisaggregatedTruckTrips(sluTrucks, mtuTrucks); + if (ResourceUtil.getBooleanProperty(appRb, "write.ii.ei.ee.trips", false)) + writeOutDisaggregatedTruckTripsByDirection(sluTrucks, mtuTrucks); + } + + + private void convertFromCommoditiesToTrucksByEmpType() { + // generate truck flows based on commodity flows, keeping track of employment type generating/attracting trucks + + logger.info("Converting flows in tons into truck trips, keeping track of employment types generating trucks"); + float emptyTruckRate = (float) ResourceUtil.getDoubleProperty(appRb, "empty.truck.rate"); + float aawdtFactor = (float) ResourceUtil.getDoubleProperty(appRb, "AADT.to.AAWDT.factor"); + HashMap countyWeights = getCountyWeightsWithDetEmpl(); + + String[] emplCat = df.getEmpCats(); + + double[][][]sluTrucks = new double[emplCat.length][countyFips.length][countyFips.length]; + double[][][]mtuTrucks = new double[emplCat.length][countyFips.length][countyFips.length]; + + for (String com: readFAF3.sctgStringCommodities) { + double avPayload = fafUtils.findAveragePayload(com, "SCTG"); + double sutPL = ResourceUtil.getDoubleProperty(appRb, "multiplier.SUT.payload") * avPayload; + double mutPL = ResourceUtil.getDoubleProperty(appRb, "multiplier.MUT.payload") * avPayload; + float[][] tonFlows = cntFlows.get(com); + for (int i: countyFips) { + float[] weights = countyWeights.get(i); + for (int j: countyFips) { + float dist = df.getCountyDistance(i, j); + if (dist < 0) continue; // skip flows to Guam, Puerto Rico, Hawaii, Alaskan Islands etc. + int orig = getCountyId(i); + int dest = getCountyId(j); + if (tonFlows[orig][dest] == 0) continue; + double[] trucksByType = df.getTrucksByType(dist, sutPL, mutPL, tonFlows[orig][dest]); + // add empty trucks + trucksByType[0] += trucksByType[0] * (emptyTruckRate/100.0); + trucksByType[1] += trucksByType[1] * (emptyTruckRate/100.0); + // Annual cntFlows divided by 365.25 days plus AAWDT-over-AADT factor + trucksByType[0] = trucksByType[0] / 365.25f * (1 + (aawdtFactor / 100)); + trucksByType[1] = trucksByType[1] / 365.25f * (1 + (aawdtFactor / 100)); + for (int eCat = 0; eCat < emplCat.length; eCat++) { + if (trucksByType[0] + trucksByType[1] == 0) continue; + try { + sluTrucks[eCat][orig][dest] += trucksByType[0] * weights[eCat]; + mtuTrucks[eCat][orig][dest] += trucksByType[1] * weights[eCat]; + } catch (Exception e){ + logger.warn(eCat+" "+orig+" "+dest+" "+i+" "+j+" "+com+": "+trucksByType[0]+trucksByType[1]); + } + } + } + } + } + writeOutDisaggregatedTruckTripsDetEmpl(sluTrucks, mtuTrucks); + } + + + private HashMap getCountyWeightsWithDetEmpl() { + // look up employment weight for each county + + HashMap weights = new HashMap<>(); + TableDataSet counties = fafUtils.importTable(ResourceUtil.getProperty(appRb, "county.ID")); + String[] emplCats = df.getEmpCats(); + for (int row = 1; row <= counties.getRowCount(); row++) { + int fips = (int) counties.getValueAt(row, "COUNTYFIPS"); + int faf = (int) counties.getValueAt(row, "FAF3region"); + if (faf == -99) continue; + for (String com: readFAF3.sctgStringCommodities) { + TableDataSet countyWeightsInOrigInFafZone = df.getCountyWeights("orig", faf, com); + for (int rw = 1; rw <= countyWeightsInOrigInFafZone.getRowCount(); rw++) { + if (countyWeightsInOrigInFafZone.getValueAt(rw, "COUNTYFIPS") == fips) { + float[] wght = new float[emplCats.length]; + for (int eCat = 0; eCat < emplCats.length; eCat++) { + wght[eCat] = countyWeightsInOrigInFafZone.getValueAt(rw, emplCats[eCat]); + } + float sum = fafUtils.getSum(wght); + // normalize weights from 0 - 1 + for (int eCat = 0; eCat < emplCats.length; eCat++) { + wght[eCat] = wght[eCat] / sum; + } + weights.put(fips, wght); + } + } + } + } + return weights; + } + + + private void writeOutDisaggregatedTruckTrips(double[][]sluTrucks, double[][]mtuTrucks) { + // write out disaggregated truck trips + + double[] truckProd = new double[fafUtils.getHighestVal(countyFips) + 1]; + + String fileName = appRb.getString("cnt.to.cnt.truck.flows") + year + ".csv"; + logger.info("Writing results to file " + fileName); + PrintWriter pw = fafUtils.openFileForSequentialWriting(fileName); + pw.println("OrigFips,DestFips,sut,mut"); + for (int i: countyFips) { + for (int j: countyFips) { + int orig = getCountyId(i); + int dest = getCountyId(j); + double slu = sluTrucks[orig][dest]; + double mtu = mtuTrucks[orig][dest]; + if (slu + mtu >= 0.00001) { + pw.format ("%d,%d,%.5f,%.5f", i, j, slu, mtu); + pw.println(); + truckProd[i] += slu + mtu; + } + } + } + pw.close(); + + if (ResourceUtil.getBooleanProperty(appRb, "report.truck.prod.by.county", false)) { + String fileNameProd = appRb.getString("truck.prod.by.county") + year + ".csv"; + PrintWriter pwp = fafUtils.openFileForSequentialWriting(fileNameProd); + pwp.println("CountyFips,TrucksGenerated"); + for (int i: countyFips) { + if (truckProd[i] > 0) pwp.println(i + "," + truckProd[i]); + } + pwp.close(); + } + } + + + private void writeOutDisaggregatedTruckTripsDetEmpl(double[][][]sluTrucks, double[][][]mtuTrucks) { + // write out disaggregated truck trips + + String fileName = appRb.getString("cnt.to.cnt.truck.flows") + "ByEmployment" + year + ".csv"; + logger.info("Writing results to file " + fileName); + PrintWriter pw = fafUtils.openFileForSequentialWriting(fileName); + pw.print("OrigFips,DestFips"); + String[] emplCats = df.getEmpCats(); + for (String emplCat : emplCats) { + if (emplCat.contains("Trade") || emplCat.contains("Financial") || + emplCat.contains("Education") || emplCat.contains("Other")) continue; + pw.print("," + emplCat + "_SUT," + emplCat + "_MUT"); + } + pw.println(); + for (int i: countyFips) { + for (int j: countyFips) { + int orig = getCountyId(i); + int dest = getCountyId(j); + pw.print(i + "," + j); + for (int eCat = 0; eCat < emplCats.length; eCat++) { + if (emplCats[eCat].contains("Trade") || emplCats[eCat].contains("Financial") || + emplCats[eCat].contains("Education") || emplCats[eCat].contains("Other")) continue; + double slu = sluTrucks[eCat][orig][dest]; + double mtu = mtuTrucks[eCat][orig][dest]; + pw.print("," + slu + "," + mtu); + } + pw.println(); + } + } + pw.close(); + } + + + private void writeOutDisaggregatedTruckTripsByDirection(double[][]sluTrucks, double[][]mtuTrucks) { + // write out disaggregated truck trips distinguishing II, EI/IE and EE trips + + TableDataSet counties = disaggregateFlows.countyIDsWithEmployment; + boolean[] relevantCounty = new boolean[fafUtils.getHighestVal(countyFips) + 1]; + String state = appRb.getString("ii.state"); + + for (int row = 1; row <= counties.getRowCount(); row++) { + relevantCounty[(int) counties.getValueAt(row, "COUNTYFIPS")] = counties.getStringValueAt(row, "StateCode").equals(state); + } + + String fileName = appRb.getString("cnt.to.cnt.truck.flows.by.dir") + year + ".csv"; + logger.info("Writing ii/ei/ie/ee flows to file " + fileName); + PrintWriter pw = fafUtils.openFileForSequentialWriting(fileName); + pw.println("OrigFips,DestFips,iiSut,iiMut,eiSut,eiMut,eeSut,eeMut,totSut,totMut"); + for (int i: countyFips) { + for (int j: countyFips) { + int orig = getCountyId(i); + int dest = getCountyId(j); + double slu = sluTrucks[orig][dest]; + double mtu = mtuTrucks[orig][dest]; + if (slu + mtu >= 0.00001) { + if (relevantCounty[i] && relevantCounty[j]) { + pw.format ("%d,%d,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f", i, j, slu, mtu, 0., 0., 0., 0., slu, mtu); + pw.println(); + } else if ((relevantCounty[i] && !relevantCounty[j]) || (!relevantCounty[i] && relevantCounty[j])) { + pw.format ("%d,%d,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f", i, j, 0., 0., slu, mtu, 0., 0., slu, mtu); + pw.println(); + } else { + pw.format ("%d,%d,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f,%.5f", i, j, 0., 0., 0., 0., slu, mtu, slu, mtu); + pw.println(); + } + } + } + } + pw.close(); + } + + + private void convertFromCommoditiesToTrucksByComGroup () { + // read flows in tons and convert into flows in trucks, distinguishing commodity groups + + float emptyTruckRate = (float) ResourceUtil.getDoubleProperty(appRb, "empty.truck.rate"); + float aawdtFactor = (float) ResourceUtil.getDoubleProperty(appRb, "AADT.to.AAWDT.factor"); + double[][][] sluTrucks = new double[numCommodityGroups+1][countyFips.length][countyFips.length]; + double[][][] mtuTrucks = new double[numCommodityGroups+1][countyFips.length][countyFips.length]; + for (String com: readFAF3.sctgStringCommodities) { + int iCom = Integer.parseInt(com.substring(4, 6)); // convert "SCTG00" into "00" + double avPayload = fafUtils.findAveragePayload(com, "SCTG"); + double sutPL = ResourceUtil.getDoubleProperty(appRb, "multiplier.SUT.payload") * avPayload; + double mutPL = ResourceUtil.getDoubleProperty(appRb, "multiplier.MUT.payload") * avPayload; + float[][] tonFlows = cntFlows.get(com); + for (int i: countyFips) { + for (int j: countyFips) { + int orig = getCountyId(i); + int dest = getCountyId(j); + if (tonFlows[orig][dest] == 0) continue; + float dist = df.getCountyDistance(i, j); + if (dist < 0) continue; // skip flows to Guam, Puerto Rico, Hawaii, Alaskan Islands etc. + double[] trucksByType = df.getTrucksByType(dist, sutPL, mutPL, tonFlows[orig][dest]); + // add empty trucks + trucksByType[0] += trucksByType[0] * (emptyTruckRate/100.0); + trucksByType[1] += trucksByType[1] * (emptyTruckRate/100.0); + // Annual cntFlows divided by 365.25 days plus AAWDT-over-AADT factor + trucksByType[0] = trucksByType[0] / 365.25f * (1 + (aawdtFactor / 100)); + trucksByType[1] = trucksByType[1] / 365.25f * (1 + (aawdtFactor / 100)); + sluTrucks[commodityGrouping[iCom]][orig][dest] += trucksByType[0]; + mtuTrucks[commodityGrouping[iCom]][orig][dest] += trucksByType[1]; + } + } + } + writeOutDisaggregatedTruckTrips(sluTrucks, mtuTrucks); + } + + + private void writeOutDisaggregatedTruckTrips(double sluTrucks[][][], double[][][] mutTrucks) { + // Write out truck trips by commodity group + + TableDataSet counties = disaggregateFlows.countyIDsWithEmployment; + boolean[] relevantCounty = new boolean[fafUtils.getHighestVal(countyFips) + 1]; + String state = appRb.getString("ii.state"); + double[][] prodByCounty = new double[countyFips.length][numCommodityGroups + 1]; + double[][] attrByCounty = new double[countyFips.length][numCommodityGroups + 1]; + + for (int row = 1; row <= counties.getRowCount(); row++) { + relevantCounty[(int) counties.getValueAt(row, "COUNTYFIPS")] = + counties.getStringValueAt(row, "StateCode").equals(state); + } + + boolean seperateEEflows = ResourceUtil.getBooleanProperty(appRb, "report.ext.flows.separately"); + String cgFile = appRb.getString("trucks.by.commodity.group") + year + ".csv"; + PrintWriter pwc = fafUtils.openFileForSequentialWriting(cgFile); + pwc.print("orig,dest"); + for (int cg = 1; cg <= numCommodityGroups; cg++) pwc.print(",com" + cg); + if (seperateEEflows) { + pwc.println(",external"); + } else { + pwc.println(); + } + for (int i = 0; i < countyFips.length; i++) { + for (int j = 0; j < countyFips.length; j++) { + + double sm = 0.; + for (int cg = 1; cg <= numCommodityGroups; cg++) sm += sluTrucks[cg][i][j] + mutTrucks[cg][i][j]; + + if (sm > 0) { + pwc.print(countyFips[i] + "," + countyFips[j]); + if (seperateEEflows) { + if (!relevantCounty[countyFips[i]] && !relevantCounty[countyFips[j]]) { + // E-E flows + for (int cg = 1; cg <= numCommodityGroups; cg++) pwc.print(",0"); + pwc.println("," + sm); + } else { + // I-I, I-E and E-I flows + for (int cg = 1; cg <= numCommodityGroups; cg++) pwc.print("," + + (sluTrucks[cg][i][j] + mutTrucks[cg][i][j])); + pwc.println(",0"); + } + } else { + // I-I, I-E, E-I and E-E flows + for (int cg = 1; cg <= numCommodityGroups; cg++) pwc.print("," + + (sluTrucks[cg][i][j] + mutTrucks[cg][i][j])); + pwc.println(); + } + for (int cg = 1; cg <= numCommodityGroups; cg++) { + prodByCounty[i][cg] += sluTrucks[cg][i][j] + mutTrucks[cg][i][j]; + attrByCounty[j][cg] += sluTrucks[cg][i][j] + mutTrucks[cg][i][j]; + } + } + } + } + pwc.close(); + + String cgFileAgg = appRb.getString("trucks.by.commodity.group") + year + "_prodAttr.csv"; + PrintWriter pwca = fafUtils.openFileForSequentialWriting(cgFileAgg); + pwca.print("countyFips"); + for (int cg = 1; cg <= numCommodityGroups; cg++) pwca.print(",prod_" + cg + ",attr_" + cg); + pwca.println(); + for (int i = 0; i < countyFips.length; i++) { + float sm = 0; + for (int cg = 1; cg <= numCommodityGroups; cg++) { + sm += prodByCounty[i][cg] + attrByCounty[i][cg]; + } + if (sm > 0) { + pwca.print(countyFips[i]); + for (int cg = 1; cg <= numCommodityGroups; cg++) pwca.print("," + prodByCounty[i][cg] + "," + + attrByCounty[i][cg]); + pwca.println(); + } + } + pwca.close(); + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/disaggregateAndAggregateFlows.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/disaggregateAndAggregateFlows.java new file mode 100644 index 0000000..004554c --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/disaggregateAndAggregateFlows.java @@ -0,0 +1,67 @@ +package org.sandag.htm.processFAF; + +import com.pb.common.datafile.TableDataSet; + +import java.util.HashMap; +import java.util.ResourceBundle; + +/** + * This class disaggregates and aggregates FAF flows from FAF zones to model zones (which may be smaller or larger than FAF zones) + * User: Rolf Moeckel, PB Albuquerque + * Date: November 17, 2011 (Santa Fe, NM) + */ + +// todo: Started this class for NCSTM, but then realized that FAF zones do not nest in RMZ of NCSTM. Some FAF zones +// todo: would have to be split in parts and aggregated in other parts. +// todo: May be useful in other projects. + +public class disaggregateAndAggregateFlows { + + private ResourceBundle appRb; + private HashMap zonesToDisaggregate; + private int[] zonesToAggregate; + + public disaggregateAndAggregateFlows(ResourceBundle appRb) { + this.appRb = appRb; + } + + + public void defineZonesToAggregate(String fileName) { + // define which FAF zones need to be aggregated to larger model zones + + TableDataSet fafZones = fafUtils.importTable(fileName); + int highestFAF = -1; + for (int row = 1; row <= fafZones.getRowCount(); row++) { + if (fafZones.getValueAt(row, "modelZone") != -1) highestFAF = (int) Math.max(highestFAF, fafZones.getValueAt(row, "modelZone")); + } + zonesToAggregate = new int[highestFAF + 1]; + for (int row = 1; row <= fafZones.getRowCount(); row++) { + if (fafZones.getValueAt(row, "modelZone") == -1) { + zonesToAggregate[(int) fafZones.getValueAt(row, "ZoneID")] = -1; + } else { + zonesToAggregate[(int) fafZones.getValueAt(row, "ZoneID")] = (int) fafZones.getValueAt(row, "modelZone"); + } + } + } + + + public void defineZonesToDisaggregate(TableDataSet zoneSystem) { + // define which FAF zones need to be disaggregated to smaller model zones + + zonesToDisaggregate = new HashMap<>(); + for (int row = 1; row <= zoneSystem.getRowCount(); row++) { + int taz = (int) zoneSystem.getValueAt(row, "TAZ"); + int faf = (int) zoneSystem.getValueAt(row, "FAFzone"); + if (!zoneSystem.getBooleanValueAt(row, "disaggregate")) continue; + if (zonesToDisaggregate.containsKey(faf)) { + int[] zones = zonesToDisaggregate.get(faf); + int[] zonesNew = new int[zones.length + 1]; + System.arraycopy(zones, 0, zonesNew, 0, zones.length); + zonesNew[zones.length] = taz; + zonesToDisaggregate.put(faf, zonesNew); + } else { + zonesToDisaggregate.put(faf, new int[]{taz}); + } + } + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/disaggregateFlows.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/disaggregateFlows.java new file mode 100644 index 0000000..5045b90 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/disaggregateFlows.java @@ -0,0 +1,1357 @@ +package org.sandag.htm.processFAF; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; +import com.pb.common.matrix.Matrix; +import com.pb.common.matrix.MatrixReader; +import java.util.HashMap; +import java.util.ResourceBundle; +import java.io.File; +import org.apache.log4j.Logger; + + +/** + * This class disaggregates FAF flows from FAF zones to counties + * User: Rolf Moeckel + * Date: May 6, 2009 + * + * Updated 2017-12-27 JEF + */ + +public class disaggregateFlows { + + static Logger logger = Logger.getLogger(disaggregateFlows.class); + public static TableDataSet countyIDsWithEmployment; + private HashMap countyShares; + private TableDataSet truckTypeShares; + private int[] truckTypeShareDistBin; + private float[] truckTypeShareMT; + private Matrix distCounties; + private static int[] countyFips; + private int FAFVersion=4; + + + private static String[] empCats = {"Agriculture", "Construction Natural Resources and Mining", "Manufacturing", + "Trade Transportation and Utilities", "Information", "Financial Activities", + "Professional and Business Services", "Education and Health Services", "Leisure and Hospitality", + "Other Services", "coalProduction"}; //, "Government"}; (no government employment available at county-level nationwide at this point + + + public void prepareCountyData(ResourceBundle rb) { + // prepare county data to provide total employment as a weight + logger.info("Preparing county data for flow disaggregation"); + + getUScountyEmployment(rb); + if (readFAF2.domRegionList == null) readFAF2.readFAF2ReferenceLists(rb); + //create HashMap that contains for every FAF region a TableDataSet of counties with their employment share + countyShares = new HashMap<>(); + for (int fafNum = 1; fafNum <= readFAF2.domRegionList.getRowCount(); fafNum++) { + for (String com: readFAF2.sctgCommodities) { + TableDataSet CountyList = getCountySpecificDataByFAF2(fafNum, com, null, null); + // dir is not really needed here, but kept for consistency reason as it is required + // in prepareCountyDataForFAF(ResourceBundle rb, TableDataSet detailEmployment) + String codeo = "orig_" + readFAF2.domRegionList.getStringValueAt(fafNum, "RegionName") + "_" + com; + countyShares.put(codeo, CountyList); + String coded = "dest_" + readFAF2.domRegionList.getStringValueAt(fafNum, "RegionName") + "_" + com; + countyShares.put(coded, CountyList); + } + } + } + + + public void prepareCountyData(ResourceBundle rb, int yr, TableDataSet detailEmployment, String truckType) { + // prepare county data to provide detailed employment given in detailEmployment and total employment elsewhere + // as a weight + logger.info("Preparing county data for flow disaggregation for year " + yr + "..."); + + HashMap useC = createMakeUseHashMap(rb, "use.coefficients"); + HashMap makeC = createMakeUseHashMap(rb, "make.coefficients"); + + truckTypeShares = fafUtils.importTable(rb.getString("truck.type.by.distance")); + if (truckType.equalsIgnoreCase("weight")) createTruckShareArraysWeight(); + else createTruckShareArraysUnit(); + distCounties = MatrixReader.readMatrix(new File(rb.getString("county.distance.in.miles")), "Distance"); + + getUScountyEmployment(rb); + + if (readFAF2.domRegionList == null) readFAF2.readFAF2ReferenceLists(rb); + //create HashMap that contains for every FAF region a TableDataSet of counties with their employment share + countyShares = new HashMap<>(); + String[] direction = {"orig", "dest"}; + for (String dir: direction) { + HashMap factors; + if (dir.equals("orig")) factors = makeC; + else factors = useC; + for (int fafNum = 1; fafNum <= readFAF2.domRegionList.getRowCount(); fafNum++) { + for (String com: readFAF2.sctgCommodities) { + TableDataSet CountyList = getCountySpecificDataByFAF2(fafNum, com, detailEmployment, factors); + String code = dir + "_" + readFAF2.domRegionList.getStringValueAt(fafNum, "RegionName") + "_" + com; + countyShares.put(code, CountyList); + } + } + } + } + + + private void createTruckShareArraysWeight() { + // create array with distance bins and shares or medium-heavy trucks + truckTypeShareDistBin = new int[truckTypeShares.getRowCount()]; + truckTypeShareMT = new float[truckTypeShares.getRowCount()]; + for (int row = 1; row <= truckTypeShares.getRowCount(); row++) { + truckTypeShareDistBin[row - 1] = (int) truckTypeShares.getValueAt(row, "DistanceGreaterThan"); + truckTypeShareMT[row - 1] = truckTypeShares.getValueAt(row, "MT(<26k_lbs)"); + // data quality check + float htShare = truckTypeShares.getValueAt(row, "HT(>26k_lbs)"); + if (htShare + truckTypeShareMT[row - 1] != 1) logger.warn("Shares of Medium and Heavy Trucks add up to " + + htShare + truckTypeShareMT[row - 1] + " instead of 1 for distance class " + truckTypeShareDistBin[row - 1]); + } + } + + + private void createTruckShareArraysUnit() { + // create array with distance bins and shares or Single-Unit/Multi-Unit trucks + truckTypeShareDistBin = new int[truckTypeShares.getRowCount()]; + truckTypeShareMT = new float[truckTypeShares.getRowCount()]; + for (int row = 1; row <= truckTypeShares.getRowCount(); row++) { + truckTypeShareDistBin[row - 1] = (int) truckTypeShares.getValueAt(row, "DistanceGreaterThan"); + truckTypeShareMT[row - 1] = truckTypeShares.getValueAt(row, "SUT"); + // data quality check + float htShare = truckTypeShares.getValueAt(row, "MUT"); + if (htShare + truckTypeShareMT[row - 1] != 1) logger.warn("Shares of SUT and MUT Trucks add up to " + + htShare + truckTypeShareMT[row - 1] + " instead of 1 for distance class " + truckTypeShareDistBin[row - 1]); + } + } + + + public void prepareCountyDataForFAF(ResourceBundle rb, int yr, TableDataSet detailEmployment, + TableDataSet specialRegions, int fafVersion) { + // prepare county data to provide detailed employment given in detailEmployment and total employment elsewhere + // as a weight using the "fafVersion" zone system + logger.info("Preparing county data for FAF" + fafVersion + " flow disaggregation for year " + yr + "..."); + + String useToken = "faf" + fafVersion + ".use.coefficients"; + String makeToken = "faf" + fafVersion + ".make.coefficients"; + HashMap useC = createMakeUseHashMap(rb, useToken); + HashMap makeC = createMakeUseHashMap(rb, makeToken); + + distCounties = MatrixReader.readMatrix(new File(rb.getString("county.distance.in.miles")), "Distance"); + + if (fafVersion == 2 && readFAF2.domRegionList == null) readFAF2.readFAF2ReferenceLists(rb); +// if (fafVersion == 3 && readFAF3.fafRegionList == null) readFAF3.readFAF3referenceLists(rb); // has been read earlier for FAF3 + + //create HashMap that contains for every FAF region a TableDataSet of counties with their employment share + countyShares = new HashMap<>(); + String[] direction = {"orig", "dest"}; + for (String dir: direction) { + HashMap factors; + if (dir.equals("orig")) factors = makeC; + else factors = useC; + + if (fafVersion == 2) { + for (int fafNum = 1; fafNum <= readFAF2.domRegionList.getRowCount(); fafNum++) { + for (String com: readFAF2.sctgCommodities) { + TableDataSet CountyList = getCountySpecificDataByFAF2(fafNum, com, detailEmployment, factors); + String code = dir + "_" + readFAF2.domRegionList.getStringValueAt(fafNum, "RegionName") + "_" + com; + countyShares.put(code, CountyList); + } + } + } else if (fafVersion==3){ // fafVersion == 3 + for (int fafNum = 1; fafNum <= readFAF3.fafRegionList.getRowCount(); fafNum++) { + for (String com: readFAF3.sctgStringCommodities) { + int zoneNum = (int) readFAF3.fafRegionList.getValueAt(fafNum, "ZoneID"); + TableDataSet CountyList = getCountySpecificDataByFAF(zoneNum, com, detailEmployment, factors); + String code = dir + "_" + zoneNum + "_" + com; + countyShares.put(code, CountyList); + } + } + } + else{ // fafVersion == 4 + for (int fafNum = 1; fafNum <= ReadFAF4.fafRegionList.getRowCount(); fafNum++) { + for (String com: ReadFAF4.sctgStringCommodities) { + int zoneNum = (int) ReadFAF4.fafRegionList.getValueAt(fafNum, "ZoneID"); + TableDataSet CountyList = getCountySpecificDataByFAF(zoneNum, com, detailEmployment, factors); + String code = dir + "_" + zoneNum + "_" + com; + countyShares.put(code, CountyList); + } + } + } + } + + // create fake county lists for special regions such as airports or seaports that shall be kept separate from the FAF regions + if (specialRegions == null) return; + for (int row = 1; row <= specialRegions.getRowCount(); row++) { + int[] fips = {(int) specialRegions.getValueAt(row, "modelCode")}; + String[] name; + if (fafVersion == 2) { + name = new String[]{specialRegions.getStringValueAt(row, "Region")}; + }else if(fafVersion==3){ + name = new String[]{specialRegions.getStringValueAt(row, "faf3code")}; + }else{ + name = new String[]{specialRegions.getStringValueAt(row, "faf4code")}; + } + + TableDataSet CountyList = new TableDataSet(); + float[] emplDummy = {1}; + CountyList.appendColumn(name, "Name"); + CountyList.appendColumn(fips, "COUNTYFIPS"); + CountyList.appendColumn(name, "FAFRegion"); + CountyList.appendColumn(emplDummy, "Employment"); + for (String dir: direction) { + if (fafVersion == 2) { + for (String com: readFAF2.sctgCommodities) { + String code = dir + "_" + name[0] + "_" + com; + countyShares.put(code, CountyList); + } + } else if (fafVersion == 3){ + for (String com: readFAF3.sctgStringCommodities) { + String code = dir + "_" + fips[0] + "_" + com; + countyShares.put(code, CountyList); + } + }else{ + for (String com: ReadFAF4.sctgStringCommodities) { + String code = dir + "_" + fips[0] + "_" + com; + countyShares.put(code, CountyList); + } + + } + + } + } + } + + + public static HashMap createMakeUseHashMap (ResourceBundle rb, String token) { + // create HashMap with make/use coefficients + TableDataSet coeff = fafUtils.importTable(ResourceUtil.getProperty(rb, token)); + HashMap hsm = new HashMap<>(); + for (int i = 1; i <= coeff.getRowCount(); i++) { + String industry = coeff.getStringValueAt(i, "Industry"); + for (int j = 2; j <= coeff.getColumnCount(); j++) { + String sctg = coeff.getColumnLabel(j); + String code = industry + "_" + sctg; + hsm.put(code, coeff.getValueAt(i, j)); + } + } + return hsm; + } + + + public TableDataSet disaggregateSingleFAF2flow(String orig, String dest, String sctg, float tons) { + // disaggregate tons from orig FAFzone to dest FAFzone to the county level for FAF2 + + TableDataSet flows = new TableDataSet(); + // get county specific data for origin FAF and destination FAF + TableDataSet CountyDatI = getCountyTableDataSet("orig", orig, sctg); + TableDataSet CountyDatJ = getCountyTableDataSet("dest", dest, sctg); + + // walk through every county combination ic/jc within current FAF Region combination origFaf/destFaf + double EmplICplusJCtotal = 0; + int count = 0; + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + EmplICplusJCtotal += CountyDatI.getValueAt(origCounty, "Employment") + + CountyDatJ.getValueAt(destCounty, "Employment"); + count++; + } + } + int[] oFips = new int[count]; + int[] dFips = new int[count]; + String[] codes = new String[count]; + float[] tonShare = new float[count]; + int k = 0; + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + int origFips = (int) CountyDatI.getValueAt(origCounty, "COUNTYFIPS"); + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + int destFips = (int) CountyDatJ.getValueAt(destCounty, "COUNTYFIPS"); + double EmplICplusJC = CountyDatI.getValueAt(origCounty, "Employment") + + CountyDatJ.getValueAt(destCounty, "Employment"); + tonShare[k] = (float) (tons * EmplICplusJC / EmplICplusJCtotal); + oFips[k] = origFips; + dFips[k] = destFips; + codes[k] = String.valueOf(origFips) + "_" + String.valueOf(destFips); + k++; + } + } + flows.appendColumn(oFips, "oFips"); + flows.appendColumn(dFips, "dFips"); + flows.appendColumn(codes, "Codes"); + flows.appendColumn(tonShare, "Tons"); + return flows; + } + + + public TableDataSet disaggregateSingleFAFFlow(int orig, int dest, String sctg, float tons, float centerDamper) { + // disaggregate tons from orig FAFzone to dest FAFzone to the county level for FAF3 + + TableDataSet flows = new TableDataSet(); + // get county specific data for origin FAF and destination FAF + + TableDataSet CountyDatI = getCountyWeights("orig", orig, sctg); + TableDataSet CountyDatJ = getCountyWeights("dest", dest, sctg); + if (CountyDatI == null) { + logger.error("Could not find table for disaggregating county " + orig + " with commodity " + sctg); + return null; + } + if (CountyDatJ == null) { + logger.error("Could not find table for disaggregating county " + dest + " with commodity " + sctg); + return null; + } + // walk through every county combination ic/jc within current FAF Region combination origFaf/destFaf + double EmplICplusJCtotal = 0; + int count = 0; + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + EmplICplusJCtotal += Math.pow(CountyDatI.getValueAt(origCounty, "Employment") * + CountyDatJ.getValueAt(destCounty, "Employment"), centerDamper); + count++; + } + } + int[] oFips = new int[count]; + int[] dFips = new int[count]; + String[] codes = new String[count]; + float[] tonShare = new float[count]; + int k = 0; + + if (EmplICplusJCtotal == 0) logger.error("Could not find weight for FAF zone " + orig + " to " + dest + " for " + sctg); + + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + int origFips = (int) CountyDatI.getValueAt(origCounty, "COUNTYFIPS"); + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + int destFips = (int) CountyDatJ.getValueAt(destCounty, "COUNTYFIPS"); + double EmplICplusJC = Math.pow(CountyDatI.getValueAt(origCounty, "Employment") * + CountyDatJ.getValueAt(destCounty, "Employment"), centerDamper); + tonShare[k] = (float) (tons * EmplICplusJC / EmplICplusJCtotal); + + oFips[k] = origFips; + dFips[k] = destFips; + codes[k] = origFips + "_" + destFips; + k++; + } + } + + flows.appendColumn(oFips, "oFips"); + flows.appendColumn(dFips, "dFips"); + flows.appendColumn(codes, "Codes"); + flows.appendColumn(tonShare, "Tons"); + return flows; + } + + + public TableDataSet disaggregateSingleFAFFlowThroughPOE(String dir, TableDataSet poe, int orig, int dest, String sctg, + float tons, float centerDamper) { + // disaggregate tons from orig FAFzone to dest FAFzone to the county level for FAF3 for import/exports through ports + // of entry/exit + + // get county specific data for origin FAF and destination FAF + TableDataSet CountyDatI = getCountyWeights("orig", orig, sctg); + if (dir.startsWith("import") && poe != null) CountyDatI = poe; + TableDataSet CountyDatJ = getCountyWeights("dest", dest, sctg); + if (dir.startsWith("export") && poe != null) CountyDatJ = poe; + if (CountyDatI == null) { + logger.error("Could not find table for " + dir + " disaggregating county " + orig + " with commodity " + sctg); + return null; + } + if (CountyDatJ == null) { + logger.error("Could not find table for " + dir + " disaggregating county " + dest + " with commodity " + sctg); + return null; + } + // walk through every county combination ic/jc within current FAF Region combination origFaf/destFaf + double EmplICplusJCtotal = 0; + int count = 0; + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + EmplICplusJCtotal += Math.pow(CountyDatI.getValueAt(origCounty, "Employment") * + CountyDatJ.getValueAt(destCounty, "Employment"), centerDamper); + count++; + } + } + int[] oFips = new int[count]; + int[] dFips = new int[count]; + String[] codes = new String[count]; + float[] tonShare = new float[count]; + int k = 0; + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + int origFips = (int) CountyDatI.getValueAt(origCounty, "COUNTYFIPS"); + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + int destFips = (int) CountyDatJ.getValueAt(destCounty, "COUNTYFIPS"); + double EmplICplusJC = Math.pow(CountyDatI.getValueAt(origCounty, "Employment") * + CountyDatJ.getValueAt(destCounty, "Employment"), centerDamper); + tonShare[k] = (float) (tons * EmplICplusJC / EmplICplusJCtotal); + oFips[k] = origFips; + dFips[k] = destFips; + codes[k] = origFips + "_" + destFips; + k++; + } + } + TableDataSet flows = new TableDataSet(); + flows.appendColumn(oFips, "oFips"); + flows.appendColumn(dFips, "dFips"); + flows.appendColumn(codes, "Codes"); + flows.appendColumn(tonShare, "Tons"); + return flows; + } + + + public float getCountyDistance(int origFips, int destFips) { + // return distance from origFips to destFips + + try { + return distCounties.getValueAt(origFips, destFips); + } catch (Exception e){ + return -1; + } + } + + + public float[] splitToTruckTypes(int origFips, int destFips, float trucks) { + // split trucks for this OD pair into two truck types + float dist; + try { + dist = distCounties.getValueAt(origFips, destFips); + } catch (Exception e) { + dist = 999; + } + float[] splitTrucks = {0, 0}; + for (int dClass = truckTypeShareDistBin.length - 1; dClass >= 0; dClass--) { + if (dist >= truckTypeShareDistBin[dClass]) { + splitTrucks[0] = trucks * truckTypeShareMT[dClass]; + splitTrucks[1] = trucks * (1 - truckTypeShareMT[dClass]); + return splitTrucks; } + } + logger.warn("Could not find truck share for distance " + dist); + return null; + } + + + public double[] splitToTruckTypes(int origFips, int destFips, double trucks) { + // split trucks for this OD pair into two truck types + int dist; + try { + dist = (int) distCounties.getValueAt(origFips, destFips); + if (dist == -999) dist = 9999; // destination unreachable on network, therefore skim is negative, but there might be trips in reality, including ferry + } catch (Exception e) { + dist = 999; + } + double[] splitTrucks = {0, 0}; + for (int dClass = truckTypeShareDistBin.length - 1; dClass >= 0; dClass--) + if (dist >= truckTypeShareDistBin[dClass]) { + splitTrucks[0] = trucks * truckTypeShareMT[dClass]; + splitTrucks[1] = trucks * (1 - truckTypeShareMT[dClass]); + return splitTrucks; + } + logger.warn("Could not find truck share for distance " + dist); + return null; + } + + + public double[] splitToTruckTypes(int origFips, int destFips) { + // split trucks for this OD pair into two truck types + int dist; + try { + dist = (int) distCounties.getValueAt(origFips, destFips); + if (dist == -999) dist = 9999; // destination unreachable on network, therefore skim is negative, but there might be trips in reality, including ferry + } catch (Exception e) { + dist = 999; + } + double[] splitTrucks = {0, 0}; + for (int dClass = truckTypeShareDistBin.length - 1; dClass >= 0; dClass--) + if (dist >= truckTypeShareDistBin[dClass]) { + splitTrucks[0] = truckTypeShareMT[dClass]; + splitTrucks[1] = (1 - truckTypeShareMT[dClass]); + return splitTrucks; + } + logger.warn("Could not find truck share for distance " + dist); + return null; + } + + + public double[] getTrucksByType(float dist, double sutPL, double mutPL, double tonFlow) { + // convert tons into trucks and split trucks into single-unit and multi-unit trucks + + double[] truckShares = splitToTruckTypes(dist); + double[] trucksByType = new double[2]; + trucksByType[0] = tonFlow / (sutPL + truckShares[1]/truckShares[0] * mutPL); + trucksByType[1] = tonFlow / (truckShares[0]/truckShares[1] * sutPL + mutPL); + return trucksByType; + } + + + public double[] getTrucksByType(float dist, double sutPL, double mutPL, double tonFlow, float adjustmentSUT) { + // convert tons into trucks and split trucks into single-unit and multi-unit trucks + + double[] truckShares = splitToTruckTypes(dist); + truckShares[0] = truckShares[0] * (1. + adjustmentSUT); + truckShares[1] = 1. - truckShares[0]; + double[] trucksByType = new double[2]; + trucksByType[0] = tonFlow / (sutPL + truckShares[1]/truckShares[0] * mutPL); + trucksByType[1] = tonFlow / (truckShares[0]/truckShares[1] * sutPL + mutPL); + return trucksByType; + } + + + public double[] splitToTruckTypes(float distance) { + // split trucks for this OD pair into two truck types + double[] splitTrucks = {0, 0}; + for (int dClass = truckTypeShareDistBin.length - 1; dClass >= 0; dClass--) + if (distance >= truckTypeShareDistBin[dClass]) { + splitTrucks[0] = truckTypeShareMT[dClass]; + splitTrucks[1] = (1 - truckTypeShareMT[dClass]); + return splitTrucks; + } + logger.warn("Could not find truck share for distance " + distance); + return null; + } + + + public float[] splitToTruckTypes(String code, float trucks) { + // split trucks for this OD pair into two truck types + String[] origDestFips = code.split("_"); + int origFips = Integer.parseInt(origDestFips[0]); + int destFips = Integer.parseInt(origDestFips[1]); + float dist; + try { + dist = distCounties.getValueAt(origFips, destFips); + } catch (Exception e) { + dist = 1; + } + int distClass = 1; + for (int row = 1; row <= truckTypeShares.getRowCount(); row++) + if (dist > truckTypeShares.getValueAt(row, "DistanceGreaterThan")) distClass = row; + float[] splitTrucks = {0, 0}; + splitTrucks[0] = trucks * truckTypeShares.getValueAt(distClass, "MT(<26k_lbs)"); + splitTrucks[1] = trucks * truckTypeShares.getValueAt(distClass, "HT(>26k_lbs)"); + return splitTrucks; + } + + + private TableDataSet getCountyTableDataSet(String direction, String FAFregion, String sctgCode) { + // check if this FAFregion equals a special generator + TableDataSet tbl; + if (FAFregion.equals("OR Portl_Airport") || FAFregion.equals("OR Portl_Port") || + FAFregion.equals("OR rem_Airport") || FAFregion.equals("OR rem_Port") || FAFregion.equals("Other")) { + tbl = new TableDataSet(); + String[] a = {FAFregion}; + float[] b = new float[1]; + if (FAFregion.equals("OR Portl_Airport")) b[0] = 90001f; + else if (FAFregion.equals("OR Portl_Port")) b[0] = 90002f; + else if (FAFregion.equals("OR rem_Airport")) b[0] = 90003f; + else if (FAFregion.equals("OR rem_Port")) b[0] = 90004f; + else if (FAFregion.equals("Other")) b[0] = 90005f; + float[] c = {1f}; + tbl.appendColumn(a, "Name"); + tbl.appendColumn(b, "COUNTYFIPS"); + tbl.appendColumn(a, "FAFRegion"); + tbl.appendColumn(c, "Employment"); + tbl.setName(FAFregion); + } else { + String code = direction + "_" + FAFregion + "_" + sctgCode; + tbl = countyShares.get(code); + } + return tbl; + } + + + public TableDataSet getCountyWeights(String direction, int FAFregion, String sctgCode) { + // check if this FAFregion equals a special generator + String code = direction + "_" + FAFregion + "_" + sctgCode; + return countyShares.get(code); + } + + + public TableDataSet disaggregateSingleFlowInOregon(String orig, String dest, String sctg, float trucks) { + // disaggregate trucks from orig FAFzone to dest FAFzone to the county level + + if (!orig.contains("OR Portl") && !orig.contains("OR rem")) orig = "Other"; + if (!dest.contains("OR Portl") && !dest.contains("OR rem")) dest = "Other"; + TableDataSet flows = new TableDataSet(); + // get county specific data for origin FAF and destination FAF + TableDataSet CountyDatI = getCountyTableDataSet("orig", orig, sctg); + TableDataSet CountyDatJ = getCountyTableDataSet("dest", dest, sctg); + + // walk through every county combination ic/jc within current FAF Region combination origFaf/destFaf + double EmplICplusJCtotal = 0; + int count = 0; + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + EmplICplusJCtotal += CountyDatI.getValueAt(origCounty, "Employment") + + CountyDatJ.getValueAt(destCounty, "Employment"); + count++; + } + } + String[] codes = new String[count]; + float[] tonShare = new float[count]; + int k = 0; + for (int origCounty = 1; origCounty <= CountyDatI.getRowCount(); origCounty++) { + int origFips = (int) CountyDatI.getValueAt(origCounty, "COUNTYFIPS"); + for (int destCounty = 1; destCounty <= CountyDatJ.getRowCount(); destCounty++) { + int destFips = (int) CountyDatJ.getValueAt(destCounty, "COUNTYFIPS"); + double EmplICplusJC = CountyDatI.getValueAt(origCounty, "Employment") + + CountyDatJ.getValueAt(destCounty, "Employment"); + tonShare[k] = (float) (trucks * EmplICplusJC / EmplICplusJCtotal); + codes[k] = String.valueOf(origFips) + "_" + String.valueOf(destFips); + k++; + } + } + flows.appendColumn(codes, "Codes"); + flows.appendColumn(tonShare, "ShortTons"); + return flows; + } + + + public static void getUScountyEmployment(ResourceBundle rb) { + // read employment and county id data + + logger.info("Reading County Employment Data..."); + countyIDsWithEmployment = fafUtils.importTable(ResourceUtil.getProperty(rb, "county.ID")); + + TableDataSet StatesTable = fafUtils.importTable(ResourceUtil.getProperty(rb, "state.list")); + String[] StateNames = StatesTable.getColumnAsString("StateName"); + TableDataSet[] StateEmployment = new TableDataSet[StateNames.length]; + for (int st = 0; st < StateNames.length; st++) { + String fileName = ResourceUtil.getProperty(rb, "state.employment.prefix") + StateNames[st] + ".csv"; + StateEmployment[st] = fafUtils.importTable(fileName); + StateEmployment[st].setName(StateNames[st]); + } + + String[] tempString = new String[countyIDsWithEmployment.getRowCount()]; + int[] tempInt = new int[countyIDsWithEmployment.getRowCount()]; + countyIDsWithEmployment.appendColumn(tempString, "stateName"); + countyIDsWithEmployment.appendColumn(tempInt, "Employment"); + + // assign employment to every county + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (!countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("County") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Legal County Equivalent")&& + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Independent City") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Borough") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Census Area") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("City and Borough") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Parish")) continue; + String CountyStateAbbreviation = countyIDsWithEmployment.getStringValueAt(i, "StateCode"); + String CountyName = countyIDsWithEmployment.getStringValueAt(i, "NAME"); + + // find full state name + String StateNameOfCounty = " "; + for (int j = 1; j <= StatesTable.getRowCount(); j++) + if (StatesTable.getStringValueAt(j, "StateAbbreviation").equals(CountyStateAbbreviation)) + StateNameOfCounty = StatesTable.getStringValueAt(j, "stateName"); + + // find right employment table for this state + int StateNumber = 0; + for (int j = 0; j < StateEmployment.length; j++) { + if (StateEmployment[j].getName().equals(StateNameOfCounty)) StateNumber = j; + } + + // delete state code from county name + StringBuffer sb = new StringBuffer(); + sb.append(CountyName); + int n = sb.lastIndexOf(CountyStateAbbreviation); + sb.delete(n-1, n+2); + // add ", StateAbbreviation" + sb.append(", "); + sb.append(CountyStateAbbreviation); + CountyName = sb.toString(); + + // find employment of current county + boolean found = false; + for (int k = 1; k <= StateEmployment[StateNumber].getRowCount(); k++) { + if (StateEmployment[StateNumber].getStringValueAt(k, "Region").equalsIgnoreCase(CountyName)) { + countyIDsWithEmployment.setValueAt + (i, "Employment", StateEmployment[StateNumber].getValueAt(k, "Employment")); + countyIDsWithEmployment.setStringValueAt + (i, countyIDsWithEmployment.getColumnPosition("stateName"), StateNameOfCounty); + found = true; + } + } + + // County Broomfield, Colorado has no polygon in the county layer. Employment is added to Boulder County: + if (CountyName.equals("BOULDER, CO")) { + for (int k = 1; k <= StateEmployment[StateNumber].getRowCount(); k++) { + if (StateEmployment[StateNumber].getStringValueAt(k, "Region").equals("Broomfield, CO")) { + float BoulderBroomfieldEmpl = countyIDsWithEmployment.getValueAt(i, "Employment") + + StateEmployment[StateNumber].getValueAt(k, "Employment"); + countyIDsWithEmployment.setValueAt(i, "Employment", BoulderBroomfieldEmpl); + } + } + } + + // write error message (unless it is an island of UM or Guam) + if (!found && !CountyStateAbbreviation.equals("UM") && !CountyStateAbbreviation.equals("GU")) + logger.warn("Not found: " + CountyName + " (" + + countyIDsWithEmployment.getStringValueAt(i, "TYPE") + ")"); + } + } + + + public static void getUScountyEmploymentFromOneFile (ResourceBundle rb) { + // read file with county employment in the US + + logger.info("Reading County Employment Data..."); + countyIDsWithEmployment = fafUtils.importTable(ResourceUtil.getProperty(rb, "county.ID")); + TableDataSet countyEmployment = fafUtils.importTable(ResourceUtil.getProperty(rb, "us.county.employment")); + + String[] tempString = new String[countyIDsWithEmployment.getRowCount()]; + int[] tempInt = new int[countyIDsWithEmployment.getRowCount()]; + countyIDsWithEmployment.appendColumn(tempString, "stateName"); + countyIDsWithEmployment.appendColumn(tempInt, "Employment"); + + // assign employment to every county + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (!countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("County") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Legal County Equivalent")&& + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Independent City") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Borough") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Census Area") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("City and Borough") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Parish")) continue; + // skip Guam and United States Minor Outlying Islands + if (countyIDsWithEmployment.getStringValueAt(i, "StateCode").equals("GU") || + countyIDsWithEmployment.getStringValueAt(i, "StateCode").equals("UM")) continue; + float fips = countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS"); + // find employment of current county + boolean found = false; + for (int row = 1; row <= countyEmployment.getRowCount(); row++) { + if (countyEmployment.getValueAt(row, "fips") == fips) { + countyIDsWithEmployment.setValueAt + (i, "Employment", countyEmployment.getValueAt(row, "totalAnnualAverageEmployment")); + found = true; + } + } + + // write error message if county was not found + if (!found) { + String CountyName = countyIDsWithEmployment.getStringValueAt(i, "NAME"); + logger.warn("Not found: " + CountyName + " (" + + countyIDsWithEmployment.getStringValueAt(i, "TYPE") + ")"); + } + } + } + + + public void getUScountyEmploymentByIndustry (ResourceBundle rb) { + // read file with employment by county by industry + + logger.info(" Reading County Employment Data..."); + countyIDsWithEmployment = fafUtils.importTable(ResourceUtil.getProperty(rb, "county.ID")); + TableDataSet countyEmployment = fafUtils.importTable(ResourceUtil.getProperty(rb, "us.county.employment.by.ind")); + countyEmployment.buildIndex(countyEmployment.getColumnPosition("FIPS")); + TableDataSet agEmpl = fafUtils.importTable(rb.getString("us.county.employment.agricult")); + agEmpl.buildIndex(agEmpl.getColumnPosition("FIPS")); + + String[] tempString = new String[countyIDsWithEmployment.getRowCount()]; + int[] tempInt = new int[countyIDsWithEmployment.getRowCount()]; + countyIDsWithEmployment.appendColumn(tempString, "stateName"); + for (String emp: empCats) countyIDsWithEmployment.appendColumn(tempInt, emp); + + // assign employment to every county + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (!countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("County") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Legal County Equivalent")&& + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Independent City") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Borough") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Census Area") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("City and Borough") && + !countyIDsWithEmployment.getStringValueAt(i, "TYPE").equals("Parish")) continue; + // skip Guam and United States Minor Outlying Islands + if (countyIDsWithEmployment.getStringValueAt(i, "StateCode").equals("GU") || + countyIDsWithEmployment.getStringValueAt(i, "StateCode").equals("UM")) continue; + int fips = (int) countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS"); + // find employment of current county + float consNatResMinEmployment = countyEmployment.getIndexedValueAt(fips, "Natural Resources and Mining") + + countyEmployment.getIndexedValueAt(fips, "Construction"); + countyIDsWithEmployment.setValueAt(i, "Construction Natural Resources and Mining", consNatResMinEmployment); + countyIDsWithEmployment.setValueAt(i, "Manufacturing", countyEmployment.getIndexedValueAt(fips, "Manufacturing")); + countyIDsWithEmployment.setValueAt(i, "Trade Transportation and Utilities", countyEmployment.getIndexedValueAt(fips, "Trade, Transportation, and Utilities")); + countyIDsWithEmployment.setValueAt(i, "Information", countyEmployment.getIndexedValueAt(fips, "Information")); + countyIDsWithEmployment.setValueAt(i, "Financial Activities", countyEmployment.getIndexedValueAt(fips, "Financial Activities")); + countyIDsWithEmployment.setValueAt(i, "Professional and Business Services", countyEmployment.getIndexedValueAt(fips, "Professional and Business Services")); + countyIDsWithEmployment.setValueAt(i, "Education and Health Services", countyEmployment.getIndexedValueAt(fips, "Education and Health Services")); + countyIDsWithEmployment.setValueAt(i, "Leisure and Hospitality", countyEmployment.getIndexedValueAt(fips, "Leisure and Hospitality")); + countyIDsWithEmployment.setValueAt(i, "Other Services", countyEmployment.getIndexedValueAt(fips, "Other Services")); + + // agricultural employment is missing in most of Alaska and in independent cities (deemed not to be relevant) + try { + countyIDsWithEmployment.setValueAt(i, "Agriculture", agEmpl.getIndexedValueAt(fips, "agEmployment")); + } catch (Exception e) { + // Set to minor value to ensure that all FAF ag production can be allocated. If the FAF zone of this + // county has other counties with ag production, this miniWeight will be irrelevant as it is small. + // If no county in this FAF zone has ag production, the employment "Construction Natural Resources and Mining" + // will be used to disaggregate flows (with all counties being multiplied by 0.0001, which doesn't affect the result. + float miniWeight = 0.0001f * countyIDsWithEmployment.getValueAt(i, "Construction Natural Resources and Mining"); + countyIDsWithEmployment.setValueAt(i, "Agriculture", miniWeight); + + } + } + // try to add coal production as a weight + try { + TableDataSet coalProd = fafUtils.importTable(rb.getString("mining.production")); + coalProd.buildIndex(coalProd.getColumnPosition("FIPS")); + countyIDsWithEmployment.appendColumn(tempInt, "coalProduction"); + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + int fips = (int) countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS"); + try { + countyIDsWithEmployment.setValueAt(i, "coalProduction", coalProd.getIndexedValueAt(fips, "Production_total")); + } catch (Exception e) { + // Set to minor value to ensure that all FAF coal production can be allocated. If the FAF zone of this + // county has other counties with coal production, this miniWeight will be irrelevant as it is small. + // If no county in this FAF zone has coal production, the employment "Construction Natural Resources and Mining" + // will be used to disaggregate flows (with all counties being multiplied by 0.0001, which doesn't affect the result. + float miniWeight = 0.0001f * countyIDsWithEmployment.getValueAt(i, "Construction Natural Resources and Mining"); + countyIDsWithEmployment.setValueAt(i, "coalProduction", miniWeight); + } + } + } catch (Exception e) { + logger.warn("Coal production not defined."); + } + countyFips = countyIDsWithEmployment.getColumnAsInt( + countyIDsWithEmployment.getColumnPosition("COUNTYFIPS")); + } + + + public int[] getCountyFips () { + return countyFips; + } + + + public int getStateNumberOfCounty (int fips) { + for (int row = 1; row <= countyIDsWithEmployment.getRowCount(); row ++) { + if (countyIDsWithEmployment.getValueAt(row, "COUNTYFIPS") == fips) return (int) countyIDsWithEmployment.getValueAt(row, "State"); + } + logger.warn ("State of county " + fips + " was not found."); + return -1; + } + + + public void defineTruckTypes (String truckType, ResourceBundle rb) { + // define truck types by weight or size + + truckTypeShares = fafUtils.importTable(rb.getString("truck.type.by.distance")); + if (truckType.equalsIgnoreCase("weight")) createTruckShareArraysWeight(); + else createTruckShareArraysUnit(); + } + + + private TableDataSet getCountySpecificDataByFAF2(int FAFNumber, String com, TableDataSet detEmpl, + HashMap factors) { + // get employment as a weight for FAF zone FAFNumber in FAF2 + // where detailed employment is available in detEmpl, use make/use factors for commodity-specific weights + + TableDataSet CountySpecifics = new TableDataSet(); + String nameOfFAF = readFAF2.domRegionList.getStringValueAt(FAFNumber, "RegionName"); + CountySpecifics.setName(nameOfFAF); + + int NoCountiesInFAF = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getStringValueAt(i, "FafRegion").equals(nameOfFAF)) NoCountiesInFAF += 1; + } + String[] CountyName = new String[NoCountiesInFAF]; + int[] CountyFips = new int[NoCountiesInFAF]; + String[] CountyFAFRegion = new String[NoCountiesInFAF]; + float[] countyEmpl = new float[NoCountiesInFAF]; + boolean hasDetailedEmployment = checkIfFAFzoneHasDetailedEmployment(nameOfFAF, NoCountiesInFAF, detEmpl, 2); + + int k = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getStringValueAt(i, "FafRegion").equals(nameOfFAF)){ + CountyName[k] = countyIDsWithEmployment.getStringValueAt(i, "NAME"); + CountyFips[k] = (int) countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS"); + CountyFAFRegion[k] = countyIDsWithEmployment.getStringValueAt(i, "FafRegion"); + if (hasDetailedEmployment) { + for (int row = 1; row <= detEmpl.getRowCount(); row++) + if (detEmpl.getValueAt(row, "CountyFips") == CountyFips[k]) + countyEmpl[k] = getWeightedEmpl(row, com, detEmpl, factors); + } else { + countyEmpl[k] = countyIDsWithEmployment.getValueAt(i, "Employment"); + } + k++; + } + } + CountySpecifics.appendColumn(CountyName, "Name"); + CountySpecifics.appendColumn(CountyFips, "COUNTYFIPS"); + CountySpecifics.appendColumn(CountyFAFRegion, "FAFRegion"); + CountySpecifics.appendColumn(countyEmpl, "Employment"); + return CountySpecifics; + } + + + private TableDataSet getCountySpecificDataByFAF(int FAFNumber, String com, TableDataSet detEmployment, + HashMap factors) { + + String fieldName = "FAF3region"; + if(FAFVersion==4) + fieldName = "FAF4region"; + + // get employment as a weight for FAF zone FAFNumber in FAF3 + // where detailed employment is available in detEmpl, use make/use factors for commodity-specific weights + + if (FAFNumber > 800) { + // foreign FAF zone + TableDataSet foreignCountry = new TableDataSet(); + String[] countyName = {String.valueOf(FAFNumber)}; + int[] countyFips = {-1}; + String[] countyFAFRegion = {String.valueOf(FAFNumber)}; + int[] countyEmpl = {1}; + foreignCountry.appendColumn(countyName, "Name"); + foreignCountry.appendColumn(countyFips, "COUNTYFIPS"); + foreignCountry.appendColumn(countyFAFRegion, "FAFRegion"); + foreignCountry.appendColumn(countyEmpl, "Employment"); + return foreignCountry; + } + TableDataSet CountySpecifics = new TableDataSet(); + String nameOfFAF = null; + if(FAFVersion==3) + nameOfFAF = readFAF3.getFAFzoneName(FAFNumber); + else + nameOfFAF = ReadFAF4.getFAFzoneName(FAFNumber); + CountySpecifics.setName(nameOfFAF); + + int NoCountiesInFAF = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getValueAt(i, fieldName) == FAFNumber) NoCountiesInFAF += 1; + } + if (NoCountiesInFAF == 0) logger.warn("No counties for FAF zone " + FAFNumber + " have been found."); + String[] countyName = new String[NoCountiesInFAF]; + int[] countyFips = new int[NoCountiesInFAF]; + String[] countyFAFRegion = new String[NoCountiesInFAF]; + float[] countyEmpl = new float[NoCountiesInFAF]; + boolean hasDetailedEmployment = checkIfFAFzoneHasDetailedEmployment(nameOfFAF, NoCountiesInFAF, detEmployment, 3); + + int k = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getValueAt(i, fieldName) == FAFNumber){ + countyName[k] = countyIDsWithEmployment.getStringValueAt(i, "NAME"); + countyFips[k] = (int) countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS"); + countyFAFRegion[k] = countyIDsWithEmployment.getStringValueAt(i, fieldName); + if (hasDetailedEmployment) { + for (int row = 1; row <= detEmployment.getRowCount(); row++) + if (detEmployment.getValueAt(row, "CountyFips") == countyFips[k]) + countyEmpl[k] = getWeightedEmpl(row, com, detEmployment, factors); + } else { + countyEmpl[k] = countyIDsWithEmployment.getValueAt(i, "Employment"); + } + k++; + } + } + CountySpecifics.appendColumn(countyName, "Name"); + CountySpecifics.appendColumn(countyFips, "COUNTYFIPS"); + CountySpecifics.appendColumn(countyFAFRegion, "FAFRegion"); + CountySpecifics.appendColumn(countyEmpl, "Employment"); + return CountySpecifics; + } + + + private TableDataSet getCountySpecificDataByFAFwithDetailedEmployment (int FAFNumber, String com, + HashMap factors, float officeReduction) { + // get employment as a weight for FAF zone FAFNumber in FAF3, use make/use factors for commodity-specific weights + String fieldName = "FAF3region"; + if(FAFVersion==4) + fieldName = "FAF4region"; + + if (FAFNumber > 800) { + // foreign FAF zone + TableDataSet foreignCountry = new TableDataSet(); + String[] countyName = {String.valueOf(FAFNumber)}; + int[] countyFips = {-1}; + String[] countyFAFRegion = {String.valueOf(FAFNumber)}; + int[] countyEmpl = {1}; + foreignCountry.appendColumn(countyName, "Name"); + foreignCountry.appendColumn(countyFips, "COUNTYFIPS"); + foreignCountry.appendColumn(countyFAFRegion, "FAFRegion"); + foreignCountry.appendColumn(countyEmpl, "Employment"); + return foreignCountry; + } + TableDataSet CountySpecifics = new TableDataSet(); + String nameOfFAF = null; + + if(FAFVersion==3) + nameOfFAF = readFAF3.getFAFzoneName(FAFNumber); + else + nameOfFAF = ReadFAF4.getFAFzoneName(FAFNumber); + + CountySpecifics.setName(nameOfFAF); + + int NoCountiesInFAF = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getValueAt(i, fieldName) == FAFNumber) NoCountiesInFAF += 1; + } + if (NoCountiesInFAF == 0) logger.warn("No counties for FAF zone " + FAFNumber + " have been found."); + String[] countyName = new String[NoCountiesInFAF]; + int[] countyFips = new int[NoCountiesInFAF]; + String[] countyFAFRegion = new String[NoCountiesInFAF]; + float[] countyEmpl = new float[NoCountiesInFAF]; + + int k = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getValueAt(i, fieldName) == FAFNumber){ + countyName[k] = countyIDsWithEmployment.getStringValueAt(i, "NAME"); + countyFips[k] = (int) countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS"); + countyFAFRegion[k] = countyIDsWithEmployment.getStringValueAt(i, fieldName); + countyEmpl[k] = getWeightedEmpl(i, com, factors, officeReduction); +// if(countyFips[k]==37082 || countyFips[k]==37058 || countyFips[k]==37152 ){//|| destFips==37082 || destFips==37058 || destFips==37152){ +// logger.info("FIPS: ("+countyFips[k]+") WeightedEmp: "+countyEmpl[k]); +// } + k++; + } + } + CountySpecifics.appendColumn(countyName, "Name"); + CountySpecifics.appendColumn(countyFips, "COUNTYFIPS"); + CountySpecifics.appendColumn(countyFAFRegion, "FAFRegion"); + CountySpecifics.appendColumn(countyEmpl, "Employment"); + return CountySpecifics; + } + + + private TableDataSet getCountySpecificDataByFAFwithDetailedEmploymentByType (int FAFNumber, String com, + HashMap factors, float officeReduction) { + // get employment as a weight for FAF zone FAFNumber in FAF3, use make/use factors for commodity-specific weights + // keep track of single employment types + + String fieldName = "FAF3region"; + if(FAFVersion==4) + fieldName = "FAF4region"; + + if (FAFNumber > 800) { + // foreign FAF zone + TableDataSet foreignCountry = new TableDataSet(); + String[] countyName = {String.valueOf(FAFNumber)}; + int[] countyFips = {-1}; + String[] countyFAFRegion = {String.valueOf(FAFNumber)}; + int[] countyEmpl = {1}; + foreignCountry.appendColumn(countyName, "Name"); + foreignCountry.appendColumn(countyFips, "COUNTYFIPS"); + foreignCountry.appendColumn(countyFAFRegion, "FAFRegion"); + foreignCountry.appendColumn(countyEmpl, "Employment"); + return foreignCountry; + } + TableDataSet CountySpecifics = new TableDataSet(); + + String nameOfFAF=null; + if(FAFVersion==3) + nameOfFAF = readFAF3.getFAFzoneName(FAFNumber); + else + nameOfFAF = ReadFAF4.getFAFzoneName(FAFNumber); + + CountySpecifics.setName(nameOfFAF); + + int NoCountiesInFAF = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getValueAt(i, fieldName) == FAFNumber) NoCountiesInFAF += 1; + } + if (NoCountiesInFAF == 0) logger.warn("No counties for FAF zone " + FAFNumber + " have been found."); + String[] countyName = new String[NoCountiesInFAF]; + int[] countyFips = new int[NoCountiesInFAF]; + String[] countyFAFRegion = new String[NoCountiesInFAF]; + float[][] countyEmpl = new float[NoCountiesInFAF][empCats.length+1]; + + int k = 0; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) { + if (countyIDsWithEmployment.getValueAt(i, fieldName) == FAFNumber){ + countyName[k] = countyIDsWithEmployment.getStringValueAt(i, "NAME"); + countyFips[k] = (int) countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS"); + countyFAFRegion[k] = countyIDsWithEmployment.getStringValueAt(i, fieldName); + HashMap detEmpl = getWeightedEmplByEmpl(i, com, factors, officeReduction); + countyEmpl[k][empCats.length] = detEmpl.get("total"); + for (int emp = 0; emp < empCats.length; emp++) countyEmpl[k][emp] = detEmpl.get(empCats[emp]); + k++; + } + } + CountySpecifics.appendColumn(countyName, "Name"); + CountySpecifics.appendColumn(countyFips, "COUNTYFIPS"); + CountySpecifics.appendColumn(countyFAFRegion, "FAFRegion"); + for (int emp = 0; emp <= empCats.length; emp++) { + float[] copy = new float[NoCountiesInFAF]; + for (int i = 0; i < copy.length; i++) copy[i] = countyEmpl[i][emp]; + if (emp < empCats.length) CountySpecifics.appendColumn(copy, empCats[emp]); + else CountySpecifics.appendColumn(copy, "Employment"); + } + return CountySpecifics; + } + + + public void prepareCountyDataForFAFwithDetailedEmployment(ResourceBundle rb, int yr, TableDataSet specialRegions) { + // prepare county data to provide detailed employment as a weight using the "fafVersion" zone system + + logger.info("Preparing county data with detailed employment for FAF flow disaggregation for year " + yr + "..."); + HashMap useC = createMakeUseHashMap(rb, "faf.use.coefficients"); + HashMap makeC = createMakeUseHashMap(rb, "faf.make.coefficients"); + distCounties = MatrixReader.readMatrix(new File(rb.getString("county.distance.in.miles")), "Distance"); + float reduction = (float) ResourceUtil.getDoubleProperty(rb, "reduction.local.office.weight", 1d); + + //create HashMap that contains for every FAF region a TableDataSet of counties with their employment share + countyShares = new HashMap<>(); + String[] direction = {"orig", "dest"}; + for (String dir: direction) { + HashMap factors; + if (dir.equals("orig")) factors = makeC; + else factors = useC; + + for (int fafNum = 1; fafNum <= readFAF3.fafRegionList.getRowCount(); fafNum++) { + for (String com: readFAF3.sctgStringCommodities) { + int zoneNum = (int) readFAF3.fafRegionList.getValueAt(fafNum, "ZoneID"); + TableDataSet CountyList = getCountySpecificDataByFAFwithDetailedEmployment(zoneNum, com, factors, reduction); + String code = dir + "_" + zoneNum + "_" + com; + countyShares.put(code, CountyList); + } + } + } + + // create fake county lists for special regions such as airports or seaports that shall be kept separate from the FAF regions + if (specialRegions == null) return; // OK truck flows + for (int row = 1; row <= specialRegions.getRowCount(); row++) { + int[] fips = {(int) specialRegions.getValueAt(row, "modelCode")}; + String[] name = new String[]{specialRegions.getStringValueAt(row, "faf3code")}; + TableDataSet CountyList = new TableDataSet(); + float[] emplDummy = {1}; + CountyList.appendColumn(name, "Name"); + CountyList.appendColumn(fips, "COUNTYFIPS"); + CountyList.appendColumn(name, "FAFRegion"); + CountyList.appendColumn(emplDummy, "Employment"); + for (String dir: direction) { + for (String com: readFAF3.sctgStringCommodities) { + String code = dir + "_" + fips[0] + "_" + com; + countyShares.put(code, CountyList); + } + } + } + } + + + public void prepareCountyDataForFAFwithDetailedEmployment(ResourceBundle rb, int yr, boolean keepTrackOfEmpType) { + // prepare county data to provide detailed employment as a weight + + logger.info(" Preparing county data with detailed employment for FAF flow disaggregation for year " + yr + "..."); + HashMap useC = createMakeUseHashMap(rb, "faf.use.coefficients"); + HashMap makeC = createMakeUseHashMap(rb, "faf.make.coefficients"); + distCounties = MatrixReader.readMatrix(new File(rb.getString("county.distance.in.miles")), "Distance"); + float reduction = (float) ResourceUtil.getDoubleProperty(rb, "reduction.local.office.weight", 1d); + + //create HashMap that contains for every FAF region a TableDataSet of counties with their employment share + countyShares = new HashMap<>(); + String[] direction = {"orig", "dest"}; + for (String dir: direction) { + HashMap factors; + if (dir.equals("orig")) factors = makeC; + else factors = useC; + + Object readFAF = null; + if(FAFVersion==3){ + + for (int fafNum = 1; fafNum <= readFAF3.fafRegionList.getRowCount(); fafNum++) { + for (String com: readFAF3.sctgStringCommodities) { + int zoneNum = (int) readFAF3.fafRegionList.getValueAt(fafNum, "ZoneID"); + TableDataSet CountyList; + if (!keepTrackOfEmpType) { + CountyList = getCountySpecificDataByFAFwithDetailedEmployment(zoneNum, com, factors, reduction); + } else { + CountyList = getCountySpecificDataByFAFwithDetailedEmploymentByType(zoneNum, com, factors, reduction); + } + String code = dir + "_" + zoneNum + "_" + com; + countyShares.put(code, CountyList); + } + } + }else{ + for (int fafNum = 1; fafNum <= ReadFAF4.fafRegionList.getRowCount(); fafNum++) { + for (String com: ReadFAF4.sctgStringCommodities) { + int zoneNum = (int) ReadFAF4.fafRegionList.getValueAt(fafNum, "ZoneID"); + TableDataSet CountyList; + if (!keepTrackOfEmpType) { + CountyList = getCountySpecificDataByFAFwithDetailedEmployment(zoneNum, com, factors, reduction); + } else { + CountyList = getCountySpecificDataByFAFwithDetailedEmploymentByType(zoneNum, com, factors, reduction); + } + String code = dir + "_" + zoneNum + "_" + com; + countyShares.put(code, CountyList); + } + } + + } + } + } + + + public void scaleSelectedCounties (ResourceBundle rb) { + // scale weight of employment up or down for selected counties + String fieldName = "FAF3region"; + if(FAFVersion==4) + fieldName = "FAF4region"; + + TableDataSet countyScaler = fafUtils.importTable(rb.getString("county.scaler")); + for (int row = 1; row <= countyScaler.getRowCount(); row++) { + int fips= (int) countyScaler.getValueAt(row, "countyFips"); + float scaler = countyScaler.getValueAt(row, "scaler"); + // find FAF zone + int fafZone = 0; + for (int countyRow = 1; countyRow <= countyIDsWithEmployment.getRowCount(); countyRow++) { + if (countyIDsWithEmployment.getValueAt(countyRow, "COUNTYFIPS") == fips) fafZone = + (int) countyIDsWithEmployment.getValueAt(countyRow, fieldName); + } + if (fafZone == 0) logger.error("Could not find FAF zone of FIPS " + fips + " in file " + rb.getString("county.ID")); + String[] direction = {"orig", "dest"}; + for (String dir: direction) { + + if(FAFVersion==3){ + for (String com: readFAF3.sctgStringCommodities) { + String code = dir + "_" + fafZone + "_" + com; + TableDataSet scalerThisCounty = countyShares.get(code); + for (int scalerRow = 1; scalerRow <= scalerThisCounty.getRowCount(); scalerRow++) { + if (scalerThisCounty.getValueAt(scalerRow, "COUNTYFIPS") == fips) { + float value = scalerThisCounty.getValueAt(scalerRow, "Employment") * scaler; + scalerThisCounty.setValueAt(scalerRow, "Employment", value); + } + } + } + }else{ + for (String com: ReadFAF4.sctgStringCommodities) { + String code = dir + "_" + fafZone + "_" + com; + TableDataSet scalerThisCounty = countyShares.get(code); + for (int scalerRow = 1; scalerRow <= scalerThisCounty.getRowCount(); scalerRow++) { + if (scalerThisCounty.getValueAt(scalerRow, "COUNTYFIPS") == fips) { + float value = scalerThisCounty.getValueAt(scalerRow, "Employment") * scaler; + scalerThisCounty.setValueAt(scalerRow, "Employment", value); + } + } + } + + + } + } + } + } + + + private boolean checkIfFAFzoneHasDetailedEmployment(String nameOfFAF, int noCountiesInFAF, TableDataSet detEmpl, + int fafVersion) { + // Check if detEmpl has detailed employment for all counties in FAF zone FAFNumber + + if (detEmpl == null) return false; + boolean[] countyHasDet = new boolean[noCountiesInFAF]; + int k = 0; + String colLabel; + if (fafVersion == 2) colLabel = "FafRegion"; + else colLabel = "FAF3region"; + for (int i = 1; i <= countyIDsWithEmployment.getRowCount(); i++) + if (countyIDsWithEmployment.getStringValueAt(i, colLabel).equals(nameOfFAF)) + for (int row = 1; row <= detEmpl.getRowCount(); row++) { + if (countyIDsWithEmployment.getValueAt(i, "COUNTYFIPS") == detEmpl.getValueAt(row, "CountyFips")) { + countyHasDet[k] = true; + k++; + } + } + int count = 0; + for (boolean county: countyHasDet) if (county) count++; + if (count == 0) return false; + else if (count == noCountiesInFAF) return true; + else logger.fatal("Detailed employment covers FAF zone " + nameOfFAF + " only partly."); + return false; + } + + + private float getWeightedEmpl(int row, String comFAF2, TableDataSet detEmpl, HashMap factors) { + // calculate weighted employment based on make/use coefficients + + float empl = 0; + String[] emplCategoriesTemp = detEmpl.getColumnLabels(); + String[] emplCategories = new String[emplCategoriesTemp.length-2]; + System.arraycopy(emplCategoriesTemp, 2, emplCategories, 0, emplCategories.length); + for (String emplCat: emplCategories) { + String code = emplCat + "_" + comFAF2; + float coeff = factors.get(code); + for (int col = 3; col <= detEmpl.getColumnCount(); col++) { + empl += detEmpl.getValueAt(row, col) * coeff; + } + } + return empl; + } + + + private float getWeightedEmpl(int row, int comFAF3, TableDataSet detEmpl, HashMap factors) { + // calculate weighted employment based on make/use coefficients + + float empl = 0; + String[] emplCategoriesTemp = detEmpl.getColumnLabels(); + String[] emplCategories = new String[emplCategoriesTemp.length-2]; + System.arraycopy(emplCategoriesTemp, 2, emplCategories, 0, emplCategories.length); + for (String emplCat: emplCategories) { + String code = emplCat + "_" + String.valueOf(comFAF3); + float coeff = factors.get(code); + for (int col = 3; col <= detEmpl.getColumnCount(); col++) { + empl += detEmpl.getValueAt(row, col) * coeff; + } + } + return empl; + } + + + private float getWeightedEmpl(int row, String comFAF, HashMap factors, float officeReduction) { + // calculate weighted employment based on make/use coefficients + float empl = 0; + for (String emp: empCats) { + String code = emp + "_" + comFAF; + float coeff = factors.get(code); + float factor = 1; + if (fafUtils.arrayContainsElement(emp, new String[]{"Information", "Financial Activities", + "Professional and Business Services", "Education and Health Services", + "Leisure and Hospitality"})) factor = officeReduction; + empl += countyIDsWithEmployment.getValueAt(row, emp) * coeff * factor; + } + return empl; + } + + + private HashMap getWeightedEmplByEmpl(int row, String comFAF, HashMap factors, float officeReduction) { + // calculate weighted employment based on make/use coefficients, keep information by employment type + + HashMap empl = new HashMap<>(); + float total = 0; + for (String emp: empCats) { + String code = emp + "_" + comFAF; + float coeff = factors.get(code); + float factor = 1; + if (fafUtils.arrayContainsElement(emp, new String[]{"Information", "Financial Activities", + "Professional and Business Services", "Education and Health Services", + "Leisure and Hospitality"})) factor = officeReduction; + float thisVal = countyIDsWithEmployment.getValueAt(row, emp) * coeff * factor; + empl.put(emp, thisVal); + total += thisVal; + } + empl.put("total", total); + return empl; + } + + + public double[][] disaggCountyToZones(float flow, double[] weightsA, double[] weightsB) { + // disaggregate flow from orig county A to orig zones i and dest county B to dest zones j + + // sum up weight products + double sm = 0; + for (double thisWeightsA : weightsA) { + for (double thisWeightsB : weightsB) { + sm += thisWeightsA * thisWeightsB; + } + } + // disaggregate flow + double[][] disFlow = new double[weightsA.length][weightsB.length]; + for (int i = 0; i < weightsA.length; i++) { + for (int j = 0; j < weightsB.length; j++) { + disFlow[i][j] = flow * weightsA[i] * weightsB[j] / sm; + } + } + return disFlow; + } + + + public static int getCountyId(int fips) { + // Return region code of regName + for (int i = 0; i < countyFips.length; i++) { + if (countyFips[i] == fips) return i; + } + logger.error("Could not find county FIPS code " + fips); + return -1; + } + + + public String[] getEmpCats() { + return empCats; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/fafUtils.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/fafUtils.java new file mode 100644 index 0000000..ee20bc4 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/fafUtils.java @@ -0,0 +1,331 @@ +package org.sandag.htm.processFAF; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.datafile.CSVFileReader; +import com.pb.common.util.ResourceUtil; + +import java.io.*; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.ResourceBundle; +import org.apache.log4j.Logger; + +/** + * Utilities to process FAF2 data + * User: Rolf Moeckel + * Date: May 6, 2009 + */ +public class fafUtils { + + private static Logger logger = Logger.getLogger(fafUtils.class); + private static ResourceBundle rb; + private static TableDataSet payloadSTCC; + private static TableDataSet payloadSCTG; + + public static TableDataSet importTable(String filePath) { + // read a csv file into a TableDataSet + TableDataSet tblData; + CSVFileReader cfrReader = new CSVFileReader(); + try { + tblData = cfrReader.readFile(new File( filePath )); + } catch (Exception e) { + throw new RuntimeException("File not found: <" + filePath + ">.", e); + } + cfrReader.close(); + return tblData; + } + + + public static ResourceBundle getResourceBundle(String pathToRb) { + File propFile = new File(pathToRb); + rb = ResourceUtil.getPropertyBundle(propFile); + if (rb == null) logger.fatal ("Problem loading resource bundle: " + pathToRb); + return rb; + } + + + public static void setResourceBundle (ResourceBundle appRb) { + rb = appRb; + } + + + public static PrintWriter openFileForSequentialWriting(String fileName) { + File outputFile = new File(fileName); + FileWriter fw = null; + try { + fw = new FileWriter(outputFile); + } catch (IOException e) { + logger.error("Could not open file <" + fileName + ">."); + } + BufferedWriter bw = new BufferedWriter(fw); + return new PrintWriter(bw); + } + + + public static HashMap createScalerHashMap (String[] tokens, double[] values) { + // create HashMap with state O-D pairs that need to be scaled + + HashMap scaler = new HashMap<>(); + if (tokens.length != values.length) { + throw new RuntimeException("Error. scaling.truck.trips.tokens must be same length as scaling.truck.trips.values"); + } + for (int i=0; i createScalerHashMap (TableDataSet scaleTable, String[] columnNames) { + // create HashMap with state O-D pairs that need to be scaled + + HashMap scaler = new HashMap<>(); + for (int row = 1; row < scaleTable.getRowCount(); row++) { + String token = String.valueOf((int) scaleTable.getValueAt(row, columnNames[0])) + "_" + + String.valueOf((int) scaleTable.getValueAt(row, columnNames[1])); + scaler.put(token, scaleTable.getValueAt(row, columnNames[2])); + } + return scaler; + } + + + public static int isOnPosition (String txt, String[] txtArray) { + // checks if txt is a value of txtArray + int position = -1; + for (int i = 0; i < txtArray.length; i++) if (txtArray[i].equals(txt)) position = i; + return position; + } + + + public static int[] createCountyFipsArray (int[] specRegCodes) { + // create array with county FIPS codes including special regions (such as airports) + + // Note: Used to readFAF2 employment from here, but should be done separately for each project +// disaggregateFlows.getUScountyEmploymentFromOneFile(appRb); + int[] countyFipsS = disaggregateFlows.countyIDsWithEmployment.getColumnAsInt( + disaggregateFlows.countyIDsWithEmployment.getColumnPosition("COUNTYFIPS")); + int[] countyFips = new int[countyFipsS.length + specRegCodes.length]; + System.arraycopy(countyFipsS, 0, countyFips, 0, countyFipsS.length); + System.arraycopy(specRegCodes, 0, countyFips, countyFipsS.length, specRegCodes.length); + return countyFips; + } + + + public static float findAveragePayload(String comm, String comClass) { + // returns average payload in tons per truck for commodity comm + + if (comm.equals("SCTG99")) comm = "SCTG42"; // FAF3 calls unknown SCTG99 instead of SCTG42 + TableDataSet payload = new TableDataSet(); + if (comClass.equals("STCC")) { + if (payloadSTCC == null) payloadSTCC = importTable(ResourceUtil.getProperty(rb, "truck.commodity.payload")); + payload = payloadSTCC; + } else if (comClass.equals("SCTG")) { + if (payloadSCTG == null) payloadSCTG = importTable(ResourceUtil.getProperty(rb, "truck.SCTG.commodity.payload")); + payload = payloadSCTG; + } + int n = -1; + for (int k = 1; k <= payload.getRowCount(); k++) { + if (payload.getStringValueAt(k, "Commodity").equals(comm)) n = k; + } + if (n == -1) { + logger.fatal("Commodity " + comm + " not found in payload factor file."); + System.exit(1); + } + // weight of each truck type, using an average for all commodities, derived from fhwa website + if (payload.containsColumn("Single Unit Trucks")) { + float[] weights = new float[] {0.307f, 0.155f, 0.269f, 0.269f}; // including pickups, minivans, other light vans, SUVs: 0.93642251f,0.022471435f,0.010687433f,0.030418621f + return (payload.getValueAt(n, "Single Unit Trucks") * weights[0]) + + (payload.getValueAt(n, "Semi Trailer") * weights[1]) + + (payload.getValueAt(n, "Double Trailers") * weights[2]) + + (payload.getValueAt(n, "Triples") * weights[3]); + } else { + return (payload.getValueAt(n, "Payload (lbs)") * (float) 0.0005); + } + } + + + public static void readPayloadFactors (ResourceBundle appRb) { + payloadSCTG = importTable(ResourceUtil.getProperty(appRb, "truck.SCTG.commodity.payload")); + } + + + public static float findAveragePayload(String comm) { + // returns average payload in tons per truck for commodity comm + + if (comm.equals("SCTG99")) comm = "SCTG42"; // FAF3 calls unknown SCTG99 instead of SCTG42 + int n = -1; + for (int k = 1; k <= payloadSCTG.getRowCount(); k++) { + if (payloadSCTG.getStringValueAt(k, "Commodity").equals(comm)) n = k; + } + if (n == -1) { + logger.fatal("Commodity " + comm + " not found in payload factor file."); + System.exit(1); + } + return (payloadSCTG.getValueAt(n, "Payload (lbs)") * (float) 0.0005); + } + + + public static int getEnumOrderNumber(ModesFAF mode) { + // return order number of mode + int num = 1; + for (ModesFAF thisMode: ModesFAF.values()) { + if (thisMode == mode) return num; + num++; + } + logger.warn("Could not find mode " + mode.toString()); + return 0; + } + + + public static ModesFAF getModeName (int mode) { + return ModesFAF.values()[mode - 1]; + } + + + public static int getHighestVal(int[] array) { + // return highest number in array + int high = Integer.MIN_VALUE; + for (int num: array) high = Math.max(high, num); + return high; + } + + + public static double sumArray (double[][] arr) { + // sum a two-dimensional double array + + double sum = 0; + for (double[] anArr : arr) { + for (int j = 0; j < arr[1].length; j++) { + sum += anArr[j]; + } + } + return sum; + } + + + public static TableDataSet createSpecialRegions(String[] specRegNames, String[] specRegModes, int[] specRegCodes, + int [] specRegZones, int[] specRegFAFCodes) { + // create TableDataSet with special regions + + if (specRegCodes.length != specRegNames.length || specRegCodes.length != specRegModes.length|| specRegCodes.length != specRegFAFCodes.length) { + logger.error ("Names of special regions and modes of special regions and codes of special regions and " + + "FAF codes of special regions all need to be of same length. No special regions created."); + return null; + } + TableDataSet specRegions = new TableDataSet(); + specRegions.appendColumn(specRegNames, "Name"); + specRegions.appendColumn(specRegCodes, "modelCode"); + specRegions.appendColumn(specRegZones, "modelZone"); + specRegions.appendColumn(specRegFAFCodes, "faf3code"); + specRegions.appendColumn(specRegModes, "mode"); + float[] dummyEmployment = new float[specRegCodes.length]; + for (int i = 0; i < dummyEmployment.length; i++) dummyEmployment[i] = 1; + specRegions.appendColumn(dummyEmployment, "Employment"); + return specRegions; + } + + + public static boolean countyFlowConnectsWithHawaii (int orig, int dest) { + // check if flow connects with Hawaii county + int oState = (int) (orig / 1000f); + int dState = (int) (dest / 1000f); + return oState == 15 || dState == 15; + } + + + public static boolean arrayContainsElement (String element, String[] array) { + // Check if Array contains Element + + boolean result = false; + for (String t: array) if (t.equals(element)) result = true; + return result; + } + + + public static int[] expandArrayByOneElement (int[] existing, int addElement) { + // create new array that has length of existing.length + 1 and copy values into new array + int[] expanded = new int[existing.length + 1]; + System.arraycopy(existing, 0, expanded, 0, existing.length); + expanded[expanded.length - 1] = addElement; + return expanded; + } + + + public static float[] expandArrayByOneElement (float[] existing, float addElement) { + // create new array that has length of existing.length + 1 and copy values into new array + float[] expanded = new float[existing.length + 1]; + System.arraycopy(existing, 0, expanded, 0, existing.length); + expanded[expanded.length - 1] = addElement; + return expanded; + } + + + public static String[] expandArrayByOneElement (String[] existing, String addElement) { + // create new array that has length of existing.length + 1 and copy values into new array + String[] expanded = new String[existing.length + 1]; + System.arraycopy(existing, 0, expanded, 0, existing.length); + expanded[expanded.length - 1] = addElement; + return expanded; + } + + + public static float rounder(float value, int digits) { + // rounds value to digits behind the decimal point + return Math.round(value * Math.pow(10, digits) + 0.5)/(float) Math.pow(10, digits); + } + + + public static String[] findUniqueElements (String[] list) { + // find unique elements in list[] and return string[] with these elements + + ArrayList unique = new ArrayList(); + for (String txt: list) { + if (!unique.contains(txt)) unique.add(txt); + } + String[] elements = new String[unique.size()]; + for (int i = 0; i < unique.size(); i++) elements[i] = unique.get(i); + return elements; + } + + + public static float getSum (float[] array) { + float sum = 0; + for (float val: array) sum += val; + return sum; + } + + public static double getSum (double[] array) { + double sum = 0; + for (double val: array) sum += val; + return sum; + } + + public static float getSum (float[][] array) { + float sum = 0; + for (float[] anArray : array) { + for (int j = 0; j < array[0].length; j++) sum += anArray[j]; + } + return sum; + } + + public static double getSum (double[][] array) { + double sum = 0; + for (double[] anArray : array) { + for (int j = 0; j < array[0].length; j++) sum += anArray[j]; + } + return sum; + } + + public static String[] getUniqueListOfValues (String[] list) { + // itentify unique list of value in list[] and return as shortened string list + ArrayList al = new ArrayList<>(); + for (String txt: list) { + if (!al.contains(txt) && txt != null) al.add(txt); + } + String[] shortenedList = new String[al.size()]; + for (int i = 0; i < al.size(); i++) { + shortenedList[i] = al.get(i); + } + return shortenedList; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/readFAF2.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/readFAF2.java new file mode 100644 index 0000000..658cc10 --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/readFAF2.java @@ -0,0 +1,547 @@ +package org.sandag.htm.processFAF; + +import org.apache.log4j.Logger; +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +import java.util.ResourceBundle; +import java.util.HashMap; + +/** + * This class reads FAF2 data and stores data in TableDataSets + * User: Rolf Moeckel + * Date: May 6, 2009 + */ + +public class readFAF2 { + + Logger logger = Logger.getLogger(readFAF2.class); + static public TableDataSet domRegionList; + static public TableDataSet rowRegionList; + static public String[] FAFzones; + static public String[] sctgCommodities; + static public String[] stccCommodities; + static private int highestDomRegion; + static public HashMap SCTGtoSTCCconversion; + static private HashMap sctgCode; + + private boolean referenceListsAreRead = false; + private TableDataSet domesticTonCommodityFlows; + private TableDataSet intBorderTonCommodityFlows; + private TableDataSet intSeaTonCommodityFlows; + private TableDataSet intAirTonCommodityFlows; + private TableDataSet domesticDollarCommodityFlows; + private TableDataSet intBorderDollarCommodityFlows; + private TableDataSet intSeaDollarCommodityFlows; + private TableDataSet intAirDollarCommodityFlows; + private int factor; + + + public void readCommodityList(ResourceBundle appRb) { + // read commodity names + TableDataSet sctgComList = fafUtils.importTable(ResourceUtil.getProperty(appRb, "faf2.sctg.commodity.list")); + sctgCommodities = new String[sctgComList.getRowCount()]; + for (int i = 1; i <= sctgComList.getRowCount(); i++) sctgCommodities[i-1] = sctgComList.getStringValueAt(i, "SCTG"); + } + + + public void readAllFAF2dataSets(ResourceBundle appRb, String unit) { + // read all FAF2 data into TableDataSets in unit (= tons or dollars) + if (unit.equals("tons")) { + domesticTonCommodityFlows = readDomesticCommodityFlows(appRb, unit); + intBorderTonCommodityFlows = readInternationalCommodityFlowsThroughLandBorder(appRb, unit); + intSeaTonCommodityFlows = readInternationalCommodityFlowsBySea(appRb, unit); + intAirTonCommodityFlows = readInternationalCommodityFlowsByAir(appRb, unit); + factor = 1000; // tons are in 1,000s + } else if (unit.equals("dollars")) { + domesticDollarCommodityFlows = readDomesticCommodityFlows(appRb, unit); + intBorderDollarCommodityFlows = readInternationalCommodityFlowsThroughLandBorder(appRb, unit); + intSeaDollarCommodityFlows = readInternationalCommodityFlowsBySea(appRb, unit); + intAirDollarCommodityFlows = readInternationalCommodityFlowsByAir(appRb, unit); + factor = 1000000; // dollars are in 1,000,000s + } else { + logger.error("Wrong token " + unit + " in method readAllFAF2dataSets. Use tons or dollars."); + } + } + + + public void adjustTruckFAF2data(ResourceBundle appRb, String mode, int[] years) { + // adjust FAF2 growth to exogenous adjustment + String fileName = appRb.getString("adjustment.of.faf." + mode); + logger.info("Adjusting FAF2 " + mode + " forecast to growth rate set in " + fileName); + TableDataSet adjust = fafUtils.importTable(fileName); + adjust.buildIndex(adjust.getColumnPosition("Year")); + for (int yr: years) { + float fafForecast = adjust.getIndexedValueAt(yr, "FAF2forecast"); + float adjForecast = adjust.getIndexedValueAt(yr, "AdjustedNumber"); + if (fafForecast == adjForecast) continue; + for (int row = 1; row <= domesticTonCommodityFlows.getRowCount(); row++) { + if (!domesticTonCommodityFlows.getStringValueAt(row, "Mode").equalsIgnoreCase(mode)) continue; + float value = domesticTonCommodityFlows.getValueAt(row, Integer.toString(yr)); + value = value * adjForecast / fafForecast; + domesticTonCommodityFlows.setValueAt(row, Integer.toString(yr), value); + } + for (int row = 1; row <= intBorderTonCommodityFlows.getRowCount(); row++) { + if (!intBorderTonCommodityFlows.getStringValueAt(row, "Mode").equalsIgnoreCase(mode)) continue; + float value = intBorderTonCommodityFlows.getValueAt(row, Integer.toString(yr)); + value = value * adjForecast / fafForecast; + intBorderTonCommodityFlows.setValueAt(row, Integer.toString(yr), value); + } + for (int row = 1; row <= intSeaTonCommodityFlows.getRowCount(); row++) { + if (!intSeaTonCommodityFlows.getStringValueAt(row, "Mode").equalsIgnoreCase(mode)) continue; + float value = intSeaTonCommodityFlows.getValueAt(row, Integer.toString(yr)); + value = value * adjForecast / fafForecast; + intSeaTonCommodityFlows.setValueAt(row, Integer.toString(yr), value); + } + for (int row = 1; row <= intAirTonCommodityFlows.getRowCount(); row++) { + if (!intAirTonCommodityFlows.getStringValueAt(row, "Mode").equalsIgnoreCase("Air & " + mode)) continue; + float value = intAirTonCommodityFlows.getValueAt(row, Integer.toString(yr)); + value = value * adjForecast / fafForecast; + intAirTonCommodityFlows.setValueAt(row, Integer.toString(yr), value); + } + } + } + + + public TableDataSet readDomesticCommodityFlows(ResourceBundle appRb, String unit) { + // read domestic FAF2 flows in unit (tons or dollars) + logger.info ("Reading domestic FAF2 data in " + unit); + + String fileName = ResourceUtil.getProperty(appRb, ("faf2.data.domestic." + unit)); + TableDataSet flows = fafUtils.importTable(fileName); + if (!referenceListsAreRead) { + readFAF2ReferenceLists(appRb); + referenceListsAreRead = true; + } + int[] originCodes = new int[flows.getRowCount()]; + int[] destinationCodes = new int[flows.getRowCount()]; + for (int i = 1; i <= flows.getRowCount(); i++) { + //find Origin and Destination codes + originCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Origin")); + destinationCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Destination")); + } + flows.appendColumn(originCodes, "OriginCode"); + flows.appendColumn(destinationCodes, "DestinationCode"); + return flows; + } + + + public static void readFAF2ReferenceLists(ResourceBundle appRb) { + // read reference lists for zones and commodities + domRegionList = fafUtils.importTable(ResourceUtil.getProperty(appRb, "faf2.region.list")); + rowRegionList = fafUtils.importTable(ResourceUtil.getProperty(appRb, "faf2.row.region.list")); + + highestDomRegion = 0; + for (int k = 1; k <= domRegionList.getRowCount(); k++) + highestDomRegion = Math.max((int) domRegionList.getValueAt(k, "RegionCode"), highestDomRegion); + int highestRegionOverAll = highestDomRegion; + for (int k = 1; k <= rowRegionList.getRowCount(); k++) + highestRegionOverAll = Math.max((int) rowRegionList.getValueAt(k, "ROWCode"), highestRegionOverAll); + FAFzones = new String[highestRegionOverAll + 1]; + for (int k = 1; k <= domRegionList.getRowCount(); k++) + FAFzones[(int) domRegionList.getValueAt(k, "RegionCode")] = domRegionList.getStringValueAt(k, "RegionName"); + for (int k = 1; k <= rowRegionList.getRowCount(); k++) + FAFzones[(int) rowRegionList.getValueAt(k, "ROWCode")] = rowRegionList.getStringValueAt(k, "ROWRegionName"); + + domRegionList.buildIndex(1); + rowRegionList.buildIndex(1); + + TableDataSet sctgNumber = fafUtils.importTable(ResourceUtil.getProperty(appRb, "faf2.commodity.reference")); + sctgCode = new HashMap(); + for (int i = 1; i <= sctgNumber.getRowCount(); i++) + sctgCode.put(sctgNumber.getStringValueAt(i, "FlowTableCategories"), (int) sctgNumber.getValueAt(i, "SCTG")); + + } + + + private int findZoneCode(String strZone) { + // find code of zone with name strZone + int zoneCode = -1; + // Domestic FAF zones + for (int k = 1; k <= domRegionList.getRowCount(); k++) + if (domRegionList.getStringValueAt(k, "RegionName").equals(strZone)) + zoneCode = (int) domRegionList.getValueAt(k, "RegionCode"); + // International FAF zones + if (zoneCode == -1) { + for (int k = 1; k <= rowRegionList.getRowCount(); k++) + if (rowRegionList.getStringValueAt(k, "ROWRegionName").equals(strZone)) + zoneCode = (int) rowRegionList.getValueAt(k, "ROWCode"); + } + if (zoneCode == -1) { + logger.error ("Unknown Zone in FAF2 data: " + strZone); + System.exit(1); + } + return zoneCode; + } + + + public HashMap getDomesticFlows(String mode, commodityClassType comClass, int yr, String unit) { + // extract domestic FAF2 flows + TableDataSet flowTbl; + if (unit.equals("tons")) { + flowTbl = domesticTonCommodityFlows; + } else { + flowTbl = domesticDollarCommodityFlows; + } + + HashMap hshFlows = new HashMap(); + for (int i = 1; i <= flowTbl.getRowCount(); i++) { + String thisMode = flowTbl.getStringValueAt(i, "Mode"); + if (!mode.equals("all") && !thisMode.equalsIgnoreCase(mode)) continue; + int origCode = (int) flowTbl.getValueAt(i, "OriginCode"); + int destCode = (int) flowTbl.getValueAt(i, "DestinationCode"); + float flows = flowTbl.getValueAt(i, Integer.toString(yr)) * factor; + String fafDataCommodity = flowTbl.getStringValueAt(i, "Commodity"); + int intSctgCommmodity = sctgCode.get(fafDataCommodity); + String sctgCommodity; + if (intSctgCommmodity <= 9) sctgCommodity = "SCTG0" + intSctgCommmodity; + else sctgCommodity = "SCTG" + intSctgCommmodity; + // report flows by STCC commodity classification + if (comClass.equals(commodityClassType.STCC)) { + for (String com: stccCommodities) { + float flowShare = SCTGtoSTCCconversion.get(sctgCommodity + "_" + com) * flows; + String code; + if (flowShare > 0) { + if (mode.equals("all")) { + code = origCode + "_" + destCode + "_" + com + "_" + thisMode; + } else { + code = origCode + "_" + destCode + "_" + com; + } + + if (hshFlows.containsKey(code)) flowShare += hshFlows.get(code); + hshFlows.put(code, flowShare); + } + } + } else { + // report flows by SCTG commodity classification + String code; + if (mode.equals("all")) { + code = origCode + "_" + destCode + "_" + sctgCommodity + "_" + thisMode; + } else { + code = origCode + "_" + destCode + "_" + sctgCommodity; + } + if (hshFlows.containsKey(code)) flows += hshFlows.get(code); + hshFlows.put(code, flows); + } + } + return hshFlows; + } + + + public TableDataSet readInternationalCommodityFlowsThroughLandBorder(ResourceBundle appRb, String unit) { + // read international FAF2 flows that cross the U.S. border by land in unit (tons or dollars) + logger.info ("Reading international FAF2 data crossing borders by land in " + unit); + + String fileName = ResourceUtil.getProperty(appRb, ("faf2.data.border." + unit)); + TableDataSet flows = fafUtils.importTable(fileName); + if (!referenceListsAreRead) { + readFAF2ReferenceLists(appRb); + referenceListsAreRead = true; + } + int[] originCodes = new int[flows.getRowCount()]; + int[] portOfEntryCodes = new int[flows.getRowCount()]; + int[] destinationCodes = new int[flows.getRowCount()]; + for (int i = 1; i <= flows.getRowCount(); i++) { + //find Origin and Destination codes + originCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Origin")); + portOfEntryCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "PortOfEntryExit")); + destinationCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Destination")); + } + flows.appendColumn(originCodes, "OriginCode"); + flows.appendColumn(portOfEntryCodes, "PortOfEntryCode"); + flows.appendColumn(destinationCodes, "DestinationCode"); + return flows; + } + + + public HashMap getIntBorderFlows(reportFormat repform, String mode, commodityClassType comClass, + int yr, String unit) { + // extract international FAF2 flows (international mode truck or train) + + TableDataSet flowTbl; + if (unit.equals("tons")) { + flowTbl = intBorderTonCommodityFlows; + } else { + flowTbl = intBorderDollarCommodityFlows; + } + + HashMap hshFlows = new HashMap(); + for (int i = 1; i <= flowTbl.getRowCount(); i++) { + String thisMode = flowTbl.getStringValueAt(i, "Mode"); + if (!mode.equals("all") && !thisMode.equals(mode)) continue; + int origCode = (int) flowTbl.getValueAt(i, "OriginCode"); + int destCode = (int) flowTbl.getValueAt(i, "DestinationCode"); + String strOrig = flowTbl.getStringValueAt(i, "Origin"); + String strDest = flowTbl.getStringValueAt(i, "Destination"); + int borderCode = (int) flowTbl.getValueAt(i, "PortOfEntryCode"); + // if flow goes from WA Blain to Canada with port of exit WA Blain, don't report domestic part. - Changed my mind, do report this flow +// if (repform == reportFormat.internat_domesticPart && (destCode == borderCode || origCode == borderCode)) continue; + if (repform == reportFormat.internat_domesticPart) { + boolean isCanadaOrMexico = checkIfMexicoOrCanada(strOrig); + if (isCanadaOrMexico) origCode = borderCode; + isCanadaOrMexico = checkIfMexicoOrCanada(strDest); + if (isCanadaOrMexico) destCode = borderCode; + } else if (repform == reportFormat.internat_internationalPart) { + boolean isCanadaOrMexico = checkIfMexicoOrCanada(strOrig); + if (isCanadaOrMexico) destCode = borderCode; + isCanadaOrMexico = checkIfMexicoOrCanada(strDest); + if (isCanadaOrMexico) origCode = borderCode; + } + // note that border flows are done differently than sea and air flows. Oregon has port and airports, that's + // why those flows are extracted separately. Oregon has no international border, therefore border flows are + // added to the US FAF region where the goods cross the border (unless reportFormat.internatOrigToDest has + // been chosen). + float flows = flowTbl.getValueAt(i, Integer.toString(yr)) * factor; + String fafDataCommodity = flowTbl.getStringValueAt(i, "Commodity"); + int intSctgCommmodity = sctgCode.get(fafDataCommodity); + String sctgCommodity; + if (intSctgCommmodity <= 9) sctgCommodity = "SCTG0" + intSctgCommmodity; + else sctgCommodity = "SCTG" + intSctgCommmodity; + if (comClass.equals(commodityClassType.STCC)) { + // report by STCC commodity classification + for (String com: stccCommodities) { + float flowShare = SCTGtoSTCCconversion.get(sctgCommodity + "_" + com) * flows; + if (flowShare > 0) { + String code; + if (mode.equals("all")) { + code = origCode + "_" + destCode + "_" + sctgCommodity + "_" + thisMode; + } else { + code = origCode + "_" + destCode + "_" + sctgCommodity; + } + if (hshFlows.containsKey(code)) flowShare += hshFlows.get(code); + hshFlows.put(code, flowShare); + } + } + } else { + // report by SCTG commodity classification + String code; + if (mode.equals("all")) { + code = origCode + "_" + destCode + "_" + sctgCommodity + "_" + thisMode; + } else { + code = origCode + "_" + destCode + "_" + sctgCommodity; + } + if (hshFlows.containsKey(code)) flows += hshFlows.get(code); + hshFlows.put(code, flows); + } + } + return hshFlows; + } + + + public TableDataSet readInternationalCommodityFlowsBySea(ResourceBundle appRb, String unit) { + // read international FAF2 flows that cross the U.S. border by sea in unit (tons or dollars) + logger.info ("Reading international FAF2 data by sea in " + unit); + + String fileName = ResourceUtil.getProperty(appRb, ("faf2.data.sea." + unit)); + TableDataSet flows = fafUtils.importTable(fileName); + if (!referenceListsAreRead) { + readFAF2ReferenceLists(appRb); + referenceListsAreRead = true; + } + int[] originCodes = new int[flows.getRowCount()]; + int[] portOfEntryCodes = new int[flows.getRowCount()]; + int[] destinationCodes = new int[flows.getRowCount()]; + for (int i = 1; i <= flows.getRowCount(); i++) { + //find Origin and Destination codes + originCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Origin")); + portOfEntryCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Port")); + destinationCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Destination")); + } + flows.appendColumn(originCodes, "OriginCode"); + flows.appendColumn(portOfEntryCodes, "PortCode"); + flows.appendColumn(destinationCodes, "DestinationCode"); + return flows; + } + + + public HashMap getIntSeaFlows (reportFormat repform, String mode, commodityClassType comClass, + int yr, String unit) { + // extract international FAF2 flows (international mode sea) + // If repform is set to internat_domesticPart port entry and exit points are set as negative origin or destination codes + + TableDataSet flowTbl; + if (unit.equals("tons")) { + flowTbl = intSeaTonCommodityFlows; + } else { + flowTbl = intSeaDollarCommodityFlows; + } + + HashMap hshFlows = new HashMap(); + for (int i = 1; i <= flowTbl.getRowCount(); i++) { + String thisMode = flowTbl.getStringValueAt(i, "Mode"); + if (!mode.equals("all") && !thisMode.equalsIgnoreCase(mode) && + repform != reportFormat.internat_internationalPart) continue; + if (!mode.equals("all") && !mode.equalsIgnoreCase("Water") && + repform == reportFormat.internat_internationalPart) continue; + int origCode = (int) flowTbl.getValueAt(i, "OriginCode"); + int destCode = (int) flowTbl.getValueAt(i, "DestinationCode"); + int portCode = -1 * (int) flowTbl.getValueAt(i, "PortCode"); + // if flow goes from Savannah GA to Europe with port of exit Savannah GA, don't report domestic part - changed my mind: do report this flow +// if (repform == reportFormat.internat_domesticPart && (destCode == -portCode || origCode == -portCode)) continue; + if (repform == reportFormat.internat_domesticPart) { + if (origCode > highestDomRegion && destCode <= highestDomRegion) + // from abroad to U.S. -> set origin to entry port + origCode = portCode; + else if (origCode <= highestDomRegion && destCode > highestDomRegion) + // from U.S. to abroad -> set destination to exit port + destCode = portCode; + else if (origCode > highestDomRegion && destCode > highestDomRegion) { + // from abroad through U.S. port to abroad + boolean origMexCan = checkIfMexicoOrCanada(flowTbl.getStringValueAt(i, "Origin")); + // from Mexico or Canada through U.S. port to Overseas -> set destination to exit port + if (origMexCan) destCode = portCode; + // from Overseas through U.S. port to Mexico or Canada -> set origin to entry port + else origCode = portCode; + // Note: if both origin and destination are MEX/CAN or both origin and destination are overseas, + // it is impossible to determine which part of the trips was made by mode mode, therefore it is + // reported as from abroad to abroad without noting the entry/exit port [seems not to exist in FAF2 data] + } + } else if (repform == reportFormat.internat_internationalPart) { + if (origCode > highestDomRegion && destCode <= highestDomRegion) + // from abroad to U.S. -> set destination to entry port + destCode = portCode; + else if (origCode <= highestDomRegion && destCode > highestDomRegion) + // from U.S. to abroad -> set origin to exit port + origCode = portCode; + else if (origCode > highestDomRegion && destCode > highestDomRegion) { + // from abroad through U.S. port to abroad + boolean origMexCan = checkIfMexicoOrCanada(flowTbl.getStringValueAt(i, "Origin")); + // from Mexico or Canada through U.S. port to Overseas -> set origin to exit port + if (origMexCan) origCode = portCode; + // from Overseas through U.S. port to Mexico or Canada -> set destination to entry port + else destCode = portCode; + // Note: if both origin and destination are MEX/CAN or both origin and destination are overseas, + // it is impossible to determine which part of the trips was made by mode mode, therefore it is + // reported as from abroad to abroad without noting the entry/exit port [seems not to exist in FAF2 data] + } + } + float flows = flowTbl.getValueAt(i, Integer.toString(yr)) * factor; + String fafDataCommodity = flowTbl.getStringValueAt(i, "Commodity"); + int intSctgCommmodity = sctgCode.get(fafDataCommodity); + String sctgCommodity; + if (intSctgCommmodity <= 9) sctgCommodity = "SCTG0" + intSctgCommmodity; + else sctgCommodity = "SCTG" + intSctgCommmodity; + if (comClass.equals(commodityClassType.STCC)) { + for (String com: stccCommodities) { + float flowShare = SCTGtoSTCCconversion.get(sctgCommodity + "_" + com) * flows; + if (flowShare > 0) { + String code; + if (mode.equals("all")) { + code = origCode + "_" + destCode + "_" + sctgCommodity + "_" + thisMode; + } else { + code = origCode + "_" + destCode + "_" + sctgCommodity; + } + if (hshFlows.containsKey(code)) flowShare += hshFlows.get(code); + hshFlows.put(code, flowShare); + } + } + } else { + // report by SCTG commodity classification + String code; + if (mode.equals("all")) { + code = origCode + "_" + destCode + "_" + sctgCommodity + "_" + thisMode; + } else { + code = origCode + "_" + destCode + "_" + sctgCommodity; + } + if (hshFlows.containsKey(code)) flows += hshFlows.get(code); + hshFlows.put(code, flows); + } + } + return hshFlows; + } + + + private boolean checkIfMexicoOrCanada (String name) { + // check if name is Canada or Mexico and return true or false + boolean contains = false; + if (name.equals("Canada") || name.equals("Mexico")) contains = true; + return contains; + } + + + public TableDataSet readInternationalCommodityFlowsByAir(ResourceBundle appRb, String unit) { + // read international FAF2 flows that cross the U.S. border by air in unit (tons or dollars) + logger.info ("Reading international FAF2 data by air in " + unit); + + String fileName = ResourceUtil.getProperty(appRb, ("faf2.data.air." + unit)); + TableDataSet flows = fafUtils.importTable(fileName); + if (!referenceListsAreRead) { + readFAF2ReferenceLists(appRb); + referenceListsAreRead = true; + } + int[] originCodes = new int[flows.getRowCount()]; + int[] portOfEntryCodes = new int[flows.getRowCount()]; + int[] destinationCodes = new int[flows.getRowCount()]; + for (int i = 1; i <= flows.getRowCount(); i++) { + //find Origin and Destination codes + originCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Origin")); + portOfEntryCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Coast")); + destinationCodes[i-1] = findZoneCode(flows.getStringValueAt(i, "Destination")); + } + flows.appendColumn(originCodes, "OriginCode"); + flows.appendColumn(portOfEntryCodes, "PortCode"); + flows.appendColumn(destinationCodes, "DestinationCode"); + return flows; + } + + + public HashMap getIntAirFlows(reportFormat repform, String mode, commodityClassType comClass, + int yr, String unit) { + // extract international FAF2 flows (international mode air) + // If repform is set to internat_domesticPart port entry and exit points are set as negative origin or destination codes + + TableDataSet flowTbl; + if (unit.equals("tons")) { + flowTbl = intAirTonCommodityFlows; + } else { + flowTbl = intAirDollarCommodityFlows; + } + + HashMap hshFlows = new HashMap(); + for (int i = 1; i <= flowTbl.getRowCount(); i++) { + // Note: Only mode "Air & Truck" is available in this data set + if (repform == reportFormat.internat_domesticPart && + !flowTbl.getStringValueAt(i, "Mode").equals(mode)) continue; + if (repform == reportFormat.internat_internationalPart && + !flowTbl.getStringValueAt(i, "Mode").equals("Air & Truck")) continue; + int origCode = (int) flowTbl.getValueAt(i, "OriginCode"); + int destCode = (int) flowTbl.getValueAt(i, "DestinationCode"); + int portCode = -1 * (int) flowTbl.getValueAt(i, "PortCode"); + // if flow goes from Houston TX to Europe with port of exit Houston TX, don't report domestic part - changed my mind: do report this flow +// if (repform == reportFormat.internat_domesticPart && (destCode == -portCode || origCode == -portCode)) continue; + if (origCode <= highestDomRegion || destCode <= highestDomRegion) { + // this should be the case for every record, there should be no international to international records + if (repform == reportFormat.internat_domesticPart) { + if (origCode > highestDomRegion) origCode = portCode; + if (destCode > highestDomRegion) destCode = portCode; + } else if (repform == reportFormat.internat_internationalPart) { + if (origCode > highestDomRegion) destCode = portCode; + if (destCode > highestDomRegion) origCode = portCode; + } + } + float flows = flowTbl.getValueAt(i, Integer.toString(yr)) * factor; + String fafDataCommodity = flowTbl.getStringValueAt(i, "Commodity"); + int intSctgCommmodity = sctgCode.get(fafDataCommodity); + String sctgCommodity; + if (intSctgCommmodity <= 9) sctgCommodity = "SCTG0" + intSctgCommmodity; + else sctgCommodity = "SCTG" + intSctgCommmodity; + if (comClass.equals(commodityClassType.STCC)) { + for (String com: stccCommodities) { + float flowShare = SCTGtoSTCCconversion.get(sctgCommodity + "_" + com) * flows; + if (flowShare > 0) { + String code = origCode + "_" + destCode + "_" + com; + if (hshFlows.containsKey(code)) flowShare += hshFlows.get(code); + hshFlows.put(code, flowShare); + } + } + } else { + // report by SCTG commodity classification + String code = origCode + "_" + destCode + "_" + sctgCommodity; + if (hshFlows.containsKey(code)) flows += hshFlows.get(code); + hshFlows.put(code, flows); + } + + } + return hshFlows; + } +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/readFAF3.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/readFAF3.java new file mode 100644 index 0000000..615d08b --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/readFAF3.java @@ -0,0 +1,520 @@ +package org.sandag.htm.processFAF; + +import org.apache.log4j.Logger; + +import java.util.ResourceBundle; +import java.util.HashMap; +import java.io.PrintWriter; + +import com.pb.common.datafile.TableDataSet; +import com.pb.common.util.ResourceUtil; + +/** + * This class reads FAF3 data and stores data in a TableDataSet + * Author: Rolf Moeckel, PB + * Date: September 9, 2010 + */ + +public class readFAF3 { + Logger logger = Logger.getLogger(readFAF3.class); + private int factor; + private String[] valueColumnName; + private TableDataSet faf3commodityFlows; + public static TableDataSet fafRegionList; + private String[] regionState; + private static int[] domRegionIndex; + static public int[] sctgCommodities; + static public String[] sctgStringCommodities; + static private int[] sctgStringIndex; + private static HashMap portsOfEntry; + private static HashMap marinePortsOfEntry; + private static HashMap railPortsOfEntry; + private static HashMap airPortsOfEntry; + private static int[] listOfBorderPortOfEntries; + + + public void readAllData (ResourceBundle appRb, int year, String unit) { + // read input data + + if (ResourceUtil.getBooleanProperty(appRb, "read.in.raw.faf.data", true)) + readAllFAF3dataSets(appRb, unit, year); + readCommodityList(appRb); + readFAF3referenceLists(appRb); + } + + + public void readCommodityList(ResourceBundle appRb) { + // read commodity names + TableDataSet sctgComList = fafUtils.importTable(ResourceUtil.getProperty(appRb, "faf3.sctg.commodity.list")); + sctgCommodities = new int[sctgComList.getRowCount()]; + sctgStringCommodities = new String[sctgCommodities.length]; + for (int i = 1; i <= sctgComList.getRowCount(); i++) { + sctgCommodities[i-1] = (int) sctgComList.getValueAt(i, "SCTG"); + if (sctgCommodities[i-1] < 10) sctgStringCommodities[i-1] = "SCTG0" + sctgCommodities[i-1]; + else sctgStringCommodities[i-1] = "SCTG" + sctgCommodities[i-1]; + } + sctgStringIndex = new int[fafUtils.getHighestVal(sctgCommodities) + 1]; + for (int num = 0; num < sctgCommodities.length; num++) sctgStringIndex[sctgCommodities[num]] = num; + } + + + public int getIndexOfCommodity (int commodity) { + return sctgStringIndex[commodity]; + } + + + public static String getSCTGname(int sctgInt) { + // get String name from sctg number + return sctgStringCommodities[sctgStringIndex[sctgInt]]; + } + + + public static String getFAFzoneName(int fafInt) { + // get String name from int FAF zone code number + return fafRegionList.getStringValueAt(domRegionIndex[fafInt], "FAF3 Zones -Short Description"); + } + + + public static String getFAFzoneState(int fafInt) { + // get String two-letter abbreviation of state of fafInt + return fafRegionList.getStringValueAt(domRegionIndex[fafInt], "State"); + } + + + public void definePortsOfEntry(ResourceBundle appRb) { + // read data to translate ports of entry in network links + + // Border crossings + portsOfEntry = new HashMap<>(); + TableDataSet poe = fafUtils.importTable(appRb.getString("ports.of.entry")); + for (int row = 1; row <= poe.getRowCount(); row++) { + int fafID = (int) poe.getValueAt(row, "faf3id"); + int node = (int) poe.getValueAt(row, "pointOfEntry"); + float weight = poe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (portsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = portsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + portsOfEntry.put(fafID, newPortsOfEntry); + } + listOfBorderPortOfEntries = poe.getColumnAsInt("pointOfEntry"); + + // Marine ports + marinePortsOfEntry = new HashMap<>(); + if (appRb.containsKey("marine.ports.of.entry")) { + TableDataSet mpoe = fafUtils.importTable(appRb.getString("marine.ports.of.entry")); + for (int row = 1; row <= mpoe.getRowCount(); row++) { + int fafID = (int) mpoe.getValueAt(row, "faf3id"); + int node = (int) mpoe.getValueAt(row, "pointOfEntry"); + float weight = mpoe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (marinePortsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = marinePortsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + marinePortsOfEntry.put(fafID, newPortsOfEntry); + } + } + // Rail ports (railyards) + railPortsOfEntry = new HashMap<>(); + if (appRb.containsKey("rail.ports.of.entry")) { + TableDataSet rpoe = fafUtils.importTable(appRb.getString("rail.ports.of.entry")); + for (int row = 1; row <= rpoe.getRowCount(); row++) { + int fafID = (int) rpoe.getValueAt(row, "faf3id"); + int node = (int) rpoe.getValueAt(row, "pointOfEntry"); + float weight = rpoe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (railPortsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = railPortsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + railPortsOfEntry.put(fafID, newPortsOfEntry); + } + } + // Airports + airPortsOfEntry = new HashMap<>(); + if (appRb.containsKey("air.ports.of.entry")) { + TableDataSet apoe = fafUtils.importTable(appRb.getString("air.ports.of.entry")); + for (int row = 1; row <= apoe.getRowCount(); row++) { + int fafID = (int) apoe.getValueAt(row, "faf3id"); + int node = (int) apoe.getValueAt(row, "pointOfEntry"); + float weight = apoe.getValueAt(row, "weight"); + TableDataSet newPortsOfEntry = new TableDataSet(); + if (airPortsOfEntry.containsKey(fafID)) { + TableDataSet existingNodes = airPortsOfEntry.get(fafID); + int[] nodes = existingNodes.getColumnAsInt("COUNTYFIPS"); // use same column labels as for + float[] weights = existingNodes.getColumnAsFloat("Employment"); //county TableDataSets to ease disaggregation + int[] newNodes = fafUtils.expandArrayByOneElement(nodes, node); + float[] newWeights = fafUtils.expandArrayByOneElement(weights, weight); + newPortsOfEntry.appendColumn(newNodes, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(newWeights, "Employment"); + } else { + newPortsOfEntry.appendColumn(new int[]{node}, "COUNTYFIPS"); + newPortsOfEntry.appendColumn(new float[]{weight}, "Employment"); + } + airPortsOfEntry.put(fafID, newPortsOfEntry); + } + } + } + + + public static int[] getListOfBorderPortOfEntries() { + return listOfBorderPortOfEntries; + } + + + + public static TableDataSet getPortsOfEntry (int fafZone) { + // return list of ports of entry if available, otherwise return fafZone + if (portsOfEntry.containsKey(fafZone)) return portsOfEntry.get(fafZone); + else return null; + } + + + public static TableDataSet getMarinePortsOfEntry (int fafZone) { + // return list of ports of entry if available, otherwise return fafZone + if (marinePortsOfEntry.containsKey(fafZone)) return marinePortsOfEntry.get(fafZone); + else return null; + } + + + public static TableDataSet getAirPortsOfEntry (int fafZone) { + // return list of ports of entry if available, otherwise return fafZone + if (airPortsOfEntry.containsKey(fafZone)) return airPortsOfEntry.get(fafZone); + else return null; + } + + + public void readAllFAF3dataSets2007(ResourceBundle appRb, String unit) { + // read all FAF3 data into TableDataSets in unit (= tons or dollars) + + logger.info ("Reading domestic FAF3 data in " + unit); + if (unit.equals("tons")) { + factor = 1000; // tons are in 1,000s + valueColumnName = new String[]{"tons_2007"}; + } else if (unit.equals("dollars")) { + factor = 1000000; // dollars are in 1,000,000s + valueColumnName = new String[]{"value_2007"}; + } else { + logger.fatal ("Wrong token " + unit + " in method readAllFAF3dataSets2007. Use tons or dollars."); + } + faf3commodityFlows = readFAF3commodityFlows(appRb, unit); + } + + + public double[] summarizeFlowByCommodity (ModesFAF fafMode) { + // sum commodity flows by commodity and return array with total tons + + double[] totalFlows = new double[sctgCommodities.length]; + int modeNum = fafUtils.getEnumOrderNumber(fafMode); + for (int row = 1; row <= faf3commodityFlows.getRowCount(); row++) { + if (faf3commodityFlows.getValueAt(row, "dms_mode") != modeNum) continue; + int com = sctgStringIndex[(int) faf3commodityFlows.getValueAt(row, "sctg2")]; + if (valueColumnName.length == 1) { + // use year provided by user + totalFlows[com] += faf3commodityFlows.getValueAt(row, valueColumnName[0]); + } else { + // interpolate between two years + float val1 = faf3commodityFlows.getValueAt(row, valueColumnName[0]); + float val2 = faf3commodityFlows.getValueAt(row, valueColumnName[1]); + totalFlows[com] += val1 + (val2 - val1) * Float.parseFloat(valueColumnName[2]); + } + } + return totalFlows; + } + + + public void readAllFAF3dataSets(ResourceBundle appRb, String unit, int year) { + // read all FAF3 data into TableDataSets in unit (= tons or dollars) + + logger.info (" Reading FAF3 data in " + unit); + switch (unit) { + case "tons": + factor = 1000; // tons are provided in 1,000s + break; + case "dollars": + factor = 1000000; // dollars are provided in 1,000,000s + break; + default: + logger.fatal("Wrong token " + unit + " in method readAllFAF3dataSets. Use tons or dollars."); + System.exit(0); + } + int[] availYears = {2007, 2015, 2020, 2025, 2030, 2035, 2040}; + boolean yearInFaf = false; + for (int y: availYears) if (year == y) yearInFaf = true; + if (!yearInFaf) { // interpolate between two years + logger.info(" Year " + year + " does not exist in FAF3 data."); + int year1 = 2007; + int year2 = 2040; + for (int availYear : availYears) if (availYear < year) year1 = availYear; + for (int i = availYears.length - 1; i >= 0; i--) if (availYears[i] > year) year2 = availYears[i]; + logger.info(" FAF3 data are interpolated between " + year1 + " and " + year2 + "."); + // first position: lower year, second position: higher year, third position: steps away from lower year + valueColumnName = new String[]{unit + "_" + year1, unit + "_" + year2, String.valueOf((1f * (year - year1)) / (1f * (year2 - year1)))}; + } else { // use year provided by user + valueColumnName = new String[]{unit + "_" + year}; + } + faf3commodityFlows = readFAF3commodityFlows(appRb, unit); + } + + + private TableDataSet readFAF3commodityFlows(ResourceBundle appRb, String unit) { + // read FAF3 data and return TableDataSet with flow data + String fileName = ResourceUtil.getProperty(appRb, ("faf3.data")); + return fafUtils.importTable(fileName); + } + + + public HashMap createScaler(String[] tokens, double[] values) { + // create HashMap with state O-D pairs that need to be scaled + + HashMap scaler = new HashMap(); + if (tokens.length != values.length) { + throw new RuntimeException("Error. scaling.truck.trips.tokens must be same length as scaling.truck.trips.values"); + } + for (int i=0; i scaler) { + // extract truck flows for year yr and scale flows according to scaler HashMap (no special regions specified) + + PrintWriter outFile = fafUtils.openFileForSequentialWriting(outFileName); + outFile.println("originFAF,destinationFAF,flowDirection," + commodityClassType.SCTG + "_commodity,shortTons"); + int modeNum = fafUtils.getEnumOrderNumber(mode); + for (int row = 1; row <= faf3commodityFlows.getRowCount(); row++) { + int type = (int) faf3commodityFlows.getValueAt(row, "trade_type"); + double val; + if (valueColumnName.length == 1) { + // use year provided by user + val = faf3commodityFlows.getValueAt(row, valueColumnName[0]); + } else { + // interpolate between two years + float val1 = faf3commodityFlows.getValueAt(row, valueColumnName[0]); + float val2 = faf3commodityFlows.getValueAt(row, valueColumnName[1]); + val = val1 + (val2 - val1) * Float.parseFloat(valueColumnName[2]); + } + val *= factor * odScaler(row, type, scaler); + if (val == 0) continue; + if (type == 1) writeDomesticFlow(modeNum, val, row, outFile); + else if (type == 2) writeImportFlow(modeNum, val, row, outFile, repF); + else if (type == 3) writeExportFlow(modeNum, val, row, outFile, repF); + else if (type == 4) writeThroughFlow(modeNum, val, row, outFile, repF); + else logger.info("Invalid trade_type in FAF3 dataset in row " + row + ": " + type); + } + outFile.close(); + } + + + public void writeFlowsByModeAndCommodity (String outFileName, ModesFAF mode, reportFormat repF, + HashMap scaler) { + // extract truck flows for year yr and scale flows according to scaler HashMap, including special regions + + PrintWriter outFile[] = new PrintWriter[sctgCommodities.length]; + for (int com: sctgCommodities) { + String fileName; + if (com < 10) fileName = outFileName + "_SCTG0" + com + ".csv"; + else fileName = outFileName + "_SCTG" + com + ".csv"; + outFile[sctgStringIndex[com]] = fafUtils.openFileForSequentialWriting(fileName); + outFile[sctgStringIndex[com]].println("originFAF,destinationFAF,flowDirection,SCTG_commodity,shortTons"); + } + int modeNum = fafUtils.getEnumOrderNumber(mode); + for (int row = 1; row <= faf3commodityFlows.getRowCount(); row++) { + int type = (int) faf3commodityFlows.getValueAt(row, "trade_type"); + double val; + if (valueColumnName.length == 1) { + // use year provided by user + val = faf3commodityFlows.getValueAt(row, valueColumnName[0]); + } else { + // interpolate between two years + float val1 = faf3commodityFlows.getValueAt(row, valueColumnName[0]); + float val2 = faf3commodityFlows.getValueAt(row, valueColumnName[1]); + val = val1 + (val2 - val1) * Float.parseFloat(valueColumnName[2]); + } + val *= factor * odScaler(row, type, scaler); + if (val == 0) continue; + int comIndex = getIndexOfCommodity((int) faf3commodityFlows.getValueAt(row, "sctg2")); + if (type == 1) writeDomesticFlow(modeNum, val, row, outFile[comIndex]); + else if (type == 2) writeImportFlow(modeNum, val, row, outFile[comIndex], repF); + else if (type == 3) writeExportFlow(modeNum, val, row, outFile[comIndex], repF); + else if (type == 4) writeThroughFlow(modeNum, val, row, outFile[comIndex], repF); + else logger.info("Invalid trade_type in FAF3 dataset in row " + row + ": " + type); + } + for (int com: sctgCommodities) outFile[sctgStringIndex[com]].close(); + } + + + public float odScaler (int row, int type, HashMap scaler) { + // find scaler for origin destination pair in row + + int orig; + int dest; + if (type == 1) { + orig = (int) faf3commodityFlows.getValueAt(row, "dms_orig"); + dest = (int) faf3commodityFlows.getValueAt(row, "dms_dest"); + } else if (type == 2) { + orig = (int) faf3commodityFlows.getValueAt(row, "fr_orig"); + dest = (int) faf3commodityFlows.getValueAt(row, "dms_dest"); + } else if (type == 3) { + orig = (int) faf3commodityFlows.getValueAt(row, "dms_orig"); + dest = (int) faf3commodityFlows.getValueAt(row, "fr_dest"); + } else { + orig = (int) faf3commodityFlows.getValueAt(row, "fr_orig"); + dest = (int) faf3commodityFlows.getValueAt(row, "fr_dest"); + } + String stateLevelToken = regionState[orig] + "_" + regionState[dest]; + String combo1Token = orig + "_" + regionState[dest]; + String combo2Token = regionState[orig] + "_" + dest; + String fafLevelToken = orig + "_" + dest; + float adj = 1; + if (scaler.containsKey(stateLevelToken)) adj = scaler.get(stateLevelToken); + if (scaler.containsKey(combo1Token)) adj = scaler.get(combo1Token); + if (scaler.containsKey(combo2Token)) adj = scaler.get(combo2Token); + if (scaler.containsKey(fafLevelToken)) adj = scaler.get(fafLevelToken); + return adj; + } + + + private int tryGettingThisValue(int row, String token) { + // for some flows, international zones/modes are empty -> catch this case and set zone to 0 + + int region; + try { + region = (int) faf3commodityFlows.getValueAt(row, token); + } catch (Exception e) { + region = 0; + } + return region; + } + + + public void writeDomesticFlow (int modeNum, double val, int row, PrintWriter outFile) { + // internal US flow + if (faf3commodityFlows.getValueAt(row, "dms_mode") == modeNum) { + int orig = (int) faf3commodityFlows.getValueAt(row, "dms_orig"); + int dest = (int) faf3commodityFlows.getValueAt(row, "dms_dest"); + int comm = (int) faf3commodityFlows.getValueAt(row, "sctg2"); + outFile.println(orig + "," + dest + ",domestic," + comm + "," + val); + } + } + + + public void writeImportFlow (int modeNum, double val, int row, PrintWriter outFile, reportFormat repF) { + // from abroad to US + + int frInMode = (int) faf3commodityFlows.getValueAt(row, "fr_inmode"); + int borderZone = (int) faf3commodityFlows.getValueAt(row, "dms_orig"); + int comm = (int) faf3commodityFlows.getValueAt(row, "sctg2"); + if (frInMode == modeNum && repF != reportFormat.internat_domesticPart) { + int orig = tryGettingThisValue(row, "fr_orig"); + outFile.println(orig + "," + borderZone + ",import," + comm + "," + val); + } + if (faf3commodityFlows.getValueAt(row, "dms_mode") == modeNum) { + int dest = (int) faf3commodityFlows.getValueAt(row, "dms_dest"); + String txt; + if (frInMode == fafUtils.getEnumOrderNumber(ModesFAF.Water)) txt = ",import_port,"; + else if (frInMode == fafUtils.getEnumOrderNumber(ModesFAF.Rail)) txt = ",import_rail,"; + else if (frInMode == fafUtils.getEnumOrderNumber(ModesFAF.Air)) txt = ",import_airport,"; + else txt = ",import,"; + outFile.println(borderZone + "," + dest + txt + comm + "," + val); + } + } + + + public void writeExportFlow (int modeNum, double val, int row, PrintWriter outFile, reportFormat repF) { + // from US to abroad + int frOutMode = tryGettingThisValue(row, "fr_outmode"); + int borderZone = (int) faf3commodityFlows.getValueAt(row, "dms_dest"); + int comm = (int) faf3commodityFlows.getValueAt(row, "sctg2"); + if (frOutMode == modeNum && repF != reportFormat.internat_domesticPart) { + int dest = tryGettingThisValue(row, "fr_dest"); + outFile.println(borderZone + "," + dest + ",export," + comm + "," + val); + } + if (faf3commodityFlows.getValueAt(row, "dms_mode") == modeNum) { + int orig = (int) faf3commodityFlows.getValueAt(row, "dms_orig"); + String txt = ",export,"; + if (frOutMode == fafUtils.getEnumOrderNumber(ModesFAF.Water)) txt = ",export_port,"; + if (frOutMode == fafUtils.getEnumOrderNumber(ModesFAF.Rail)) txt = ",export_rail,"; + if (frOutMode == fafUtils.getEnumOrderNumber(ModesFAF.Air)) txt = ",export_airport,"; + outFile.println(orig + "," + borderZone + txt + comm + "," + val); + } + } + + + public void writeThroughFlow(int modeNum, double val, int row, PrintWriter outFile, reportFormat repF) { + // flows in transit through US + if ((int) faf3commodityFlows.getValueAt(row, "dms_mode") != modeNum) return; + int borderInZone = (int) faf3commodityFlows.getValueAt(row, "dms_orig"); + int borderOutZone = (int) faf3commodityFlows.getValueAt(row, "dms_dest"); + logger.warn("Through flows not yet implemented. This flow from " + borderInZone + " to " + borderOutZone + " is lost."); + } + + + public void readFAF3referenceLists(ResourceBundle rb) { + // read list of regions for FAF3 + String regFileName = rb.getString("faf3.region.list"); + fafRegionList = fafUtils.importTable(regFileName); + int[] reg = fafRegionList.getColumnAsInt(fafRegionList.getColumnPosition("ZoneID")); + domRegionIndex = new int[fafUtils.getHighestVal(reg) + 1]; + for (int num = 0; num < reg.length; num++) domRegionIndex[reg[num]] = num + 1; + regionState = new String[fafUtils.getHighestVal(reg) + 1]; + for (int row = 1; row <= fafRegionList.getRowCount(); row++) { + int zone = (int) fafRegionList.getValueAt(row, "ZoneID"); + regionState[zone] = fafRegionList.getStringValueAt(row, "State"); + } + } + + + public int[] getFAFzoneIDs () { + return fafRegionList.getColumnAsInt("ZoneID"); + } + + + public TableDataSet getFAF3flows() { + return faf3commodityFlows; + } + + + public int getFactor() { + return factor; + } + + + public TableDataSet getFaf3commodityFlows() { + return faf3commodityFlows; + } + + + public String[] getValueColumnName() { + return valueColumnName; + } + +} diff --git a/sandag_abm/src/main/java/org/sandag/htm/processFAF/reportFormat.java b/sandag_abm/src/main/java/org/sandag/htm/processFAF/reportFormat.java new file mode 100644 index 0000000..a33927a --- /dev/null +++ b/sandag_abm/src/main/java/org/sandag/htm/processFAF/reportFormat.java @@ -0,0 +1,23 @@ +package org.sandag.htm.processFAF; + +/** + * Defines reporting method + * internationalByEntryPoint reports international flows + * internat_domesticPart = International flow from port of entry to final domestic destination or from + * domestic origin to port of exit + * internat_internationalPart = International flow from foreign origin to port of entry or from port of exit to + * foreign destination + * internatOrigToDest = International flow from foreign origin to domestic destination or from domestic + * origin to foreign destination + * internatOrigToBorderToDest = International flow from origin to port of entry/port of exit to destination (2 flows) + * + * User: Rolf Moeckel, PB New York + * Date: May 7, 2009 + */ + +public enum reportFormat { + internat_domesticPart, + internat_internationalPart, + internatOrigToDest, + internatOrigToBorderToDest, +} diff --git a/sandag_abm/src/main/python/assignScenarioID.py b/sandag_abm/src/main/python/assignScenarioID.py new file mode 100644 index 0000000..0571fe4 --- /dev/null +++ b/sandag_abm/src/main/python/assignScenarioID.py @@ -0,0 +1,27 @@ +import os +import glob +import pandas as pd +import pyodbc + +toolpath = os.getcwd()[3:-7] + +conn = pyodbc.connect("DRIVER={SQL Server};" + "SERVER=DDAMWSQL16;" + "DATABASE=abm_14_2_0;" + "Trusted_Connection=yes;") +sql = ("SELECT * FROM [abm_14_2_0].[dimension].[scenario] where RIGHT(path, len(path)-23) = '%s'" % toolpath) +df_sql = pd.read_sql_query(sql, conn) +scenid = df_sql['scenario_id'].max() +list = glob.glob(os.getcwd()[:-6]+'report\\hwyload*') +list_shape = glob.glob(os.getcwd()[:-6]+'report\\hwyload*.shp') + +if len(list_shape) and len(df_sql): + for item in list: + if 'csv' not in item: + try: + os.rename(item, os.getcwd()[:-6]+'report\\hwyLoad_'+ str(scenid) + item[-4:]) + except Exception as error: + print('Caught this error: ' + repr(error)) + print ('The scenaio ID has been added to the shapefile.') +else: + print ("Cannot find the scenario in the SQ database or hwyloadshape file is not available. Please check...") \ No newline at end of file diff --git a/sandag_abm/src/main/python/calculate_micromobility.py b/sandag_abm/src/main/python/calculate_micromobility.py new file mode 100644 index 0000000..a277359 --- /dev/null +++ b/sandag_abm/src/main/python/calculate_micromobility.py @@ -0,0 +1,273 @@ +#!/usr/bin/env python3 +# -*- coding: utf-8 -*- +# Author: RSG Inc. +"""calculate_micromobility.py + +This Python 3 script calculates Generalized Time between MGRAs for micromobility +and microtransit modes in the SANDAG activity-based model. + +Constants are read from the properties file specified at the command line. + +Currently this script uses three files to perform its calculations: + - mgra.socec.file, contains MicroAccessTime for origin MRGAs + - active.logsum.matrix.file.walk.mgra, contains the pre-calculated + walk times between MGRAs + - active.logsum.matrix.file.walk.mgratap, contains the pre-calculated + walk times from MGRAs to TAPs + - active.microtransit.tap.file, contains a list of TAPs with microtransit availability + - active.microtransit.mgra.file, contains a list of MGRAs with microtransit availability + + +The script then writes a fresh MGRA file with the newly calculated micromobility calculations: + - walkTime: the original walk time + - mmTime: the micro-mobility time, including travel time, rental time, access time + - mmCost: micro-mobility variable cost * travel time + fixed cost + - mmGenTime: mmTime + mmCost converted to time + constant + - mtTime: the micro-transit time, including travel time, wait time, access time + - mtCost: micro-transit variable cost * travel time + fixed cost + - minTime: minimum of walkTime, mmGenTime, and mtGenTime + +Run `python calculate_micromobility.py -h` for more command-line usage. +""" + +import argparse +import os +import pandas as pd + + +def process_file(config, zone): + """Performs micromobility calculations using given output_file + and attributes from the provided MGRA file and properties file + + Writes newly calculated micromobility time and intermediate calculations + """ + + filename = config.walk_mgra_output_file if zone == 'mgra' else config.walk_mgra_tap_output_file + + output_file = os.path.join(config.cli.outputs_directory, filename) + config.validate_file(output_file) + + if zone == 'mgra': + walk_time_col = 'actual' + orig_col = 'i' + dest_col = 'j' + + else: + walk_time_col = 'boardingActual' + orig_col = 'mgra' + dest_col = 'tap' + + print('Processing %s ...' % output_file) + df = pd.read_csv(output_file, usecols=[walk_time_col, orig_col, dest_col]) + df.rename(columns={walk_time_col:'walkTime'}, inplace=True) + + # OD vectors + length = df['walkTime'] / config.walk_coef + + # availability masks + if zone == 'mgra': + mt_avail = \ + (df[orig_col].isin(config.mt_mgras) & df[dest_col].isin(config.mt_mgras)) & \ + (length <= config.mt_max_dist_mgra) + + walk_avail = length <= config.walk_max_dist_mgra + mm_avail = length <= config.mm_max_dist_mgra + + else: + mt_avail = \ + df[orig_col].isin(config.mt_mgras) & df[dest_col].isin(config.mt_taps) & \ + (length <= config.mt_max_dist_tap) + walk_avail = length <= config.walk_max_dist_tap + mm_avail = length <= config.mm_max_dist_tap + + all_rows = df.shape[0] + df = df[mt_avail | walk_avail | mm_avail] + print('Filtered out %s unavailable pairs' % str(all_rows - df.shape[0])) + + # micro-mobility + mm_ivt = length * 60 / config.mm_speed # micro-mobility in-vehicle time + orig_mat = df[orig_col].map(config.mat) # micro-access time at origin + mm_time = mm_ivt + config.mm_rental_time + orig_mat # total mm time + mm_cost = config.mm_variable_cost * mm_ivt + config.mm_fixed_cost + mm_cost_as_time = mm_cost * 60 / config.vot + + # micro-transit + mt_ivt = length * 60 / config.mt_speed + mt_time = mt_ivt + 2 * config.mt_wait_time + config.mt_access_time + mt_cost = mt_time * config.mt_variable_cost + config.mt_fixed_cost + mt_cost_as_time = mt_cost * 60 / config.vot + + # save intermediate calculations + df['dist'] = length + df['mmTime'] = mm_time + df['mmCost'] = mm_cost + df['mtTime'] = mt_time + df['mtCost'] = mt_cost + + # calculate micromobility and microtransit Generalized Time + df['mmGenTime'] = mm_time + mm_cost_as_time + config.mm_constant + df['mtGenTime'] = mt_time + mt_cost_as_time + config.mt_constant + + # update zones with unavailable walk, micromobility, and microtransit + df.loc[~walk_avail, ['walkTime']] = config.mt_not_avail + df.loc[~mm_avail, ['mmTime', 'mmCost', 'mmGenTime']] = config.mt_not_avail + df.loc[~mt_avail, ['mtTime', 'mtCost', 'mtGenTime']] = config.mt_not_avail + + # calculate the minimum of walk time vs. generalized time + df['minTime'] = df[['walkTime', 'mmGenTime', 'mtGenTime']].min(axis=1) + + # write output + outfile = os.path.join( + config.cli.outputs_directory, + os.path.basename(output_file).replace('walk', 'micro') + ) + + print("Writing final table to %s" % outfile) + df.to_csv(outfile, index=False) + print("Done.") + + +class Config(): + + def __init__(self): + + self.init_cli_args() + self.init_properties() + self.init_micro_access_time() + self.init_tap_mgra_lists() + + def init_cli_args(self): + """Use argparse to set command-line args + + """ + + self.parser = argparse.ArgumentParser(formatter_class=argparse.ArgumentDefaultsHelpFormatter) + + self.parser.add_argument( + '-p', '--properties_file', + default=os.path.join('..', 'conf', 'sandag_abm.properties'), + help="Java properties file.") + + self.parser.add_argument( + '-o', '--outputs_directory', + default=os.path.join('..', 'output'), + help="Directory containing walk MGRA output files.") + + self.parser.add_argument( + '-i', '--inputs_parent_directory', + default='..', + help="Directory containing 'input' folder") + + self.cli = self.parser.parse_args() + + def validate_file(self, filename): + if not os.path.isfile(filename): + self.parser.print_help() + raise IOError("Could not locate %s" % filename) + + def init_properties(self): + """Parses attributes from a Java properties file + + """ + + filename = self.cli.properties_file + self.validate_file(filename) + print('Parsing tokens from %s ...' % filename) + + all_props = {} + with open(filename, 'r') as f: + for line in f: + if line.startswith("#"): + continue + if '=' in line: + atr, val = list(map(str.strip, line.split('='))) + all_props[atr] = val + + def parse(property_name): + if property_name not in all_props: + raise KeyError("Could not find %s in %s" % (property_name, filename)) + + return all_props.get(property_name) + + self.mgra_file = parse('mgra.socec.file') + self.walk_mgra_output_file = parse('active.logsum.matrix.file.walk.mgra') + self.walk_mgra_tap_output_file = parse('active.logsum.matrix.file.walk.mgratap') + self.mt_tap_file = parse('active.microtransit.tap.file') + self.mt_mgra_file = parse('active.microtransit.mgra.file') + + self.walk_coef = float(parse('active.walk.minutes.per.mile')) + self.walk_max_dist_mgra = float(parse('active.maxdist.walk.mgra')) + self.walk_max_dist_tap = float(parse('active.maxdist.walk.tap')) + + self.vot = float(parse('active.micromobility.vot')) + + self.mm_speed = float(parse('active.micromobility.speed')) + self.mm_rental_time = float(parse('active.micromobility.rentalTime')) + self.mm_constant = float(parse('active.micromobility.constant')) + self.mm_variable_cost = float(parse('active.micromobility.variableCost')) + self.mm_fixed_cost = float(parse('active.micromobility.fixedCost')) + self.mm_max_dist_mgra = float(parse('active.maxdist.micromobility.mgra')) + self.mm_max_dist_tap = float(parse('active.maxdist.micromobility.tap')) + + self.mt_speed = float(parse('active.microtransit.speed')) + self.mt_wait_time = float(parse('active.microtransit.waitTime')) + self.mt_access_time = float(parse('active.microtransit.accessTime')) + self.mt_constant = float(parse('active.microtransit.constant')) + self.mt_variable_cost = float(parse('active.microtransit.variableCost')) + self.mt_fixed_cost = float(parse('active.microtransit.fixedCost')) + self.mt_not_avail = float(parse('active.microtransit.notAvailable')) + self.mt_max_dist_mgra = float(parse('active.maxdist.microtransit.mgra')) + self.mt_max_dist_tap = float(parse('active.maxdist.microtransit.tap')) + + def init_micro_access_time(self): + """Reads the MicroAccessTime for each origin MGRA from + the provided MGRA file. If no MicroAccessTime is found, + a simple calculation is performed instead. + + """ + mgra_file_path = os.path.join(self.cli.inputs_parent_directory, self.mgra_file) + self.validate_file(mgra_file_path) + + with open(mgra_file_path, 'r') as f: + use_dummy = 'MicroAccessTime' not in f.readline() + + if use_dummy: + print('No MicroAccessTime column found in %s, using 2 minute ' + 'default for PARKAREA==1, 15 minutes otherwise.' % mgra_file_path) + park_area = pd.read_csv(mgra_file_path, usecols=['mgra', 'parkarea'], + index_col='mgra', dtype='Int64', squeeze=True) + mat = pd.Series(index=park_area.index, data=15.0, name='MicroAccessTime') + mat.loc[park_area == 1] = 2.0 + else: + mat = pd.read_csv(mgra_file_path, usecols=['mgra', 'MicroAccessTime'], + index_col='mgra', squeeze=True) + + self.mat = mat + + def init_tap_mgra_lists(self): + """Reads in lists of ids that identify micro-transit accessibility TAPs/MGRAs + + """ + mt_tap_file_path = os.path.join(self.cli.inputs_parent_directory, self.mt_tap_file) + mt_mgra_file_path = os.path.join(self.cli.inputs_parent_directory, self.mt_mgra_file) + self.validate_file(mt_tap_file_path) + self.validate_file(mt_mgra_file_path) + + self.mt_taps = \ + pd.read_csv(mt_tap_file_path, + usecols=lambda x: x.strip().lower() == 'tap', + squeeze=True).values + + self.mt_mgras = \ + pd.read_csv(mt_mgra_file_path, + usecols=lambda x: x.strip().lower() == 'mgra', + squeeze=True).values + + +if __name__ == '__main__': + + config = Config() + process_file(config, zone='tap') + process_file(config, zone='mgra') + + print('Finished!') diff --git a/sandag_abm/src/main/python/checkFreeSpace.py b/sandag_abm/src/main/python/checkFreeSpace.py new file mode 100644 index 0000000..d94812f --- /dev/null +++ b/sandag_abm/src/main/python/checkFreeSpace.py @@ -0,0 +1,33 @@ +__author__ = 'wsu' +import sys +import ctypes +""" +ctypes is a foreign function library for Python. +It provides C compatible data types, and allows calling functions in DLLs or shared libraries. + +sys provides access to operating system. +It provides access to some variables used by the interpreter. +""" +path=sys.argv[1] +minSpace=sys.argv[2] +_, total, free = ctypes.c_ulonglong(), ctypes.c_ulonglong(), ctypes.c_ulonglong() +if sys.version_info >= (3,) or isinstance(path, unicode): + fun = ctypes.windll.kernel32.GetDiskFreeSpaceExW +else: + fun = ctypes.windll.kernel32.GetDiskFreeSpaceExA +ret = fun(path, ctypes.byref(_), ctypes.byref(total), ctypes.byref(free)) +if ret == 0: + raise ctypes.WinError() +totalMB=total.value/1024.0/1024.0 +freeMB=free.value/2014.0/1024.0 +usedMB = totalMB- freeMB + +if freeMB < int(minSpace): + print "free space on C <",minSpace,"MB!" + sys.exit() +else: + print "Total MB on C:",totalMB + print "Used MB on C:",usedMB + print "Free MB on C:",freeMB + + diff --git a/sandag_abm/src/main/python/check_output.py b/sandag_abm/src/main/python/check_output.py new file mode 100644 index 0000000..b0dc43b --- /dev/null +++ b/sandag_abm/src/main/python/check_output.py @@ -0,0 +1,139 @@ +""" Output Checker + +Checks that ABM components successfully generate required files. + +""" + +# Import libraries +import os +import sys + + +# Define model-output dictionary +output_dict = { + "Setup": [ + "walkMgraTapEquivMinutes.csv", + "microMgraTapEquivMinutes.csv", + "microMgraEquivMinutes.csv", + "bikeTazLogsum.csv", + "bikeMgraLogsum.csv", + "walkMgraEquivMinutes.csv" + ], + "SDRM": [ + "wsLocResults_ITER.csv", + "aoResults.csv", + "householdData_ITER.csv", + "indivTourData_ITER.csv", + "indivTripData_ITER.csv", + "jointTourData_ITER.csv", + "jointTripData_ITER.csv", + "personData_ITER.csv" + ], + "IE": [ + "internalExternalTrips.csv" + ], + "SAN": [ + "airport_out.SAN.csv" + ], + "CBX": [ + "airport_out.CBX.csv" + ], + "CBM": [ + "crossBorderTrips.csv", + "crossBorderTours.csv" + ], + "Visitor": [ + "visitorTrips.csv", + "visitorTours.csv" + ], + "TNC": [ + "TNCTrips.csv" + ], + "AV": [ + "householdAVTrips.csv" + ], + "CVM": [ + "Gen and trip sum.csv" + ], + "Exporter": [ + # NOTE: This is an incomplete list of the 40+ output files. + # These shapefiles are last to be generated and their + # existence indicates a successful Data Export. + "hwyLoad.prj", + "hwyLoad.cpg", + "hwyLoad.shx", + "hwyLoad.shp", + "hwyLoad.dbf" + ] +} + + +def check_output(scenario_fp, component, iteration=None): + """ + Checks that a specific ABM component generated + required files. + + :param component: String representing ABM component + :param scenario_fp: String representing scenario file path + :param iteration: Integer representing ABM iteration + :returns: Exit code + """ + + # Get required files + files = output_dict[component] + + # Construct output file path + if component == 'Exporter': + out_dir = 'report' + else: + out_dir = 'output' + output_dir = os.path.join(scenario_fp, out_dir) + + # Check that required files were generated + missing = [] + for file in files: + + # Append iteration integer if needed + if 'ITER' in file: + file = file.replace('ITER', iteration) + + file_path = os.path.join(output_dir, file) + if os.path.exists(file_path): + continue + else: + missing.append(file+'\n') + + # Write out missing files to log file + if len(missing) > 0: + create_log(scenario_fp, component, missing) + return sys.exit(2) + + return sys.exit(0) + + +def create_log(scenario_fp, component, lst): + """ + Creates a log file containing the files an ABM component + failed to generate. + + :param scenario_fp: String representing scenario file path + :param component: ABM component + :param lst: List of missing file names + """ + + # Create log file path + log_fp = os.path.join(scenario_fp, 'logFiles', 'missing_files.log') + + # Create and write to log file + with open(log_fp, "w") as log: + header = "'{}' failed to generate the following files:\n".format(component) + log.write(header) + log.writelines(lst) + + return + + +if __name__ == '__main__': + targets = sys.argv[1:] + check_output(*targets) + diff --git a/sandag_abm/src/main/python/cvm_analysis.zip b/sandag_abm/src/main/python/cvm_analysis.zip new file mode 100644 index 0000000..dd5fd7b Binary files /dev/null and b/sandag_abm/src/main/python/cvm_analysis.zip differ diff --git a/sandag_abm/src/main/python/cvm_input_create.py b/sandag_abm/src/main/python/cvm_input_create.py new file mode 100644 index 0000000..16868e9 --- /dev/null +++ b/sandag_abm/src/main/python/cvm_input_create.py @@ -0,0 +1,462 @@ +''' +PURPOSE: +Commercial Vehicle Model (CVM) input file creation + +INSTALL (LIBRARY): +Numpy +https://pypi.python.org/pypi/numpy + +Pandas +https://pypi.python.org/pypi/pandas + +HOW TO RUN: +[script_filepath] [Project Directory] [MGRA filename] [TAZ Centroid flename] [output filename] + +example: cvm_input_create.py "C:\Projects\SANDAG_CTM_Validation\_Tasks" "input/mgra13_based_input2012.csv" "tazcentroids_cvm.csv" "Zonal Properties CVM.csv" + +Note: The script name is sufficient if the run folder is the same as the script folder. Otherwise, a full path of the script would be needed. Also, if the output file does not contain spaces, the command line does not need to have quotation marks around the arguments. + +STEPS: +STEP 0: read mgra socio-economic file +STEP 1: find min and max tazids +STEP 2: read taz centroids. +STEP 3: calculate taz level variables +STEP 4. write to output + +REFERENCES: +Following reference are used for calculations: +T:\devel\CVM\sr13\2012_calib5\input\mgra13_based_input2012_CVM.xlsx +T:\devel\CVM\sr13\2012_calib5\CVM\Zonal Properties SDCVM_SR13 KJS rcu_check.xlsx +The final example product: T:\devel\CVM\sr13\2012_calib5\CVM\Inputs\Zonal Properties CVM.csv + +CREATED BY: +nagendra.dhakar@rsginc.com + +LAST MODIFIED: +03/13/2018 + +Updates: +03/13/2018 - nagendra.dhakar@rsginc.com +Updated to remove transformation of coordinates +Instead an input file is provided with taz centroids (tazcentroids_cvm.csv +the script now reads the input centroid file that already has transformed coordinates that are reported in the output +no need for GDAL library +''' + +import sys +import os +import numpy as np +import datetime +import math +import csv +import pandas as pd + +class Constant: + """ Represents constants in the script + constants: FEET_TO_MILE, COORDS_EPSG_SOURCE,COORDS_EPSG_TARGET + """ + ACRES_TO_SQMILE = 0.0015625 + #COORDS_EPSG_SOURCE = 2230 #EPSG: 2230 - NAD83/ California zone 6 (ftUS) + #COORDS_EPSG_TARGET = 3310 #EPSG: 3310 - NAD83/ California Albers + +class Header: + """ Represents header for output files """ + temptazdatafile = ['taz','pop','hh','i1','i2','i3','i4','i5','i6','i7','i8','i9','i10','emp_total','emp_fed_mil','sqmile','land_sqmile','Emp_IN','Emp_RE','Emp_SV','Emp_TU','Emp_WH','Emp_OFF', + 'HHIncome','EmpDens','PopDens','Per/Emp','Emp_ServRet_Pct','Ret_ServRet','Emp_Office','Low Density','Residential','Commercial','Industrial','Employment Node', + 'Industrial_pct','TU_pct','Wholesale_pct','Retail_pct','Service_pct','Office_pct','E500_Industrial','E500_TU','E500_Wholesale','E500_Retail','E500_Service', + 'E500_Office','RetailZone','ZoneType'] + + temptazcentroidsfile = ["hnode","x_coord_spft","y_coord_spft","x_coord_albers","y_coord_albers"] + + outfile = ['TAZ','Pop','Income','Area_SqMi','x-meters','y-meters','EmpDens','PopDens','TotEmp','Military', + 'CVM_IN','CVM_RE','CVM_SV','CVM_TH','CVM_WH','CVM_GO','CVM_LU_Type','SqrtArea','CVM_LU_Low','CVM_LU_Res', + 'CVM_LU_Ret','CVM_LU_Ind','CVM_LU_Emp','Emp_LU_Lo','Emp_LU_Re','Emp_LU_RC','Emp_LU_In','Emp_LU_EN'] + +class TazId: + """ Represents Taz Id range + attributes: min, max + """ + +class Input: + """ Represents input settings + attributes: dir, mgrafile, nodebinfile. + """ +class Output: + """ Represents output settings + attributes: dir, outfile, temp_centroidfile, temp_tazfile + """ + +def read_node_header(node_file): + """Returns name and type of the fields in the node bin file """ + + # node header file + nodeheaderfile = os.path.join(os.path.splitext(node_file)[0]+".DCB") + + # first row is blank + # second row is total bytes in a row + # start reading fields names from third row + # header file format - field_name, type, start_byte, length, .. + + fields_info=[] + with open(nodeheaderfile) as headerfile: + reader = csv.reader(headerfile) + i=0 + for row in reader: + if i >= 2: + field_name = row[0] + field_length = row[3] + + # integer + if row[1] == 'I': + field_type = int + + # character/string + elif row[1] == 'C': + field_type = 'S' + field_length + + # first field + if i == 2: + fields_info.append([field_name]) + fields_info.append([field_type]) + + # remaining fields + else: + fields_info[0].append(field_name) + fields_info[1].append(field_type) + + i=i+1 + + return fields_info + +def get_tazid_range(data): + """Returns min and maz taz ids""" + + # max and min tazid + + id_list = np.array(data.keys()) + id_list = id_list.astype(np.float) + + id_max = int(max(id_list)) + id_min = int(min(id_list)) + + return([id_min,id_max]) + +def read_node_file(tazcentroid_file): + """ + Reads taz centroids from node bin file + Transforms them into the coordinate system expected by the CTM + Returns transformed (projected) coordinates + """ + + centroids = pd.read_csv(tazcentroid_file) + centroids = centroids[centroids['taz']>0] + centroids = centroids.reset_index() + + coords_proj = {} + for i in range(0,max(centroids['taz'])): + coords_proj[str(centroids['taz'][i])] = [float(centroids['x_coord_albers'][i]), float(centroids['y_coord_albers'][i])] + + return coords_proj + +def read_mgra_input(mgrafile): + """ + Reads MGRA socia-economic file + Calculates some variables at MGRA level + Aggregates data by TAZ + Returns TAZ level data + """ + + data={} + + with open (mgrafile) as csvfile: + reader = csv.DictReader(csvfile) # read in dictionary format + i=1 + for row in reader: + # calculate new variables at MGRA + row['sqmile'] = float(row['acres'])*Constant.ACRES_TO_SQMILE + row['land_sqmile'] = float(row['land_acres'])*Constant.ACRES_TO_SQMILE + + row['CVM_IN'] = float(row['emp_ag']) + float(row['emp_const_non_bldg_prod']) + float(row['emp_const_non_bldg_office']) + \ + float(row['emp_const_bldg_prod']) + float(row['emp_const_bldg_office']) + float(row['emp_mfg_prod']) + float(row['emp_mfg_office']) + + row['CVM_RE'] = float(row['emp_retail']) + + row['CVM_SV'] = float(row['emp_pvt_ed_k12']) + float(row['emp_pvt_ed_post_k12_oth']) + float(row['emp_health']) + \ + float(row['emp_personal_svcs_office']) + float(row['emp_amusement']) + float(row['emp_hotel']) + \ + float(row['emp_restaurant_bar']) + float(row['emp_personal_svcs_retail']) + float(row['emp_religious']) + \ + float(row['emp_pvt_hh']) + float(row['emp_public_ed']) + + row['CVM_TH'] = float(row['emp_utilities_prod']) + float(row['emp_utilities_office']) + float(row['emp_trans']) + + row['CVM_WH'] = float(row['emp_whsle_whs']) + + + row['CVM_OFF'] = float(row['emp_prof_bus_svcs']) + float(row['emp_prof_bus_svcs_bldg_maint']) + \ + float(row['emp_state_local_gov_ent']) + float(row['emp_fed_non_mil']) + float(row['emp_state_local_gov_blue']) + \ + float(row['emp_state_local_gov_white']) + float(row['emp_own_occ_dwell_mgmt']) + + # aggregate data by TAZ + if row['taz'] not in data: + data[row['taz']] = [int(row['taz']),int(row['pop']), int(row['hh']), float(row['i1']), float(row['i2']), float(row['i3']), float(row['i4']), float(row['i5']), float(row['i6']), float(row['i7']), + float(row['i8']), float(row['i9']), float(row['i10']), float(row['emp_total']), float(row['emp_fed_mil']), float(row['sqmile']), + float(row['land_sqmile']), float(row['CVM_IN']), float(row['CVM_RE']), float(row['CVM_SV']), float(row['CVM_TH']), float(row['CVM_WH']), float(row['CVM_OFF'])] + + else: + #taz_data[row['TAZ']][0] = int(row['TAZ']) + data[row['taz']][1] += int(row['pop']) + data[row['taz']][2] += int(row['hh']) + data[row['taz']][3] += float(row['i1']) + data[row['taz']][4] += float(row['i2']) + data[row['taz']][5] += float(row['i3']) + data[row['taz']][6] += float(row['i4']) + data[row['taz']][7] += float(row['i5']) + data[row['taz']][8] += float(row['i6']) + data[row['taz']][9] += float(row['i7']) + data[row['taz']][10] += float(row['i8']) + data[row['taz']][11] += float(row['i9']) + data[row['taz']][12] += float(row['i10']) + data[row['taz']][13] += float(row['emp_total']) + data[row['taz']][14] += float(row['emp_fed_mil']) + data[row['taz']][15] += float(row['sqmile']) + data[row['taz']][16] += float(row['land_sqmile']) + data[row['taz']][17] += float(row['CVM_IN']) + data[row['taz']][18] += float(row['CVM_RE']) + data[row['taz']][19] += float(row['CVM_SV']) + data[row['taz']][20] += float(row['CVM_TH']) + data[row['taz']][21] += float(row['CVM_WH']) + data[row['taz']][22] += float(row['CVM_OFF']) + + return data + +# calculate taz level variables +def calculate_taz_variables(data, coords, taz_ids, outfile): + """ + Reads TAZ data stored in read_mgra_input + Calculates variables + Returns calculated taz variables that would be in the output file + """ + + data_calc = {} + with open(outfile,"wb") as csvfile: + fieldnames = Header.temptazdatafile + + writer = csv.writer(csvfile) + writer.writerow(fieldnames) + + for taz in range(1, taz_ids.max+1): + + if taz>=taz_ids.min: + + # initialize variables to 0 + emp_dens, pop_dens, cvm_emp_dens, emp_cvm_total=(0,)*4 + per_emp, emp_servret_pct, ret_servret, emp_office, low_dens, residential, commercial, industrial=(0,)*8 + industrial_pct, transport_pct, wholesale_pct, retail_pct, service_pct, office_pct=(0,)*6 + emp_office, retail_zone=(0,)*2 + industrial_e500, transport_e500, wholesale_e500, retail_e500, service_e500, office_e500=(0,)*6 + cvm_lu_low, cvm_lu_res, cvm_lu_ret, cvm_lu_ind, cvm_lu_emp=(0,)*5 + + # get data + [taz_id,pop,hh,inc1,inc2,inc3,inc4,inc5,inc6,inc7,inc8,inc9,inc10,emp_total,emp_fed_mil,sqmile,land_sqmile,cvm_in,cvm_re,cvm_sv,cvm_th,cvm_wh,cvm_off]=data[str(taz)] + + # average hh income + if (hh>0): + hh_income = (inc1*7500+inc2*22500+inc3*37500+inc4*52500+inc5*67500+inc6*87500+inc7*112500+inc8*137500+inc9*175000+inc10*225)/hh + else: + hh_income=64678 + + # total CVM employment = industrial + retail + service + transport + wholesale + office + emp_cvm_total = cvm_in + cvm_re + cvm_sv + cvm_th + cvm_wh + cvm_off + + # calculate densities + if (land_sqmile > 0): + emp_dens = emp_total/land_sqmile + pop_dens = pop/land_sqmile + cvm_emp_dens = emp_cvm_total/land_sqmile + + # share of employment in each sector + if (emp_total > 0): + per_emp = pop/emp_total + emp_servret_pct = (cvm_re + cvm_sv + cvm_off)/emp_total + + if ((cvm_re+cvm_sv+cvm_off)/emp_total) < 0.8: + emp_office = 1 + + # additional shares/variables - not for the final output + industrial_pct = cvm_in/emp_total + transport_pct = cvm_th/emp_total + wholesale_pct = cvm_wh/emp_total + retail_pct = cvm_re/emp_total + service_pct = cvm_sv/emp_total + office_pct = cvm_off/emp_total + + if cvm_re/emp_total > 0.5: + retail_zone = 1 + + # end of additional variables + + # calculate flags + if ((cvm_re+cvm_sv) > 0): + if ((cvm_re/(cvm_re+cvm_sv+cvm_off)) > 0.25): + ret_servret = 1 + + # landuse flags + + if (emp_dens < 250 and pop_dens < 250): + # low density + low_dens = 1 + + if (low_dens == 0 and pop_dens > 250 and per_emp > 2): + # residential + residential = 1 + + if (low_dens == 0 and residential == 0 and emp_servret_pct > 0.6 and emp_dens > 1500 and ret_servret == 1): + # retail/commercial + commercial = 1 + + if (low_dens == 0 and residential == 0 and commercial == 0 and emp_dens < 15000 and emp_office == 1): + # industrial + industrial = 1 + + if (low_dens == 1 or residential == 1 or commercial == 1 or industrial == 1): + employment_node = 0 + else: + # other + employment_node = 1 + + # employment more than 500 flags - additional, not for the final output + if cvm_in > 500: + industrial_e500 = 1 + if cvm_th > 500: + transport_e500 = 1 + if cvm_wh > 500: + wholesale_e500 = 1 + if cvm_re > 500: + retail_e500 = 1 + if cvm_sv > 500: + service_e500 = 1 + if cvm_off > 500: + office_e500 = 1 + + # end of additional variables + + # zone type + zone_type = 1*low_dens + 2*residential + 3*commercial + 4*industrial + 5*employment_node + sqrt_area = math.sqrt(land_sqmile) + + # TAZ centroids + taz_x_meters = coords[str(taz)][0] + taz_y_meters = coords[str(taz)][1] + + # landuse flags + if zone_type == 1: + # low density + cvm_lu_low = 1 + elif zone_type == 2: + # residential + cvm_lu_res = 1 + elif zone_type == 3: + # retail/commercial + cvm_lu_ret = 1 + elif zone_type == 4: + # industrial + cvm_lu_ind = 1 + elif zone_type == 5: + # other + cvm_lu_emp = 1 + + # employment by land use + emp_lu_low = cvm_lu_low * emp_cvm_total + emp_lu_res = cvm_lu_res * emp_cvm_total + emp_lu_ret = cvm_lu_ret * emp_cvm_total + emp_lu_ind = cvm_lu_ind * emp_cvm_total + emp_lu_emp = cvm_lu_emp * emp_cvm_total + + # write all taz data to a temp file + data[str(taz)].extend([hh_income,emp_dens,pop_dens,per_emp,emp_servret_pct,ret_servret,emp_office, + low_dens,residential,commercial,industrial,employment_node,industrial_pct, + transport_pct,wholesale_pct,retail_pct,service_pct,office_pct,industrial_e500, + transport_e500,wholesale_e500,retail_e500,service_e500,office_e500,retail_zone,zone_type]) + writer.writerow(data[str(taz)]) + + # store calculated variables + data_calc[str(taz)]=[taz_id,pop,hh_income,land_sqmile,taz_x_meters,taz_y_meters,cvm_emp_dens,pop_dens,emp_cvm_total, + emp_fed_mil,cvm_in,cvm_re,cvm_sv,cvm_th,cvm_wh,cvm_off,zone_type,sqrt_area, + cvm_lu_low,cvm_lu_res,cvm_lu_ret,cvm_lu_ind,cvm_lu_emp, + emp_lu_low,emp_lu_res,emp_lu_ret,emp_lu_ind,emp_lu_emp] + return data_calc + +def write_output(data, taz_ids, outfile): + """ + Writes taz data to an output + """ + + with open(outfile,"wb") as csvfile: + fieldnames = Header.outfile + + writer = csv.writer(csvfile) + writer.writerow(fieldnames) + + for taz in range(1, taz_ids.max+1): + if taz None: + self.scenario_path = scenario_path + + @property + @lru_cache(maxsize=1) + def mgra_xref(self) -> pd.DataFrame: + """ Cross reference of Master Geographic Reference Area (MGRA) model + geography to Transportation Analysis Zone (TAZ) and Land Use Zone + (LUZ) model geographies. Cross reference is stored in each ABM + scenario input MGRA file (input/mgra13_based_input<>.csv). + """ + + # load the mgra based input file + fn = "mgra13_based_input" + str(self.properties["year"]) + ".csv" + + mgra = pd.read_csv(os.path.join(self.scenario_path, "input", fn), + usecols=["mgra", # MGRA geography + "taz", # TAZ geography + "luz_id"], + dtype={"mgra": "int16", + "taz": "int16", + "luz_id": "int16"}) # LUZ geography + + # genericize column names + mgra.rename(columns={"mgra": "MGRA", + "taz": "TAZ", + "luz_id": "LUZ"}, + inplace=True) + + return mgra + + @property + @lru_cache(maxsize=1) + def pnr_taps(self) -> pd.DataFrame: + """ Create the transit TAP park and ride lot data-set. + + Read in and combine the transit TAP parking lot type information and + parking lot vehicles by time of day information. + + Returns: + A Pandas DataFrame of the transit TAP park and ride lot data-set """ + # load parking lot type data-set + lots = pd.read_fwf( + os.path.join(self.scenario_path, "input", "tap.ptype"), + names=["TAP", + "lotID", + "parkingType", + "lotTAZ", + "capacity", + "distance", + "mode"], + header=None, + widths=[5, 6, 6, 5, 5, 5, 3]) + + # replicate parking lot data by ABM five time of day + five_tod = pd.DataFrame( + {"key": [0]*5, + "timeFiveTod": ["EA", "AM", "MD", "PM", "EV"]}) + + lots["key"] = 0 + lots = lots.merge(five_tod) + + # load parking lot vehicles by time of day + vehicles = pd.read_csv( + os.path.join(self.scenario_path, "output", "PNRByTAP_Vehicles.csv"), + usecols=["TAP", + "EA", + "AM", + "MD", + "PM", + "EV"]) + + # restructure vehicle data from wide to long by ABM five time of day + vehicles = pd.melt( + vehicles, + id_vars=["TAP"], + value_vars=["EA", "AM", "MD", "PM", "EV"], + var_name="timeFiveTod", + value_name="vehicles") + + # merge parking lot and vehicle data + lots = lots.merge(vehicles, how="left") + + # set missing vehicle fields to 0 + lots["vehicles"] = lots["vehicles"].fillna(0) + + # convert distance field from feet to miles + lots["distance"] = lots["distance"] / 5280 + + # apply exhaustive field mappings where applicable + mappings = { + "timeFiveTod": {"EA": 1, + "AM": 2, + "MD": 3, + "PM": 4, + "EV": 5}, + "parkingType": {1: "Formal Parking", + 2: "Other Parking", + 3: "Other Light Rail Trolley Parking", + 4: "Non-formal parking area based on the on-board survey", + 5: "Non-formal parking area based on the on-board survey"} + } + + for field in mappings: + lots[field] = lots[field].map(mappings[field]) + + # rename columns to standard/generic ABM naming conventions + lots.rename(columns={"TAP": "tapID"}, inplace=True) + + return lots[["tapID", + "lotID", + "lotTAZ", + "timeFiveTod", + "parkingType", + "capacity", + "distance", + "vehicles"]] + + @property + @lru_cache(maxsize=1) + def properties(self) -> dict: + """ Get the ABM scenario properties from the ABM scenario + properties file (conf/sandag_abm.properties). + + The return dictionary contains the following ABM scenario properties: + cvmScaleLight - commercial vehicle model trip scaling factor for + light vehicles for each ABM five time of day + cvmScaleMedium - commercial vehicle model trip scaling factor for + intermediate and medium vehicles for each ABM five time of day + cvmScaleHeavy - commercial vehicle model trip scaling factor for + heavy vehicles for each ABM five time of day + cvmShareLight - commercial vehicle model trip intermediate vehicle + share factor for light vehicles + cvmShareMedium - commercial vehicle model trip intermediate vehicle + share factor for medium vehicles + cvmShareHeavy - commercial vehicle model trip intermediate vehicle + share factor for heavy vehicles + iterations - number of model iteration + nonPooledTNCPassengers - average number of passengers to assume for + Non-Pooled TNC mode in models without party size specifications + pooledTNCPassengers - average number of passengers to assume for + Pooled TNC mode in models without party size specifications + sr2Passengers - average number of passengers to assume for Shared + Ride 2 mode in models without party size specifications + sr3Passengers - average number of passengers to assume for Shared + Ride 3+ mode in models without party size specifications + taxiPassengers - average number of passengers to assume for Taxi + mode in models without party size specifications + timePeriodWidthTNC - time period width (in minutes) for custom + fixed-width time periods used in TNC routing model, note that + this is not currently restricted to nest within ABM model time + periods + sampleRate - sample rate of final iteration + valueOfTimeLow - upper limit of 'Low' value of time category + valueOfTimeMedium - upper limit of 'Medium' value of time category + year - analysis year of the ABM scenario + + Returns: + A dictionary defining the ABM scenario properties. """ + + # create dictionary holding ABM properties file information + # each property contains a dictionary {line, value} where the line + # is the string to match in the properties file to + # return the value of the property + lookup = { + "cvmScaleLight": { + "line": "cvm.scale_light=", + "type": "list", + "value": None}, + "cvmScaleMedium": { + "line": "cvm.scale_medium=", + "type": "list", + "value": None}, + "cvmScaleHeavy": { + "line": "cvm.scale_heavy=", + "type": "list", + "value": None}, + "cvmShareLight": { + "line": "cvm.share.light=", + "type": "float", + "value": None}, + "cvmShareMedium": { + "line": "cvm.share.medium=", + "type": "float", + "value": None}, + "cvmShareHeavy": { + "line": "cvm.share.heavy=", + "type": "float", + "value": None}, + "iterations": { + "line": None, + "type": "int", + "value": None}, + "nonPooledTNCPassengers": { + "line": "TNC.single.passengersPerVehicle=", + "type": "float", + "value": None}, + "pooledTNCPassengers": { + "line": "TNC.shared.passengersPerVehicle=", + "type": "float", + "value": None}, + "sr2Passengers": { + "line": None, + "type": "int", + "value": 2}, + "sr3Passengers": { + "line": None, + "type": "float", + "value": 3.34}, + "taxiPassengers": { + "line": "Taxi.passengersPerVehicle=", + "type": "float", + "value": None}, + "timePeriodWidthTNC": { + "line": "Maas.RoutingModel.minutesPerSimulationPeriod=", + "type": "int", + "value": None}, + "sampleRate": { + "line": "sample_rates=", + "type": "float", + "value": None}, + "valueOfTimeLow": { + "line": "valueOfTime.threshold.low=", + "type": "float", + "value": None}, + "valueOfTimeMedium": { + "line": "valueOfTime.threshold.med=", + "type": "float", + "value": None}, + "year": { + "line": "scenarioYear=", + "type": "int", + "value": None} + } + + # open the ABM scenario properties file + file = open(os.path.join(self.scenario_path, "conf", "sandag_abm.properties"), "r") + + # loop through each line of the properties file + for line in file: + # strip all white space from the line + line = line.replace(" ", "") + + # for each element of the properties dictionary + for name in lookup: + item = lookup[name] + + # if the properties file contains the matching line + if item["line"] is not None: + match = re.compile(item["line"]).match(line) + else: + match = False + + if match: + # if the match is for the sample rate element + # then take the portion of the line after the matching string + # and split by the comma character + if name == "sampleRate": + line = line[match.end():].split(",") + + # set number of iterations to number of sample rates + # that are specified + lookup["iterations"]["value"] = len(line) + + # if the split line contains a single element + # return that element otherwise return the final element + if len(line) == 1: + value = line[0] + else: + value = line[-1] + # if the match is for a cvm scale element then take the + # portion of the line after the matching string and split + # by the comma character into a list of floats + elif "cvmScale" in name: + value = line[match.end():].split(",") + value = list(map(float, value)) + # otherwise take the final element of the line + else: + value = line[match.end():] + + # update the dictionary value using the appropriate data type + if item["type"] == "float": + value = float(value) + elif item["type"] == "int": + value = int(value) + else: + pass + + item["value"] = value + + break + + file.close() + + # convert the property name and value to a non-nested dictionary + results = {} + for name in lookup: + results[name] = lookup[name]["value"] + + return results + + @property + def time_periods(self) -> dict: + """ Dictionary of ABM model time resolution periods with start and + end times where the start time is inclusive and the end time is + exclusive. Dictionary is of the form: + {"period": "startTime": "endTime":} + + Returns: + A Dictionary of the ABM model time resolution periods. + """ + periods = { + "abmHalfHour": [ + {"period": 1, + "startTime": time(3, 0), + "endTime": time(5, 0)}, + {"period": 2, + "startTime": time(5, 0), + "endTime": time(5, 30)}, + {"period": 3, + "startTime": time(5, 30), + "endTime": time(6, 0)}, + {"period": 4, + "startTime": time(6, 0), + "endTime": time(6, 30)}, + {"period": 5, + "startTime": time(6, 30), + "endTime": time(7, 0)}, + {"period": 6, + "startTime": time(7, 0), + "endTime": time(7, 30)}, + {"period": 7, + "startTime": time(7, 30), + "endTime": time(8, 0)}, + {"period": 8, + "startTime": time(8, 0), + "endTime": time(8, 30)}, + {"period": 9, + "startTime": time(8, 30), + "endTime": time(9, 0)}, + {"period": 10, + "startTime": time(9, 0), + "endTime": time(9, 30)}, + {"period": 11, + "startTime": time(9, 30), + "endTime": time(10, 0)}, + {"period": 12, + "startTime": time(10, 0), + "endTime": time(10, 30)}, + {"period": 13, + "startTime": time(10, 30), + "endTime": time(11, 0)}, + {"period": 14, + "startTime": time(11, 0), + "endTime": time(11, 30)}, + {"period": 15, + "startTime": time(11, 30), + "endTime": time(12, 0)}, + {"period": 16, + "startTime": time(12, 0), + "endTime": time(12, 30)}, + {"period": 17, + "startTime": time(12, 30), + "endTime": time(13, 0)}, + {"period": 18, + "startTime": time(13, 0), + "endTime": time(13, 30)}, + {"period": 19, + "startTime": time(13, 30), + "endTime": time(14, 0)}, + {"period": 20, + "startTime": time(14, 0), + "endTime": time(14, 30)}, + {"period": 21, + "startTime": time(14, 30), + "endTime": time(15, 0)}, + {"period": 22, + "startTime": time(15, 0), + "endTime": time(15, 30)}, + {"period": 23, + "startTime": time(15, 30), + "endTime": time(16, 0)}, + {"period": 24, + "startTime": time(16, 0), + "endTime": time(16, 30)}, + {"period": 25, + "startTime": time(16, 30), + "endTime": time(17, 0)}, + {"period": 26, + "startTime": time(17, 0), + "endTime": time(17, 30)}, + {"period": 27, + "startTime": time(17, 30), + "endTime": time(18, 0)}, + {"period": 28, + "startTime": time(18, 0), + "endTime": time(18, 30)}, + {"period": 29, + "startTime": time(18, 30), + "endTime": time(19, 0)}, + {"period": 30, + "startTime": time(19, 0), + "endTime": time(19, 30)}, + {"period": 31, + "startTime": time(19, 30), + "endTime": time(20, 0)}, + {"period": 32, + "startTime": time(20, 0), + "endTime": time(20, 30)}, + {"period": 33, + "startTime": time(20, 30), + "endTime": time(21, 0)}, + {"period": 34, + "startTime": time(21, 0), + "endTime": time(21, 30)}, + {"period": 35, + "startTime": time(21, 30), + "endTime": time(22, 0)}, + {"period": 36, + "startTime": time(22, 0), + "endTime": time(22, 30)}, + {"period": 37, + "startTime": time(22, 30), + "endTime": time(23, 0)}, + {"period": 38, + "startTime": time(23, 0), + "endTime": time(23, 30)}, + {"period": 39, + "startTime": time(23, 30), + "endTime": time.max}, + {"period": 40, + "startTime": time.min, + "endTime": time(3, 0)} + ], + "abm5Tod": [ + {"period": 1, + "startTime": time(3, 0), + "endTime": time(6, 0)}, + {"period": 2, + "startTime": time(6, 0), + "endTime": time(9, 0)}, + {"period": 3, + "startTime": time(9, 0, 0), + "endTime": time(15, 30)}, + {"period": 4, + "startTime": time(15, 30), + "endTime": time(19, 0)}, + {"period": 5, + "startTime": time(19, 0), + "endTime": time.max}, + {"period": 5, + "startTime": time.min, + "endTime": time(3, 0)} + ] + } + + return periods + + @staticmethod + def _map_time_periods(abm_half_hour: pd.Series) -> pd.Series: + """ Map ABM half hour time periods to ABM five time of day periods + + Returns: + A Pandas Series of ABM five time of day periods """ + + conditions = [abm_half_hour.between(1, 3), + abm_half_hour.between(4, 9), + abm_half_hour.between(10, 22), + abm_half_hour.between(23, 29), + abm_half_hour.between(30, 40)] + + choices = [1, 2, 3, 4, 5] + + abm_5_tod = np.select(conditions, choices, default=np.NaN) + + return pd.Series(abm_5_tod).astype("float") + + def _map_vot_categories(self, vot: pd.Series) -> pd.Series: + """ Map Pandas Series of continuous ABM value of time (vot) values to + vot categories ("Low", "Medium", "High") defined in the ABM scenario + properties file. + + Returns: + A Pandas Series of value of time categories. """ + + # get vot thresholds + low = self.properties["valueOfTimeLow"] + med = self.properties["valueOfTimeMedium"] + + # map continuous values of time to categories + conditions = [vot < low, + (low <= vot) & (vot < med), + vot >= med] + + choices = ["Low", "Medium", "High"] + + vot_category = np.select(conditions, choices, default=np.NaN) + + return pd.Series(vot_category).astype("category") + + +class LandUse(ScenarioData): + """ A subclass of the ScenarioData class. Holds all land use + data for a completed ABM scenario model run. As of now, this includes only + the MGRA-based input file. This is held as a class property. + + Properties: + mgra_input: MGRA-based input file + """ + @property + @lru_cache(maxsize=1) + def mgra_input(self) -> pd.DataFrame: + """ Create the MGRA-based input file data-set. """ + # load the MGRA-based input file + fn = "mgra13_based_input" + str(self.properties["year"]) + ".csv" + + mgra = pd.read_csv( + os.path.join(self.scenario_path, "input", fn), + usecols=["mgra", + "taz", + "hs", + "hs_sf", + "hs_mf", + "hs_mh", + "hh", + "hh_sf", + "hh_mf", + "hh_mh", + "gq_civ", + "gq_mil", + "i1", + "i2", + "i3", + "i4", + "i5", + "i6", + "i7", + "i8", + "i9", + "i10", + "hhs", + "pop", + "hhp", + "emp_ag", + "emp_const_non_bldg_prod", + "emp_const_non_bldg_office", + "emp_utilities_prod", + "emp_utilities_office", + "emp_const_bldg_prod", + "emp_const_bldg_office", + "emp_mfg_prod", + "emp_mfg_office", + "emp_whsle_whs", + "emp_trans", + "emp_retail", + "emp_prof_bus_svcs", + "emp_prof_bus_svcs_bldg_maint", + "emp_pvt_ed_k12", + "emp_pvt_ed_post_k12_oth", + "emp_health", + "emp_personal_svcs_office", + "emp_amusement", + "emp_hotel", + "emp_restaurant_bar", + "emp_personal_svcs_retail", + "emp_religious", + "emp_pvt_hh", + "emp_state_local_gov_ent", + "emp_fed_non_mil", + "emp_fed_mil", + "emp_state_local_gov_blue", + "emp_state_local_gov_white", + "emp_public_ed", + "emp_own_occ_dwell_mgmt", + "emp_fed_gov_accts", + "emp_st_lcl_gov_accts", + "emp_cap_accts", + "emp_total", + "enrollgradekto8", + "enrollgrade9to12", + "collegeenroll", + "othercollegeenroll", + "adultschenrl", + "ech_dist", + "hch_dist", + "pseudomsa", + "parkarea", + "hstallsoth", + "hstallssam", + "hparkcost", + "numfreehrs", + "dstallsoth", + "dstallssam", + "dparkcost", + "mstallsoth", + "mstallssam", + "mparkcost", + "zip09", + "parkactive", + "openspaceparkpreserve", + "beachactive", + "hotelroomtotal", + "truckregiontype", + "district27", + "milestocoast", + "acres", + "effective_acres", + "land_acres", + "MicroAccessTime", + "remoteAVParking", + "refueling_stations", + "totint", + "duden", + "empden", + "popden", + "retempden", + "totintbin", + "empdenbin", + "dudenbin", + "PopEmpDenPerMi"]) + + return mgra + + +class SyntheticPopulation(ScenarioData): + """ A subclass of the ScenarioData class. Holds all synthetic population + data for a completed ABM scenario model run. This includes the input + synthetic persons and households sampled in the ABM model run as well as + model results pertaining to person and household attributes (e.g. work + location, parking reimbursement, etc...). The synthetic population persons + and households are held as class properties and include: + Synthetic Households + Synthetic Persons + + Properties: + households: Synthetic households sampled + persons: Synthetic persons sampled + """ + @property + @lru_cache(maxsize=1) + def households(self) -> pd.DataFrame: + """ Create the synthetic households data-set. + + Read in the input synthetic household list and the sampled synthetic + household list, combine the lists taking only sampled households, + map field values, and genericize field names. + + Returns: + A Pandas DataFrame of the synthetic households """ + # load input synthetic household list into Pandas DataFrame + input_households = pd.read_csv( + os.path.join(self.scenario_path, "input", "households.csv"), + usecols=["hhid", + "taz", + "mgra", + "hinccat1", + "hinc", + "hworkers", + "persons", + "bldgsz", + "unittype", + "poverty"], + dtype={"hhid": "int32", + "taz": "int16", + "mgra": "int16", + "hinccat1": "int8", + "hinc": "int32", + "hworkers": "int8", + "persons": "int8", + "bldgsz": "int8", + "unittype": "int8", + "poverty": "float32"}) + + # load output sampled synthetic household list + fn = "householdData_" + str(self.properties["iterations"]) + ".csv" + output_households = pd.read_csv( + os.path.join(self.scenario_path, "output", fn), + usecols=["hh_id", + "autos", + "HVs", + "AVs", + "transponder"], + dtype={"hh_id": "int32", + "autos": "int8", + "HVs": "int8", + "AVs": "int8", + "transponder": "bool"}) + + # merge output sampled households with input sampled households + # keep only households present in the sampled households + households = output_households.merge( + input_households, + how="inner", + left_on="hh_id", + right_on="hhid" + ) + + # apply exhaustive field mappings where applicable + mappings = { + "hinccat1": {1: "Less than 30k", + 2: "30k-60k", + 3: "60k-100k", + 4: "100k-150k", + 5: "150k+"}, + "bldgsz": {1: "Mobile Home or Trailer", + 2: "Single Family Home - Detached", + 3: "Single Family Home - Attached", + 8: "Multi-Family Home", + 9: "Other (includes Group Quarters)"}, + "unittype": {0: "Non-Group Quarters", + 1: "Group Quarters"} + } + + for field in mappings: + households[field] = households[field].map(mappings[field]).astype("category") + + # rename columns to standard/generic ABM naming conventions + households.rename(columns={"hh_id": "hhId", + "HVs": "autosHumanVehicles", + "AVs": "autosAutonomousVehicles", + "transponder": "transponderAvailable", + "mgra": "homeMGRA", + "taz": "homeTAZ", + "hinccat1": "hhIncomeCategory", + "hinc": "hhIncome", + "hworkers": "hhWorkers", + "persons": "hhPersons", + "bldgsz": "buildingCategory", + "unittype": "unitType"}, + inplace=True) + + return households[["hhId", + "autos", + "autosHumanVehicles", + "autosAutonomousVehicles", + "transponderAvailable", + "homeMGRA", + "homeTAZ", + "hhIncomeCategory", + "hhIncome", + "hhWorkers", + "hhPersons", + "buildingCategory", + "unitType", + "poverty"]] + + @property + @lru_cache(maxsize=1) + def persons(self) -> pd.DataFrame: + """ Create the synthetic persons data-set. + + Read in the input synthetic person list and the sampled synthetic + person list, combine the lists taking only sampled persons, + map field values, and genericize field names. + + Returns: + A Pandas DataFrame of the synthetic persons """ + # load input synthetic person list into Pandas DataFrame + input_persons = pd.read_csv( + os.path.join(self.scenario_path, "input", "persons.csv"), + usecols=["hhid", + "perid", + "pnum", + "age", + "sex", + "miltary", + "pemploy", + "pstudent", + "ptype", + "educ", + "grade", + "weeks", + "hours", + "rac1p", + "hisp"], + dtype={"hhid": "int32", + "perid": "int32", + "pnum": "int8", + "age": "int8", + "sex": "int8", + "miltary": "int8", + "pemploy": "int8", + "pstudent": "int8", + "ptype": "int8", + "educ": "int8", + "grade": "int8", + "weeks": "int8", + "hours": "int8", + "rac1p": "int8", + "hisp": "int8"}) + + # load output sampled synthetic person list + fn_person_data = "personData_" + str(self.properties["iterations"]) + ".csv" + output_persons = pd.read_csv( + os.path.join(self.scenario_path, "output", fn_person_data), + usecols=["person_id", + "activity_pattern", + "fp_choice", + "reimb_pct", + "tele_choice"], + dtype={"person_id": "int32", + "activity_pattern": "string", + "fp_choice": "int8", + "reimb_pct": "float32", + "tele_choice": "int8"}) + + # load work-school location model results + fn_ws_loc_results = "wsLocResults_" + str(self.properties["iterations"]) + ".csv" + ws_loc_results = pd.read_csv( + os.path.join(self.scenario_path, "output", fn_ws_loc_results), + usecols=["PersonID", + "HomeMGRA", + "WorkSegment", + "SchoolSegment", + "WorkLocation", + "SchoolLocation"], + dtype={"PersonID": "int32", + "HomeMGRA": "int16", + "WorkSegment": "int32", + "SchoolSegment": "int32", + "WorkLocation": "int32", + "SchoolLocation": "int32"}) + + # merge output sampled persons with input sampled persons + # keep only persons present in the sampled persons + persons = output_persons.merge( + input_persons, + how="inner", + left_on="person_id", + right_on="perid" + ) + + # merge in work-school location model results + persons = persons.merge( + ws_loc_results, + how="inner", + left_on="person_id", + right_on="PersonID" + ) + + # if person works at home set work location to home MGRA + # if person is home-school set school location to home MGRA + persons["WorkLocation"] = np.where( + persons["WorkSegment"] == 99999, + persons["HomeMGRA"], + persons["WorkLocation"]) + + persons["SchoolLocation"] = np.where( + persons["SchoolSegment"] == 88888, + persons["HomeMGRA"], + persons["SchoolLocation"]) + + # apply exhaustive field mappings where applicable + mappings = { + "sex": {1: "Male", + 2: "Female"}, + "miltary": {0: "Not Active Military", + 1: "Active Military"}, + "pemploy": {1: "Employed Full-Time", + 2: "Employed Part-Time", + 3: "Unemployed or Not in Labor Force", + 4: "Less than 16 Years Old"}, + "pstudent": {1: "Pre K-12", + 2: "College Undergrad+Grad and Prof. School", + 3: "Not Attending School"}, + "ptype": {1: "Full-Time Worker", + 2: "Part-Time Worker", + 3: "College Student", + 4: "Non-Working Adult", + 5: "Non-Working Senior", + 6: "Driving Age Student", + 7: "Non-Driving Age Student", + 8: "Pre K or Child too Young for School"}, + "educ": {1: "Not a High School Graduate", + 9: "High School Graduate or Associates Degree", + 13: "Bachelors Degree or Higher"}, + "grade": {0: "Preschool or Not Attending School", + 2: "Kindergarten - Grade 8", + 5: "Grade 9 to Grade 12", + 6: "College Undergraduate or Higher"}, + "weeks": {1: "27 or More Weeks Worked per Year", + 5: "Less than 27 Weeks Worked per Year"}, + "hours": {0: "Less than 35 Hours Worked or Not Working", + 35: "35 or More Hours Worked"}, + "rac1p": {1: "White Alone", + 2: "Black or African American Alone", + 3: "American Indian Alone", + 4: "Alaska Native Alone", + 5: "American Indian and Alaska Native Tribes specified; or American Indian or Alaska Native not specified and no other races", + 6: "Asian Alone", + 7: "Native Hawaiian and Other Pacific Islander Alone", + 8: "Some Other Race Alone", + 9: "Two or More Major Race Groups"}, + "hisp": {1: "Non-Hispanic", + 2: "Hispanic"}, + "activity_pattern": {"H": "Home", + "M": "Mandatory", + "N": "Non-Mandatory"}, + "fp_choice": {1: "Has Free Parking", + 2: "Employer Pays for Parking", + 3: "Employer Reimburses for Parking"}, + "tele_choice": {0: "No telecommute", + 1: "One Day a Week", + 2: "Two-Three Days a Week", + 3: "Four or More Days a Week", + 9: "Telecommuter Only"}, + "WorkSegment": {0: "Management Business Science and Labor", + 1: "Services Labor", + 2: "Sales and Office Labor", + 3: "Natural Resources Construction and Maintenance Labor", + 4: "Production Transportation and Material Moving Labor", + 5: "Military Labor", + 99999: "Work from Home"}, + "SchoolSegment": {**{88888: "Home Schooled"}, + **{key: value for (key, value) in zip(list(range(0, 57)), + ["Unknown"] * 57)} + }, + "WorkLocation": {key: value for (key, value) in zip(list(range(1, 23003)), + list(range(1, 23003)))}, + "SchoolLocation": {key: value for (key, value) in zip(list(range(1, 23003)), + list(range(1, 23003)))} + } + + for field in mappings: + if field in ["WorkLocation", "SchoolLocation"]: + persons[field] = persons[field].map(mappings[field]).astype("float32") + else: + persons[field] = persons[field].map(mappings[field]).astype("category") + + # if employer does not reimburse for parking + # set parking reimbursement percentage to missing + persons.loc[persons["fp_choice"] != "Employer Reimburses for Parking", "reimb_pct"] = np.nan + persons.loc[persons["fp_choice"].isna(), "reimb_pct"] = np.nan + + # rename columns to standard/generic ABM naming conventions + persons.rename(columns={"perid": "personId", + "hhid": "hhId", + "pnum": "personNumber", + "miltary": "militaryStatus", + "pemploy": "employmentStatus", + "pstudent": "studentStatus", + "ptype": "abmPersonType", + "educ": "education", + "rac1p": "race", + "hisp": "hispanic", + "activity_pattern": "abmActivityPattern", + "fp_choice": "freeParkingChoice", + "reimb_pct": "parkingReimbursementPercentage", + "tele_choice": "telecommuteChoice", + "WorkSegment": "workSegment", + "SchoolSegment": "schoolSegment", + "WorkLocation": "workLocation", + "SchoolLocation": "schoolLocation"}, + inplace=True) + + return persons[["personId", + "hhId", + "personNumber", + "age", + "sex", + "militaryStatus", + "employmentStatus", + "studentStatus", + "abmPersonType", + "education", + "grade", + "weeks", + "hours", + "race", + "hispanic", + "abmActivityPattern", + "freeParkingChoice", + "parkingReimbursementPercentage", + "telecommuteChoice", + "workSegment", + "schoolSegment", + "workLocation", + "schoolLocation"]] + + +class TourLists(ScenarioData): + """ A subclass of the ScenarioData class. Holds all tour list data for a + completed ABM scenario model run. This includes all data from the ABM + sub-models with tours. These are held as class properties and include: + Cross Border Model + Commercial Vehicle Model + Internal-External Model + Individual Model + Joint Model + Visitor Model + + The tour list data is loaded from raw ABM output files in the scenario + output folder and transformed where applicable. + + Properties: + cross_border: Mexican Resident Cross Border model tour list + cvm: Commercial Vehicle model tour list + ie: San Diego Resident Internal-External model tour list + individual: San Diego Resident Individual travel model tour list + joint: San Diego Resident Joint travel model tour list + Visitor: Visitor model tour list + """ + @property + @lru_cache(maxsize=1) + def cross_border(self) -> pd.DataFrame: + """ Create the Cross-border Model tour list. + + Read in the Cross-border tour list, map field values, and genericize + field names. + + Returns: + A Pandas DataFrame of the Cross-border tour list """ + + # load tour list into Pandas DataFrame + tours = pd.read_csv( + os.path.join(self.scenario_path, "output", "crossBorderTours.csv"), + usecols=["id", + "purpose", + "sentri", + "poe", + "departTime", + "arriveTime", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tourMode"], + dtype={"id": "int32", + "purpose": "int8", + "sentri": "boolean", + "poe": "int8", + "departTime": "int8", + "arriveTime": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "originTAZ": "int16", + "destinationTAZ": "int16", + "tourMode": "int8"}) + + # apply exhaustive field mappings where applicable + mappings = { + "purpose": {0: "Work", + 1: "School", + 2: "Cargo", + 3: "Shop", + 4: "Visit", + 5: "Other"}, + "poe": {0: "San Ysidro", + 1: "Otay Mesa", + 2: "Tecate", + 3: "Otay Mesa East", + 4: "Jacumba"}, + "tourMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk"} + } + + for field in mappings: + tours[field] = tours[field].map(mappings[field]).astype("category") + + # map abm half hours to abm five time of day + tours["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.departTime) + tours["arriveTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.arriveTime) + + # rename columns to standard/generic ABM naming conventions + tours.rename(columns={"id": "tourID", + "purpose": "tourPurpose", + "poe": "pointOfEntry", + "departTime": "departTimeAbmHalfHour", + "arriveTime": "arriveTimeAbmHalfHour"}, + inplace=True) + + return tours[["tourID", + "tourPurpose", + "sentri", + "pointOfEntry", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tourMode"]] + + @property + @lru_cache(maxsize=1) + def cvm(self) -> pd.DataFrame: + """ Create the Commercial Vehicle Model tour list. + + Read in the Commercial Vehicle trip lists, apply share allocation, map + field values, genericize field names, and create the tour list from the + trip list. + + Returns: + A Pandas DataFrame of the Commercial Vehicle tour list """ + # create list of all Commercial Vehicle model trip list files + # files are of the form Trip_<>_<> + files = ["Trip" + "_" + i + "_" + j + ".csv" for i, j in + itertools.product(["FA", "GO", "IN", "RE", "SV", "TH", "WH"], + ["OE", "AM", "MD", "PM", "OL"])] + + # read all trip list files into a Pandas DataFrame + trips = pd.concat(( + pd.read_csv(os.path.join(self.scenario_path, "output", file), + usecols=["SerialNo", + "Trip", + "ActorType", + "HomeZone", + "Mode", + "StartTime", + "EndTime", + "TourType", + "OriginalTimePeriod"], + dtype={"SerialNo": "int32", + "Trip": "int8", + "ActorType": "string", + "HomeZone": "int16", + "Mode": "string", + "StartTime": "float32", + "EndTime": "float32", + "TourType": "string", + "OriginalTimePeriod": "string"}) + for file in files)) + + # apply re-allocation originally implemented in + # Java by Nagendra Dhakar + Joel Freedman at RSG + + # create lookup table of mode-tod-share using scenario properties + lookup = pd.DataFrame( + {"Mode": ["L"] * 5 + ["I"] * 5 + ["M"] * 5 + ["H"] * 5, + "OriginalTimePeriod": ["OE", "AM", "MD", "PM", "OL"] * 4, + "cvmShare": [self.properties["cvmShareLight"]] * 5 + + [0] * 5 + + [self.properties["cvmShareMedium"]] * 5 + + [self.properties["cvmShareHeavy"]] * 5}) + + # merge trip list and lookup table + trips = trips.merge(lookup) + + # within each mode, the properties file designates a percentage of the + # trip weight to be removed from the original trip and given to a new + # identical trip with the "I" (light-heavy duty truck) mode + new_trips = trips.loc[trips["cvmShare"] > 0].copy() + new_trips.reset_index(drop=True, inplace=True) + new_trips["Mode"] = "I" + trips = pd.concat([trips, new_trips], ignore_index=True) + + # create tour surrogate key + # unique tour is defined by (SerialNo, Mode) + trips["tourID"] = trips.groupby(["SerialNo", "Mode"]).ngroup().astype("int32") + 1 + + # create tour list using the first and last trip within each tour + # all tour data constant across trips excepting start/end times + # first trip provides start time, last trip provides end time + tours = trips.sort_values(by=["tourID", "Trip"]).groupby(["tourID"]) + tours = tours.head(1).merge(tours.tail(1)[["tourID", "EndTime"]], + on="tourID", + suffixes=("_start", "")) + + # apply exhaustive field mappings where applicable + mappings = { + "ActorType": {"FA": "Fleet Allocator", + "GO": "Government\\Office", + "IN": "Industry", + "RE": "Retail", + "SV": "Service", + "TH": "Transport", + "WH": "Wholesale"}, + "Mode": {"L": "Drive Alone", + "I": "Light Heavy Duty Truck", + "M": "Medium Heavy Duty Truck", + "H": "Heavy Heavy Duty Truck"}, + "TourType": {"G": "Goods", + "S": "Service", + "O": "Other"} + } + + for field in mappings: + tours[field] = tours[field].map(mappings[field]).astype("category") + + # map continuous start and end times to ABM half hour time periods + # times are in continuous hours of the day (0-24) and can wrap into + # the following day or even multiple following days (>24) with no + # upper limit + + # create times from continuous hour start and end times + # taking into account their wrapping into subsequent days + tours["StartTime"] = tours["StartTime"].apply( + lambda x: (datetime.combine(date.today(), time.min) + + timedelta(hours=(x % 24))).time()) + tours["EndTime"] = tours["EndTime"].apply( + lambda x: (datetime.combine(date.today(), time.min) + + timedelta(hours=(x % 24))).time()) + + # map continuous times to abm half hour periods + depart_half_hour = [ + [p["period"] for p in self.time_periods["abmHalfHour"] + if p["startTime"] <= x < p["endTime"]] + for x in tours["StartTime"]] + depart_half_hour = [val for sublist in depart_half_hour for val in sublist] + tours = tours.assign(departTimeAbmHalfHour=depart_half_hour) + tours["departTimeAbmHalfHour"] = tours["departTimeAbmHalfHour"].astype("int8") + + arrive_half_hour = [ + [p["period"] for p in self.time_periods["abmHalfHour"] + if p["startTime"] <= x < p["endTime"]] + for x in tours["EndTime"]] + arrive_half_hour = [val for sublist in arrive_half_hour for val in sublist] + tours = tours.assign(arriveTimeAbmHalfHour=arrive_half_hour) + tours["arriveTimeAbmHalfHour"] = tours["arriveTimeAbmHalfHour"].astype("int8") + + # map abm half hours to abm five time of day + tours["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.departTimeAbmHalfHour) + tours["arriveTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.arriveTimeAbmHalfHour) + + # rename columns to standard/generic ABM naming conventions + tours.rename(columns={"ActorType": "actorType", + "TourType": "tourPurpose", + "HomeZone": "originTAZ", + "Mode": "tourMode"}, + inplace=True) + + return tours[["tourID", + "actorType", + "tourPurpose", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "originTAZ", + "tourMode"]] + + @property + @lru_cache(maxsize=1) + def ie(self) -> pd.DataFrame: + """ Create the Internal-External Model tour list. + + Read in the Internal-External trip list, map field values, genericize + field names, and create the tour list from the trip list. + + Returns: + A Pandas DataFrame of the Internal-External tour list """ + + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", "internalExternalTrips.csv"), + usecols=["personID", + "tourID", + "inbound", + "period", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tripMode"], + dtype={"personID": "int32", + "tourID": "int32", + "inbound": "boolean", + "period": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "originTAZ": "int16", + "destinationTAZ": "int16", + "tripMode": "int8"}) + + # create tour list using the first and last trip within each tour + # all tour data constant across trips excepting start/end times + # first trip provides start time, last trip provides end time + # first trip also provides the tour destination + tours = trips.sort_values(by=["tourID", "inbound"]).groupby(["tourID"]) + tours = tours.head(1).merge(tours.tail(1)[["tourID", "period"]], + on="tourID", + suffixes=("Start", "End")) + + # apply exhaustive field mappings where applicable + mappings = { + "tripMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"}, + } + + for field in mappings: + tours[field] = tours[field].map(mappings[field]).astype("category") + + # map abm half hours to abm five time of day + tours["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.periodStart) + tours["arriveTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.periodEnd) + + # rename columns to standard/generic ABM naming conventions + tours.rename(columns={"periodStart": "departTimeAbmHalfHour", + "periodEnd": "arriveTimeAbmHalfHour", + "tripMode": "tourMode"}, + inplace=True) + + return tours[["tourID", + "personID", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tourMode"]] + + @property + @lru_cache(maxsize=1) + def individual(self) -> pd.DataFrame: + """ Create the Individual Model tour list. + + Read in the Individual tour list, map field values and genericize + field names. + + Returns: + A Pandas DataFrame of the Individual tour list """ + + # load tour list into Pandas DataFrame + fn = "indivTourData_" + str(self.properties["iterations"]) + ".csv" + tours = pd.read_csv( + os.path.join(self.scenario_path, "output", fn), + usecols=["person_id", + "tour_id", + "tour_category", + "tour_purpose", + "orig_mgra", + "dest_mgra", + "start_period", + "end_period", + "tour_mode"], + dtype={"person_id": "int32", + "tour_id": "int8", + "tour_category": "string", + "tour_purpose": "string", + "orig_mgra": "int16", + "dest_mgra": "int16", + "start_period": "int8", + "end_period": "int8", + "tour_mode": "int8"}) + + # apply exhaustive field mappings where applicable + mappings = { + "tour_category": {"AT_WORK": "At-Work", + "INDIVIDUAL_NON_MANDATORY": "Individual Non-Mandatory", + "MANDATORY": "Mandatory"}, + "tour_mode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC", + 13: "School Bus"} + } + + for field in mappings: + tours[field] = tours[field].map(mappings[field]).astype("category") + + # create tour surrogate key (person_id, tour_id, tour_purpose) + tour_key = ["person_id", "tour_id", "tour_purpose"] + tours["tourID"] = tours.groupby(tour_key).ngroup().astype("int32") + 1 + + # add TAZ information in addition to MGRA information + taz_info = self.mgra_xref[["MGRA", "TAZ"]] + + tours = tours.merge(taz_info, left_on="orig_mgra", right_on="MGRA") + tours.rename(columns={"TAZ": "originTAZ"}, inplace=True) + + tours = tours.merge(taz_info, left_on="dest_mgra", right_on="MGRA") + tours.rename(columns={"TAZ": "destinationTAZ"}, inplace=True) + + # map abm half hours to abm five time of day + tours["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.start_period) + tours["arriveTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.end_period) + + # rename columns to standard/generic ABM naming conventions + tours.rename(columns={"person_id": "personID", + "tour_category": "tourCategory", + "tour_purpose": "tourPurpose", + "start_period": "departTimeAbmHalfHour", + "end_period": "arriveTimeAbmHalfHour", + "orig_mgra": "originMGRA", + "dest_mgra": "destinationMGRA", + "tour_mode": "tourMode"}, + inplace=True) + + return tours[["tourID", + "personID", + "tourCategory", + "tourPurpose", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tourMode"]] + + @property + @lru_cache(maxsize=1) + def joint(self) -> pd.DataFrame: + """ Create the Joint Model tour list. + + Read in the Joint tour list, map field values and genericize field + names. + + Returns: + A Pandas DataFrame of the Joint tour list """ + + # load tour list into Pandas DataFrame + fn = "jointTourData_" + str(self.properties["iterations"]) + ".csv" + tours = pd.read_csv( + os.path.join(self.scenario_path, "output", fn), + usecols=["hh_id", + "tour_id", + "tour_category", + "tour_purpose", + "tour_participants", + "orig_mgra", + "dest_mgra", + "start_period", + "end_period", + "tour_mode"], + dtype={"hh_id": "int32", + "tour_id": "int8", + "tour_category": "string", + "tour_purpose": "string", + "tour_participants": "string", + "orig_mgra": "int16", + "dest_mgra": "int16", + "start_period": "int8", + "end_period": "int8", + "tour_mode": "int8"}) + + # apply exhaustive field mappings where applicable + mappings = { + "tour_category": {"JOINT_NON_MANDATORY": "Joint Non-Mandatory"}, + "tour_mode": {2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"} + } + + for field in mappings: + tours[field] = tours[field].map(mappings[field]).astype("category") + + # create tour surrogate key (hh_id, tour_id) + tour_key = ["hh_id", "tour_id"] + tours["tourID"] = tours.groupby(tour_key).ngroup().astype("int32") + 1 + + # add TAZ information in addition to MGRA information + taz_info = self.mgra_xref[["MGRA", "TAZ"]] + + tours = tours.merge(taz_info, left_on="orig_mgra", right_on="MGRA") + tours.rename(columns={"TAZ": "originTAZ"}, inplace=True) + + tours = tours.merge(taz_info, left_on="dest_mgra", right_on="MGRA") + tours.rename(columns={"TAZ": "destinationTAZ"}, inplace=True) + + # map abm half hours to abm five time of day + tours["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.start_period) + tours["arriveTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.end_period) + + # rename columns to standard/generic ABM naming conventions + tours.rename(columns={"hh_id": "hhID", + "tour_category": "tourCategory", + "tour_purpose": "tourPurpose", + "tour_participants": "tourParticipants", + "start_period": "departTimeAbmHalfHour", + "end_period": "arriveTimeAbmHalfHour", + "orig_mgra": "originMGRA", + "dest_mgra": "destinationMGRA", + "tour_mode": "tourMode"}, + inplace=True) + + return tours[["tourID", + "hhID", + "tourParticipants", + "tourCategory", + "tourPurpose", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tourMode"]] + + @property + @lru_cache(maxsize=1) + def visitor(self) -> pd.DataFrame: + """ Create the Visitor Model tour list. + + Read in the Visitor tour list, map field values and genericize field + names. + + Returns: + A Pandas DataFrame of the Visitor tour list """ + + # load tour list into Pandas DataFrame + tours = pd.read_csv( + os.path.join(self.scenario_path, "output", "visitorTours.csv"), + usecols=["id", + "segment", + "purpose", + "partySize", + "income", + "departTime", + "arriveTime", + "originMGRA", + "destinationMGRA", + "tourMode"], + dtype={"id": "int32", + "segment": "int8", + "purpose": "int8", + "partySize": "int8", + "income": "int8", + "departTime": "int8", + "arriveTime": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "tourMode": "int8"}) + + # apply exhaustive field mappings where applicable + mappings = { + "segment": {0: "Business", + 1: "Personal"}, + "purpose": {0: "Work", + 1: "Recreation", + 2: "Dining"}, + "income": {0: "Less than 30k", + 1: "30k-60k", + 2: "60k-100k", + 3: "100k-150k", + 4: "150k+"}, + "tourMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"} + } + + for field in mappings: + tours[field] = tours[field].map(mappings[field]).astype("category") + + # add TAZ information in addition to MGRA information + taz_info = self.mgra_xref[["MGRA", "TAZ"]] + + tours = tours.merge(taz_info, left_on="originMGRA", right_on="MGRA") + tours.rename(columns={"TAZ": "originTAZ"}, inplace=True) + + tours = tours.merge(taz_info, left_on="destinationMGRA", right_on="MGRA") + tours.rename(columns={"TAZ": "destinationTAZ"}, inplace=True) + + # map abm half hours to abm five time of day + tours["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.departTime) + tours["arriveTimeFiveTod"] = self._map_time_periods(abm_half_hour=tours.arriveTime) + + # rename columns to standard/generic ABM naming conventions + tours.rename(columns={"id": "tourID", + "purpose": "tourPurpose", + "departTime": "departTimeAbmHalfHour", + "arriveTime": "arriveTimeAbmHalfHour"}, + inplace=True) + + return tours[["tourID", + "segment", + "tourPurpose", + "partySize", + "income", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tourMode"]] + + +class TripLists(ScenarioData): + """ A subclass of the ScenarioData class. Holds all trip list data for a + completed ABM scenario model run. This includes all data from the ten ABM + sub-models. These are held as class properties and include: + Airport (CBX) Model + Airport (SAN) Model + Cross Border Model + Commercial Vehicle Model + External-External Model + External-Internal Model + Internal-External Model + Individual Model + Joint Model + Truck Model + Visitor Model + Zombie AV Trips + Zombie TNC Trips + + The trip list data is loaded from raw ABM output files in the scenario + output folder and given consistent fields and field values. + + Methods: + _combine_mode_set: Combines ABM mode field with transit skim set + field + _combine_mode_walk: Recodes ABM mode field using the ABM walk mode + field for walk mode trips + + Properties: + airport_cbx: Cross Border Express (CBX) model trip list + airport_san: San Diego Airport (SAN) model trip list + cross_border: Mexican Resident Cross Border model trip list + cvm: Commercial Vehicle model trip list + ee: External-External model trip list, placed here until it can be + properly incorporated into the EMME data exporter process + ei: External-Internal model trip list, placed here until it can be + properly incorporated into the EMME data exporter process + ie: San Diego Resident Internal-External model trip list + individual: San Diego Resident Individual travel model trip list + joint: San Diego Resident Joint travel model trip list + truck: Truck model trip list, placed here until it can be + properly incorporated into the EMME data exporter process + visitor: Visitor model trip list + zombie_av: 0-passenger Autonomous Vehicle trip list + zombie_tnc: 0-passenger TNC Vehicle trip list + """ + + @staticmethod + def _combine_mode_set(mode: pd.Series, transit_set: pd.Series) -> pd.Series: + """ Combine Pandas Series of ABM mode field values with Pandas Series + of ABM transit skim set field values. + + Returns: + A Pandas Series of the combined mode and transit skim set field + values + """ + + # ensure series are string data type + mode = mode.astype("string") + transit_set = transit_set.astype("string") + + # if ABM mode field value contains the string Transit + # append the transit skim set field value + mode = np.where(mode.str.contains("Transit"), + mode + " - " + transit_set, + mode) + + return pd.Series(mode).astype("category") + + @staticmethod + def _combine_mode_walk(mode: pd.Series, walk_mode: pd.Series) -> pd.Series: + """ Combine Pandas Series of ABM mode field values with Pandas Series + of ABM walk mode (micro_walkMode) field values. Update the ABM mode + field value to the indicated ABM walk mode where appropriate. + + Returns: + A Pandas Series of the recoded ABM mode field values. + """ + + # ensure series are string data type + mode = mode.astype("string") + walk_mode = walk_mode.astype("string") + + # if ABM mode field value is Walk then use the ABM walk mode field + # value as the ABM mode, otherwise use the ABM mode field value + mode = np.where(mode == "Walk", + walk_mode, + mode) + + return pd.Series(mode).astype("category") + + @property + @lru_cache(maxsize=1) + def airport_cbx(self) -> pd.DataFrame: + """ Create the Cross Border Express (CBX) Airport Model trip list. + + Read in the CBX trip list, map field values, and genericize field + names. + + Returns: + A Pandas DataFrame of the CBX trip list """ + + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", "airport_out.CBX.csv"), + usecols=["id", + "direction", + "purpose", + "size", + "income", + "nights", + "departTime", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tripMode", + "arrivalMode", + "boardingTAP", + "alightingTAP", + "set", + "valueOfTime"], + dtype={"id": "int32", + "direction": "bool", + "purpose": "int8", + "size": "int8", + "income": "int8", + "nights": "int8", + "departTime": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "originTAZ": "int16", + "destinationTAZ": "int16", + "tripMode": "int8", + "arrivalMode": "int8", + "boardingTAP": "int16", + "alightingTAP": "int16", + "set": "int8", + "valueOfTime": "float32"}) + + # apply exhaustive field mappings where applicable + mappings = { + "purpose": {0: "Resident Business", + 1: "Resident Personal", + 2: "Visitor Business", + 3: "Visitor Personal", + 4: "External"}, + "income": {0: "Less than 25k", + 1: "25k-50k", + 2: "50k-75k", + 3: "75k-100k", + 4: "100k-125k", + 5: "125k-150k", + 6: "150k-200k", + 7: "200k+"}, + "tripMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"}, + "arrivalMode": {1: "Parking lot terminal", + 2: "Parking lot off-site San Diego airport area", + 3: "Parking lot off-site private", + 4: "Pickup/Drop-off escort", + 5: "Pickup/Drop-off curbside", + 6: "Rental car", + 7: "Taxi", + 8: "Non-Pooled TNC", + 9: "Pooled TNC", + 10: "Shuttle/van/courtesy vehicle", + 11: "Transit"}, + "boardingTAP": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "alightingTAP": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "set": {-1: "", + 0: "Local Bus", + 1: "Premium Transit", + 2: "Local Bus and Premium Transit"} + } + + for field in mappings: + if field in ["boardingTAP", "alightingTAP"]: + data_type = "float32" + else: + data_type = "category" + trips[field] = trips[field].map(mappings[field]).astype(data_type) + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=trips.departTime) + + # concatenate mode and transit skim set for transit trips + trips["tripMode"] = self._combine_mode_set(mode=trips.tripMode, transit_set=trips.set) + + # calculate value of time category auto skim set used + trips["valueOfTimeCategory"] = self._map_vot_categories(vot=trips.valueOfTime) + + # no airport trips use transponders or AVs + # no airport trips are allowed to park in another MGRA + # there is no destination purpose + trips["transponderAvailable"] = False + trips["avUsed"] = False + trips["parkingMGRA"] = pd.Series(np.NaN, dtype="float32") + trips["parkingTAZ"] = pd.Series(np.NaN, dtype="float32") + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + trips["weightTrip"] = 1 / self.properties["sampleRate"] + trips["weightTrip"] = trips["weightTrip"].astype("float32") + trips["weightPersonTrip"] = pd.Series(trips["size"] / self.properties["sampleRate"], dtype="float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"id": "tripID", + "direction": "inbound", + "purpose": "tripPurpose", + "income": "incomeCategory", + "nights": "nightsStayed", + "departTime": "departTimeAbmHalfHour"}, + inplace=True) + + return trips[["tripID", + "inbound", + "tripPurpose", + "incomeCategory", + "nightsStayed", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "arrivalMode", + "boardingTAP", + "alightingTAP", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip"]] + + @property + @lru_cache(maxsize=1) + def airport_san(self) -> pd.DataFrame: + """ Create the San Diego (SAN) Airport Model trip list. + + Read in the SAN trip list, map field values, and genericize field + names. + + Returns: + A Pandas DataFrame of the SAN trip list """ + + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", "airport_out.SAN.csv"), + usecols=["id", + "direction", + "purpose", + "size", + "income", + "nights", + "departTime", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tripMode", + "arrivalMode", + "boardingTAP", + "alightingTAP", + "set", + "valueOfTime"], + dtype={"id": "int32", + "direction": "bool", + "purpose": "int8", + "size": "int8", + "income": "int8", + "nights": "int8", + "departTime": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "originTAZ": "int16", + "destinationTAZ": "int16", + "tripMode": "int8", + "arrivalMode": "int8", + "boardingTAP": "int16", + "alightingTAP": "int16", + "set": "int8", + "valueOfTime": "float32"}) + + # apply exhaustive field mappings where applicable + mappings = { + "purpose": {0: "Resident Business", + 1: "Resident Personal", + 2: "Visitor Business", + 3: "Visitor Personal", + 4: "External"}, + "income": {0: "Less than 25k", + 1: "25k-50k", + 2: "50k-75k", + 3: "75k-100k", + 4: "100k-125k", + 5: "125k-150k", + 6: "150k-200k", + 7: "200k+"}, + "tripMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"}, + "arrivalMode": {1: "Parking lot terminal", + 2: "Parking lot off-site San Diego airport area", + 3: "Parking lot off-site private", + 4: "Pickup/Drop-off escort", + 5: "Pickup/Drop-off curbside", + 6: "Rental car", + 7: "Taxi", + 8: "Non-Pooled TNC", + 9: "Pooled TNC", + 10: "Shuttle/van/courtesy vehicle", + 11: "Transit"}, + "boardingTAP": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "alightingTAP": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "set": {-1: "", + 0: "Local Bus", + 1: "Premium Transit", + 2: "Local Bus and Premium Transit"} + } + + for field in mappings: + if field in ["boardingTAP", "alightingTAP"]: + data_type = "float32" + else: + data_type = "category" + trips[field] = trips[field].map(mappings[field]).astype(data_type) + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.departTime) + + # concatenate mode and transit skim set for transit trips + trips["tripMode"] = self._combine_mode_set(mode=trips.tripMode, transit_set=trips.set) + + # calculate value of time category auto skim set used + trips["valueOfTimeCategory"] = self._map_vot_categories(vot=trips.valueOfTime) + + # no airport trips use transponders or AVs + # no airport trips are allowed to park in another MGRA + # there is no destination purpose + trips["transponderAvailable"] = False + trips["avUsed"] = False + trips["parkingMGRA"] = pd.Series(np.NaN, dtype="float32") + trips["parkingTAZ"] = pd.Series(np.NaN, dtype="float32") + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + trips["weightTrip"] = 1 / self.properties["sampleRate"] + trips["weightTrip"] = trips["weightTrip"].astype("float32") + trips["weightPersonTrip"] = pd.Series(trips["size"] / self.properties["sampleRate"], dtype="float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"id": "tripID", + "direction": "inbound", + "purpose": "tripPurpose", + "income": "incomeCategory", + "nights": "nightsStayed", + "departTime": "departTimeAbmHalfHour"}, + inplace=True) + + return trips[["tripID", + "inbound", + "tripPurpose", + "incomeCategory", + "nightsStayed", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "arrivalMode", + "boardingTAP", + "alightingTAP", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip"]] + + @property + @lru_cache(maxsize=1) + def cross_border(self) -> pd.DataFrame: + """ Create the Cross-border Model trip list. + + Read in the Cross-border trip list, map field values, and genericize + field names. + + Returns: + A Pandas DataFrame of the Cross-border trip list """ + + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", "crossBorderTrips.csv"), + usecols=["tourID", + "tripID", + "inbound", + "period", + "originPurp", + "destPurp", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tripMode", + "boardingTap", + "alightingTap", + "set", + "valueOfTime", + "parkingCost"], + dtype={"tourID": "int32", + "tripID": "int8", + "inbound": "boolean", + "period": "int8", + "originPurp": "int8", + "destPurp": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "originTAZ": "int16", + "destinationTAZ": "int16", + "tripMode": "int8", + "boardingTap": "int16", + "alightingTap": "int16", + "set": "int8", + "valueOfTime": "float32", + "parkingCost": "float32"}) + + # use the tripID column from the data-set as stopID within the tour + # and create actual tripID field + trips.rename(columns={"tripID": "stopID"}, inplace=True) + trips = trips.sort_values(by=["tourID", "stopID"]).reset_index(drop=True) + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # apply exhaustive field mappings where applicable + mappings = { + "originPurp": {-1: "Unknown", + 0: "Work", + 1: "School", + 2: "Cargo", + 3: "Shop", + 4: "Visit", + 5: "Other"}, + "destPurp": {-1: "Unknown", + 0: "Work", + 1: "School", + 2: "Cargo", + 3: "Shop", + 4: "Visit", + 5: "Other"}, + "tripMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"}, + "boardingTap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "alightingTap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "set": {-1: "", + 0: "Local Bus", + 1: "Premium Transit", + 2: "Local Bus and Premium Transit"} + } + + for field in mappings: + if field in ["boardingTap", "alightingTap"]: + trips[field] = trips[field].map(mappings[field]).astype("float32") + else: + trips[field] = trips[field].map(mappings[field]).astype("category") + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.period) + + # concatenate mode and transit skim set for transit trips + trips["tripMode"] = self._combine_mode_set(mode=trips.tripMode, + transit_set=trips.set) + + # calculate value of time category auto skim set used + trips["valueOfTimeCategory"] = self._map_vot_categories( + vot=trips.valueOfTime) + + # transform parking cost from cents to dollars + trips["parkingCost"] = round(trips.parkingCost / 100, 2) + + # no cross-border trips use transponders or AVs + # no cross-border trips are allowed to park in another MGRA + trips["transponderAvailable"] = False + trips["avUsed"] = False + trips["parkingMGRA"] = pd.Series(np.NaN, dtype="float32") + trips["parkingTAZ"] = pd.Series(np.NaN, dtype="float32") + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + conditions = [(trips["tripMode"] == "Shared Ride 2"), + (trips["tripMode"] == "Shared Ride 3+"), + (trips["tripMode"] == "Taxi"), + (trips["tripMode"] == "Non-Pooled TNC"), + (trips["tripMode"] == "Pooled TNC")] + choices = [1 / self.properties["sr2Passengers"], + 1 / self.properties["sr3Passengers"], + 1 / self.properties["taxiPassengers"], + 1 / self.properties["nonPooledTNCPassengers"], + 1 / self.properties["pooledTNCPassengers"]] + + trips["weightTrip"] = pd.Series(np.select(conditions, choices, default=1) / self.properties["sampleRate"], dtype="float32") + trips["weightPersonTrip"] = 1 / self.properties["sampleRate"] + trips["weightPersonTrip"] = trips["weightPersonTrip"].astype("float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"id": "tripID", + "period": "departTimeAbmHalfHour", + "originPurp": "tripPurposeOrigin", + "destPurp": "tripPurposeDestination", + "parkingCost": "costParking", + "boardingTap": "boardingTAP", + "alightingTap": "alightingTAP"}, + inplace=True) + + return trips[["tripID", + "tourID", + "stopID", + "inbound", + "tripPurposeOrigin", + "tripPurposeDestination", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "boardingTAP", + "alightingTAP", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip", + "costParking"]] + + @property + @lru_cache(maxsize=1) + def cvm(self) -> pd.DataFrame: + """ Create the Commercial Vehicle Model trip list. + + Read in the Commercial Vehicle trip list, apply trip scaling and share + allocation, map field values, and genericize field names. + + Returns: + A Pandas DataFrame of the Commercial Vehicle trip list """ + + # create list of all Commercial Vehicle model trip list files + # files are of the form Trip_<>_<> + files = ["Trip" + "_" + i + "_" + j + ".csv" for i, j in + itertools.product(["FA", "GO", "IN", "RE", "SV", "TH", "WH"], + ["OE", "AM", "MD", "PM", "OL"])] + + # read all trip list files into a Pandas DataFrame + trips = pd.concat(( + pd.read_csv(os.path.join(self.scenario_path, "output", file), + usecols=["SerialNo", + "Trip", + "HomeZone", + "ActorType", + "OPurp", + "DPurp", + "I", + "J", + "Mode", + "StartTime", + "EndTime", + "StopDuration", + "TourType", + "OriginalTimePeriod"], + dtype={"SerialNo": "int32", + "Trip": "int8", + "ActorType": "string", + "HomeZone": "int16", + "OPurp": "string", + "DPurp": "string", + "I": "int16", + "J": "int16", + "Mode": "string", + "StartTime": "float32", + "EndTime": "float32", + "StopDuration": "float32", + "TourType": "string", + "OriginalTimePeriod": "string"} + ) + for file in files)) + + # apply weighting and share re-allocation originally implemented in + # Java by Nagendra Dhakar + Joel Freedman at RSG + + # create lookup table of mode-tod-scale-share using scenario properties + lookup = pd.DataFrame( + {"Mode": ["L"] * 5 + ["I"] * 5 + ["M"] * 5 + ["H"] * 5, + "OriginalTimePeriod": ["OE", "AM", "MD", "PM", "OL"] * 4, + "cvmScale": self.properties["cvmScaleLight"] + + self.properties["cvmScaleMedium"] + + self.properties["cvmScaleMedium"] + + self.properties["cvmScaleHeavy"], + "cvmShare": [self.properties["cvmShareLight"]] * 5 + + [0] * 5 + + [self.properties["cvmShareMedium"]] * 5 + + [self.properties["cvmShareHeavy"]] * 5}) + + # merge trip list and lookup table + trips = trips.merge(lookup) + + # within each mode, the properties file designates a percentage of the + # trip weight to be removed from the original trip and given to a new + # identical trip with the "I" (light-heavy duty truck) mode + new_trips = trips.loc[trips["cvmShare"] > 0].copy() + new_trips.reset_index(drop=True, inplace=True) + new_trips["Mode"] = "I" + + # within each mode and tour start abm five time of day period, the + # properties file designates a scaling factor to apply to the trip + # weight taking into account the share factor + new_trips["weightTrip"] = new_trips["cvmScale"] * new_trips["cvmShare"] + trips["weightTrip"] = trips["cvmScale"] * (1 - trips["cvmShare"]) + trips = pd.concat([trips, new_trips], ignore_index=True) + + # apply exhaustive field mappings where applicable + mappings = { + "OPurp": {"Est": "Return to Establishment", + "Gds": "Goods", + "Srv": "Service", + "Oth": "Other"}, + "DPurp": {"Est": "Return to Establishment", + "Gds": "Goods", + "Srv": "Service", + "Oth": "Other"}, + "Mode": {"L": "Drive Alone", + "I": "Light Heavy Duty Truck", + "M": "Medium Heavy Duty Truck", + "H": "Heavy Heavy Duty Truck"}, + } + + for field in mappings: + trips[field] = trips[field].map(mappings[field]).astype("category") + + # create tour and trip surrogate keys + # unique tour is defined by (SerialNo, Mode) + # unique trip is defined by (SerialNo, Mode, Trip) + trips["tourID"] = trips.groupby(["SerialNo", "Mode"]).ngroup().astype("int32") + 1 + trips = trips.sort_values(by=["SerialNo", "Mode", "Trip"]).reset_index(drop=True) + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # map continuous start and end times to ABM half hour time periods + # times are in continuous hours of the day (0-24) and can wrap into + # the following day or even multiple following days (>24) with no + # upper limit + + # create times from continuous hour start and end times + # taking into account their wrapping into subsequent days + trips["StartTime"] = trips["StartTime"].apply( + lambda x: (datetime.combine(date.today(), time.min) + + timedelta(hours=(x % 24))).time()) + trips["EndTime"] = trips["EndTime"].apply( + lambda x: (datetime.combine(date.today(), time.min) + + timedelta(hours=(x % 24))).time()) + + # map continuous times to abm half hour periods + depart_half_hour = [ + [p["period"] for p in self.time_periods["abmHalfHour"] + if p["startTime"] <= x < p["endTime"]] + for x in trips["StartTime"]] + depart_half_hour = [val for sublist in depart_half_hour for val in sublist] + trips = trips.assign(departTimeAbmHalfHour=depart_half_hour) + trips["departTimeAbmHalfHour"] = trips["departTimeAbmHalfHour"].astype("int8") + + arrive_half_hour = [ + [p["period"] for p in self.time_periods["abmHalfHour"] + if p["startTime"] <= x < p["endTime"]] + for x in trips["EndTime"]] + arrive_half_hour = [val for sublist in arrive_half_hour for val in sublist] + trips = trips.assign(arriveTimeAbmHalfHour=arrive_half_hour) + trips["arriveTimeAbmHalfHour"] = trips["arriveTimeAbmHalfHour"].astype("int8") + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.departTimeAbmHalfHour) + + trips["arriveTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.arriveTimeAbmHalfHour) + + # all cvm trips are high value of time + # only Drive Alone cvm trips use transponders + # no cvm trips use AVs + # no cvm trips are allowed to park in another MGRA + trips["valueOfTimeCategory"] = "High" + trips["valueOfTimeCategory"] = trips["valueOfTimeCategory"].astype("category") + trips["transponderAvailable"] = np.where(trips["Mode"] == "Drive Alone", True, False) + trips["avUsed"] = False + trips["parkingTAZ"] = pd.Series(np.NaN, dtype="float32") + + # add person-based weight and adjust weights + # by the ABM scenario final iteration sample rate + trips["weightTrip"] = pd.Series(trips["weightTrip"] / self.properties["sampleRate"], dtype="float32") + trips["weightPersonTrip"] = trips["weightTrip"] + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"Trip": "stopID", + "OPurp": "tripPurposeOrigin", + "DPurp": "tripPurposeDestination", + "I": "originTAZ", + "J": "destinationTAZ", + "Mode": "tripMode", + "StopDuration": "stopDuration"}, + inplace=True) + + return trips[["tripID", + "tourID", + "stopID", + "tripPurposeOrigin", + "tripPurposeDestination", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "stopDuration", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip"]] + + @property + @lru_cache(maxsize=1) + def ee(self) -> pd.DataFrame: + """ Create the External-External Model trip list. + + Read in the External-External trip last, map field values, and + genericize field names. + + Returns: + A Pandas DataFrame of the External-External trips list """ + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "report", "eetrip.csv"), + usecols=["OTAZ", + "DTAZ", + "TOD", + "MODE", + "TRIPS", + "TIME", + "DIST", + "AOC", + "TOLLCOST"], + dtype={"OTAZ": "int16", + "DTAZ": "int16", + "TOD": "string", + "MODE": "string", + "TRIPS": "float32", + "TIME": "float32", + "DIST": "float32", + "AOC": "float32", + "TOLLCOST": "float32"}) + + # expand trip list by 3x + # divide [TRIPS] field by 3 + # assign each copy of trip list to each value of time category + trips_low = trips.copy() + trips_low["valueOfTimeCategory"] = "Low" + + trips_med = trips.copy() + trips_med["valueOfTimeCategory"] = "Medium" + + trips_high = trips.copy() + trips_high["valueOfTimeCategory"] = "High" + + trips = pd.concat([trips_low, trips_med, trips_high], ignore_index=True) + + trips["TRIPS"] = trips["TRIPS"] / 3 + + # create trip surrogate key + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # apply exhaustive field mappings where applicable + mappings = { + "TOD": {"EA": 1, + "AM": 2, + "MD": 3, + "PM": 4, + "EV": 5}, + "MODE": {"DA": "Drive Alone", + "S2": "Shared Ride 2", + "S3": "Shared Ride 3+"} + } + + for field in mappings: + if field == "TOD": + trips[field] = trips[field].map(mappings[field]).astype("int8") + else: + trips[field] = trips[field].map(mappings[field]).astype("category") + + # convert cents-based cost fields to dollars + trips["AOC"] = trips["AOC"] / 100 + trips["TOLLCOST"] = trips["TOLLCOST"] / 100 + + # no trips use transponders or autonomous vehicles + trips["transponderAvailable"] = False + trips["avUsed"] = False + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + conditions = [(trips["MODE"] == "Shared Ride 2"), + (trips["MODE"] == "Shared Ride 3+")] + choices = [self.properties["sr2Passengers"], + self.properties["sr3Passengers"]] + + trips["weightPersonTrip"] = pd.Series( + trips["TRIPS"] * np.select(conditions, choices, default=1) / self.properties["sampleRate"], + dtype="float32") + trips["weightTrip"] = trips["TRIPS"] / self.properties["sampleRate"] + trips["weightTrip"] = trips["weightTrip"].astype("float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"OTAZ": "originTAZ", + "DTAZ": "destinationTAZ", + "TOD": "departTimeFiveTod", + "MODE": "tripMode", + "TIME": "timeDrive", + "DIST": "distanceDrive", + "AOC": "costOperatingDrive", + "TOLLCOST": "costTollDrive"}, + inplace=True) + + # create total time/distance/cost columns + trips["timeTotal"] = trips["timeDrive"] + trips["distanceTotal"] = trips["distanceDrive"] + trips["costTotal"] = trips["costTollDrive"] + trips["costOperatingDrive"] + + return trips[["tripID", + "departTimeFiveTod", + "originTAZ", + "destinationTAZ", + "tripMode", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip", + "timeDrive", + "distanceDrive", + "costTollDrive", + "costOperatingDrive", + "timeTotal", + "distanceTotal", + "costTotal"]] + + @property + @lru_cache(maxsize=1) + def ei(self) -> pd.DataFrame: + """ Create the External-Internal Model trip list. + + Read in the External-Internal trip last, map field values, and + genericize field names. + + Returns: + A Pandas DataFrame of the External-Internal trips list """ + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "report", "eitrip.csv"), + usecols=["OTAZ", + "DTAZ", + "TOD", + "MODE", + "PURPOSE", + "TRIPS", + "TIME", + "DIST", + "AOC", + "TOLLCOST"], + dtype={"OTAZ": "int16", + "DTAZ": "int16", + "TOD": "string", + "MODE": "string", + "PURPOSE": "string", + "TRIPS": "float32", + "TIME": "float32", + "DIST": "float32", + "AOC": "float32", + "TOLLCOST": "float32"}) + + # expand trip list by 3x + # divide [TRIPS] field by 3 + # assign each copy of trip list to each value of time category + trips_low = trips.copy() + trips_low["valueOfTimeCategory"] = "Low" + + trips_med = trips.copy() + trips_med["valueOfTimeCategory"] = "Medium" + + trips_high = trips.copy() + trips_high["valueOfTimeCategory"] = "High" + + trips = pd.concat([trips_low, trips_med, trips_high], ignore_index=True) + + trips["TRIPS"] = trips["TRIPS"] / 3 + + # create trip surrogate key + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # apply exhaustive field mappings where applicable + mappings = { + "TOD": {"EA": 1, + "AM": 2, + "MD": 3, + "PM": 4, + "EV": 5}, + "MODE": {"DAN": "Drive Alone", + "DAT": "Drive Alone", + "S2N": "Shared Ride 2", + "S2T": "Shared Ride 2", + "S3N": "Shared Ride 3+", + "S3T": "Shared Ride 3+"}, + "PURPOSE": {"NONWORK": "Non-Work", + "WORK": "Work"} + } + + for field in mappings: + if field == "TOD": + trips[field] = trips[field].map(mappings[field]).astype("int8") + else: + trips[field] = trips[field].map(mappings[field]).astype("category") + + # convert cents-based cost fields to dollars + trips["AOC"] = trips["AOC"] / 100 + trips["TOLLCOST"] = trips["TOLLCOST"] / 100 + + # no trips use transponders or autonomous vehicles + trips["transponderAvailable"] = False + trips["avUsed"] = False + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + conditions = [(trips["MODE"] == "Shared Ride 2"), + (trips["MODE"] == "Shared Ride 3+")] + choices = [self.properties["sr2Passengers"], + self.properties["sr3Passengers"]] + + trips["weightPersonTrip"] = pd.Series( + trips["TRIPS"] * np.select(conditions, choices, default=1) / self.properties["sampleRate"], + dtype="float32") + trips["weightTrip"] = trips["TRIPS"] / self.properties["sampleRate"] + trips["weightTrip"] = trips["weightTrip"].astype("float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"OTAZ": "originTAZ", + "DTAZ": "destinationTAZ", + "TOD": "departTimeFiveTod", + "MODE": "tripMode", + "PURPOSE": "tripPurpose", + "TIME": "timeDrive", + "DIST": "distanceDrive", + "AOC": "costOperatingDrive", + "TOLLCOST": "costTollDrive"}, + inplace=True) + + # create total time/distance/cost columns + trips["timeTotal"] = trips["timeDrive"] + trips["distanceTotal"] = trips["distanceDrive"] + trips["costTotal"] = trips["costTollDrive"] + trips["costOperatingDrive"] + + return trips[["tripID", + "departTimeFiveTod", + "originTAZ", + "destinationTAZ", + "tripMode", + "tripPurpose", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip", + "timeDrive", + "distanceDrive", + "costTollDrive", + "costOperatingDrive", + "timeTotal", + "distanceTotal", + "costTotal"]] + + @property + @lru_cache(maxsize=1) + def ie(self) -> pd.DataFrame: + """ Create the Internal-External Model trip list. + + Read in the Internal-External trip list, map field values, + and genericize field names. + + Returns: + A Pandas DataFrame of the Internal-External trip list """ + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", "internalExternalTrips.csv"), + usecols=["hhID", + "personID", + "tourID", + "inbound", + "period", + "originMGRA", + "destinationMGRA", + "originTAZ", + "destinationTAZ", + "tripMode", + "av_avail", + "boardingTap", + "alightingTap", + "set", + "valueOfTime"], + dtype={"hhID": "int32", + "personID": "int32", + "tourID": "int32", + "inbound": "boolean", + "period": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "originTAZ": "int16", + "destinationTAZ": "int16", + "tripMode": "int8", + "av_avail": "bool", + "boardingTap": "int16", + "alightingTap": "int16", + "set": "int8", + "valueOfTime": "float32"}) + + # load output household transponder ownership data + hh_fn = "householdData_" + str(self.properties["iterations"]) + ".csv" + hh = pd.read_csv( + os.path.join(self.scenario_path, "output", hh_fn), + usecols=["hh_id", + "transponder"], + dtype={"hh_id": "int32", + "transponder": "bool"}) + + # if household has a transponder then all trips can use it + trips = trips.merge(hh, left_on="hhID", right_on="hh_id") + + # apply exhaustive field mappings where applicable + mappings = { + "tripMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"}, + "boardingTap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "alightingTap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "set": {-1: "", + 0: "Local Bus", + 1: "Premium Transit", + 2: "Local Bus and Premium Transit"} + } + + for field in mappings: + if field in ["boardingTap", "alightingTap"]: + data_type = "float32" + else: + data_type = "category" + trips[field] = trips[field].map(mappings[field]).astype(data_type) + + # create trip surrogate key + # create stop surrogate key + # every tourID contains only two trips (outbound and inbound) + trips["stopID"] = trips.sort_values(by=["tourID", "inbound"]).groupby(["tourID"]).cumcount().astype("int8") + 1 + trips = trips.sort_values(by=["tourID", "stopID"]).reset_index(drop=True) + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.period + ) + + # concatenate mode and transit skim set for transit trips + trips["tripMode"] = self._combine_mode_set( + mode=trips.tripMode, + transit_set=trips.set + ) + + # calculate value of time category auto skim set used + trips["valueOfTimeCategory"] = self._map_vot_categories( + vot=trips.valueOfTime + ) + + # no internal-external trips are allowed to park in another MGRA + trips["parkingMGRA"] = pd.Series(np.nan, dtype="float32") + trips["parkingTAZ"] = pd.Series(np.nan, dtype="float32") + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + conditions = [(trips["tripMode"] == "Shared Ride 2"), + (trips["tripMode"] == "Shared Ride 3+"), + (trips["tripMode"] == "Taxi"), + (trips["tripMode"] == "Non-Pooled TNC"), + (trips["tripMode"] == "Pooled TNC")] + choices = [1 / self.properties["sr2Passengers"], + 1 / self.properties["sr3Passengers"], + 1 / self.properties["taxiPassengers"], + 1 / self.properties["nonPooledTNCPassengers"], + 1 / self.properties["pooledTNCPassengers"]] + + trips["weightTrip"] = pd.Series( + np.select(conditions, choices, default=1) / self.properties["sampleRate"], + dtype="float32") + trips["weightPersonTrip"] = 1 / self.properties["sampleRate"] + trips["weightPersonTrip"] = trips["weightPersonTrip"].astype("float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"period": "departTimeAbmHalfHour", + "av_avail": "avUsed", + "boardingTap": "boardingTAP", + "alightingTap": "alightingTAP", + "transponder": "transponderAvailable"}, + inplace=True) + + return trips[["tripID", + "personID", + "tourID", + "stopID", + "inbound", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "boardingTAP", + "alightingTAP", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip"]] + + @property + @lru_cache(maxsize=1) + def individual(self) -> pd.DataFrame: + """ Create the Individual Model trip list. + + Read in the Individual trip list, map field values, and genericize + field names. + + Returns: + A Pandas DataFrame of the Individual trip list """ + # load trip list into Pandas DataFrame + fn = "indivTripData_" + str(self.properties["iterations"]) + ".csv" + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", fn), + usecols=["person_id", + "tour_id", + "stop_id", + "inbound", + "tour_purpose", + "orig_purpose", + "dest_purpose", + "orig_mgra", + "dest_mgra", + "parking_mgra", + "stop_period", + "trip_mode", + "av_avail", + "trip_board_tap", + "trip_alight_tap", + "set", + "valueOfTime", + "transponder_avail", + "micro_walkMode", + "micro_trnAcc", + "micro_trnEgr", + "parkingCost"], + dtype={"person_id": "int32", + "tour_id": "int8", + "stop_id": "int8", + "inbound": "bool", + "tour_purpose": "string", + "orig_purpose": "string", + "dest_purpose": "string", + "orig_mgra": "int16", + "dest_mgra": "int16", + "parking_mgra": "int16", + "stop_period": "int8", + "trip_mode": "int8", + "av_avail": "bool", + "trip_board_tap": "int16", + "trip_alight_tap": "int16", + "set": "int8", + "valueOfTime": "float32", + "transponder_avail": "bool", + "micro_walkMode": "int8", + "micro_trnAcc": "int8", + "micro_trnEgr": "int8", + "parkingCost": "float32"}) + + # apply exhaustive field mappings where applicable + mappings = { + "parking_mgra": {key: value for (key, value) in + zip(list(range(1, 23003)), + list(range(1, 23003)))}, + "trip_mode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC", + 13: "School Bus"}, + "trip_board_tap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "trip_alight_tap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "set": {0: "Local Bus", + 1: "Premium Transit", + 2: "Local Bus and Premium Transit"}, + "micro_walkMode": {1: "Walk", + 2: "Micro-Mobility", + 3: "Micro-Transit"}, + "micro_trnAcc": {1: "Walk", + 2: "Micro-Mobility", + 3: "Micro-Transit"}, + "micro_trnEgr": {1: "Walk", + 2: "Micro-Mobility", + 3: "Micro-Transit"} + } + + for field in mappings: + if field in ["parking_mgra", "trip_board_tap", "trip_alight_tap"]: + data_type = "float32" + else: + data_type = "category" + trips[field] = trips[field].map(mappings[field]).astype(data_type) + + # create tour surrogate key (person_id, tour_id, tour_purpose) + tour_key = ["person_id", "tour_id", "tour_purpose"] + trips["tourID"] = pd.Series(trips.groupby(tour_key).ngroup() + 1, dtype="int32") + + # create tour stop surrogate key (inbound, stop_id) + stop_key = ["inbound", "stop_id"] + trips["stopID"] = pd.Series(trips.sort_values(by=stop_key).groupby(tour_key).cumcount() + 1, dtype="int8") + + # create unique trip surrogate key + trips = trips.sort_values(by=tour_key + stop_key).reset_index(drop=True) + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # add TAZ information in addition to MGRA information + taz_info = self.mgra_xref[["MGRA", "TAZ"]] + + trips = trips.merge(taz_info, left_on="orig_mgra", right_on="MGRA") + trips.rename(columns={"TAZ": "originTAZ"}, inplace=True) + + trips = trips.merge(taz_info, left_on="dest_mgra", right_on="MGRA") + trips.rename(columns={"TAZ": "destinationTAZ"}, inplace=True) + + trips = trips.merge(taz_info, how="left", left_on="parking_mgra", right_on="MGRA") + trips.rename(columns={"TAZ": "parkingTAZ"}, inplace=True) + trips["parkingTAZ"] = trips["parkingTAZ"].astype("float32") + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.stop_period + ) + + # concatenate mode and transit skim set for transit trips + trips["tripMode"] = self._combine_mode_set( + mode=trips.trip_mode, + transit_set=trips.set + ) + + # set appropriate walk mode for walk trips + trips["tripMode"] = self._combine_mode_walk( + mode=trips.tripMode, + walk_mode=trips.micro_walkMode + ) + + # calculate value of time category auto skim set used + trips["valueOfTimeCategory"] = self._map_vot_categories( + vot=trips.valueOfTime + ) + + # transform parking cost from cents to dollars + trips["parkingCost"] = round(trips.parkingCost / 100, 2) + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + conditions = [(trips["tripMode"] == "Shared Ride 2"), + (trips["tripMode"] == "Shared Ride 3+"), + (trips["tripMode"] == "Taxi"), + (trips["tripMode"] == "Non-Pooled TNC"), + (trips["tripMode"] == "Pooled TNC")] + choices = [1 / self.properties["sr2Passengers"], + 1 / self.properties["sr3Passengers"], + 1 / self.properties["taxiPassengers"], + 1 / self.properties["nonPooledTNCPassengers"], + 1 / self.properties["pooledTNCPassengers"]] + + trips["weightTrip"] = pd.Series(np.select(conditions, choices, default=1) / self.properties["sampleRate"], dtype="float32") + trips["weightPersonTrip"] = 1 / self.properties["sampleRate"] + trips["weightPersonTrip"] = trips["weightPersonTrip"].astype("float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"person_id": "personID", + "orig_purpose": "tripPurposeOrigin", + "dest_purpose": "tripPurposeDestination", + "stop_period": "departTimeAbmHalfHour", + "orig_mgra": "originMGRA", + "dest_mgra": "destinationMGRA", + "parking_mgra": "parkingMGRA", + "parkingCost": "costParking", + "av_avail": "avUsed", + "trip_board_tap": "boardingTAP", + "trip_alight_tap": "alightingTAP", + "transponder_avail": "transponderAvailable", + "micro_trnAcc": "microMobilityTransitAccess", + "micro_trnEgr": "microMobilityTransitEgress"}, + inplace=True) + + return trips[["tripID", + "personID", + "tourID", + "stopID", + "inbound", + "tripPurposeOrigin", + "tripPurposeDestination", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "boardingTAP", + "alightingTAP", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "microMobilityTransitAccess", + "microMobilityTransitEgress", + "weightTrip", + "weightPersonTrip", + "costParking"]] + + @property + @lru_cache(maxsize=1) + def joint(self) -> pd.DataFrame: + """ Create the Joint Model trip list. + + Read in the Joint trip list, map field values, genericize field + names, append skim values, replicate data-set records for each trip + participant creating data-set format of one record per participant, + and assign trip weights accounting for replicated records. + + Returns: + A Pandas DataFrame of the Joint trip list """ + # load trip list into Pandas DataFrame + fn_trips = "jointTripData_" + str(self.properties["iterations"]) + ".csv" + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", fn_trips), + usecols=["hh_id", + "tour_id", + "stop_id", + "inbound", + "orig_purpose", + "dest_purpose", + "orig_mgra", + "dest_mgra", + "parking_mgra", + "stop_period", + "trip_mode", + "av_avail", + "num_participants", + "trip_board_tap", + "trip_alight_tap", + "set", + "valueOfTime", + "transponder_avail", + "parkingCost"], + dtype={"hh_id": "int32", + "tour_id": "int8", + "stop_id": "int8", + "inbound": "bool", + "orig_purpose": "string", + "dest_purpose": "string", + "orig_mgra": "int16", + "dest_mgra": "int16", + "parking_mgra": "int16", + "stop_period": "int8", + "trip_mode": "int8", + "av_avail": "bool", + "num_participants": "int8", + "trip_board_tap": "int16", + "trip_alight_tap": "int16", + "set": "int8", + "valueOfTime": "float32", + "transponder_avail": "bool", + "parkingCost": "float32"}) + + # apply exhaustive field mappings where applicable + mappings = { + "parking_mgra": {key: value for (key, value) in + zip(list(range(1, 23003)), + list(range(1, 23003)))}, + "trip_mode": {2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"}, + "trip_board_tap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "trip_alight_tap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "set": {0: "Local Bus", + 1: "Premium Transit", + 2: "Local Bus and Premium Transit"}, + } + + for field in mappings: + if field in ["parking_mgra", "trip_board_tap", "trip_alight_tap"]: + data_type = "float32" + else: + data_type = "category" + trips[field] = trips[field].map(mappings[field]).astype(data_type) + + # create tour surrogate key (hh_id, tour_id) + tour_key = ["hh_id", "tour_id"] + trips["tourID"] = pd.Series( + trips.groupby(tour_key).ngroup() + 1, + dtype="int32") + + # create tour stop surrogate key (inbound, stop_id) + stop_key = ["inbound", "stop_id"] + trips["stopID"] = pd.Series( + trips.sort_values(by=stop_key).groupby(tour_key).cumcount() + 1, + dtype="int8") + + # create unique trip surrogate key + trips = trips.sort_values(by=tour_key + stop_key).reset_index(drop=True) + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # add TAZ information in addition to MGRA information + taz_info = self.mgra_xref[["MGRA", "TAZ"]] + + trips = trips.merge(taz_info, left_on="orig_mgra", right_on="MGRA") + trips.rename(columns={"TAZ": "originTAZ"}, inplace=True) + + trips = trips.merge(taz_info, left_on="dest_mgra", right_on="MGRA") + trips.rename(columns={"TAZ": "destinationTAZ"}, inplace=True) + + trips = trips.merge(taz_info, how="left", left_on="parking_mgra", + right_on="MGRA") + trips.rename(columns={"TAZ": "parkingTAZ"}, inplace=True) + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.stop_period + ) + + # concatenate mode and transit skim set for transit trips + trips["tripMode"] = self._combine_mode_set( + mode=trips.trip_mode, + transit_set=trips.set + ) + + # calculate value of time category auto skim set used + trips["valueOfTimeCategory"] = self._map_vot_categories( + vot=trips.valueOfTime + ) + + # transform parking cost from cents to dollars + trips["parkingCost"] = round(trips.parkingCost / 100, 2) + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"orig_purpose": "tripPurposeOrigin", + "dest_purpose": "tripPurposeDestination", + "stop_period": "departTimeAbmHalfHour", + "orig_mgra": "originMGRA", + "dest_mgra": "destinationMGRA", + "parking_mgra": "parkingMGRA", + "parkingCost": "costParking", + "av_avail": "avUsed", + "trip_board_tap": "boardingTAP", + "trip_alight_tap": "alightingTAP", + "transponder_avail": "transponderAvailable"}, + inplace=True) + + # load tour list into Pandas DataFrame + fn_tours = "jointTourData_" + str( + self.properties["iterations"]) + ".csv" + tours = pd.read_csv( + os.path.join(self.scenario_path, "output", fn_tours), + usecols=["hh_id", + "tour_id", + "tour_participants"], + dtype={"hh_id": "int32", + "tour_id": "int8", + "tour_participants": "string"}) + + # split the tour participants column by " " and append in wide-format + # to each record + tours = pd.concat( + [tours[["hh_id", "tour_id"]], + tours["tour_participants"].str.split(" ", expand=True)], + axis=1 + ) + + # melt the wide-format tour participants to long-format + tours = pd.melt(tours, id_vars=["hh_id", "tour_id"], + value_name="person_num") + tours = tours[tours["person_num"].notnull()] + tours["person_num"] = tours["person_num"].astype("int8") + + # load output person data into Pandas DataFrame + fn_persons = "personData_" + str(self.properties["iterations"]) + ".csv" + persons = pd.read_csv( + os.path.join(self.scenario_path, "output", fn_persons), + usecols=["hh_id", + "person_num", + "person_id"], + dtype={"hh_id": "int32", + "person_num": "int8", + "person_id": "int32"}) + persons.rename(columns={"person_id": "personID"}, inplace=True) + + # merge persons with the long-format tour participants to get the person id + tours = tours.merge(persons, on=["hh_id", "person_num"]) + + # merge long-format tour participants with the trip list + # this many-to-one merge replicates trip records for each participant + # as well as appending the person id to each replicated record + trips = trips.merge(tours, on=["hh_id", "tour_id"]) + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + # each record is per-person on trip + # data-set has single person record with multiple trip records + trips["weightTrip"] = pd.Series( + 1 / (trips["num_participants"] * self.properties["sampleRate"]), + dtype="float32") + trips["weightPersonTrip"] = 1 / self.properties["sampleRate"] + trips["weightPersonTrip"] = trips["weightPersonTrip"].astype("float32") + + return trips[["tripID", + "personID", + "tourID", + "stopID", + "inbound", + "tripPurposeOrigin", + "tripPurposeDestination", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "boardingTAP", + "alightingTAP", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip", + "costParking"]] + + @property + @lru_cache(maxsize=1) + def truck(self) -> pd.DataFrame: + """ Create the Truck Model trip list. + + Read in the External-External trip last, map field values, and + genericize field names. + + Returns: + A Pandas DataFrame of the External-External trips list """ + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "report", "trucktrip.csv"), + usecols=["OTAZ", + "DTAZ", + "TOD", + "MODE", + "TRIPS", + "TIME", + "DIST", + "AOC", + "TOLLCOST"], + dtype={"OTAZ": "int16", + "DTAZ": "int16", + "TOD": "string", + "MODE": "string", + "TRIPS": "float32", + "TIME": "float32", + "DIST": "float32", + "AOC": "float32", + "TOLLCOST": "float32"}) + + # create trip surrogate key + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # apply exhaustive field mappings where applicable + mappings = { + "TOD": {"EA": 1, + "AM": 2, + "MD": 3, + "PM": 4, + "EV": 5}, + "MODE": {"lhdn": "Light Heavy Duty Truck", + "lhdt": "Light Heavy Duty Truck", + "mhdn": "Medium Heavy Duty Truck", + "mhdt": "Medium Heavy Duty Truck", + "hhdn": "Heavy Heavy Duty Truck", + "hhdt": "Heavy Heavy Duty Truck"} + } + + for field in mappings: + if field == "TOD": + trips[field] = trips[field].map(mappings[field]).astype("int8") + else: + trips[field] = trips[field].map(mappings[field]).astype("category") + + # convert cents-based cost fields to dollars + trips["AOC"] = trips["AOC"] / 100 + trips["TOLLCOST"] = trips["TOLLCOST"] / 100 + + # all trips are High value of time + # no trips use transponders or autonomous vehicles + trips["valueOfTimeCategory"] = "High" + trips["transponderAvailable"] = False + trips["avUsed"] = False + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + trips["weightTrip"] = trips["TRIPS"] / self.properties["sampleRate"] + trips["weightPersonTrip"] = trips["TRIPS"] / self.properties["sampleRate"] + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"OTAZ": "originTAZ", + "DTAZ": "destinationTAZ", + "TOD": "departTimeFiveTod", + "MODE": "tripMode", + "TIME": "timeDrive", + "DIST": "distanceDrive", + "AOC": "costOperatingDrive", + "TOLLCOST": "costTollDrive"}, + inplace=True) + + # create total time/distance/cost columns + trips["timeTotal"] = trips["timeDrive"] + trips["distanceTotal"] = trips["distanceDrive"] + trips["costTotal"] = trips["costTollDrive"] + trips["costOperatingDrive"] + + return trips[["tripID", + "departTimeFiveTod", + "originTAZ", + "destinationTAZ", + "tripMode", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip", + "timeDrive", + "distanceDrive", + "costTollDrive", + "costOperatingDrive", + "timeTotal", + "distanceTotal", + "costTotal"]] + + @property + @lru_cache(maxsize=1) + def visitor(self) -> pd.DataFrame: + """ Create the Visitor Model trip list. + + Read in the Visitor trip list, map field values, and genericize + field names. + + Returns: + A Pandas DataFrame of the Visitor trip list """ + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", "visitorTrips.csv"), + usecols=["tourID", + "tripID", + "originPurp", + "destPurp", + "originMGRA", + "destinationMGRA", + "inbound", + "period", + "tripMode", + "avAvailable", + "boardingTap", + "alightingTap", + "set", + "valueOfTime", + "partySize", + "micro_walkMode", + "micro_trnAcc", + "micro_trnEgr", + "parkingCost"], + dtype={"tourID": "int32", + "tripID": "int8", + "originPurp": "int8", + "destPurp": "int8", + "originMGRA": "int16", + "destinationMGRA": "int16", + "inbound": "boolean", + "period": "int8", + "tripMode": "int8", + "avAvailable": "bool", + "boardingTap": "int16", + "alightingTap": "int16", + "set": "int8", + "valueOfTime": "float32", + "partySize": "int8", + "micro_walkMode": "int8", + "micro_trnAcc": "int8", + "micro_trnEgr": "int8", + "parkingCost": "float32"}) + + # apply exhaustive field mappings where applicable + mappings = { + "originPurp": {-1: "Unknown", + 0: "Work", + 1: "Recreation", + 2: "Dining"}, + "destPurp": {-1: "Unknown", + 0: "Work", + 1: "Recreation", + 2: "Dining"}, + "tripMode": {1: "Drive Alone", + 2: "Shared Ride 2", + 3: "Shared Ride 3+", + 4: "Walk", + 5: "Bike", + 6: "Walk to Transit", + 7: "Park and Ride to Transit", + 8: "Kiss and Ride to Transit", + 9: "TNC to Transit", + 10: "Taxi", + 11: "Non-Pooled TNC", + 12: "Pooled TNC"}, + "boardingTap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "alightingTap": {key: value for (key, value) in + zip(list(range(1, 99999)), + list(range(1, 99999)))}, + "set": {0: "Local Bus", + 1: "Premium Transit", + 2: "Local Bus and Premium Transit"}, + "micro_walkMode": {1: "Walk", + 2: "Micro-Mobility", + 3: "Micro-Transit"}, + "micro_trnAcc": {1: "Walk", + 2: "Micro-Mobility", + 3: "Micro-Transit"}, + "micro_trnEgr": {1: "Walk", + 2: "Micro-Mobility", + 3: "Micro-Transit"} + } + + for field in mappings: + if field in ["boardingTap", "alightingTap"]: + data_type = "float32" + else: + data_type = "category" + trips[field] = trips[field].map(mappings[field]).astype(data_type) + + # create unique trip surrogate key + # the tripID field included in the data-set is a stopID + trips.rename(columns={"tripID": "stopID"}, inplace=True) + trips = trips.sort_values(by=["tourID", "stopID"]).reset_index(drop=True) + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # add TAZ information in addition to MGRA information + taz_info = self.mgra_xref[["MGRA", "TAZ"]] + + trips = trips.merge(taz_info, left_on="originMGRA", right_on="MGRA") + trips.rename(columns={"TAZ": "originTAZ"}, inplace=True) + + trips = trips.merge(taz_info, left_on="destinationMGRA", right_on="MGRA") + trips.rename(columns={"TAZ": "destinationTAZ"}, inplace=True) + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.period + ) + + # concatenate mode and transit skim set for transit trips + trips["tripMode"] = self._combine_mode_set( + mode=trips.tripMode, + transit_set=trips.set + ) + + # set appropriate walk mode for walk trips + trips["tripMode"] = self._combine_mode_walk( + mode=trips.tripMode, + walk_mode=trips.micro_walkMode + ) + + # calculate value of time category auto skim set used + trips["valueOfTimeCategory"] = self._map_vot_categories( + vot=trips.valueOfTime + ) + + # transform parking cost from cents to dollars + trips["parkingCost"] = round(trips.parkingCost / 100, 2) + + # no visitor trips use transponders + # no visitor trips are allowed to park in another MGRA + trips["transponderAvailable"] = False + trips["parkingMGRA"] = pd.Series(np.nan, dtype="float32") + trips["parkingTAZ"] = pd.Series(np.nan, dtype="float32") + + # add vehicle/trip-based weight and person-based weight + # adjust by the ABM scenario final iteration sample rate + trips["weightTrip"] = 1 / self.properties["sampleRate"] + trips["weightTrip"] = trips["weightTrip"].astype("float32") + trips["weightPersonTrip"] = pd.Series( + trips["partySize"] / self.properties["sampleRate"], + dtype="float32") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"originPurp": "tripPurposeOrigin", + "destPurp": "tripPurposeDestination", + "period": "departTimeAbmHalfHour", + "parkingCost": "costParking", + "avAvailable": "avUsed", + "boardingTap": "boardingTAP", + "alightingTap": "alightingTAP", + "micro_trnAcc": "microMobilityTransitAccess", + "micro_trnEgr": "microMobilityTransitEgress"}, + inplace=True) + + return trips[["tripID", + "tourID", + "stopID", + "inbound", + "tripPurposeOrigin", + "tripPurposeDestination", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "boardingTAP", + "alightingTAP", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "microMobilityTransitAccess", + "microMobilityTransitEgress", + "weightTrip", + "weightPersonTrip", + "costParking"]] + + @property + @lru_cache(maxsize=1) + def zombie_av(self) -> pd.DataFrame: + """ Create the 0-Passenger Autonomous Vehicle trip list. + + Read in the Autonomous Vehicle trip list, select only 0-passenger + trips, map field values, and genericize field names. + + Returns: + A Pandas DataFrame of the 0-Passenger Autonomous Vehicle trip + list """ + fn = os.path.join(self.scenario_path, "output", "householdAVTrips.csv") + # file does not exist if AV-component of model is turned off + if os.path.isfile(fn): + # load trip list into Pandas DataFrame + trips = pd.read_csv( + fn, + usecols=["hh_id", + "veh_id", + "vehicleTrip_id", + "orig_mgra", + "dest_gra", + "period", + "occupants", + "originIsHome", + "destinationIsHome", + "originIsRemoteParking", + "destinationIsRemoteParking", + "remoteParkingCostAtDest"], + dtype={"hh_id": "int32", + "veh_id": "int32", + "vehicleTrip_id": "int32", + "orig_mgra": "int32", + "dest_gra": "int32", + "period": "int32", + "occupants": "int32", + "originIsHome": "bool", + "destinationIsHome": "bool", + "originIsRemoteParking": "bool", + "destinationIsRemoteParking": "bool", + "remoteParkingCostAtDest": "float32"} + ) + + # filter trip list to empty/zombie av trips + trips = trips.loc[trips["occupants"] == 0].copy() + + # create unique trip surrogate key + trip_key = ["hh_id", "veh_id", "vehicleTrip_id"] + trips = trips.sort_values(by=trip_key).reset_index(drop=True) + trips["tripID"] = pd.Series(trips.index + 1, dtype="int32") + + # load output household transponder ownership data + hh_fn = "householdData_" + str(self.properties["iterations"]) + ".csv" + hh = pd.read_csv( + os.path.join(self.scenario_path, "output", hh_fn), + usecols=["hh_id", "transponder"], + dtype={"hh_id": "int32", + "transponder": "bool"}) + + # if household has a transponder then all trips can use it + trips = trips.merge(hh, on="hh_id") + + # add TAZ information in addition to MGRA information + taz_info = self.mgra_xref[["MGRA", "TAZ"]] + + trips = trips.merge(taz_info, left_on="orig_mgra", right_on="MGRA") + trips.rename(columns={"TAZ": "originTAZ"}, inplace=True) + + trips = trips.merge(taz_info, left_on="dest_gra", right_on="MGRA") + trips.rename(columns={"TAZ": "destinationTAZ"}, inplace=True) + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=trips.period) + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods(abm_half_hour=trips.period) + + # all zombie AV trips are Drive Alone and High vot + trips["tripMode"] = "Drive Alone" + trips["valueOfTimeCategory"] = "High" + trips["avUsed"] = True + trips["parkingMGRA"] = np.nan + trips["parkingTAZ"] = np.nan + + # add person-based weight and adjust weights + # by the ABM scenario final iteration sample rate + # no people are in zombie AV trips + trips["weightTrip"] = 1 / self.properties["sampleRate"] + trips["weightPersonTrip"] = 0 + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"hh_id": "hhID", + "veh_id": "vehID", + "vehicleTrip_id": "vehicleTripID", + "orig_mgra": "originMGRA", + "dest_gra": "destinationMGRA", + "period": "departTimeAbmHalfHour", + "transponder": "transponderAvailable", + "remoteParkingCostAtDest": "costParking"}, + inplace=True) + + return trips[["tripID", + "hhID", + "vehID", + "vehicleTripID", + "originIsHome", + "destinationIsHome", + "originIsRemoteParking", + "destinationIsRemoteParking", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip", + "costParking"]] + else: # return empty DataFrame if file does not exist + return(pd.DataFrame( + columns=["tripID", + "hhID", + "vehID", + "vehicleTripID", + "originIsHome", + "destinationIsHome", + "originIsRemoteParking", + "destinationIsRemoteParking", + "parkingChoiceAtDestination", + "departTimeAbmHalfHour", + "departTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip"])) + + @property + @lru_cache(maxsize=1) + def zombie_tnc(self) -> pd.DataFrame: + """ Create the 0-Passenger TNC trip list. + + Read in the TNC Vehicle trip list, select only 0-passenger + trips, map field values, and genericize field names. + + Returns: + A Pandas DataFrame of the 0-Passenger TNC Vehicle trip list """ + # load trip list into Pandas DataFrame + trips = pd.read_csv( + os.path.join(self.scenario_path, "output", "TNCTrips.csv"), + usecols=["trip_ID", + "originMgra", + "destinationMgra", + "originTaz", + "destinationTaz", + "totalPassengers", + "startPeriod", + "endPeriod", + " originPurpose", + " destinationPurpose"], + dtype={"trip_ID": "int32", + "originMgra": "int16", + "destinationMgra": "int16", + "originTaz": "int16", + "destinationTaz": "int16", + "totalPassengers": "int8", + "startPeriod": "int16", + "endPeriod": "int16", + " originPurpose": "int8", + " destinationPurpose": "int8"}) + + # filter trip list to empty/zombie tnc trips + trips = trips.loc[trips["totalPassengers"] == 0].copy() + trips.reset_index(drop=True, inplace=True) + + # apply exhaustive field mappings where applicable + mappings = { + " originPurpose": {0: "Home", + 1: "Pickup Only", + 2: "Drop-off Only", + 3: "Pickup and Drop-off", + 4: "Refuel"}, + " destinationPurpose": {0: "Home", + 1: "Pickup Only", + 2: "Drop-off Only", + 3: "Pickup and Drop-off", + 4: "Refuel"} + } + + for field in mappings: + trips[field] = trips[field].map(mappings[field]).astype("category") + + # only map TNC time periods to ABM time periods if they nest + period_width = self.properties["timePeriodWidthTNC"] + if 30 % period_width == 0: + # map TNC time periods to actual period start times + # take the defined width of the time periods multiplied + # by the time period number as the minutes after 3am allowing + # the time periods to wrap around 12am and set the time value + trips["StartTime"] = trips["startPeriod"].apply( + lambda x: (datetime.combine(date.today(), time(3, 0)) + + timedelta(minutes=(x-1) * period_width)).time()) + trips["EndTime"] = trips["endPeriod"].apply( + lambda x: (datetime.combine(date.today(), time(3, 0)) + + timedelta(minutes=(x-1) * period_width)).time()) + + # map continuous times to abm half hour periods + depart_half_hour = [ + [p["period"] for p in self.time_periods["abmHalfHour"] + if p["startTime"] <= x < p["endTime"]] + for x in trips["StartTime"]] + depart_half_hour = [val for sublist in depart_half_hour for val in sublist] + trips = trips.assign(departTimeAbmHalfHour=depart_half_hour) + trips["departTimeAbmHalfHour"] = trips["departTimeAbmHalfHour"].astype("int8") + + arrive_half_hour = [ + [p["period"] for p in self.time_periods["abmHalfHour"] + if p["startTime"] <= x < p["endTime"]] + for x in trips["EndTime"]] + arrive_half_hour = [val for sublist in arrive_half_hour for val in sublist] + trips = trips.assign(arriveTimeAbmHalfHour=arrive_half_hour) + trips["arriveTimeAbmHalfHour"] = trips["arriveTimeAbmHalfHour"].astype("int8") + + # map abm half hours to abm five time of day + trips["departTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.departTimeAbmHalfHour) + + trips["arriveTimeFiveTod"] = self._map_time_periods( + abm_half_hour=trips.arriveTimeAbmHalfHour) + else: + # if time periods are not able to nest within ABM model time periods + # set the ABM model time period fields to NaN + # RSG has been made aware of this issue + trips["departTimeAbmHalfHour"] = pd.Series(np.nan, dtype="float32") + trips["departTimeFiveTod"] = pd.Series(np.nan, dtype="float32") + trips["arriveTimeAbmHalfHour"] = pd.Series(np.nan, dtype="float32") + trips["arriveTimeFiveTod"] = pd.Series(np.nan, dtype="float32") + + # all zombie TNC trips are Drive Alone and High vot + # assumed Transponder ownership for Drive Alone TNC + trips["tripMode"] = "Drive Alone" + trips["tripMode"] = trips["tripMode"].astype("category") + trips["valueOfTimeCategory"] = "High" + trips["valueOfTimeCategory"] = trips["valueOfTimeCategory"].astype("category") + trips["transponderAvailable"] = True + trips["avUsed"] = False + trips["parkingMGRA"] = pd.Series(np.nan, dtype="float32") + trips["parkingTAZ"] = pd.Series(np.nan, dtype="float32") + + # add person-based weight and adjust weights + # by the ABM scenario final iteration sample rate + # no people are in zombie AV trips + trips["weightTrip"] = 1 / self.properties["sampleRate"] + trips["weightTrip"] = trips["weightTrip"].astype("float32") + trips["weightPersonTrip"] = 0 + trips["weightPersonTrip"] = trips["weightPersonTrip"].astype("int8") + + # rename columns to standard/generic ABM naming conventions + trips.rename(columns={"trip_ID": "tripID", + "originMgra": "originMGRA", + "destinationMgra": "destinationMGRA", + "originTaz": "originTAZ", + "destinationTaz": "destinationTAZ", + " originPurpose": "originPurpose", + " destinationPurpose": "destinationPurpose"}, + inplace=True) + + return trips[["tripID", + "originPurpose", + "destinationPurpose", + "departTimeAbmHalfHour", + "arriveTimeAbmHalfHour", + "departTimeFiveTod", + "arriveTimeFiveTod", + "originMGRA", + "destinationMGRA", + "parkingMGRA", + "originTAZ", + "destinationTAZ", + "parkingTAZ", + "tripMode", + "valueOfTimeCategory", + "transponderAvailable", + "avUsed", + "weightTrip", + "weightPersonTrip"]] diff --git a/sandag_abm/src/main/python/dataExporter/environment.yml b/sandag_abm/src/main/python/dataExporter/environment.yml new file mode 100644 index 0000000..e00766c --- /dev/null +++ b/sandag_abm/src/main/python/dataExporter/environment.yml @@ -0,0 +1,92 @@ +name: abmDataExporter +channels: + - defaults +dependencies: + - attrs=19.3.0=py_0 + - blas=1.0=mkl + - bzip2=1.0.8=he774522_0 + - ca-certificates=2020.6.24=0 + - certifi=2020.6.20=py38_0 + - cfitsio=3.470=he774522_5 + - click=7.1.2=py_0 + - click-plugins=1.1.1=py_0 + - cligj=0.5.0=py38_0 + - curl=7.67.0=h2a8f88b_0 + - expat=2.2.9=h33f27b4_2 + - fiona=1.8.13.post1=py38hd760492_0 + - freexl=1.0.5=hfa6e2cd_0 + - gdal=3.0.2=py38hdf43c64_0 + - geopandas=0.8.1=py_0 + - geos=3.8.0=h33f27b4_0 + - geotiff=1.5.1=h5770a2b_1 + - hdf4=4.2.13=h712560f_2 + - hdf5=1.10.4=h7ebc959_0 + - icc_rt=2019.0.0=h0cc432a_1 + - icu=58.2=ha925a31_3 + - intel-openmp=2020.0=166 + - jpeg=9b=hb83a4c4_2 + - kealib=1.4.7=h07cbb95_6 + - krb5=1.16.4=hc04afaa_0 + - libboost=1.67.0=hd9e427e_4 + - libcurl=7.67.0=h2a8f88b_0 + - libgdal=3.0.2=h1155b67_0 + - libiconv=1.15=h1df5818_7 + - libkml=1.3.0=he5f2a48_4 + - libnetcdf=4.6.1=h411e497_2 + - libpng=1.6.37=h2a8f88b_0 + - libpq=11.2=h3235a2c_0 + - libspatialindex=1.9.3=h33f27b4_0 + - libspatialite=4.3.0a=h7ffb84d_0 + - libssh2=1.9.0=h7a1dbc1_1 + - libtiff=4.1.0=h56a325e_0 + - libxml2=2.9.10=h464c3ec_1 + - lz4-c=1.8.1.2=h2fa13f4_0 + - m2w64-expat=2.1.1=2 + - m2w64-gcc-libgfortran=5.3.0=6 + - m2w64-gcc-libs=5.3.0=7 + - m2w64-gcc-libs-core=5.3.0=7 + - m2w64-gettext=0.19.7=2 + - m2w64-gmp=6.1.0=2 + - m2w64-libiconv=1.14=6 + - m2w64-libwinpthread-git=5.0.0.4634.697f757=2 + - m2w64-xz=5.2.2=2 + - mkl=2020.0=166 + - mkl-service=2.3.0=py38hb782905_0 + - mkl_fft=1.0.15=py38h14836fe_0 + - mkl_random=1.1.0=py38hf9181ef_0 + - msys2-conda-epoch=20160418=1 + - munch=2.5.0=py_0 + - numpy=1.18.1=py38h93ca92e_0 + - numpy-base=1.18.1=py38hc3f5095_1 + - openjpeg=2.3.0=h5ec785f_1 + - openssl=1.1.1g=he774522_1 + - pandas=1.0.1=py38h47e9c7a_0 + - pcre=8.44=ha925a31_0 + - pip=20.0.2=py38_1 + - postgresql=11.2=h3235a2c_0 + - proj=6.2.1=h9f7ef89_0 + - pyproj=2.6.1.post1=py38hcfa1391_1 + - python=3.8.1=h5fd99cc_1 + - python-dateutil=2.8.1=py_0 + - pytz=2019.3=py_0 + - rtree=0.9.4=py38h21ff451_1 + - setuptools=45.2.0=py38_0 + - shapely=1.7.0=py38h210f175_0 + - six=1.14.0=py38_0 + - sqlite=3.31.1=he774522_0 + - tbb=2018.0.5=he980bc4_0 + - tiledb=1.6.3=h7b000aa_0 + - tk=8.6.10=he774522_0 + - vc=14.1=h0510ff6_4 + - vs2015_runtime=14.16.27012=hf0eaf9b_1 + - wheel=0.34.2=py38_0 + - wincertstore=0.2=py38_0 + - xerces-c=3.2.2=ha925a31_0 + - xz=5.2.5=h62dcd97_0 + - zlib=1.2.11=h62dcd97_4 + - zstd=1.3.7=h508b16e_0 + - pip: + - numexpr==2.7.1 + - openmatrix==0.3.5.0 + - tables==3.6.1 + diff --git a/sandag_abm/src/main/python/dataExporter/hwyShapeExport.py b/sandag_abm/src/main/python/dataExporter/hwyShapeExport.py new file mode 100644 index 0000000..1fe6271 --- /dev/null +++ b/sandag_abm/src/main/python/dataExporter/hwyShapeExport.py @@ -0,0 +1,523 @@ +import geopandas +import numpy as np +import os +import pandas as pd +from shapely import wkt + + +def export_highway_shape(scenario_path: str) -> geopandas.GeoDataFrame: + """ Takes an input path to a completed ABM scenario model run, reads the + input and loaded highway networks from the report folder, and outputs a + geography shape file to the report folder of the loaded highway network. + + Args: + scenario_path: String location of the completed ABM scenario folder + + Returns: + A GeoPandas GeoDataFrame of the loaded highway network """ + # read in input highway network + hwy_tcad = pd.read_csv(os.path.join(scenario_path, "report", "hwyTcad.csv"), + usecols=["ID", # highway coverage id + "NM", # link name + "Length", # link length in miles + "COJUR", # count jurisdiction code + "COSTAT", # count station number + "COLOC", # count location code + "IFC", # initial functional class + "IHOV", # link operation type + "ITRUCK", # truck restriction code + "ISPD", # posted speed limit + "IWAY", # one or two way operations + "IMED", # median type + "AN", # A node number + "FXNM", # cross street name at from end of link + "BN", # B node number + "TXNM", # cross street name at to end of link + "ABLN_EA", # lanes - from-to - Early AM + "ABLN_AM", # lanes - from-to - AM Peak + "ABLN_MD", # lanes - from-to - Midday + "ABLN_PM", # lanes - from-to - PM Peak + "ABLN_EV", # lanes - from-to - Evening + "BALN_EA", # lanes - to-from - Early AM + "BALN_AM", # lanes - to-from - AM Peak + "BALN_MD", # lanes - to-from - Midday + "BALN_PM", # lanes - to-from - PM Peak + "BALN_EV", # lanes - to-from - Evening + "ABPRELOAD_EA", # preloaded bus flow - to-from - Early AM + "BAPRELOAD_EA", # preloaded bus flow - from-to - Early AM + "ABPRELOAD_AM", # preloaded bus flow - to-from - AM Peak + "BAPRELOAD_AM", # preloaded bus flow - from-to - AM Peak + "ABPRELOAD_MD", # preloaded bus flow - to-from - Midday + "BAPRELOAD_MD", # preloaded bus flow - from-to - Midday + "ABPRELOAD_PM", # preloaded bus flow - to-from - PM Peak + "BAPRELOAD_PM", # preloaded bus flow - from-to - PM Peak + "ABPRELOAD_EV", # preloaded bus flow - to-from - Evening + "BAPRELOAD_EV", # preloaded bus flow - from-to - Evening + "geometry"]) # WKT geometry + + # read in loaded highway network for each time period + for tod in ["EA", "AM", "MD", "PM", "EV"]: + fn = "hwyload_" + tod + ".csv" + + file = pd.read_csv(os.path.join(scenario_path, "report", fn), + usecols=["ID1", # highway coverage id + "AB_Time", # a-b loaded travel time + "BA_Time", # b-a loaded travel time + "AB_Speed", # a-b loaded speed + "BA_Speed", # b-a loaded speed + "AB_VOC", # a-b volume to capacity + "BA_VOC", # b-a volume to capacity + "AB_Flow_SOV_NTPL", + "BA_Flow_SOV_NTPL", + "AB_Flow_SOV_TPL", + "BA_Flow_SOV_TPL", + "AB_Flow_SR2L", + "BA_Flow_SR2L", + "AB_Flow_SR3L", + "BA_Flow_SR3L", + "AB_Flow_SOV_NTPM", + "BA_Flow_SOV_NTPM", + "AB_Flow_SOV_TPM", + "BA_Flow_SOV_TPM", + "AB_Flow_SR2M", + "BA_Flow_SR2M", + "AB_Flow_SR3M", + "BA_Flow_SR3M", + "AB_Flow_SOV_NTPH", + "BA_Flow_SOV_NTPH", + "AB_Flow_SOV_TPH", + "BA_Flow_SOV_TPH", + "AB_Flow_SR2H", + "BA_Flow_SR2H", + "AB_Flow_SR3H", + "BA_Flow_SR3H", + "AB_Flow_lhd", + "BA_Flow_lhd", + "AB_Flow_mhd", + "BA_Flow_mhd", + "AB_Flow_hhd", + "BA_Flow_hhd"]) + + # match input highway network to loaded highway network + # to get preload bus flows + file = file.merge(right=hwy_tcad, + how="inner", + left_on="ID1", + right_on="ID") + + # calculate aggregated flows + file["AB_Flow_SOV"] = file[["AB_Flow_SOV_NTPL", + "AB_Flow_SOV_TPL", + "AB_Flow_SOV_NTPM", + "AB_Flow_SOV_TPM", + "AB_Flow_SOV_NTPH", + "AB_Flow_SOV_TPH"]].sum(axis=1) + + file["BA_Flow_SOV"] = file[["BA_Flow_SOV_NTPL", + "BA_Flow_SOV_TPL", + "BA_Flow_SOV_NTPM", + "BA_Flow_SOV_TPM", + "BA_Flow_SOV_NTPH", + "BA_Flow_SOV_TPH"]].sum(axis=1) + + file["AB_Flow_SR2"] = file[["AB_Flow_SR2L", + "AB_Flow_SR2M", + "AB_Flow_SR2H"]].sum(axis=1) + + file["BA_Flow_SR2"] = file[["BA_Flow_SR2L", + "BA_Flow_SR2M", + "BA_Flow_SR2H"]].sum(axis=1) + + file["AB_Flow_SR3"] = file[["AB_Flow_SR3L", + "AB_Flow_SR3M", + "AB_Flow_SR3H"]].sum(axis=1) + + file["BA_Flow_SR3"] = file[["BA_Flow_SR3L", + "BA_Flow_SR3M", + "BA_Flow_SR3H"]].sum(axis=1) + + file["AB_Flow_Truck"] = file[["AB_Flow_lhd", + "AB_Flow_mhd", + "AB_Flow_hhd"]].sum(axis=1) + + file["BA_Flow_Truck"] = file[["BA_Flow_lhd", + "BA_Flow_mhd", + "BA_Flow_hhd"]].sum(axis=1) + + file["AB_Flow_Bus"] = file["ABPRELOAD_" + tod] + + file["BA_Flow_Bus"] = file["BAPRELOAD_" + tod] + + file["AB_Flow"] = file[["AB_Flow_SOV", + "AB_Flow_SR2", + "AB_Flow_SR3", + "AB_Flow_Truck", + "AB_Flow_Bus"]].sum(axis=1) + + file["BA_Flow"] = file[["BA_Flow_SOV", + "BA_Flow_SR2", + "BA_Flow_SR3", + "BA_Flow_Truck", + "BA_Flow_Bus"]].sum(axis=1) + + # fill NAs with 0s + na_vars = ["AB_Time", + "BA_Time", + "AB_Speed", + "BA_Speed", + "AB_VOC", + "BA_VOC"] + + file[na_vars] = file[na_vars].fillna(0) + + # select columns of interest + file = file[["ID1", + "AB_Time", + "BA_Time", + "AB_Speed", + "BA_Speed", + "AB_VOC", + "BA_VOC", + "AB_Flow_SOV", + "BA_Flow_SOV", + "AB_Flow_SR2", + "BA_Flow_SR2", + "AB_Flow_SR3", + "BA_Flow_SR3", + "AB_Flow_Truck", + "BA_Flow_Truck", + "AB_Flow_Bus", + "BA_Flow_Bus", + "AB_Flow", + "BA_Flow"]] + + # add time of day suffix to column names + file = file.add_suffix("_" + tod) + + # merge loaded highway network into input highway network + hwy_tcad = hwy_tcad.merge(right=file, + how="inner", + left_on="ID", + right_on="ID1_" + tod) + + # create string description of [IFC] field + conditions = [hwy_tcad["IFC"] == 1, + hwy_tcad["IFC"] == 2, + hwy_tcad["IFC"] == 3, + hwy_tcad["IFC"] == 4, + hwy_tcad["IFC"] == 5, + hwy_tcad["IFC"] == 6, + hwy_tcad["IFC"] == 7, + hwy_tcad["IFC"] == 8, + hwy_tcad["IFC"] == 9, + hwy_tcad["IFC"] == 10] + + choices = ["Freeway", + "Prime Arterial", + "Major Arterial", + "Collector", + "Local Collector", + "Rural Collector", + "Local (non-circulation element) Road", + "Freeway Connector Ramp", + "Local Ramp", + "Zone Connector"] + + hwy_tcad["IFC_Desc"] = np.select(conditions, choices, default="") + + # calculate aggregate flows + hwy_tcad["AB_Flow_SOV"] = hwy_tcad[["AB_Flow_SOV_EA", + "AB_Flow_SOV_AM", + "AB_Flow_SOV_MD", + "AB_Flow_SOV_PM", + "AB_Flow_SOV_EV"]].sum(axis=1) + + hwy_tcad["BA_Flow_SOV"] = hwy_tcad[["BA_Flow_SOV_EA", + "BA_Flow_SOV_AM", + "BA_Flow_SOV_MD", + "BA_Flow_SOV_PM", + "BA_Flow_SOV_EV"]].sum(axis=1) + + hwy_tcad["AB_Flow_SR2"] = hwy_tcad[["AB_Flow_SR2_EA", + "AB_Flow_SR2_AM", + "AB_Flow_SR2_MD", + "AB_Flow_SR2_PM", + "AB_Flow_SR2_EV"]].sum(axis=1) + + hwy_tcad["BA_Flow_SR2"] = hwy_tcad[["BA_Flow_SR2_EA", + "BA_Flow_SR2_AM", + "BA_Flow_SR2_MD", + "BA_Flow_SR2_PM", + "BA_Flow_SR2_EV"]].sum(axis=1) + + hwy_tcad["AB_Flow_SR3"] = hwy_tcad[["AB_Flow_SR3_EA", + "AB_Flow_SR3_AM", + "AB_Flow_SR3_MD", + "AB_Flow_SR3_PM", + "AB_Flow_SR3_EV"]].sum(axis=1) + + hwy_tcad["BA_Flow_SR3"] = hwy_tcad[["BA_Flow_SR3_EA", + "BA_Flow_SR3_AM", + "BA_Flow_SR3_MD", + "BA_Flow_SR3_PM", + "BA_Flow_SR3_EV"]].sum(axis=1) + + hwy_tcad["AB_Flow_Truck"] = hwy_tcad[["AB_Flow_Truck_EA", + "AB_Flow_Truck_AM", + "AB_Flow_Truck_MD", + "AB_Flow_Truck_PM", + "AB_Flow_Truck_EV"]].sum(axis=1) + + hwy_tcad["BA_Flow_Truck"] = hwy_tcad[["BA_Flow_Truck_EA", + "BA_Flow_Truck_AM", + "BA_Flow_Truck_MD", + "BA_Flow_Truck_PM", + "BA_Flow_Truck_EV"]].sum(axis=1) + + hwy_tcad["AB_Flow_Bus"] = hwy_tcad[["AB_Flow_Bus_EA", + "AB_Flow_Bus_AM", + "AB_Flow_Bus_MD", + "AB_Flow_Bus_PM", + "AB_Flow_Bus_EV"]].sum(axis=1) + + hwy_tcad["BA_Flow_Bus"] = hwy_tcad[["BA_Flow_Bus_EA", + "BA_Flow_Bus_AM", + "BA_Flow_Bus_MD", + "BA_Flow_Bus_PM", + "BA_Flow_Bus_EV"]].sum(axis=1) + + hwy_tcad["AB_Flow_Auto"] = hwy_tcad[["AB_Flow_SOV", + "AB_Flow_SR2", + "AB_Flow_SR3"]].sum(axis=1) + + hwy_tcad["BA_Flow_Auto"] = hwy_tcad[["BA_Flow_SOV", + "BA_Flow_SR2", + "BA_Flow_SR3"]].sum(axis=1) + + hwy_tcad["AB_Flow"] = hwy_tcad[["AB_Flow_EA", + "AB_Flow_AM", + "AB_Flow_MD", + "AB_Flow_PM", + "AB_Flow_EV"]].sum(axis=1) + + hwy_tcad["BA_Flow"] = hwy_tcad[["BA_Flow_EA", + "BA_Flow_AM", + "BA_Flow_MD", + "BA_Flow_PM", + "BA_Flow_EV"]].sum(axis=1) + + hwy_tcad["Flow"] = hwy_tcad[["AB_Flow", + "BA_Flow"]].sum(axis=1) + + # calculate vehicle miles travelled (vmt) + hwy_tcad["AB_VMT"] = hwy_tcad["AB_Flow"] * hwy_tcad["Length"] + hwy_tcad["BA_VMT"] = hwy_tcad["BA_Flow"] * hwy_tcad["Length"] + hwy_tcad["VMT"] = hwy_tcad["Flow"] * hwy_tcad["Length"] + + # calculate vehicle hours travelled (vht) + hwy_tcad["AB_VHT"] = hwy_tcad["AB_Time_EA"] * hwy_tcad["AB_Flow_EA"] + \ + hwy_tcad["AB_Time_AM"] * hwy_tcad["AB_Flow_AM"] + \ + hwy_tcad["AB_Time_MD"] * hwy_tcad["AB_Flow_MD"] + \ + hwy_tcad["AB_Time_PM"] * hwy_tcad["AB_Flow_PM"] + \ + hwy_tcad["AB_Time_EV"] * hwy_tcad["AB_Flow_EV"] + + hwy_tcad["BA_VHT"] = hwy_tcad["BA_Time_EA"] * hwy_tcad["BA_Flow_EA"] + \ + hwy_tcad["BA_Time_AM"] * hwy_tcad["BA_Flow_AM"] + \ + hwy_tcad["BA_Time_MD"] * hwy_tcad["BA_Flow_MD"] + \ + hwy_tcad["BA_Time_PM"] * hwy_tcad["BA_Flow_PM"] + \ + hwy_tcad["BA_Time_EV"] * hwy_tcad["BA_Flow_EV"] + + hwy_tcad["VHT"] = hwy_tcad["AB_VHT"] + hwy_tcad["BA_VHT"] + + # select columns of interest + hwy_tcad = hwy_tcad[["ID", + "NM", + "Length", + "COJUR", + "COSTAT", + "COLOC", + "IFC", + "IFC_Desc", + "IHOV", + "ITRUCK", + "ISPD", + "IWAY", + "IMED", + "AN", + "FXNM", + "BN", + "TXNM", + "Flow", + "AB_Flow", + "BA_Flow", + "AB_VMT", + "BA_VMT", + "VMT", + "AB_VHT", + "BA_VHT", + "VHT", + "AB_Flow_EA", + "BA_Flow_EA", + "AB_Flow_AM", + "BA_Flow_AM", + "AB_Flow_MD", + "BA_Flow_MD", + "AB_Flow_PM", + "BA_Flow_PM", + "AB_Flow_EV", + "BA_Flow_EV", + "AB_Flow_Auto", + "BA_Flow_Auto", + "AB_Flow_SOV", + "BA_Flow_SOV", + "AB_Flow_SR2", + "BA_Flow_SR2", + "AB_Flow_SR3", + "BA_Flow_SR3", + "AB_Flow_Truck", + "BA_Flow_Truck", + "AB_Flow_Bus", + "BA_Flow_Bus", + "AB_Speed_EA", + "BA_Speed_EA", + "AB_Speed_AM", + "BA_Speed_AM", + "AB_Speed_MD", + "BA_Speed_MD", + "AB_Speed_PM", + "BA_Speed_PM", + "AB_Speed_EV", + "BA_Speed_EV", + "AB_Time_EA", + "BA_Time_EA", + "AB_Time_AM", + "BA_Time_AM", + "AB_Time_MD", + "BA_Time_MD", + "AB_Time_PM", + "BA_Time_PM", + "AB_Time_EV", + "BA_Time_EV", + "ABLN_EA", + "BALN_EA", + "ABLN_AM", + "BALN_AM", + "ABLN_MD", + "BALN_MD", + "ABLN_PM", + "BALN_PM", + "ABLN_EV", + "BALN_EV", + "AB_VOC_EA", + "BA_VOC_EA", + "AB_VOC_AM", + "BA_VOC_AM", + "AB_VOC_MD", + "BA_VOC_MD", + "AB_VOC_PM", + "BA_VOC_PM", + "AB_VOC_EV", + "BA_VOC_EV", + "geometry"]] + + # rename fields to match old process field names + hwy_tcad.rename(columns={"ID": "hwycovid", + "NM": "link_name", + "Length": "len_mile", + "COJUR": "count_jur", + "COSTAT": "count_stat", + "COLOC": "count_loc", + "IFC": "ifc", + "IFC_Desc": "ifc_desc", + "IHOV": "ihov", + "ITRUCK": "itruck", + "ISPD": "post_speed", + "IWAY": "iway", + "IMED": "imed", + "AN": "from_node", + "FXNM": "from_nm", + "BN": "to_node", + "TXNM": "to_nm", + "Flow": "total_flow", + "AB_Flow": "abTotFlow", + "BA_Flow": "baTotFlow", + "AB_VMT": "ab_vmt", + "BA_VMT": "ba_vmt", + "VMT": "vmt", + "AB_VHT": "ab_vht", + "BA_VHT": "ba_vht", + "VHT": "vht", + "AB_Flow_EA": "ab_ea_flow", + "BA_Flow_EA": "ba_ea_flow", + "AB_Flow_AM": "ab_am_flow", + "BA_Flow_AM": "ba_am_flow", + "AB_Flow_MD": "ab_md_flow", + "BA_Flow_MD": "ba_md_flow", + "AB_Flow_PM": "ab_pm_flow", + "BA_Flow_PM": "ba_pm_flow", + "AB_Flow_EV": "ab_ev_flow", + "BA_Flow_EV": "ba_ev_flow", + "AB_Flow_Auto": "abAutoFlow", + "BA_Flow_Auto": "baAutoFlow", + "AB_Flow_SOV": "abSovFlow", + "BA_Flow_SOV": "baSovFlow", + "AB_Flow_SR2": "abHov2Flow", + "BA_Flow_SR2": "baHov2Flow", + "AB_Flow_SR3": "abHov3Flow", + "BA_Flow_SR3": "baHov3Flow", + "AB_Flow_Truck": "abTrucFlow", + "BA_Flow_Truck": "baTrucFlow", + "AB_Flow_Bus": "abBusFlow", + "BA_Flow_Bus": "baBusFlow", + "AB_Speed_EA": "ab_ea_mph", + "BA_Speed_EA": "ba_ea_mph", + "AB_Speed_AM": "ab_am_mph", + "BA_Speed_AM": "ba_am_mph", + "AB_Speed_MD": "ab_md_mph", + "BA_Speed_MD": "ba_md_mph", + "AB_Speed_PM": "ab_pm_mph", + "BA_Speed_PM": "ba_pm_mph", + "AB_Speed_EV": "ab_ev_mph", + "BA_Speed_EV": "ba_ev_mph", + "AB_Time_EA": "ab_ea_min", + "BA_Time_EA": "ba_ea_min", + "AB_Time_AM": "ab_am_min", + "BA_Time_AM": "ba_am_min", + "AB_Time_MD": "ab_md_min", + "BA_Time_MD": "ba_md_min", + "AB_Time_PM": "ab_pm_min", + "BA_Time_PM": "ba_pm_min", + "AB_Time_EV": "ab_ev_min", + "BA_Time_EV": "ba_ev_min", + "ABLN_EA": "ab_ea_lane", + "BALN_EA": "ba_ea_lane", + "ABLN_AM": "ab_am_lane", + "BALN_AM": "ba_am_lane", + "ABLN_MD": "ab_md_lane", + "BALN_MD": "ba_md_lane", + "ABLN_PM": "ab_pm_lane", + "BALN_PM": "ba_pm_lane", + "ABLN_EV": "ab_ev_lane", + "BALN_EV": "ba_ev_lane", + "AB_VOC_EA": "ab_ea_voc", + "BA_VOC_EA": "ba_ea_voc", + "AB_VOC_AM": "ab_am_voc", + "BA_VOC_AM": "ba_am_voc", + "AB_VOC_MD": "ab_md_voc", + "BA_VOC_MD": "ba_md_voc", + "AB_VOC_PM": "ab_pm_voc", + "BA_VOC_PM": "ba_pm_voc", + "AB_VOC_EV": "ab_ev_voc", + "BA_VOC_EV": "ba_ev_voc"}, + inplace=True) + + # create geometry from WKT geometry field + hwy_tcad["geometry"] = hwy_tcad["geometry"].apply(wkt.loads) + + # create GeoPandas DataFrame + hwy_tcad = geopandas.GeoDataFrame( + hwy_tcad, + geometry="geometry", + crs=2230) + + return hwy_tcad diff --git a/sandag_abm/src/main/python/dataExporter/serialRun.py b/sandag_abm/src/main/python/dataExporter/serialRun.py new file mode 100644 index 0000000..9b6b7b0 --- /dev/null +++ b/sandag_abm/src/main/python/dataExporter/serialRun.py @@ -0,0 +1,168 @@ +from hwyShapeExport import export_highway_shape +from skimAppender import SkimAppender +from abmScenario import ScenarioData, LandUse, SyntheticPopulation, TourLists, TripLists +import os +import sys + + +def export_data(fp): + # set file path to completed ABM run scenario folder + # set report folder path + scenarioPath = fp + reportPath = os.path.join(scenarioPath, "report") + + + # initialize base ABM scenario data class + print("Initializing Scenario Data") + scenario_data = ScenarioData(scenarioPath) + + # write out transit TAP park and ride file + print("Writing: Transit PNR Input File") + scenario_data.pnr_taps.to_csv(os.path.join(reportPath, "transitPNR.csv"), index=False) + + + # initialize land use class + # write out MGRA-based input file + print("Initializing Land Use Output") + land_use = LandUse(scenarioPath) + print("Writing: MGRA-Based Input File") + land_use.mgra_input.to_csv(os.path.join(reportPath, "mgraBasedInput.csv"), index=False) + + + # initialize synthetic population class + # write out households and persons files + print("Initializing Synthetic Population Output") + population = SyntheticPopulation(scenarioPath) + + print("Writing: Households File") + population.households.to_csv(os.path.join(reportPath, "households.csv"), index=False) + + print("Writing: Persons File") + population.persons.to_csv(os.path.join(reportPath, "persons.csv"), index=False) + + + # initialize tour list class + # write out tour list files + print("Initializing Tour List Output") + tours = TourLists(scenarioPath) + + print("Writing: Commercial Vehicle Tours") + tours.cvm.to_csv(os.path.join(reportPath, "commercialVehicleTours.csv"), index=False) + + print("Writing: Cross Border Tours") + tours.cross_border.to_csv(os.path.join(reportPath, "crossBorderTours.csv"), index=False) + + print("Writing: Individual Tours") + tours.individual.to_csv(os.path.join(reportPath, "individualTours.csv"), index=False) + + print("Writing: Internal-External Tours") + tours.ie.to_csv(os.path.join(reportPath, "internalExternalTours.csv"), index=False) + + print("Writing: Joint Tours") + tours.joint.to_csv(os.path.join(reportPath, "jointTours.csv"), index=False) + + print("Writing: Visitor Tours") + tours.visitor.to_csv(os.path.join(reportPath, "visitorTours.csv"), index=False) + + + print("Initializing Trip List Output") + + # initialize trip list class + trips = TripLists(scenarioPath) + + # initialize skim appender class + skims = SkimAppender(scenarioPath) + + # write out trip list files + print("Writing: Airport-SAN Trips") + skims.append_skims(trips.airport_san, + auto_only=False, + terminal_skims=False).to_csv( + os.path.join(reportPath, "airportSANTrips.csv"), + index=False) + + print("Writing: Airport-CBX Trips") + skims.append_skims(trips.airport_cbx, + auto_only=False, + terminal_skims=False).to_csv( + os.path.join(reportPath, "airportCBXTrips.csv"), + index=False) + + print("Writing: Commercial Vehicle Trips") + skims.append_skims(trips.cvm, + auto_only=True, + terminal_skims=False).to_csv( + os.path.join(reportPath, "commercialVehicleTrips.csv"), + index=False) + + print("Writing: Cross-Border Trips") + skims.append_skims(trips.cross_border, + auto_only=False, + terminal_skims=False).to_csv( + os.path.join(reportPath, "crossBorderTrips.csv"), + index=False) + + print("Writing: External-External Trips") + trips.ee.to_csv( + os.path.join(reportPath, "externalExternalTrips.csv"), + index=False) + + print("Writing: External-Internal Trips") + trips.ei.to_csv( + os.path.join(reportPath, "externalInternalTrips.csv"), + index=False) + + print("Writing: Individual Trips") + skims.append_skims(trips.individual, + auto_only=False, + terminal_skims=True).to_csv( + os.path.join(reportPath, "individualTrips.csv"), + index=False) + + print("Writing: Internal-External Trips") + skims.append_skims(trips.ie, + auto_only=False, + terminal_skims=False).to_csv( + os.path.join(reportPath, "internalExternalTrips.csv"), + index=False) + + print("Writing: Joint Trips") + skims.append_skims(trips.joint, + auto_only=False, + terminal_skims=True).to_csv( + os.path.join(reportPath, "jointTrips.csv"), + index=False) + + print("Writing: Truck Trips") + trips.truck.to_csv( + os.path.join(reportPath, "truckTrips.csv"), + index=False) + + print("Writing: Visitor Trips") + skims.append_skims(trips.visitor, + auto_only=False, + terminal_skims=False).to_csv( + os.path.join(reportPath, "visitorTrips.csv"), + index=False) + + print("Writing: Zombie AV Trips") + skims.append_skims(trips.zombie_av, + auto_only=True, + terminal_skims=False).to_csv( + os.path.join(reportPath, "zombieAVTrips.csv"), + index=False) + + print("Writing: Zombie TNC Trips") + skims.append_skims(trips.zombie_tnc, + auto_only=True, + terminal_skims=False).to_csv( + os.path.join(reportPath, "zombieTNCTrips.csv"), + index=False) + + print("Writing: Highway Load Shape File") + export_highway_shape(scenarioPath).to_file( + os.path.join(reportPath, "hwyLoad.shp")) + +if __name__ == '__main__': + targets = sys.argv[1:] + export_data(targets[0]) diff --git a/sandag_abm/src/main/python/dataExporter/skimAppender.py b/sandag_abm/src/main/python/dataExporter/skimAppender.py new file mode 100644 index 0000000..cb6c5f1 --- /dev/null +++ b/sandag_abm/src/main/python/dataExporter/skimAppender.py @@ -0,0 +1,1895 @@ +# -*- coding: utf-8 -*- +""" ABM Scenario Skim Appender Module. + +This module contains classes holding all utilities relating to appending +transportation skims to a completed SANDAG Activity-Based Model (ABM) +scenario. This module is used to append time, distance, cost, and other +related transportation skims to ABM trip lists. + +Notes: + docstring style guide - http://google.github.io/styleguide/pyguide.html +""" + +import itertools +import os +import re +from functools import lru_cache # caching decorator for modules +import numpy as np +import openmatrix as omx # https://github.com/osPlanning/omx-python +import pandas as pd + + +class SkimAppender(object): + """ This class holds all utilities relating to appending transportation + skims to a completed SANDAG Activity-Based Model (ABM) scenario + + Args: + scenario_path: String location of the completed ABM scenario folder + + Methods: + _get_omx_auto_skim_dataset: Maps ABM trip list records to OMX files + and OMX skim matrices + append_skims: Master method to append all skims to ABM trip lists + auto_fare_cost: Appends auto fare cost to ABM trip list records + auto_operating_cost: Appends auto operating cost to ABM trip list records + auto_terminal_skims: Appends auto-mode terminal walk time and distance + from the zone.term file to ABM trip list records + auto_wait_time: Appends auto wait times to ABM trip list records + bicycle_skims: Appends bicycle mode skims (time, distance) to ABM trip + list records + drive_transit_skims: Appends input file accessam.csv drive to + transit auto mode skims (time, distance, no cost) to ABM trip + list records + omx_auto_skim_appender: Appends OMX auto mode skims (time, distance, + cost) to ABM trip list records + omx_transit_skims: Appends OMX transit mode skims (time, distance, + cost) to transit mode trip list records + tnc_fare_cost: Appends TNC fare costs to ABM trip list records + tnc_wait_time: Appends TNC wait time to ABM trip list records + walk_skims: Appends walk/micro-mobility/micro-transit mode skims + (time, distance, cost) to ABM trip list records for + walk/micro-mobility/micro-transit mode trips + _walk_skims_at: Appends walk/micro-mobility/micro-transit mode skims + (time, distance, cost) to ABM trip list records for + walk/micro-mobility/micro-transit mode trips that do not use auto + mode skim sets for trip time + _walk_skims_auto: Appends walk/micro-mobility/micro-transit mode skims + (time, distance, cost) to ABM trip list records for + walk/micro-mobility/micro-transit mode trips that use auto mode + skim sets for trip time + walk_transit_skims: Appends walk/micro-mobility/micro-transit + access/egress to/from transit to ABM transit mode trip list + records + + Properties: + mgra_xref: Pandas DataFrame geography cross-reference of MGRAs to + TAZs and LUZs + properties: Dictionary of ABM properties file token values + (conf/sandag_abm.properties) """ + + def __init__(self, scenario_path: str) -> None: + self.scenario_path = scenario_path + + @property + @lru_cache(maxsize=1) + def mgra_xref(self) -> pd.DataFrame: + """ Cross reference of Master Geographic Reference Area (MGRA) model + geography to Transportation Analysis Zone (TAZ) and Land Use Zone + (LUZ) model geographies. Cross reference is stored in each ABM + scenario input MGRA file (input/mgra13_based_input<>.csv). + """ + + # load the mgra based input file + fn = "mgra13_based_input" + str(self.properties["year"]) + ".csv" + + mgra = pd.read_csv(os.path.join(self.scenario_path, "input", fn), + usecols=["mgra", # MGRA geography + "taz", # TAZ geography + "luz_id", # LUZ geography + "MicroAccessTime"], # Micro-Mobility AccessTime + dtype={"mgra": "int16", + "taz": "int16", + "luz_id": "int16"}) + + # genericize column names + mgra.rename(columns={"mgra": "MGRA", + "taz": "TAZ", + "luz_id": "LUZ"}, + inplace=True) + + return mgra + + @property + @lru_cache(maxsize=1) + def properties(self) -> dict: + """ Get the ABM scenario properties from the ABM scenario + properties file (conf/sandag_abm.properties). + + The return dictionary contains the following ABM scenario properties: + accessTimeMicroTransit - Micro-Transit access time in minutes + aocFuel - auto operating fuel cost in $/mile + aocMaintenance - auto operating maintenance cost in $/mile + baseFareMicroMobility - initial Micro-Mobility fare in $ + baseFareMicroTransit - initial Micro-Mobility fare in $ + baseFareNonPooledTNC - initial Non-Pooled TNC fare in $ + baseFarePooledTNC - initial Pooled TNC fare in $ + baseFareTaxi - initial taxi fare in $ + bicycleSpeed - bicycle mode speed (miles/hour) + costMinimumNonPooledTNC - minimum Non-Pooled TNC fare cost in $ + costMinimumPooledTNC - minimum Pooled TNC fare cost in $ + costPerMileFactorAV - auto operating cost per mile factor to + apply to AV trips + costPerMileNonPooledTNC - Non-Pooled TNC fare cost per mile in $ + costPerMilePooledTNC - Pooled TNC fare cost per mile in $ + costPerMileTaxi - Taxi fare cost per mile in $ + costPerMinuteMicroMobility - Micro-Mobility fare cost per minute in $ + costPerMinuteMicroTransit - Micro-Transit fare cost per minute in $ + costPerMinuteNonPooledTNC - Non-Pooled TNC fare cost per minute in $ + costPerMinutePooledTNC - Pooled TNC fare cost per minute in $ + costPerMinuteTaxi - Taxi fare cost per minute in $ + microMobilitySpeed - Micro-Mobility mode speed (miles/hour) + microTransitSpeed - Micro-Transit mode speed (miles/hour) + terminalTimeFactorAV - terminal time factor to apply to AV trips + waitTimeMicroTransit - Micro-Mobility wait time in minutes + waitTimeNonPooledTNC - list of mean wait times in minutes for + Non-Pooled TNC by PopEmpDenPerMi categories + (see waitTimePopEmpDenPerMi) + waitTimePooledTNC - list of mean wait times in minutes for Pooled + TNC by PopEmpDenPerMi categories (see waitTimePopEmpDenPerMi) + waitTimePopEmpDenPerMi - list of MGRA-Based input file + PopEmpDenPerMi values defining the wait time categories for + Taxi/TNC modes + waitTimeTaxi - list of mean wait times in minutes for Taxi by + PopEmpDenPerMi categories (see waitTimePopEmpDenPerMi) + walkSpeed - walk mode speed (miles/hour) + year - analysis year of the ABM scenario + + Returns: + A dictionary defining the ABM scenario properties. """ + + # create dictionary holding ABM properties file information + # each property contains a dictionary {line, value} where the line + # is the string to match in the properties file to + # return the value of the property + lookup = { + "accessTimeMicroTransit": { + "line": "active.microtransit.accessTime=", + "type": "float", + "value": None + }, + "aocFuel": { + "line": "aoc.fuel=", + "type": "float", + "value": None + }, + "aocMaintenance": { + "line": "aoc.maintenance=", + "type": "float", + "value": None + }, + "baseFareMicroMobility": { + "line": "active.micromobility.fixedCost=", + "type": "float", + "value": None + }, + "baseFareMicroTransit": { + "line": "active.microtransit.fixedCost=", + "type": "float", + "value": None + }, + "baseFareNonPooledTNC": { + "line": "TNC.single.baseFare=", + "type": "float", + "value": None + }, + "baseFarePooledTNC": { + "line": "TNC.shared.baseFare=", + "type": "float", + "value": None + }, + "baseFareTaxi": { + "line": "taxi.baseFare=", + "type": "float", + "value": None + }, + "bicycleSpeed": { + "line": "active.bike.minutes.per.mile=", + "type": "float", + "value": None}, + "costMinimumNonPooledTNC": { + "line": "TNC.single.costMinimum=", + "type": "float", + "value": None + }, + "costMinimumPooledTNC": { + "line": "TNC.shared.costMinimum=", + "type": "float", + "value": None + }, + "costPerMileFactorAV": { + "line": "Mobility.AV.CostPerMileFactor=", + "type": "float", + "value": None + }, + "costPerMileNonPooledTNC": { + "line": "TNC.single.costPerMile=", + "type": "float", + "value": None + }, + "costPerMilePooledTNC": { + "line": "TNC.shared.costPerMile=", + "type": "float", + "value": None + }, + "costPerMileTaxi": { + "line": "taxi.costPerMile=", + "type": "float", + "value": None + }, + "costPerMinuteMicroMobility": { + "line": "active.micromobility.variableCost=", + "type": "float", + "value": None + }, + "costPerMinuteMicroTransit": { + "line": "active.microtransit.variableCost=", + "type": "float", + "value": None + }, + "costPerMinuteNonPooledTNC": { + "line": "TNC.single.costPerMinute=", + "type": "float", + "value": None + }, + "costPerMinutePooledTNC": { + "line": "TNC.shared.costPerMinute=", + "type": "float", + "value": None + }, + "costPerMinuteTaxi": { + "line": "taxi.costPerMinute=", + "type": "float", + "value": None + }, + "microMobilitySpeed": { + "line": "active.micromobility.speed=", + "type": "float", + "value": None}, + "microTransitSpeed": { + "line": "active.microtransit.speed=", + "type": "float", + "value": None}, + "terminalTimeFactorAV": { + "line": "Mobility.AV.TerminalTimeFactor=", + "type": "float", + "value": None + }, + "waitTimeMicroTransit": { + "line": "active.microtransit.waitTime=", + "type": "float", + "value": None + }, + "waitTimeNonPooledTNC": { + "line": "TNC.single.waitTime.mean=", + "type": "list", + "value": None + }, + "waitTimePooledTNC": { + "line": "TNC.shared.waitTime.mean=", + "type": "list", + "value": None + }, + "waitTimePopEmpDenPerMi": { + "line": "WaitTimeDistribution.EndPopEmpPerSqMi=", + "type": "list", + "value": None + }, + "waitTimeTaxi": { + "line": "Taxi.waitTime.mean=", + "type": "list", + "value": None + }, + "walkSpeed": { + "line": "active.walk.minutes.per.mile=", + "type": "float", + "value": None}, + "year": { + "line": "scenarioYear=", + "type": "int", + "value": None} + } + + # open the ABM scenario properties file + file = open(os.path.join(self.scenario_path, "conf", "sandag_abm.properties"), "r") + + # loop through each line of the properties file + for line in file: + # strip all white space from the line + line = line.replace(" ", "") + + # for each element of the properties dictionary + for name in lookup: + item = lookup[name] + + if item["line"] is not None: + match = re.compile(item["line"]).match(line) + # if the properties file contains the matching line + if match: + # for waitTime properties create list from matching line + # + if "waitTime" in name and item["type"] == "list": + value = line[match.end():].split(",") + value = list(map(float, value)) + # otherwise take the final element of the line + else: + value = line[match.end():] + + # update the dictionary value using the appropriate data type + if item["type"] == "float": + value = float(value) + elif item["type"] == "int": + value = int(value) + else: + pass + + item["value"] = value + break + + file.close() + + # convert the property name and value to a non-nested dictionary + results = {} + for name in lookup: + results[name] = lookup[name]["value"] + + # convert auto operating costs from cents per mile to dollars per mile + results["aocFuel"] = results["aocFuel"] / 100 + results["aocMaintenance"] = results["aocMaintenance"] / 100 + + # convert AT speeds from minutes per mile to miles per hour + results["bicycleSpeed"] = (results["bicycleSpeed"] * 1/60)**-1 + results["microMobilitySpeed"] = (results["microMobilitySpeed"] * 1 / 60) ** -1 + results["microTransitSpeed"] = (results["microTransitSpeed"] * 1 / 60) ** -1 + results["walkSpeed"] = (results["walkSpeed"] * 1/60)**-1 + + return results + + @staticmethod + def _get_omx_auto_skim_dataset(df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame and returns a subset of trips + with two columns indicating the proper auto-mode omx file name and + skim matrix to use to append omx auto-mode transportation skims. + + If trips in the input DataFrame are not mapped to omx files + and matrices (non-auto mode trips) they are not present in the return + DataFrame. The return DataFrame is an interim DataFrame ready for + input to the omx_auto_skim_appender + + The process uses the trip departure ABM 5 TOD period, trip mode, + transponder availability, and the trip value of time (vot) category + to select the correct auto skim-set file and matrix to use to get + the auto-mode trip times, distances, and toll costs. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [departTimeFiveTod] - trip departure ABM 5 TOD periods (1-5) + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [transponderAvailable] - indicator if transponder available + on the trip (False, True) + [valueOfTimeCategory] - trip value of time categories + (Low, Medium, High) + [originTAZ] - trip origin TAZ (1-4996) + [destinationTAZ] - trip destination TAZ (1-4996) + [parkingTAZ] - trip parking TAZ ("", 1-4996) + + Returns: + A Pandas DataFrame containing mapping of auto-mode trips to omx + files and matrices containing auto-mode skims: + [tripID] - unique identifier of a trip + [omxFileName] - omx skim file name (e.g. traffic_skims_EA) + [matrixName] - omx skim matrix name (e.g. EA_HOV2_M) + [originTAZ] - trip origin TAZ (1-4996) + [destinationTAZ] - trip destination TAZ (1-4996) """ + + # set destinationTAZ equal to parkingTAZ is parkingTAZ is not missing + # auto portion of trip ends at the parkingTAZ + df.destinationTAZ = np.where(pd.notna(df.parkingTAZ), + df.parkingTAZ, + df.destinationTAZ).astype("int16") + + # create mappings from trip list to skim matrices + # segmented by SOV and Non-SOV as process differs between the two + # due to Transponder/Non-Transponder skimming in SOV mode + # SOV - departTimeFiveTod + tripMode + transponderAvailable + + # valueOfTimeCategory + # nonSOV - departTimeFiveTod + tripMode + valueOfTimeCategory + skim_map = {"SOV": {"values": [[1, 2, 3, 4, 5], + ["Drive Alone"], + [False, True], + ["Low", "Medium", "High"]], + "labels": [["EA", "AM", "MD", "PM", "EV"], + ["SOV"], + ["NT", "TR"], + ["L", "M", "H"]], + "cols": ["departTimeFiveTod", + "tripMode", + "transponderAvailable", + "valueOfTimeCategory", + "matrixName"]}, + "Non-SOV": {"values": [[1, 2, 3, 4, 5], + ["Shared Ride 2", + "Shared Ride 3+", + "Light Heavy Duty Truck", + "Medium Heavy Duty Truck", + "Heavy Heavy Duty Truck", + "Taxi", + "Non-Pooled TNC", + "Pooled TNC", + "School Bus"], + ["Low", "Medium", "High"]], + "labels": [["EA", "AM", "MD", "PM", "EV"], + ["HOV2", "HOV3", "TRK", "TRK", + "TRK", "HOV3", "HOV3", "HOV3", + "HOV3"], + ["L", "M", "H"]], + "cols": ["departTimeFiveTod", + "tripMode", + "valueOfTimeCategory", + "matrixName"]}} + + # initialize empty auto trips DataFrame + trips = pd.DataFrame() + + # map possible values of trip list columns to skim matrix names + # filter input DataFrame to auto trips mapped to skim matrices + for key in skim_map: + values = skim_map[key]["values"] + labels = skim_map[key]["labels"] + cols = skim_map[key]["cols"] + + mapping = [list(i) + ["_".join(j)] for i, j in + zip(itertools.product(*values), + itertools.product(*labels))] + + # create Pandas DataFrame lookup table of column values + # to skim matrix names + lookup = pd.DataFrame(mapping, columns=cols) + lookup["omxFileName"] = "traffic_skims_" + lookup["matrixName"].str[0:2] + + # set lookup DataFrame data types + lookup = lookup.astype({ + "departTimeFiveTod": "int8", + "tripMode": "category", + "valueOfTimeCategory": "category", + "omxFileName": "category", + "matrixName": "category"}) + + # merge lookup table to trip list and append to auto trips DataFrame + trips = trips.append(df.merge(lookup, how="inner"), ignore_index=True) + + # ABM Joint sub-model has multiple records per tripID + # per person on trip records are identical otherwise + trips.drop_duplicates(subset="tripID", inplace=True, ignore_index=True) + + return trips[["tripID", + "omxFileName", + "matrixName", + "originTAZ", + "destinationTAZ"]] + + def append_skims(self, df: pd.DataFrame, auto_only: bool, terminal_skims: bool) -> pd.DataFrame: + """ Takes an input Pandas DataFrame, runs all skimming class + methods and appends all skims to the input Pandas DataFrame. + See documentation of included class methods. Additionally creates and + appends three fields to the input Pandas DataFrame: + [timeTotal] - total trip time in minutes + [distanceTotal] - total trip distance in miles + [costTotal] - total trip cost in dollars + + Args: + df: Input Pandas DataFrame containing fields required by the + included class methods. + terminal_skims: Boolean of whether to include auto-mode terminal + skims, only apply to Resident model trip lists. + auto_only: Boolean of whether to include only basic auto-mode + skims, applies to Commercial Vehicle, Zombie AV, and Zombie + TNC trip lists. + + Returns: + A Pandas DataFrame containing all skims appended by the included + class methods. The DataFrame contains all original fields + of the input DataFrame along with fields appended by the + aforementioned class methods. """ + + # append omx auto skims + df = self.omx_auto_skim_appender(df) + + # append auto operating cost + df = self.auto_operating_cost(df) + + if auto_only: + pass + else: + # append auto terminal skims if applicable + if terminal_skims: + df = self.auto_terminal_skims(df) + + # append TNC fare costs + df = self.tnc_fare_cost(df) + + # append TNC wait times + df = self.tnc_wait_time(df) + + # append omx transit skims + df = self.omx_transit_skims(df) + + # append drive to transit skims + # auto-operating cost not included + # TNC fare costs and wait times not included + df = self.drive_transit_skims(df) + + # append (micro-mobility/micro-transit/walk) to transit skims + df = self.walk_transit_skims(df) + + # append micro-mobility/micro-transit/walk skims + df = self.walk_skims(df) + + # append bicycle skims + df = self.bicycle_skims(df) + + # append total trip time, distance, and cost skims + # transit in vehicle times by line haul mode and initial wait time + # are not included due to double-counting + transit_line_haul_cols = ["timeTier1TransitInVehicle", + "timeFreewayRapidTransitInVehicle", + "timeArterialRapidTransitInVehicle", + "timeExpressBusTransitInVehicle", + "timeLocalBusTransitInVehicle", + "timeLightRailTransitInVehicle", + "timeCommuterRailTransitInVehicle", + "timeTransitInitialWait"] + + df["timeTotal"] = df[df.columns.difference(transit_line_haul_cols)].filter(regex="^time").sum(axis=1) + + df["distanceTotal"] = df.filter(regex="^distance").sum(axis=1) + + df["costTotal"] = df.filter(regex="^cost").sum(axis=1) + + # sort return DataFrame by tripID for user-experience + # and faster database loading via ORDER hints + df.sort_values(by="tripID", inplace=True) + + return df + + def auto_operating_cost(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [avUsed]) and the fields appended by the + SkimAppender class method omx_auto_skim_appender + ([distanceDrive]) and returns the associated + auto-mode operating cost. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [avUsed] - indicator if AV used on trip (True, False) + [distanceDrive] - distance in miles for auto mode + + Returns: + A Pandas DataFrame containing all associated auto-mode + operating costs. The DataFrame contains all original fields + of the input DataFrame along with the field: + [costOperatingDrive] - auto operating cost in $ """ + + # calculate auto operating cost as fuel+maintenance cents per mile + # note this is scaled for AV trips by a factor + aoc = self.properties["aocFuel"] + self.properties["aocMaintenance"] + aoc_av = aoc * self.properties["costPerMileFactorAV"] + + # calculate auto operating cost for auto-mode trips + # exclude Taxi/TNC as operating cost is passed to drivers + # who are not considered part of the model universe + auto_modes = ["Drive Alone", + "Shared Ride 2", + "Shared Ride 3+", + "Light Heavy Duty Truck", + "Medium Heavy Duty Truck", + "Heavy Heavy Duty Truck"] + + conditions = [ + np.array(df["tripMode"].isin(auto_modes) & ~df["avUsed"], + dtype="bool"), + np.array(df["tripMode"].isin(auto_modes) & df["avUsed"], + dtype="bool") + ] + + choices = [df["distanceDrive"] * aoc, + df["distanceDrive"] * aoc_av] + + df["costOperatingDrive"] = pd.Series( + np.select(conditions, choices, default=np.NaN), + dtype="float32") + + # return input DataFrame with appended auto operating cost column + return df + + def auto_terminal_skims(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [destinationTAZ]) and appends the auto-mode + terminal walk time from the input/zone.term file. Distance is created + from the walk speed specified in the properties file + conf/sandag_abm.properties + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [destinationTAZ] - indicator if AV used on trip (True, False) + + Returns: + A Pandas DataFrame containing auto-mode terminal walk time and + distance. The DataFrame contains all original fields of the input + DataFrame along with the fields: + [timeAutoTerminalWalk] - auto terminal walk time in minutes + [distanceAutoTerminalWalk] - auto terminal walk distance in + miles + """ + # read in auto terminal time fixed width file + skims = pd.read_fwf( + os.path.join(self.scenario_path, "input", "zone.term"), + widths=[5, 7], + names=["destinationTAZ", + "timeAutoTerminalWalk"], + dtype={"destinationTAZ": "int16", + "timeAutoTerminalWalk": "float32"} + ) + + # merge auto terminal times into input DataFrame + # add 0s for TAZs with no terminal times + df = df.merge(skims, on="destinationTAZ", how="left") + df["timeAutoTerminalWalk"] = df["timeAutoTerminalWalk"].fillna(0) + + # set auto terminal times to 0 for non-auto modes + # reduce auto terminal time if AV is used + auto_modes = ["Drive Alone", "Shared Ride 2", "Shared Ride 3+"] + av_factor = self.properties["terminalTimeFactorAV"] + + conditions = [ + np.array(df["tripMode"].isin(auto_modes) & ~df["avUsed"], + dtype="bool"), + np.array(df["tripMode"].isin(auto_modes) & df["avUsed"], + dtype="bool") + ] + + choices = [df["timeAutoTerminalWalk"], + df["timeAutoTerminalWalk"] * av_factor] + + df["timeAutoTerminalWalk"] = pd.Series( + np.select(conditions, choices, default=np.NaN), + dtype="float32") + + # create auto terminal distance from walk speed property + df["distanceAutoTerminalWalk"] = pd.Series( + df["timeAutoTerminalWalk"] * self.properties["walkSpeed"] / 60, + dtype="float32") + + return df + + def bicycle_skims(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [originMGRA], [destinationMGRA], [originTAZ], + [destinationTAZ]) and returns the associated bicycle mode skims for + time and distance. + + Bicycle mode skims are given at the MGRA-MGRA level by the + output/bikeMgraLogsum.csv file and TAZ-TAZ level by the + output/bikeTazLogsum.csv file. If a MGRA-MGRA o-d pair is not present + in the MGRA-MGRA level then the TAZ-TAZ level skim is used. Note the + skims only provide time in minutes so distance is created using the + bicycle speed property set in the conf/sandag_abm.properties file. + Non-bicycle modes have all skims set to NaN. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [originMGRA] - trip origin MGRA (1-23002) + [destinationMGRA] - trip destination MGRA (1-23002) + [originTAZ] - trip origin TAZ (1-4996) + [destinationTAZ] - trip destination TAZ (1-4996) + + Returns: + A Pandas DataFrame containing all associated bicycle mode + skims for time and distance. The DataFrame contains all the + original fields of the input DataFrame along with the fields: + [timeBike] - time in minutes for bicycle mode + [distanceBike] - distance in miles for bicycle mode """ + + # load the MGRA-MGRA bicycle skims + mgra_skims = pd.read_csv( + os.path.join(self.scenario_path, "output", "bikeMgraLogsum.csv"), + usecols=["i", # origin MGRA geography + "j", # destination MGRA geography + "time"], # time in minutes + dtype={"i": "int16", + "j": "int16", + "time": "float32"} + ) + + # load the TAZ-TAZ bicycle skims + taz_skims = pd.read_csv( + os.path.join(self.scenario_path, "output", "bikeTazLogsum.csv"), + usecols=["i", # origin TAZ geography + "j", # destination TAZ geography + "time"], # time in minutes + dtype={"i": "int16", + "j": "int16", + "time": "float32"} + ) + + # merge the skims with the input DataFrame bicycle mode records + # use left outer joins to keep all bicycle mode records + # if MGRA-MGRA skims do not exist + # ABM Joint sub-model has multiple records per tripID + # per person on trip records are identical otherwise + records = df.loc[(df["tripMode"] == "Bike")].copy() + records.drop_duplicates(subset="tripID", inplace=True, ignore_index=True) + + records = records.merge( + right=mgra_skims, + how="left", + left_on=["originMGRA", "destinationMGRA"], + right_on=["i", "j"] + ) + records = records.merge( + right=taz_skims, + how="left", + left_on=["originTAZ", "destinationTAZ"], + right_on=["i", "j"], + suffixes=["MGRA", "TAZ"] + ) + + # if MGRA-MGRA skims do not exist use TAZ-TAZ skims + records["timeBike"] = pd.Series( + np.where(records["timeMGRA"].isna(), + records["timeTAZ"], + records["timeMGRA"]), + dtype="float32") + + # calculate distance using bicycle speed + records["distanceBike"] = pd.Series( + records["timeBike"] * self.properties["bicycleSpeed"] / 60, + dtype="float32") + + # merge result set DataFrame back into initial trip list + # keep missing skim records as missing skim means no bike trip + records = records[["tripID", "timeBike", "distanceBike"]] + df = df.merge(records, on="tripID", how="left") + + # return input DataFrame with appended skim columns + return df + + def drive_transit_skims(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [originTAZ], [destinationTAZ], + [boardingTAP], [alightingTAP], and [inbound]) and returns the + associated drive to transit auto-mode skims for time and distance. + + The model uses an on-the-fly input file (input\accessam.csv) for + drive to transit auto-mode skims and assumes no fare or toll costs. + Non-drive to transit modes have all skims set to NaN. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [originTAZ] - trip origin TAZ (1-4996) + [destinationTAZ] - trip destination TAZ (1-4996) + [boardingTAP] - trip boarding transit access point (TAP) + [alightingTAP] - trip alighting transit access point (TAP) + [inbound] - direction of trip on tour (False, True) + + Returns: + A Pandas DataFrame containing all associated drive to transit + auto-mode skims for time and distance (assumed no toll cost). + The DataFrame contains all the original fields of the input + DataFrame along with the fields: + [timeDriveTransit] - time in minutes for auto mode + [distanceDriveTransit] - distance in miles for auto mode """ + + # read in the input accessam csv file + # this file is used in place of auto skim matrices for drive to transit + skims = pd.read_csv(self.scenario_path + "/input/accessam.csv", + names=["TAZ", # TAZ geography + "TAP", # transit access point (TAP) + "timeDriveTransit", # time in minutes + "distanceDriveTransit", # distance in miles + "mode"], + usecols=["TAZ", + "TAP", + "timeDriveTransit", + "distanceDriveTransit"], + dtype={"TAZ": "int16", + "TAP": "int16", + "timeDriveTransit": "float32", + "distanceDriveTransit": "float32"}) + + # select drive to transit records + # ABM Joint sub-model has multiple records per tripID + # per person on trip records are identical otherwise + modes = ["Park and Ride to Transit - Local Bus", + "Park and Ride to Transit - Premium Transit", + "Park and Ride to Transit - Local Bus and Premium Transit", + "Kiss and Ride to Transit - Local Bus", + "Kiss and Ride to Transit - Premium Transit", + "Kiss and Ride to Transit - Local Bus and Premium Transit", + "TNC to Transit - Local Bus", + "TNC to Transit - Premium Transit", + "TNC to Transit - Local Bus and Premium Transit"] + records = df.loc[(df["tripMode"].isin(modes))].copy() + records.drop_duplicates(subset="tripID", inplace=True, ignore_index=True) + + # create MGRA-TAP origin-destinations based on inbound direction + records["MGRA"] = np.where(records["inbound"], + records["destinationMGRA"], + records["originMGRA"]) + + records["TAP"] = np.where(records["inbound"], + records["alightingTAP"], + records["boardingTAP"]) + + # use the origin/destination MGRA to derive the origin/destination + # TAZ, this accounts for issues where external TAZs (1-12) do not have + # TAP-based skims, the skims are derived from the internal TAZ of the + # internal MGRA of the trip origin/destination + records = records.merge(self.mgra_xref, on="MGRA") + + # merge with the drive to transit access skims + records = records[["tripID", "TAZ", "TAP"]] + records = records.merge(skims, how="inner", on=["TAZ", "TAP"]) + records = records[["tripID", "timeDriveTransit", "distanceDriveTransit"]] + + # merge result set DataFrame back into initial trip list + # keep missing skim records as missing skim means no transit trip + df = df.merge(records, on="tripID", how="left") + + # return input DataFrame with appended skim columns + return df + + def omx_auto_skim_appender(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame and returns the DataFrame with + associated auto-mode skims for time, distance, and toll cost appended. + + The process uses the trip departure ABM 5 TOD period, trip mode, + transponder availability, and the trip value of time (vot) category + to select the correct auto skim-set to get the trip time, distance, + and toll costs. Non-auto modes have all skims set to NaN. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [departTimeFiveTod] - trip departure ABM 5 TOD periods (1-5) + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [transponderAvailable] - indicator if transponder available + on the trip (False, True) + [valueOfTimeCategory] - trip value of time categories + (Low, Medium, High) + [originTAZ] - trip origin TAZ (1-4996) + [destinationTAZ] - trip destination TAZ (1-4996) + [parkingTAZ] - trip parking TAZ ("", 1-4996) + + Returns: + The input Pandas DataFrame with auto-mode skims for time, + distance, and toll cost appended. The DataFrame contains all the + original fields of the input DataFrame along with the fields: + [timeDrive] - time in minutes for auto mode + [distanceDrive] - distance in miles for auto mode + [costTollDrive] - toll cost in $ for auto mode """ + + # prepare the input DataFrame for skim appending + # selecting records that use the input omx file + df_map = self._get_omx_auto_skim_dataset(df) + + # initialize output skim list + output = [] + + for omx_fn in df_map.omxFileName.unique(): + + # open the input omx file and TAZ:element mapping + fn = os.path.join(self.scenario_path, "output", omx_fn + ".omx") + omx_file = omx.open_file(fn) + omx_map = omx_file.mapping("zone_number") + + # filter records mapped to omx file + records_omx = df_map.loc[df_map.omxFileName == omx_fn] + + # for each skim matrix in the data-set + for matrix in records_omx.matrixName.unique(): + # filter records mapped to skim matrix + records = records_omx.loc[records_omx.matrixName == matrix] + + # create set of unique origin-destination pairs + # get time, distance, cost associated with the o-d pairs + od = set(zip(records.originTAZ, records.destinationTAZ)) + o, d = zip(*od) + + # map o-ds to omx matrix indices + o_idx = [omx_map[number] for number in o] + d_idx = [omx_map[number] for number in d] + + skims = list(zip( + [omx_fn] * len(o), + [matrix] * len(o), + o, d, + omx_file[matrix + "_TIME"][o_idx, d_idx], + omx_file[matrix + "_DIST"][o_idx, d_idx], + omx_file[matrix + "_TOLLCOST"][o_idx, d_idx] / 100)) + + output.extend(skims) + + omx_file.close() + + # create DataFrame from output skim list + output = pd.DataFrame(data=output, + columns=["omxFileName", + "matrixName", + "originTAZ", + "destinationTAZ", + "timeDrive", + "distanceDrive", + "costTollDrive"]) + + # set data types of output skims list + output = output.astype({ + "omxFileName": "category", + "matrixName": "category", + "originTAZ": "int16", + "destinationTAZ": "int16", + "timeDrive": "float32", + "distanceDrive": "float32", + "costTollDrive": "float32" + }) + + # merge the output skim list back to the mapped input DataFrame + # appending auto skims to tripIDs + output = output.merge(right=df_map, how="inner") + + output = output[["tripID", + "timeDrive", + "distanceDrive", + "costTollDrive"]] + + # merge the output skim list back to the original input DataFrame + # keep missing skim records as missing skim means no auto trip + df = df.merge(right=output, on="tripID", how="left") + + # return input DataFrame with appended skim columns + return df + + def omx_transit_skims(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the fields + ([tripID], [departTimeFiveTod], [tripMode], [boardingTAP], + [alightingTAP]) and returns the associated transit mode skims for time, + distance, and fare cost. + + The process uses the trip departure ABM 5 TOD period and trip mode to + select the correct transit skim-set to use to get the trip time, + distance, and fare costs. Non-transit modes have all skims set to NaN. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [departTimeFiveTod] - trip departure ABM 5 TOD periods (1-5) + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [boardingTAP] - trip boarding transit access point (TAP) + [alightingTAP] - trip alighting transit access point (TAP) + + Returns: + A Pandas DataFrame containing all associated transit-mode skims for + time, distance, and fare cost. The DataFrame contains all the + original fields of the input DataFrame along with the fields: + [timeTransitInVehicle] - transit in-vehicle time in minutes + [timeTier1TransitInVehicle] - tier 1 line haul mode transit + in-vehicle time in minutes + [timeFreewayRapidTransitInVehicle] - freeway rapid line haul + mode transit in-vehicle time in minutes + [timeArterialRapidTransitInVehicle] - arterial rapid line haul + mode transit in-vehicle time in minutes + [timeExpressBusTransitInVehicle] - express bus line haul + mode transit in-vehicle time in minutes + [timeLocalBusTransitInVehicle] - local bus line haul + mode transit in-vehicle time in minutes + [timeLightRailTransitInVehicle] - light rail line haul + mode transit in-vehicle time in minutes + [timeCommuterRailTransitInVehicle] - commuter rail line haul + mode transit in-vehicle time in minutes + [timeTransitInitialWait] - initial transit wait time in minutes + [timeTransitWait] - total transit wait time in minutes + [timeTransitWalk] - total transit walk time in minutes + [distanceTransitInVehicle] - transit in-vehicle distance in miles + [distanceTransitWalk] - total transit walk distance in miles + [costFareTransit] - fare cost in $ for transit mode + [transfersTransit] - number of transfers """ + + # create mappings from trip list to skim matrices + # departTimeFiveTod + tripMode + skim_map = {"values": [[1, 2, 3, 4, 5], + ["Walk to Transit - Local Bus", + "Walk to Transit - Premium Transit", + "Walk to Transit - Local Bus and Premium Transit", + "Park and Ride to Transit - Local Bus", + "Park and Ride to Transit - Premium Transit", + "Park and Ride to Transit - Local Bus and Premium Transit", + "Kiss and Ride to Transit - Local Bus", + "Kiss and Ride to Transit - Premium Transit", + "Kiss and Ride to Transit - Local Bus and Premium Transit", + "TNC to Transit - Local Bus", + "TNC to Transit - Premium Transit", + "TNC to Transit - Local Bus and Premium Transit"]], + "labels": [["EA", "AM", "MD", "PM", "EV"], + ["BUS", "PREM", "ALLPEN", + "BUS", "PREM", "ALLPEN", + "BUS", "PREM", "ALLPEN", + "BUS", "PREM", "ALLPEN"]], + "cols": ["departTimeFiveTod", + "tripMode", + "matrixName"]} + + # initialize empty result set DataFrame + result = pd.DataFrame() + + # map possible values of trip list columns to skim matrix names + mapping = [list(i) + ["_".join(j)] for i, j in + zip(itertools.product(*skim_map["values"]), + itertools.product(*skim_map["labels"]))] + + # create Pandas DataFrame lookup table of column values + # to skim matrix names + lookup = pd.DataFrame(mapping, columns=skim_map["cols"]) + + # set data types of lookup table + lookup = lookup.astype({ + "departTimeFiveTod": "int8", + "tripMode": "category", + "matrixName": "category" + }) + + # merge lookup table to trip list make DataFrame unique by tripID + # ABM Joint sub-model has multiple records per tripID + # per person on trip records are identical otherwise + trips = df.merge(lookup, how="inner") + trips.drop_duplicates(subset="tripID", inplace=True, ignore_index=True) + + # open omx transit skim file and get TAP:element matrix mapping + omx_file = omx.open_file(self.scenario_path + "/output/transit_skims.omx") + omx_map = omx_file.mapping("zone_number") + + # for each skim matrix in the data-set + for matrix in trips.matrixName.unique(): + # select records that use the skim matrix + records = trips.loc[(trips["matrixName"] == matrix)].copy() + + # get lists of o-ds + o = records.boardingTAP.astype("int16").tolist() + d = records.alightingTAP.astype("int16").tolist() + + # map o-ds to omx matrix indices + o_idx = [omx_map[number] for number in o] + d_idx = [omx_map[number] for number in d] + + # append skims + records["timeTransitInVehicle"] = omx_file[matrix + "_TOTALIVTT"][o_idx, d_idx] + records["timeTier1TransitInVehicle"] = omx_file[matrix + "_TIER1IVTT"][o_idx, d_idx] + records["timeFreewayRapidTransitInVehicle"] = omx_file[matrix + "_BRTYELIVTT"][o_idx, d_idx] + records["timeArterialRapidTransitInVehicle"] = omx_file[matrix + "_BRTREDIVTT"][o_idx, d_idx] + records["timeExpressBusTransitInVehicle"] = omx_file[matrix + "_EXPIVTT"][o_idx, d_idx] + records["timeLocalBusTransitInVehicle"] = omx_file[matrix + "_BUSIVTT"][o_idx, d_idx] + records["timeLightRailTransitInVehicle"] = omx_file[matrix + "_LRTIVTT"][o_idx, d_idx] + records["timeCommuterRailTransitInVehicle"] = omx_file[matrix + "_CMRIVTT"][o_idx, d_idx] + records["timeTransitInitialWait"] = omx_file[matrix + "_FIRSTWAIT"][o_idx, d_idx] + records["timeTransitWait"] = omx_file[matrix + "_TOTALWAIT"][o_idx, d_idx] + records["timeTransitWalk"] = omx_file[matrix + "_TOTALWALK"][o_idx, d_idx] + records["distanceTransitInVehicle"] = omx_file[matrix + "_TOTDIST"][o_idx, d_idx] + records["costFareTransit"] = omx_file[matrix + "_FARE"][o_idx, d_idx] + records["transfersTransit"] = omx_file[matrix + "_XFERS"][o_idx, d_idx] + records["distanceTransitWalk"] = records.timeTransitWalk * self.properties["walkSpeed"] / 60 + + # set skim data types + records = records.astype({ + "timeTransitInVehicle": "float32", + "timeTransitInitialWait": "float32", + "timeTransitWait": "float32", + "timeTransitWalk": "float32", + "distanceTransitInVehicle": "float32", + "costFareTransit": "float32", + "transfersTransit": "float32", + "distanceTransitWalk": "float32"}) + + records = records[["tripID", + "timeTransitInVehicle", + "timeTier1TransitInVehicle", + "timeFreewayRapidTransitInVehicle", + "timeArterialRapidTransitInVehicle", + "timeExpressBusTransitInVehicle", + "timeLocalBusTransitInVehicle", + "timeLightRailTransitInVehicle", + "timeCommuterRailTransitInVehicle", + "timeTransitInitialWait", + "timeTransitWait", + "timeTransitWalk", + "distanceTransitInVehicle", + "distanceTransitWalk", + "costFareTransit", + "transfersTransit"]] + + result = result.append(records, ignore_index=True) + + omx_file.close() + + skim_cols = ["timeTransitInVehicle", + "timeTier1TransitInVehicle", + "timeFreewayRapidTransitInVehicle", + "timeArterialRapidTransitInVehicle", + "timeExpressBusTransitInVehicle", + "timeLocalBusTransitInVehicle", + "timeLightRailTransitInVehicle", + "timeCommuterRailTransitInVehicle", + "timeTransitInitialWait", + "timeTransitWait", + "timeTransitWalk", + "distanceTransitInVehicle", + "distanceTransitWalk", + "costFareTransit", + "transfersTransit"] + + # if there are no transit trip skim records + if result.empty: + # append skim columns to input DataFrame + # set to missing as a missing skim means no transit trip + for col in skim_cols: + df[col] = np.NaN + else: + # merge result set DataFrame back into initial trip list + # keep missing skim records as missing skim means no transit trip + df = df.merge(result, on="tripID", how="left") + + # return input DataFrame with appended skim columns + return df + + def tnc_fare_cost(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [avUsed]) and the fields appended by the + SkimAppender class method omx_auto_skim_appender + ([timeDrive], [distanceDrive]) and returns the associated + fare costs. + + Note that drive to transit modes assume no fare costs and are not + included here. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [timeDrive] - time in minutes for auto mode + [distanceDrive] - distance in miles for auto mode + + Returns: + A Pandas DataFrame containing all associated auto-mode fare + costs. The DataFrame contains all original fields of the input + DataFrame along with the field: + [costFareDrive] - auto mode fare cost in $ """ + + # calculate fare costs for non-pooled TNC, pooled TNC, and taxi modes + conditions = [df["tripMode"] == "Non-Pooled TNC", + df["tripMode"] == "Pooled TNC", + df["tripMode"] == "Taxi"] + + # calculate non-pooled TNC fare incorporating minimum fare + non_pooled_tnc_fare = pd.Series( + self.properties["baseFareNonPooledTNC"] + + self.properties["costPerMileNonPooledTNC"] * df["distanceDrive"] + + self.properties["costPerMinuteNonPooledTNC"] * df["timeDrive"], + dtype="float32") + + non_pooled_tnc_fare = np.where( + non_pooled_tnc_fare < self.properties["costMinimumNonPooledTNC"], + self.properties["costMinimumNonPooledTNC"], + non_pooled_tnc_fare) + + # calculate pooled TNC fare incorporating minimum fare + pooled_tnc_fare = pd.Series( + self.properties["baseFarePooledTNC"] + + self.properties["costPerMilePooledTNC"] * df["distanceDrive"] + + self.properties["costPerMinutePooledTNC"] * df["timeDrive"], + dtype="float32") + + pooled_tnc_fare = np.where( + pooled_tnc_fare < self.properties["costMinimumPooledTNC"], + self.properties["costMinimumPooledTNC"], + pooled_tnc_fare) + + choices = [ + non_pooled_tnc_fare, + pooled_tnc_fare, + self.properties["baseFareTaxi"] + + self.properties["costPerMileTaxi"] * df["distanceDrive"] + + self.properties["costPerMinuteTaxi"] * df["timeDrive"] + ] + + df["costFareDrive"] = pd.Series( + np.select(conditions, choices, default=np.NaN), + dtype="float32") + + # return input DataFrame with appended auto fare cost column + return df + + def tnc_wait_time(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [originMGRA]) and returns the associated wait + times for Taxi and TNC modes. + + Note that drive to transit modes assume no auto-mode wait time and + are not included here. + + Note that the actual wait times experienced by trips are drawn from a + distribution but not written out to the trip output files making it + impossible to write out the actual wait time experienced. The mean is + used here for all trips as an approximation. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [originMGRA] - trip origin MGRA geography + + Returns: + A Pandas DataFrame containing all associated auto-mode wait times. + The DataFrame contains all original fields of the input DataFrame + along with the field: + [timeWaitDrive] - auto mode wait time in minutes """ + + # load the mgra based input file + fn = "mgra13_based_input" + str(self.properties["year"]) + ".csv" + + mgra = pd.read_csv(os.path.join(self.scenario_path, "input", fn), + usecols=["mgra", # MGRA geography + "PopEmpDenPerMi"], # density per mi + dtype={"mgra": "int16", + "PopEmpDenPerMi": "float32"}) + + # add PopEmpDenPerMi field to the input DataFrame + df = df.merge(mgra, left_on="originMGRA", right_on="mgra") + + # select mean wait time for Taxi/TNC mode trips based on + # the category the PopEmpDenPerMi value falls in + # note the first true condition encountered is chosen + conditions = [ + ((df["tripMode"] == "Non-Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][0])), + ((df["tripMode"] == "Non-Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][1])), + ((df["tripMode"] == "Non-Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][2])), + ((df["tripMode"] == "Non-Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][3])), + ((df["tripMode"] == "Non-Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][4])), + ((df["tripMode"] == "Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][0])), + ((df["tripMode"] == "Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][1])), + ((df["tripMode"] == "Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][2])), + ((df["tripMode"] == "Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][3])), + ((df["tripMode"] == "Pooled TNC") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][4])), + ((df["tripMode"] == "Taxi") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][0])), + ((df["tripMode"] == "Taxi") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][1])), + ((df["tripMode"] == "Taxi") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][2])), + ((df["tripMode"] == "Taxi") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][3])), + ((df["tripMode"] == "Taxi") & ( + df["PopEmpDenPerMi"] < self.properties["waitTimePopEmpDenPerMi"][4])) + ] + + choices = [ + *self.properties["waitTimeNonPooledTNC"], + *self.properties["waitTimePooledTNC"], + *self.properties["waitTimeTaxi"], + ] + + df["timeWaitDrive"] = pd.Series( + np.select(conditions, choices, default=np.NaN), + dtype="float32") + + # remove mgra, PopEmpDenPerMi from the input DataFrame + df.drop(columns=["mgra", "PopEmpDenPerMi"], inplace=True) + + # return input DataFrame with appended auto wait time column + return df + + def walk_skims(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [originMGRA], [destinationMGRA]) and returns + the associated micro-mobility, micro-transit, and walk mode skims for + time, distance, and fare cost. Non-micro-mobility/micro-transit/walk + modes have all skims set to NaN. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [originMGRA] - trip origin MGRA (1-23002) + [destinationMGRA] - trip destination MGRA (1-23002) + + Returns: + A Pandas DataFrame containing all associated micro-mobility, + micro-transit, and walk mode skims for time, distance, and + fare cost. The DataFrame contains all original fields of the + input DataFrame along with the field: + [timeWalk] - time in minutes for walk mode + [distanceWalk] - distance in miles for walk mode + [timeMM] - time in minutes for micro-mobility mode + [distanceMM] - distance in miles for micro-mobility mode + [costFareMM] - fare cost in dollars for micro-mobility mode + [timeMT] - time in minutes for micro-transit mode + [distanceMT] - distance in miles for micro-transit mode + [costFareMT] - fare cost in dollars for micro-transit mode + """ + # get skims for walk/micro-mobility/micro-transit trips + # some use AT skim sets while others use auto skim set + records_at = self._walk_skims_at(df) + records_auto = self._walk_skims_auto(df) + + # if there are no mm/mt/walk trip skim records + if records_at.empty and records_auto.empty: + # append skim columns to input DataFrame + # set to missing as a missing skim means no walk trip + skim_cols = ["timeWalk", + "distanceWalk", + "timeMM", + "distanceMM", + "costFareMM", + "timeMT", + "distanceMT", + "costFareMT"] + + for col in skim_cols: + df[col] = np.NaN + else: + # merge result set DataFrame back into initial trip list + # keep missing skim records as missing skim means no walk trip + records = records_at.append(records_auto, ignore_index=True) + df = df.merge(records, on="tripID", how="left") + + # return input DataFrame with appended skim columns + return df + + def _walk_skims_at(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [originMGRA], [destinationMGRA]) and returns + the associated micro-mobility, micro-transit, and walk mode skims for + time, distance, and fare cost. Non-micro-mobility/micro-transit/walk + modes have all skims set to NaN. Note that some micro-mobility, + micro-transit and walk mode trips use an auto mode skim to define + time, distance, and fare cost. These are removed from consideration + in this method and handled elsewhere. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [originMGRA] - trip origin MGRA (1-23002) + [destinationMGRA] - trip destination MGRA (1-23002) + + Returns: + A Pandas DataFrame containing all associated micro-mobility, + micro-transit, and walk mode skims for time, distance, and + fare cost. The DataFrame contains only micro-mobility, + micro-transit, and walk mode trip records that do not use the + auto mode skim set for time: + [tripID] - unique identifier of a trip + [timeWalk] - time in minutes for walk mode + [distanceWalk] - distance in miles for walk mode + [timeMM] - time in minutes for micro-mobility mode + [distanceMM] - distance in miles for micro-mobility mode + [costFareMM] - fare cost in dollars for micro-mobility mode + [timeMT] - time in minutes for micro-transit mode + [distanceMT] - distance in miles for micro-transit mode + [costFareMT] - fare cost in dollars for micro-transit mode + """ + # load the mgra-mgra walk/micro-mobility/micro-transit skim file + skims = pd.read_csv(os.path.join(self.scenario_path, + "output", + "microMgraEquivMinutes.csv"), + usecols=["i", # origin MGRA geography + "j", # destination MGRA geography + "walkTime", # walk time in minutes + "dist", # distance in miles + "mmTime", # micro-mobility time in minutes + "mmCost", # micro-mobility cost in dollars + "mtTime", # micro-transit time in minutes + "mtCost"], # micro-transit cost in dollars + dtype={"i": "int16", + "j": "int16", + "walkTime": "float32", + "dist": "float32", + "mmTime": "float32", + "mmCost": "float32", + "mtTime": "float32", + "mtCost": "float32"}) + + # merge the skims with the input DataFrame walk/mm/mt mode records + # ABM Joint sub-model has multiple records per tripID + # per person on trip records are identical otherwise + records = df.loc[(df["tripMode"].isin(["Micro-Mobility", + "Micro-Transit", + "Walk"]))].copy() + + records.drop_duplicates(subset="tripID", inplace=True, ignore_index=True) + + records = records.merge( + right=skims, + how="inner", # some of these trips can use auto skims, use inner join to remove them + left_on=["originMGRA", "destinationMGRA"], + right_on=["i", "j"] + ) + + # set skims based on mode + records["timeWalk"] = np.where(records["tripMode"] == "Walk", + records["walkTime"], + 0) + + records["distanceWalk"] = np.where(records["tripMode"] == "Walk", + records["dist"], + 0) + + records["timeMM"] = np.where(records["tripMode"] == "Micro-Mobility", + records["mmTime"], + 0) + + records["distanceMM"] = np.where(records["tripMode"] == "Micro-Mobility", + records["dist"], + 0) + + records["costFareMM"] = np.where(records["tripMode"] == "Micro-Mobility", + records["mmCost"], + 0) + + records["timeMT"] = np.where(records["tripMode"] == "Micro-Transit", + records["mtTime"], + 0) + + records["distanceMT"] = np.where(records["tripMode"] == "Micro-Transit", + records["dist"], + 0) + + records["costFareMT"] = np.where(records["tripMode"] == "Micro-Transit", + records["mtCost"], + 0) + + # return result set of walk/micro-mobility/micro-transit trips + # that use AT skim sets + return records[["tripID", + "timeWalk", + "distanceWalk", + "timeMM", + "distanceMM", + "costFareMM", + "timeMT", + "distanceMT", + "costFareMT"]] + + def _walk_skims_auto(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [tripMode], [originMGRA], [originTAZ] [destinationMGRA], + [destinationTAZ]) and returns the associated micro-mobility, + micro-transit, and walk mode skims for time, distance, and fare cost + for micro-mobility, micro-transit, and walk mode trips that use + auto mode skim set for time. Note that micro-mobility, micro-transit, + and walk mode trips that do not use auto mode skim set for time are + removed from consideration and handled elsewhere. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [originMGRA] - trip origin MGRA (1-23002) + [originTAZ] - trip origin TAZ (1-4996) + [destinationMGRA] - trip destination MGRA (1-23002) + [destinationTAZ] - trip destination TAZ (1-4996) + + Returns: + A Pandas DataFrame containing all associated micro-mobility, + micro-transit, and walk mode skims for time, distance, and + fare cost. The DataFrame contains only micro-mobility, + micro-transit, and walk mode trip records that use the auto + mode skim set for time: + [tripID] - unique identifier of a trip + [timeWalk] - time in minutes for walk mode + [distanceWalk] - distance in miles for walk mode + [timeMM] - time in minutes for micro-mobility mode + [distanceMM] - distance in miles for micro-mobility mode + [costFareMM] - fare cost in dollars for micro-mobility mode + [timeMT] - time in minutes for micro-transit mode + [distanceMT] - distance in miles for micro-transit mode + [costFareMT] - fare cost in dollars for micro-transit mode + """ + # load the mgra-mgra walk/micro-mobility/micro-transit skim file + skims = pd.read_csv(os.path.join(self.scenario_path, + "output", + "microMgraEquivMinutes.csv"), + usecols=["i", # origin MGRA geography + "j", # destination MGRA geography + "walkTime", # walk time in minutes + "dist", # distance in miles + "mmTime", # micro-mobility time in minutes + "mmCost", # micro-mobility cost in dollars + "mtTime", # micro-transit time in minutes + "mtCost"], # micro-transit cost in dollars + dtype={"i": "int16", + "j": "int16", + "walkTime": "float32", + "dist": "float32", + "mmTime": "float32", + "mmCost": "float32", + "mtTime": "float32", + "mtCost": "float32"}) + + # merge the skims with the input DataFrame walk/mm/mt mode records + # ABM Joint sub-model has multiple records per tripID + # per person on trip records are identical otherwise + records = df.loc[(df["tripMode"].isin(["Micro-Mobility", + "Micro-Transit", + "Walk"]))].copy() + + records.drop_duplicates(subset="tripID", inplace=True, ignore_index=True) + + # select records that are NOT in the mgra-mgra + # walk/micro-mobility/micro-transit skim file + records = records.merge( + right=skims, + how="left", # use outer join to keep all trip records + left_on=["originMGRA", "destinationMGRA"], + right_on=["i", "j"], + indicator=True + ) + + records = records[records["_merge"] == "left_only"] + + # if there are no eligible records return an empty DataFrame + if records.empty: + return pd.DataFrame( + columns=["tripID", + "timeWalk", + "distanceWalk", + "timeMM", + "distanceMM", + "costFareMM", + "timeMT", + "distanceMT", + "costFareMT"] + ) + else: + # append trip time from auto skim set + # midday drive alone non-transponder low value of time + + # open omx transit skim file and get TAZ matrix mapping + omx_file = omx.open_file(self.scenario_path + "/output/traffic_skims_MD.omx") + omx_map = omx_file.mapping("zone_number") + + # get lists of o-ds + o = records.originTAZ.astype("int16").tolist() + d = records.destinationTAZ.astype("int16").tolist() + + # map o-ds to omx matrix indices + o_idx = [omx_map[number] for number in o] + d_idx = [omx_map[number] for number in d] + + # append travel time skim from auto skim set + records["sovTime"] = omx_file["MD_SOV_NT_M_TIME"][o_idx, d_idx] + + omx_file.close() + + # load the MGRA-MGRA based input file + # merge with trips to get micro-mobility access time for origin MGRAs + records = records.merge( + right=self.mgra_xref, + how="inner", + left_on="originMGRA", + right_on="MGRA" + ) + + # set skims based on mode + records["timeWalk"] = np.where(records["tripMode"] == "Walk", + records["sovTime"], + 0) + + records["distanceWalk"] = np.where(records["tripMode"] == "Walk", + records["sovTime"] * self.properties["walkSpeed"] / 60, + 0) + + records["timeMM"] = np.where(records["tripMode"] == "Micro-Mobility", + records["sovTime"] + records["MicroAccessTime"], + 0) + + records["distanceMM"] = np.where(records["tripMode"] == "Micro-Mobility", + records["sovTime"] * self.properties["microMobilitySpeed"] / 60, + 0) + + records["costFareMM"] = np.where(records["tripMode"] == "Micro-Mobility", + records["sovTime"] * self.properties["costPerMinuteMicroMobility"] + + self.properties["baseFareMicroMobility"], + 0) + + records["timeMT"] = np.where(records["tripMode"] == "Micro-Transit", + records["sovTime"] + self.properties["accessTimeMicroTransit"] + + self.properties["waitTimeMicroTransit"], + 0) + + records["distanceMT"] = np.where(records["tripMode"] == "Micro-Transit", + records["sovTime"] * self.properties["microTransitSpeed"] / 60, + 0) + + records["costFareMT"] = np.where(records["tripMode"] == "Micro-Transit", + records["sovTime"] * self.properties["costPerMinuteMicroTransit"] + + self.properties["baseFareMicroTransit"], + 0) + + # return result set of walk/micro-mobility/micro-transit trips + # that use auto mode skim set + return records[["tripID", + "timeWalk", + "distanceWalk", + "timeMM", + "distanceMM", + "costFareMM", + "timeMT", + "distanceMT", + "costFareMT"]] + + def walk_transit_skims(self, df: pd.DataFrame) -> pd.DataFrame: + """ Takes an input Pandas DataFrame containing the ABM fields + ([tripID], [inbound], [tripMode], [originMGRA], [destinationMGRA], + [boardingTAP], [alightingTAP]) and the optional fields + ([microMobilityTransitAccess], [microMobilityTransitEgress]) and + returns the associated micro-mobility, micro-transit, and walk mode + skims for transit access/egress for time, distance, and fare cost. + Trips without micro-mobility, micro-transit, or walk mode + access/egress to transit have all skims set to 0. + + Args: + df: Input Pandas DataFrame containing the fields + [tripID] - unique identifier of a trip + [inbound] - boolean indicator of inbound/outbound direction + [tripMode] - ABM trip modes (Drive Alone, Shared Ride 2, etc...) + [originMGRA] - trip origin MGRA (1-23002) + [destinationMGRA] - trip destination MGRA (1-23002) + [boardingTAP] - transit boarding TAP + [alightingTAP] - transit alighting TAP + [microMobilityTransitAccess] - optional field indicating if + micro-mobility, micro-transit, or walk mode was used to + access transit + [microMobilityTransitEgress] - optional field indicating if + micro-mobility, micro-transit, or walk mode was used to + egress transit + + Returns: + A Pandas DataFrame containing all associated micro-mobility, + micro-transit, and walk to transit mode access/egress skims for + time, distance, and fare cost. The DataFrame contains all the + original fields of the input DataFrame along with the fields: + [timeTransitWalkAccessEgress] - time in minutes for walk + portion of transit access/egress + [distanceTransitWalkAccessEgress] - distance in miles for + walk portion of transit access/egress + [timeTransitMMAccessEgress] - time in minutes for + micro-mobility portion of transit access/egress + [distanceTransitMMAccessEgress] - distance in miles for + micro-mobility portion of transit access/egress + [costFareTransitMMAccessEgress] - fare cost in dollars for + micro-mobility portion of transit access/egress + [timeTransitMTAccessEgress] - time in minutes for + micro-transit portion of transit access/egress + [distanceTransitMTAccessEgress] - distance in miles for + micro-transit portion of transit access/egress + [costFareTransitMTAccessEgress] - fare cost in dollars for + micro-transit portion of transit access/egress """ + + # load the micro-mobility, micro-transit, and walk from MGRA-TAP + # skim file containing time, distance, and cost + skims = pd.read_csv(os.path.join(self.scenario_path, + "output", + "microMgraTapEquivMinutes.csv"), + usecols=["mgra", # origin MGRA geography + "tap", # destination TAP + "walkTime", # walk time in minutes + "dist", # distance in miles + "mmTime", # micro-mobility time in minutes + "mmCost", # micro-mobility cost in dollars + "mtTime", # micro-transit time in minutes + "mtCost"], # micro-transit cost in dollars + dtype={"mgra": "int16", + "tap": "int16", + "walkTime": "float32", + "dist": "float32", + "mmTime": "float32", + "mmCost": "float32", + "mtTime": "float32", + "mtCost": "float32"}) + + # filter input DataFrame to records that have access/egress + # micro-mobility, micro-transit, or walk segments + records = df.loc[(df["tripMode"].isin( + ["Walk to Transit - Local Bus", + "Walk to Transit - Premium Transit", + "Walk to Transit - Local Bus and Premium Transit", + "Park and Ride to Transit - Local Bus", + "Park and Ride to Transit - Premium Transit", + "Park and Ride to Transit - Local Bus and Premium Transit", + "Kiss and Ride to Transit - Local Bus", + "Kiss and Ride to Transit - Premium Transit", + "Kiss and Ride to Transit - Local Bus and Premium Transit", + "TNC to Transit - Local Bus", + "TNC to Transit - Premium Transit", + "TNC to Transit - Local Bus and Premium Transit"]))].copy() + + # ABM Joint sub-model has multiple records per tripID + # per person on trip records are identical otherwise + records.drop_duplicates(subset="tripID", inplace=True, ignore_index=True) + + # merge micro-mobility, micro-transit, and walk access/egress skims + # for both the access and egress portions + records = records.merge( + right=skims, + how="left", + left_on=["originMGRA", "boardingTAP"], + right_on=["mgra", "tap"] + ) + + records = records.merge( + right=skims, + how="left", + left_on=["destinationMGRA", "alightingTAP"], + right_on=["mgra", "tap"], + suffixes=["Access", "Egress"] + ) + + # conditionally set access/egress skim fields to 0 based on trip mode + # and inbound direction of trip, note that walk to transit uses both + records.loc[(records["tripMode"].isin( + ["Park and Ride to Transit - Local Bus", + "Park and Ride to Transit - Premium Transit", + "Park and Ride to Transit - Local Bus and Premium Transit", + "Kiss and Ride to Transit - Local Bus", + "Kiss and Ride to Transit - Premium Transit", + "Kiss and Ride to Transit - Local Bus and Premium Transit", + "TNC to Transit - Local Bus", + "TNC to Transit - Premium Transit", + "TNC to Transit - Local Bus and Premium Transit"])) & + (records["inbound"] == False), + ["walkTimeAccess", + "distAccess", + "mmTimeAccess", + "mmCostAccess", + "mtTimeAccess", + "mtCostAccess"]] = 0 + + records.loc[(records["tripMode"].isin([ + "Park and Ride to Transit - Local Bus", + "Park and Ride to Transit - Premium Transit", + "Park and Ride to Transit - Local Bus and Premium Transit", + "Kiss and Ride to Transit - Local Bus", + "Kiss and Ride to Transit - Premium Transit", + "Kiss and Ride to Transit - Local Bus and Premium Transit", + "TNC to Transit - Local Bus", + "TNC to Transit - Premium Transit", + "TNC to Transit - Local Bus and Premium Transit"])) & + (records["inbound"] == True), + ["walkTimeEgress", + "distEgress", + "mmTimeEgress", + "mmCostEgress", + "mtTimeEgress", + "mtCostEgress"]] = 0 + + # if optional micro-mobility access/egress fields are not present + # assume Walk modes only for access/egress skims + if not {"microMobilityTransitAccess", "microMobilityTransitEgress"}.issubset(df.columns): + records["timeTransitWalkAccessEgress"] = records["walkTimeAccess"] + records["walkTimeEgress"] + records["distanceTransitWalkAccessEgress"] = records["distAccess"] + records["distEgress"] + records["timeTransitMMAccessEgress"] = 0 + records["distanceTransitMMAccessEgress"] = 0 + records["costFareTransitMMAccessEgress"] = 0 + records["timeTransitMTAccessEgress"] = 0 + records["distanceTransitMTAccessEgress"] = 0 + records["costFareTransitMTAccessEgress"] = 0 + else: # if optional micro-mobility access/egress fields are present + # set skim fields based on micro-mobility access/egress fields + records["timeTransitWalkAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Walk", + records["walkTimeAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Walk", + records["walkTimeEgress"], 0) + + records["distanceTransitWalkAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Walk", + records["distAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Walk", + records["distEgress"], 0) + + records["timeTransitMMAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Micro-Mobility", + records["mmTimeAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Micro-Mobility", + records["mmTimeEgress"], 0) + + records["distanceTransitMMAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Micro-Mobility", + records["distAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Micro-Mobility", + records["distEgress"], 0) + + records["costFareTransitMMAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Micro-Mobility", + records["mmCostAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Micro-Mobility", + records["mmCostEgress"], 0) + + records["timeTransitMTAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Micro-Transit", + records["mtTimeAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Micro-Transit", + records["mtTimeEgress"], 0) + + records["distanceTransitMTAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Micro-Transit", + records["distAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Micro-Transit", + records["distEgress"], 0) + + records["costFareTransitMTAccessEgress"] = \ + np.where(records["microMobilityTransitAccess"] == "Micro-Transit", + records["mtCostAccess"], 0) + \ + np.where(records["microMobilityTransitEgress"] == "Micro-Transit", + records["mtCostEgress"], 0) + + # merge result set DataFrame back into initial trip list + records = records[["tripID", + "timeTransitWalkAccessEgress", + "distanceTransitWalkAccessEgress", + "timeTransitMMAccessEgress", + "distanceTransitMMAccessEgress", + "costFareTransitMMAccessEgress", + "timeTransitMTAccessEgress", + "distanceTransitMTAccessEgress", + "costFareTransitMTAccessEgress"]] + + # access/egress transit trip + skim_cols = ["timeTransitWalkAccessEgress", + "distanceTransitWalkAccessEgress", + "timeTransitMMAccessEgress", + "distanceTransitMMAccessEgress", + "costFareTransitMMAccessEgress", + "timeTransitMTAccessEgress", + "distanceTransitMTAccessEgress", + "costFareTransitMTAccessEgress"] + + # if there are no mm/mt/walk access/egress skim records + if records.empty: + # append skim columns to input DataFrame + # set to missing as a missing skim means no transit trip + for col in skim_cols: + df[col] = np.NaN + else: + # merge result set DataFrame back into initial trip list + # keep missing skim records as missing skim means no transit trip + df = df.merge(records, on="tripID", how="left") + + # return input DataFrame with appended skim columns + return df diff --git a/sandag_abm/src/main/python/database_summary.py b/sandag_abm/src/main/python/database_summary.py new file mode 100644 index 0000000..63f441f --- /dev/null +++ b/sandag_abm/src/main/python/database_summary.py @@ -0,0 +1,190 @@ +# __author__ = 'yma' +# This file is to get data summary from the database, 1/23/2019 + +import openpyxl +from openpyxl import load_workbook +from datetime import datetime +from pandas import DataFrame +import pandas as pd +import pyodbc +import sys +import os + +# usage = ("Correct Usage: database_summary.py ") + +# check if too few/many arguments passed raise error +if len(sys.argv) != 4: + sys.exit(-1) + +output_path = str(sys.argv[1]) +sceYear = int(sys.argv[2]) +scenario = int(sys.argv[3]) + +# create settings data frame +settings = {"Parameter": ["Date", "Scenario_id","Year"], + "Value": [datetime.now().strftime("%x %X"),scenario,sceYear]} +settings = pd.DataFrame(data=settings) + + +# set sql server connection to ws +sql_con = pyodbc.connect(driver='{SQL Server}', + server='sql2014a8', + database='ws', + trusted_connection='yes') + + +### data summary for sensitivty analysis + +# 0_scenarioInfor +scenarioInfor = pd.read_sql_query( + sql="exec [ws].[sst2].[m0_scenario] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 1_modeshare +modeShare = pd.read_sql_query( + sql="exec [ws].[sst2].[m1_mode_share] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 4_PtripLengthByPurpose +ptripLengthByPurpose = pd.read_sql_query( + sql="exec [ws].[sst2].[m4_ptrip_distance_purpose] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 5_PtripLengthByMode +ptripDistanceMode = pd.read_sql_query( + sql="exec [ws].[sst2].[m5_ptrip_distance_mode] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 23_VMT +VMT = pd.read_sql_query( + sql="exec [ws].[sst2].[m23_vmt_capita] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 6_VHT +VHT = pd.read_sql_query( + sql="exec [ws].[sst2].[m6_vht_capita] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 7_VHD +VHD = pd.read_sql_query( + sql="exec [ws].[sst2].[m7_vhd_capita] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 8_TransitBoardingByMode +transitBoardingLinehaulMode = pd.read_sql_query( + sql="exec [ws].[sst2].[m8_transit_boarding_linehaulmode] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + +# 9_TransitTripsbyMode +transitTripsbyMode = pd.read_sql_query( + sql="exec [ws].[sst2].[m9_transit_trips_by_mode] @scenario_id = ? ", + con=sql_con, + params=[scenario] +) + + +# output to excel book 'source_sensitivity' +output_file_sens = output_path + "\\analysis\\summary\\source_summary.xlsx" +book = load_workbook(output_file_sens) + +with pd.ExcelWriter(output_file_sens, engine='openpyxl') as writer: + + writer.book = book + writer.sheets = dict((ws.title, ws) for ws in book.worksheets) + + settings.to_excel(writer,'Settings',index=False) + scenarioInfor.to_excel(writer,'0_scenarioInfor', index=False) + modeShare.to_excel(writer,'1_modeshare', index=False) + ptripLengthByPurpose.to_excel(writer, '4_PtripLengthByPurpose', index=False) + ptripDistanceMode.to_excel(writer, '5_PtripLengthByMode', index=False) + VMT.to_excel(writer, '23_VMT', index=False) + VHT.to_excel(writer, '6_VHT', index=False) + VHD.to_excel(writer, '7_VHD', index=False) + transitBoardingLinehaulMode.to_excel(writer, '8_TransitBoardingByMode', index=False) + transitTripsbyMode.to_excel(writer, '9_TransitTripsbyMode', index=False) + + writer.save() + + +### data summary for validation analysis, if scenario_year = 2016 or 2018 + +if sceYear == 2016 or sceYear == 2018: + + # get hwy flow given scenario_id + hwyFlow = pd.read_sql_query( + sql="select * from [ws].[validate2].[FlowDay2016_nonmsa] (?)", + con=sql_con, + params=[scenario] + ) + + # get freeway flow by TOD given scenario_id + fwyFlow = pd.read_sql_query( + sql="select * from [ws].[validate2].[FlowFreewayTod2016] (?)", + con=sql_con, + params=[scenario] + ) + + # get truck flow given scenario_id + truckFlow = pd.read_sql_query( + sql="select * from [ws].[validate2].[TruckFlow2016] (?)", + con=sql_con, + params=[scenario] + ) + + # get hwy speed given scenario_id + hwySpeed = pd.read_sql_query( + sql="select * from [ws].[validate2].[SpeedFreewayTod2016] (?)", + con=sql_con, + params=[scenario] + ) + + # get transit general summary given scenario_id + transitGeneral = pd.read_sql_query( + sql="select * from [ws].[validate2].[transit2016] (?)", + con=sql_con, + params=[scenario] + ) + + # get transit hub summary given scenario_id + transitHub = pd.read_sql_query( + sql="select * from [ws].[validate2].[transit2016_Hub] (?)", + con=sql_con, + params=[scenario] + ) + + + # output to excel book 'source' + output_file_vald = output_path + "\\analysis\\validation\\source.xlsx" + book = load_workbook(output_file_vald) + + with pd.ExcelWriter(output_file_vald, engine='openpyxl') as writer: + + writer.book = book + writer.sheets = dict((ws.title, ws) for ws in book.worksheets) + + settings.to_excel(writer,'Settings',index=False) + hwyFlow.to_excel(writer,'flow_raw', index=False) + fwyFlow.to_excel(writer,'flow_freeway', index=False) + truckFlow.to_excel(writer,'truck_flow', index=False) + hwySpeed.to_excel(writer,'hwy_speed', index=False) + transitGeneral.to_excel(writer,'transit_general', index=False) + transitHub.to_excel(writer,'transit_hub', index=False) + + writer.save() + diff --git a/sandag_abm/src/main/python/excel_update.py b/sandag_abm/src/main/python/excel_update.py new file mode 100644 index 0000000..ad17762 --- /dev/null +++ b/sandag_abm/src/main/python/excel_update.py @@ -0,0 +1,85 @@ +# __author__ = 'yma' +# This file is to force to update links in excel, 1/23/2019 + +import os +import sys +import win32com.client +from win32com.client import Dispatch + +# usage = ("Correct Usage: excel_update.py ") + +# check if too few/many arguments passed raise error +if len(sys.argv) != 4: + sys.exit(-1) + +output_path = str(sys.argv[1]) +sceYear = int(sys.argv[2]) +scenario = str(sys.argv[3]) + + +path_name_s = output_path + "\\analysis\\summary\\" +file_names_s = ["ModelResultSummary"] + +path_name_v = output_path + "\\analysis\\validation\\" +file_names_v = ["HighwayAssignmentValidation_2016_AllClass_EMME", + "HighwayAssignmentValidation_2016_Truck_EMME", + "HighwayAssignmentValidation_2016_Speed_FreewayCorridor_AMPM_EMME", + "HighwayAssignmentValidation_2016_FreewayCorridor_Daily_EMME", + "HighwayAssignmentValidation_2016_FreewayCorridor_AM_EMME", + "HighwayAssignmentValidation_2016_FreewayCorridor_PM_EMME", + "TransitAssignmentValidation_2016_General_EMME", + #"TransitAssignmentValidation_2016_Hub", + ] +ext = ".xlsm" + +# file list of sensitivity +list_s = [] +list_s_new = [] +for file in file_names_s: + file_s = path_name_s + file + ext + #file_s_new = path_name_s + file + "_" + scenario + ext + file_s_new = path_name_s + file + ext + list_s.append(file_s) + list_s_new.append(file_s_new) + +# file list of validation +list_v = [] +list_v_new = [] +for file in file_names_v: + file_v = path_name_v + file + ext + #file_v_new = path_name_v + file + "_" + scenario + ext # since the data was read from EMME, scenario is not needed - CL 05222020 + file_v_new = path_name_v + file + ext + list_v.append(file_v) + list_v_new.append(file_v_new) + + +file_list = list_s +file_list_new = list_s_new + +if sceYear == 2016 or sceYear == 2018: + file_list = file_list + list_v + file_list_new = file_list_new + list_v_new + + +xl = Dispatch("Excel.Application") +xl.Visible = False +xl.DisplayAlerts = False +xl.AskToUpdateLinks = False + +for file in file_list: + wb = xl.workbooks.open(file) + xl.Application.Run("UpdateLinks") + wb.Close(True) + +EMME = os.path.join(path_name_v, 'source_EMME.xlsx') #with source_EMME.xlsx opened, links in validation Excel files will work well. This is a temporary solution - CL 05222020 +wb_emme = xl.Workbooks.Open(EMME) +for file in file_list: + wb = xl.workbooks.open(file) + xl.Application.Run("UpdateLinks") + wb.Close(True) +wb_emme.Close(True) + +xl.Quit() + +#for i in range(len(file_list)): # since the data was read from EMME, scenario is not needed and the file names are not renamed with scenrio ID - CL 05222020 +# os.rename(file_list[i], file_list_new[i]) diff --git a/sandag_abm/src/main/python/parameterUpdate.py b/sandag_abm/src/main/python/parameterUpdate.py new file mode 100644 index 0000000..cfa06ca --- /dev/null +++ b/sandag_abm/src/main/python/parameterUpdate.py @@ -0,0 +1,60 @@ +# Author:Yun.Ma@sandag.org +# Oct 5,2016 + +#import +import os +import csv +import string +import sys + +# check if property file exists +if not os.path.isfile('..\\conf\\sandag_abm.properties'): + print "Property File Not Found" + raise sys.exit() + +# search scenarioYear +TheYear='' +propFile = open('..\\conf\\sandag_abm.properties','r') +for line in propFile: + if line.find('scenarioYear') > -1: + TheYear = line.strip('\n').split('=')[1] + break +else: + print "scenarioYear Not Found" +propFile.close() + +# read csv file +ParaDict={} +csvFileIn = open('..\\input\\parametersByYears.csv','rU') +reader = csv.DictReader(csvFileIn) +for row in reader: + if row['year'] == TheYear: + ParaDict=row.copy() + break +csvFileIn.close() +ParaDict.pop('year',ParaDict['year']) + +# read and update str in property file +OldVal='' +NewVal='' +Paralines=[] + +propInFile = open('..\\conf\\sandag_abm.properties','r') +for line in propInFile: + for key in ParaDict: + if line.find(key) > -1: + NewVal = ParaDict[key] + print NewVal + OldVal = line.strip('\n').split('=')[1] + line = string.replace(line,OldVal,NewVal) + print line + break + Paralines.append(line) +propInFile.close() + +# write into property file +propOutFile = open('..\\conf\\sandag_abm.properties','w') +for line in Paralines: + propOutFile.write(line) +propOutFile.close() + diff --git a/sandag_abm/src/main/python/pythonGUI/createStudyAndScenario.py b/sandag_abm/src/main/python/pythonGUI/createStudyAndScenario.py new file mode 100644 index 0000000..a6a9eb9 --- /dev/null +++ b/sandag_abm/src/main/python/pythonGUI/createStudyAndScenario.py @@ -0,0 +1,237 @@ +__author__ = 'wsu' +#Wu.Sun@sandag.org 10-27-2016 +import Tkinter +import Tkconstants +import tkFileDialog +import os +from Tkinter import * +from PIL import Image,ImageTk +import popupMsg + +class CreateScenarioGUI(Tkinter.Frame): + def __init__(self, root): + Tkinter.Frame.__init__(self, root, border=5) + body = Tkinter.Frame(self) + body.pack(fill=Tkconstants.X, expand=1) + sticky = Tkconstants.E + Tkconstants.W + body.grid_columnconfigure(1, weight=2) + + #divider line + divider=u"_"*120 + self.releaseDir='T:\\ABM\\release\\ABM' + self.defaultScenarioDir="T:\\projects\\sr14" + self.defaultNetworkDir="T:\\projects\\sr14\\version14_2_0\\network_build" + + self.buttonVar= IntVar(root) + self.yButton=Radiobutton(body, text="Yes", variable=self.buttonVar, value=1, command=self.initStudy) + self.nButton=Radiobutton(body, text="No", variable=self.buttonVar, value=0,command=self.initStudy) + Tkinter.Label(body, text=divider, font=("Helvetica", 11, 'bold'), width=50, fg='royal blue').grid(row=0,columnspan=5) + Tkinter.Label(body, text=u"Create an ABM Work Space", font=("Helvetica", 10, 'bold')).grid(row=1,columnspan=3) + self.yButton.grid(row=2,column=0, columnspan=2) + self.nButton.grid(row=2,column=1, columnspan=2) + + Tkinter.Label(body, text=u"Study Folder", font=("Helvetica", 8, 'bold')).grid(row=3) + self.studypath = Tkinter.Entry(body, width=40) + self.studypath.grid(row=3, column=1, sticky=sticky) + self.studypath.delete(0, Tkconstants.END) + self.studypath.insert(0, self.defaultScenarioDir) + self.studybutton = Tkinter.Button(body, text=u"...",width=4,command=lambda:self.get_path("study")) + self.studybutton.grid(row=3, column=2) + + Tkinter.Label(body, text=u"Network Folder",font=("Helvetica", 8, 'bold')).grid(row=4) + self.studynetworkpath = Tkinter.Entry(body, width=40) + self.studynetworkpath.grid(row=4, column=1, sticky=sticky) + self.studynetworkpath.delete(0, Tkconstants.END) + self.studynetworkpath.insert(0, self.defaultNetworkDir) + self.studynetworkbutton = Tkinter.Button(body, text=u"...",width=4,command=lambda: self.get_path("studynetwork")) + self.studynetworkbutton.grid(row=4, column=2) + + self.copyButton = Tkinter.Button(body, text=u"Create", font=("Helvetica", 8, 'bold'),width=10, command=lambda: self.checkPath("study")) + self.copyButton.grid(row=5,column=0,columnspan=4) + + Tkinter.Label(body, text=divider, font=("Helvetica", 11, 'bold'), width=50, fg='royal blue').grid(row=6,columnspan=5) + Tkinter.Label(body, text=u"Create an ABM scenario", font=("Helvetica", 10, 'bold')).grid(row=7,columnspan=3) + + Tkinter.Label(body, text=u"Version", font=("Helvetica", 8, 'bold')).grid(row=8) + var = StringVar(root) + self.version="version_14_2_2" + optionList=["version_14_2_2"] + option=Tkinter.OptionMenu(body,var,*optionList,command=self.setversion) + option.config(width=50) + option.grid(row=8, column=1) + + Tkinter.Label(body, text=u"Emme Version", font=("Helvetica", 8, 'bold')).grid(row=9) + var = StringVar(root) + self.emme_version = "4.4.4.1" + optionList = ["4.3.7", "4.4.4.1"] + option = Tkinter.OptionMenu(body, var, *optionList, command=self.setEmmeVersion) + option.config(width=50) + option.grid(row=9, column=1) + + Tkinter.Label(body, text=u"Year", font=("Helvetica", 8, 'bold')).grid(row=10) + + var = StringVar(root) + self.year="2016" + yearOptionList = ["2016", "2020", "2023", "2025", "2025nb", "2026", "2029", "2030", "2030nb", "2032", "2035", "2035nb", "2040", "2040nb", "2050","2050nb"] + option=Tkinter.OptionMenu(body,var,*yearOptionList,command=self.setyear) + option.config(width=50) + option.grid(row=10, column=1) + + Tkinter.Label(body, text=u"Scenario Folder", font=("Helvetica", 8, 'bold')).grid(row=11) + self.scenariopath = Tkinter.Entry(body, width=40) + self.scenariopath.grid(row=11, column=1, sticky=sticky) + button = Tkinter.Button(body, text=u"...",width=4,command=lambda: self.get_path("scenario")) + button.grid(row=11, column=2) + + Tkinter.Label(body, text=u"Network Folder",font=("Helvetica", 8, 'bold')).grid(row=12) + self.networkpath = Tkinter.Entry(body, width=40) + self.networkpath.grid(row=12, column=1, sticky=sticky) + button = Tkinter.Button(body, text=u"...",width=4,command=lambda: self.get_path("network")) + button.grid(row=12, column=2) + + buttons = Tkinter.Frame(self) + buttons.pack() + botton = Tkinter.Button(buttons, text=u"Create", font=("Helvetica", 8, 'bold'),width=10, command=lambda: self.checkPath("scenario")) + botton.pack(side=Tkconstants.LEFT) + Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT) + button = Tkinter.Button(buttons, text=u"Quit", font=("Helvetica", 8, 'bold'), width=10, command=self.quit) + button.pack(side=Tkconstants.RIGHT) + + self.initStudy() + + def initStudy(self): + #disable study setting buttons + if self.buttonVar.get()==1: + self.studypath.config(state=NORMAL) + self.studybutton.config(state=NORMAL) + self.studynetworkpath.config(state=NORMAL) + self.studynetworkbutton.config(state=NORMAL) + self.copyButton.configure(state=NORMAL) + #enable study setting buttons + elif self.buttonVar.get()==0: + self.studypath.config(state=DISABLED) + self.studybutton.config(state=DISABLED) + self.studynetworkpath.config(state=DISABLED) + self.studynetworkbutton.config(state=DISABLED) + self.copyButton.configure(state=DISABLED) + + #set default input and network paths based on selected year + def setversion(self,value): + self.version=value + return + + # set Emme version + def setEmmeVersion(self, value): + self.emme_version = value + return + + #set default input and network paths based on selected year + def setyear(self,value): + self.defaultpath=self.releaseDir+"\\"+self.version+'\\input\\'+value + self.scenariopath.delete(0, Tkconstants.END) + self.scenariopath.insert(0, self.defaultScenarioDir) + self.networkpath.delete(0, Tkconstants.END) + self.networkpath.insert(0, self.defaultpath) + self.year=value + return + + #set cluster + def setcluster(self,value): + self.cluster=value + return + + #set default options for folded browsers + def setPathOptions(self): + self.dir_opt = options = {} + options['initialdir'] = self.defaultScenarioDir + options['mustexist'] = False + options['parent'] = root + options['title'] = 'This is a title' + + #get a path after the browse button is clicked on + def get_path(self,type): + self.setPathOptions() + path = tkFileDialog.askdirectory(**self.dir_opt) + if type=="scenario": + if path: + spath = os.path.normpath(path) + self.scenariopath.delete(0, Tkconstants.END) + self.scenariopath.insert(0, spath) + elif type=="network": + if path: + npath = os.path.normpath(path) + self.networkpath.delete(0, Tkconstants.END) + self.networkpath.insert(0, npath) + elif type=="study": + if path: + studypath = os.path.normpath(path) + self.studypath.delete(0, Tkconstants.END) + self.studypath.insert(0, studypath) + elif type=="studynetwork": + if path: + studynetworkpath = os.path.normpath(path) + self.studynetworkpath.delete(0, Tkconstants.END) + self.studynetworkpath.insert(0, studynetworkpath) + return + + #check if a path already exisits or is empty + def checkPath(self,type): + self.popup=Tkinter.Tk() + if type=="scenario": + if os.path.exists(self.scenariopath.get()): + if not self.networkpath.get(): + popupMsg.popupmsg(self,"Network folder is empty!",1,type) + else: + popupMsg.popupmsg(self,"Selected scenario folder already exists! Proceeding will overwrite existing files!",2,type) + else: + if not self.scenariopath.get(): + popupMsg.popupmsg(self,"Scenario folder is empty!",1,type) + elif not self.networkpath.get(): + popupMsg.popupmsg(self,"Network folder is empty!",1,type) + else: + self.executeBatch(type) + elif type=="study": + if os.path.exists(self.studypath.get()): + if not self.studynetworkpath.get(): + popupMsg.popupmsg(self,"Network folder is empty!",1,type) + else: + popupMsg.popupmsg(self,"Selected study folder already exists! Proceeding will overwrite existing files!",2,type) + else: + if not self.studypath.get(): + popupMsg.popupmsg(self,"Study folder is empty!",1,type) + elif not self.studynetworkpath.get(): + popupMsg.popupmsg(self,"Network folder is empty!",1,type) + else: + self.executeBatch(type) + return + + #execute DOS commands + def executeBatch(self, type): + self.popup.destroy() + if type=="scenario": + commandstr = u"create_scenario.cmd %s %s %s %s" % ( + self.scenariopath.get(), + self.year, + self.networkpath.get(), + self.emme_version + ) + elif type=="study": + commandstr=u"copy_networkfiles_to_study.cmd "+self.studypath.get()+" "+self.studynetworkpath.get() + print (commandstr) + os.chdir(self.releaseDir+"\\"+self.version+'\\') + os.system(commandstr) + self.popup=Tkinter.Tk() + msg="You have successfully created the "+ type+"!" + popupMsg.popupmsg(self,msg,1,type) + return + +root = Tkinter.Tk() +root.resizable(True, False) +root.minsize(370, 0) +logo = Tkinter.PhotoImage(file=r"T:\ABM\release\ABM\SANDAG_logo.gif") +w=Label(root, image=logo, width=200) +w.pack(side='top', fill='both', expand='yes') +CreateScenarioGUI(root).pack(fill=Tkconstants.X, expand=1) +root.mainloop() + + diff --git a/sandag_abm/src/main/python/pythonGUI/parameterEditor.py b/sandag_abm/src/main/python/pythonGUI/parameterEditor.py new file mode 100644 index 0000000..bdc12cb --- /dev/null +++ b/sandag_abm/src/main/python/pythonGUI/parameterEditor.py @@ -0,0 +1,253 @@ +__author__ = 'wsu' +#Wu.Sun@sandag.org 7-20-2016 + +import Tkinter +import Tkconstants +import tkFileDialog +import os +from Tkinter import * +from PIL import Image,ImageTk +import stringFinder +import popupMsg + + +class ParametersGUI(Tkinter.Frame): + def __init__(self, root): + Tkinter.Frame.__init__(self, root, border=5) + self.status = Tkinter.Label(self, text=u"ABM Parameter Editor", font=("Helvetica", 12, 'bold')) + self.status.pack(fill=Tkconstants.X, expand=1) + body = Tkinter.Frame(self) + body.pack(fill=Tkconstants.X, expand=1) + sticky = Tkconstants.E + Tkconstants.W + body.grid_columnconfigure(1, weight=2) + + #section labels + sectionLabels=(u"Model Initial Start Options",u"Network Building Options",u"Final Assignment Options:",u"Data Loading Options:") + #radio button lables + rbLabels=(u"Copy warm start trip tables:",u"Copy bike AT access files:",u"Create bike AT access files:",u"Build highway network:",u"Build transit network:",u"Run highway assignment:", + u"Run highway skimming:",u"Run transit assignment:",u"Run transit skimming:",u"Export results to CSVs:",u"Load results to database:") + #properties + self.properties=("RunModel.skipCopyWarmupTripTables","RunModel.skipCopyBikeLogsum","RunModel.skipBikeLogsums","RunModel.skipBuildHwyNetwork","RunModel.skipBuildTransitNetwork","RunModel.skipFinalHighwayAssignment", + "RunModel.skipFinalHighwaySkimming","RunModel.skipFinalTransitAssignment","RunModel.skipFinalTransitSkimming", + "RunModel.skipDataExport","RunModel.skipDataLoadRequest") + + #divider line + divider=u"_"*120 + + #number of properties in GUI + self.pNum=self.properties.__len__() + + #initialize yes and no buttons + self.yButton = [0 for x in range(self.pNum)] + self.nButton = [0 for x in range(self.pNum)] + self.buttonVar= [0 for x in range(self.pNum)] + for i in range(self.pNum): + self.buttonVar[i] = IntVar(root) + self.yButton[i]=Radiobutton(body, text="Yes", variable=self.buttonVar[i], value=1) + self.nButton[i]=Radiobutton(body, text="No", variable=self.buttonVar[i], value=0) + + #set standard property values + self.setDefaultProperties() + + #set AT states-activate and deactivate by selections + #self.setATButtons() + + #scenario folder browser + Tkinter.Label(body, text=u"Scenario Folder", font=("Helvetica", 8, 'bold'),width=15).grid(row=0) + self.scenariopath = Tkinter.Entry(body, width=25) + self.scenariopath.grid(row=0, column=1, sticky=sticky, columnspan=3) + self.scenariopath.insert(0,sys.argv[1]) + button = Tkinter.Button(body, text=u"...",width=4,command=self.get_scenariopath) + button.grid(row=0, column=4) + + #initial start section + for i in range(1,25): + if i==1: #intial start section header + Tkinter.Label(body, text=divider, font=("Helvetica", 10, 'bold'), width=40, fg='royal blue').grid(row=i,columnspan=5) + Tkinter.Label(body, text=sectionLabels[0], font=("Helvetica", 10, 'bold'), width=30, fg='royal blue').grid(row=i+1,columnspan=5) + elif i>2 and i<6: + Tkinter.Label(body, text=rbLabels[i-3], font=("Helvetica", 8, 'bold')).grid(row=i) + self.yButton[i-3].grid(row=i,column=1) + self.nButton[i-3].grid(row=i,column=3) + elif i==6: #network building section header + Tkinter.Label(body, text=divider, font=("Helvetica", 10, 'bold'), width=40, fg='royal blue').grid(row=i,columnspan=5) + Tkinter.Label(body, text=sectionLabels[1], font=("Helvetica", 10, 'bold'), width=30, fg='royal blue').grid(row=i+1,columnspan=5) + elif i>7 and i<10: + Tkinter.Label(body, text=rbLabels[i-5], font=("Helvetica", 8, 'bold')).grid(row=i) + self.yButton[i-5].grid(row=i,column=1) + self.nButton[i-5].grid(row=i,column=3) + elif i==10: #final assignment section header + Tkinter.Label(body, text=divider, font=("Helvetica", 10, 'bold'), width=40, fg='royal blue').grid(row=i,columnspan=5) + Tkinter.Label(body, text=sectionLabels[2], font=("Helvetica", 10, 'bold'), width=30, fg='royal blue').grid(row=i+1,columnspan=5) + elif i>11 and i<16: + Tkinter.Label(body, text=rbLabels[i-7], font=("Helvetica", 8, 'bold')).grid(row=i) + self.yButton[i-7].grid(row=i,column=1) + self.nButton[i-7].grid(row=i,column=3) + elif i==16: #data load section header + Tkinter.Label(body, text=divider, font=("Helvetica", 10, 'bold'), width=40, fg='royal blue').grid(row=i,columnspan=5) + Tkinter.Label(body, text=sectionLabels[3], font=("Helvetica", 10, 'bold'), width=30, fg='royal blue').grid(row=i+1,columnspan=5) + elif i>17 and i<20: + Tkinter.Label(body, text=rbLabels[i-9], font=("Helvetica", 8, 'bold')).grid(row=i) + self.yButton[i-9].grid(row=i,column=1) + self.nButton[i-9].grid(row=i,column=3) + elif i==20: #iteration section + Tkinter.Label(body, text=divider, font=("Helvetica", 10, 'bold'), width=40, fg='royal blue').grid(row=i,columnspan=5) + Tkinter.Label(body, text=u"Iteration Options", font=("Helvetica", 10, 'bold'), width=30, fg='royal blue').grid(row=i+1,columnspan=5) + Tkinter.Label(body, text=u"Start from iteration:", font=("Helvetica", 8, 'bold')).grid(row=i+2) + self.var = IntVar(root) + self.button1=Radiobutton(body, text="1", variable=self.var, value=1) + self.button1.grid(row=i+2,column=1) + self.button1.select() + self.button2=Radiobutton(body, text="2", variable=self.var, value=2).grid(row=i+2,column=2) + self.button3=Radiobutton(body, text="3", variable=self.var, value=3).grid(row=i+2,column=3) + self.button4=Radiobutton(body, text="Skip", variable=self.var, value=4).grid(row=i+2,column=4) + elif i==23: + Tkinter.Label(body, text=u"Sample rates:", font=("Helvetica", 8, 'bold')).grid(row=i) + sv = StringVar(root) + sv.set("0.2,0.5,1.0") + self.samplerates="0.2,0.5,1.0" + sv.trace("w", lambda name, index, mode, sv=sv: self.setsamplerates(sv)) + e = Entry(body, textvariable=sv) + e.config(width=15) + e.grid(row=i,column=1,columnspan=3) + elif i==24:#action buttons + Tkinter.Label(body, text=u"", width=30).grid(row=i,columnspan=2) + buttons = Tkinter.Frame(self) + buttons.pack() + botton = Tkinter.Button(buttons, text=u"Update", font=("Helvetica", 9, 'bold'),width=10, command=self.update_parameters) + botton.pack(side=Tkconstants.LEFT) + Tkinter.Frame(buttons, width=10).pack(side=Tkconstants.LEFT) + button = Tkinter.Button(buttons, text=u"Quit", font=("Helvetica", 9, 'bold'), width=10, command=self.quit) + button.pack(side=Tkconstants.RIGHT) + + def setsamplerates(self,value): + self.samplerates=value.get() + + def setDefaultProperties(self): + self.runtimeFile=sys.argv[1]+"\\conf\\sandag_abm.properties" + self.standardFile=sys.argv[1]+"\\conf\\sandag_abm_standard.properties" + self.populateProperties() + """ + for i in range(self.pNum): + if i<3 or i>6: + self.yButton[i].select() + self.nButton[i].deselect() + else: + self.yButton[i].deselect() + self.nButton[i].select() + """ + + def setATButtons(self): + #disable create bike and walk logsums if 'copy' is chosen + self.yButton[1].config(command=lambda: self.yButton[3].config(state=DISABLED)) + #self.yButton[2].config(command=lambda: self.yButton[4].config(state=DISABLED)) + #disable copy bike and walk logsums if 'create' is chosen + self.yButton[3].config(command=lambda: self.yButton[1].config(state=DISABLED)) + #self.yButton[4].config(command=lambda: self.yButton[2].config(state=DISABLED)) + #enable create bike and walk logsums if NOT 'copy' is chosen + self.nButton[1].config(command=lambda: self.yButton[3].config(state=ACTIVE)) + #self.nButton[2].config(command=lambda: self.yButton[4].config(state=ACTIVE)) + #enable copy bike and walk logsums if NOT 'create' is chosen + self.nButton[3].config(command=lambda: self.yButton[1].config(state=ACTIVE)) + #self.nButton[4].config(command=lambda: self.yButton[2].config(state=ACTIVE)) + + #set scenario path + def get_scenariopath(self): + # defining options for opening a directory; initialize default path from command line + self.dir_opt = options = {} + options['initialdir'] = sys.argv[1] + options['mustexist'] = False + options['parent'] = root + options['title'] = 'This is a title' + scenariopath = tkFileDialog.askdirectory(**self.dir_opt) + if scenariopath: + scenariopath = os.path.normpath(scenariopath) + self.scenariopath.delete(0, Tkconstants.END) + self.scenariopath.insert(0, scenariopath) + else: + self.scenariopath.delete(0, Tkconstants.END) + self.scenariopath.insert(0, sys.argv[1]) + + #property file settings + self.runtimeFile=self.scenariopath.get()+"\\conf\\sandag_abm.properties" + self.standardFile=self.scenariopath.get()+"\\conf\\sandag_abm_standard.properties" + + #populate properties + self.populateProperties() + + return + + #populate properties with exisiting settings in scenario folder + def populateProperties(self): + if self.checkFile(): + for i in range(self.pNum): + if stringFinder.find(self.runtimeFile, self.properties[i]+" = true"): + self.yButton[i].deselect() + self.nButton[i].select() + elif stringFinder.find(self.runtimeFile, self.properties[i]+" = false"): + self.yButton[i].select() + self.nButton[i].deselect() + else: + print "Invalid property "+self.properties[i]+" value!, Property either has to be set to true or false." + return + + # update parameters with user inputs + def update_parameters(self): + #property file settings + self.runtimeFile=self.scenariopath.get()+"\\conf\\sandag_abm.properties" + self.standardFile=self.scenariopath.get()+"\\conf\\sandag_abm_standard.properties" + + self.deleteProperty() + self.old_text = [0 for x in range(self.pNum)] + self.new_text = [0 for x in range(self.pNum)] + for i in range(self.pNum): + if self.buttonVar[i].get()==1: + self.old_text[i]=self.properties[i]+" = true" + self.new_text[i]=self.properties[i]+" = false" + elif self.buttonVar[i].get()==0: + self.old_text[i]=self.properties[i]+" = false" + self.new_text[i]=self.properties[i]+" = true" + + #create a property update dictionary + dic=[] + for i in range(self.pNum): + pair=(self.old_text[i],self.new_text[i]) + dic.append(pair) + print dic[i][0],dic[i][1] + #add iteration update to dictionary + dic.append(("RunModel.startFromIteration = 1","RunModel.startFromIteration = "+str(self.var.get()))) + #add sample rates update to dictionary + dic.append(("sample_rates=0.2,0.5,1.0","sample_rates="+self.samplerates)) + stringFinder.replace(self.standardFile,self.runtimeFile,dic) + self.quit() + + #check if property file exists + def checkFile(self): + result=True + if not os.path.exists(self.runtimeFile): + self.popup=Tkinter.Tk() + popupMsg.popupmsg(self,self.runtimeFile+" doesn't exist!",1) + result=False + return result + + #close popup window and run batch + def letsgo(self): + self.popup.destroy() + return + + #run batch + def deleteProperty(self): + commandstr=u"del "+self.scenariopath.get()+"\\conf\\sandag_abm.properties" + print commandstr + os.system(commandstr) + return + +root = Tkinter.Tk() +root.resizable(True, False) +root.minsize(370, 0) +logo = Tkinter.PhotoImage(file=r"T:\ABM\release\ABM\SANDAG_logo.gif") +w=Label(root, image=logo, width=200) +w.pack(side='top', fill='both', expand='yes') +ParametersGUI(root).pack(fill=Tkconstants.X, expand=1, anchor=W) + +root.mainloop() diff --git a/sandag_abm/src/main/python/pythonGUI/popupMsg.py b/sandag_abm/src/main/python/pythonGUI/popupMsg.py new file mode 100644 index 0000000..e9ce061 --- /dev/null +++ b/sandag_abm/src/main/python/pythonGUI/popupMsg.py @@ -0,0 +1,17 @@ +__author__ = 'wsu' +import Tkinter +import Tkconstants +#popup window for path validity checking +def popupmsg(self,msg,numButtons,type): + self.popup.wm_title("!!!WARNING!!!") + label = Tkinter.Label(self.popup, text=msg) + label.pack(side="top", fill="x", pady=10) + popbuttons = Tkinter.Frame(self.popup) + popbuttons.pack() + #can't pass arguments to a callback, otherwise callback is called before widget is constructed; use lambda function instead + B1 = Tkinter.Button(popbuttons, text="Proceed", command =lambda: self.executeBatch(type)) + B2 = Tkinter.Button(popbuttons, text="Quit", command = self.popup.destroy) + if numButtons>1: + B1.pack(side=Tkconstants.LEFT) + B2.pack(side=Tkconstants.RIGHT) + Tkinter.Frame(popbuttons, width=10).pack(side=Tkconstants.LEFT) diff --git a/sandag_abm/src/main/python/pythonGUI/setup.py b/sandag_abm/src/main/python/pythonGUI/setup.py new file mode 100644 index 0000000..08db6ca --- /dev/null +++ b/sandag_abm/src/main/python/pythonGUI/setup.py @@ -0,0 +1,9 @@ +__author__ = 'wsu' +from distutils.core import setup +import py2exe + +setup(windows=['./src/main/python/pythonGUI/parameterEditor.py']) +setup(windows=['./src/main/python/pythonGUI/createStudyAndScenario.py']) +setup(windows=['./src/main/python/pythonGUI/validatorGUI.py']) + + diff --git a/sandag_abm/src/main/python/pythonGUI/stringFinder.py b/sandag_abm/src/main/python/pythonGUI/stringFinder.py new file mode 100644 index 0000000..3679eef --- /dev/null +++ b/sandag_abm/src/main/python/pythonGUI/stringFinder.py @@ -0,0 +1,21 @@ +__author__ = 'wsu' +def check(fname, txt): + with open(fname) as dataf: + return any(txt in line for line in dataf) + +def replace(old_fname, new_fname, replaceDic): + f1 = open(old_fname, 'r') + f2 = open(new_fname, 'w') + for line in f1: + for pair in replaceDic: + line=line.replace(pair[0], pair[1]) + f2.write(line) + f1.close() + f2.close() + return + +def find(fname, txt): + if check(fname, txt): + return True + else: + return False \ No newline at end of file diff --git a/sandag_abm/src/main/python/pythonGUI/validatorGUI.py b/sandag_abm/src/main/python/pythonGUI/validatorGUI.py new file mode 100644 index 0000000..b3770ce --- /dev/null +++ b/sandag_abm/src/main/python/pythonGUI/validatorGUI.py @@ -0,0 +1,122 @@ +__author__ = 'wsu' +#Wu.Sun@sandag.org 2-10-2017 +#wsu updated 5/2/2017 for release 13.3.2 +import Tkinter +import Tkconstants +import tkFileDialog +import os +from Tkinter import * +from PIL import Image,ImageTk +import popupMsg +import stringFinder + +class CreateScenarioGUI(Tkinter.Frame): + def __init__(self, root): + Tkinter.Frame.__init__(self, root, border=5) + body = Tkinter.Frame(self) + body.pack(fill=Tkconstants.X, expand=1) + sticky = Tkconstants.E + Tkconstants.W + body.grid_columnconfigure(1, weight=2) + + self.version="version_13_3_2" + + #divider line + divider=u"_"*120 + self.releaseDir='T:\\ABM\\release\\ABM' + self.defaultScenarioDir="T:\\projects\\sr13" + + #validation section + Tkinter.Label(body, text=divider, font=("Helvetica", 11, 'bold'), width=50, fg='royal blue').grid(row=13,columnspan=5) + Tkinter.Label(body, text=u"Validate a Base Year Scenario", font=("Helvetica", 10, 'bold')).grid(row=14,columnspan=3) + Tkinter.Label(body, text=u"Base Year", font=("Helvetica", 8, 'bold')).grid(row=15) + var = StringVar(root) + self.year="2012" + optionList=["2012", "2014"] + option=Tkinter.OptionMenu(body,var,*optionList,command=self.setyear) + option.config(width=50) + option.grid(row=15, column=1) + + Tkinter.Label(body, text=u"Scenario Number", font=("Helvetica", 8, 'bold')).grid(row=16) + vv = StringVar(root) + vv.set("540") + self.validationScenario="540" + vv.trace("w", lambda name, index, mode, vv=vv: self.setValidationScenario(vv)) + self.ve = Entry(body, textvariable=vv) + self.ve.config(width=15) + self.ve.grid(row=16,column=1,sticky=sticky) + + Tkinter.Label(body, text=u"Output Folder", font=("Helvetica", 8, 'bold')).grid(row=17) + self.validationpath = Tkinter.Entry(body, width=40) + self.validationpath.grid(row=17, column=1, sticky=sticky) + self.voutbutton = Tkinter.Button(body, text=u"...",width=4,command=lambda:self.get_path("validate")) + self.voutbutton.grid(row=17, column=2) + + self.validateButton = Tkinter.Button(body, text=u"Validate", font=("Helvetica", 8, 'bold'),width=10, command=lambda:self.checkPath("validate")) + self.validateButton.grid(row=18,column=0,columnspan=4) + + #set default input and network paths based on selected year + def setyear(self,value): + dic=[] + pair=("xxxx",value) + dic.append(pair) + dir=self.releaseDir+"\\"+self.version+'\\validation\\' + stringFinder.replace(dir+"sandag_validate_generic.properties",dir+"sandag_validate.properties",dic) + return + + #set default options for folded browsers + def setPathOptions(self): + self.dir_opt = options = {} + options['initialdir'] = self.defaultScenarioDir + options['mustexist'] = False + options['parent'] = root + options['title'] = 'This is a title' + + #get a path after the browse button is clicked on + def get_path(self,type): + self.setPathOptions() + path = tkFileDialog.askdirectory(**self.dir_opt) + if path: + vpath = os.path.normpath(path) + self.validationpath.delete(0, Tkconstants.END) + self.validationpath.insert(0, vpath) + return + + #check if a path already exisits or is empty + def checkPath(self,type): + self.popup=Tkinter.Tk() + if not self.validationScenario: + popupMsg.popupmsg(self,"No validation scenario was selected!",1,type) + else: + if not self.validationpath.get(): + popupMsg.popupmsg(self,"Validation output directory is empty!",1,type) + else: + self.executeBatch(type) + return + + #execute DOS commands + def executeBatch(self, type): + self.popup.destroy() + msg="You have successfully created the "+ type+"!" + commandstr=u"validate.cmd "+self.validationScenario+" "+self.validationpath.get()+"\\" + msg="Validation results are in "+self.validationpath.get() + dir=self.releaseDir+"\\"+self.version+'\\validation\\' + print commandstr + os.chdir(dir) + os.system(commandstr) + self.popup=Tkinter.Tk() + popupMsg.popupmsg(self,msg,1,type) + return + + def setValidationScenario(self,value): + self.validationScenario=value.get() + +root = Tkinter.Tk() +root.resizable(True, False) +root.minsize(370, 0) +logo = Tkinter.PhotoImage(file=r"T:\ABM\release\ABM\SANDAG_logo.gif") +w=Label(root, image=logo, width=200) +w.pack(side='top', fill='both', expand='yes') +CreateScenarioGUI(root).pack(fill=Tkconstants.X, expand=1) +root.mainloop() + + diff --git a/sandag_abm/src/main/python/remote_run_traffic.py b/sandag_abm/src/main/python/remote_run_traffic.py new file mode 100644 index 0000000..57634e0 --- /dev/null +++ b/sandag_abm/src/main/python/remote_run_traffic.py @@ -0,0 +1,123 @@ +#////////////////////////////////////////////////////////////////////////////// +#//// /// +#//// Copyright INRO, 2016-2017. /// +#//// Rights to use and modify are granted to the /// +#//// San Diego Association of Governments and partner agencies. /// +#//// This copyright notice must be preserved. /// +#//// /// +#//// remote_run_traffic.py /// +#//// /// +#//// Runs the traffic assignment(s) for the specified periods. /// +#//// For running assignments on a remote server using PsExec, /// +#//// via batch file which configures for Emme python, starts /// +#//// or restarts the ISM and and maps T drive. /// +#//// /// +#//// The input arguments for the traffic assignment is read from /// +#//// start_*.args file in the database directory (database_dir). /// +#//// The "*" is one of the five time period abbreviations. /// +#//// /// +#//// Usage: remote_run_traffic.py database_dir /// +#//// /// +#//// database_dir: The path to the directory with the period /// +#//// specific traffic assignment data (scenarios and /// +#//// matrices). /// +#//// /// +#//// /// +#//// /// +#////////////////////////////////////////////////////////////////////////////// + + +import inro.emme.desktop.app as _app +import inro.modeller as _m +import inro.emme.database.emmebank as _emmebank +import json as _json +import traceback as _traceback +import glob as _glob +import time as _time +import sys +import os + +_join = os.path.join +_dir = os.path.dirname + + +class LogFile(object): + def __init__(self, log_path): + self._log_path = log_path + def write(self, text): + with open(self._log_path, 'a') as f: + f.write(text) + def write_timestamp(self, text): + text = "%s - %s\n" % (_time.strftime("%Y-%m-%d %H:%M:%S"), text) + self.write(text) + def write_dict(self, value): + with open(self._log_path, 'a') as f: + _json.dump(value, f, indent=4) + f.write("\n") + + +def run_assignment(modeller, database_path, period, msa_iteration, + relative_gap, max_assign_iterations, num_processors, + period_scenario, select_link, logger): + logger.write_timestamp("start for period %s" % period) + traffic_assign = modeller.tool("sandag.assignment.traffic_assignment") + export_traffic_skims = modeller.tool("sandag.export.export_traffic_skims") + with _emmebank.Emmebank(_join(database_path, 'emmebank')) as eb: + period_scenario = eb.scenario(period_scenario) + logger.write_timestamp("start traffic assignment") + traffic_assign( + period, msa_iteration, relative_gap, max_assign_iterations, + num_processors, period_scenario, select_link) + logger.write_timestamp("traffic assignment finished, start export to OMX") + output_dir = _join(_dir(_dir(database_path)), "output") + omx_file = _join(output_dir, "traffic_skims_%s.omx" % period) + logger.write_timestamp("start export to OMX %s" % omx_file) + if msa_iteration < 4: + export_traffic_skims(period, omx_file, period_scenario) + logger.write_timestamp("export to OMX finished") + logger.write_timestamp("period %s completed successfully" % period) + + +if __name__ == "__main__": + python_file, database_dir = sys.argv + file_ref = os.path.split(database_dir)[1].lower() + log_path = _join(_dir(_dir(database_dir)), "logFiles", "traffic_assign_%s.log" % file_ref) + logger = LogFile(log_path) + try: + logger.write_timestamp("remote process started") + # Test out licence by using the API + eb = _emmebank.Emmebank(_join(database_dir, 'emmebank')) + eb.close() + logger.write_timestamp("starting Emme Desktop application") + project_path = _join(_dir(database_dir), "emme_project.emp") + desktop = _app.start_dedicated(True, "abc", project_path) + try: + logger.write_timestamp("Emme Desktop open") + proc_logbook = _join("%<$ProjectPath>%", "Logbook", "project_%s_temp.mlbk" % file_ref) + desktop.project.par("ModellerLogbook").set(proc_logbook) + modeller = _m.Modeller(desktop) + + from_file = _join(database_dir, "start_*.args") + all_files = _glob.glob(from_file) + for path in all_files: + input_args_file = _join(database_dir, path) # communication file + logger.write_timestamp("input args read from %s" % input_args_file) + with open(input_args_file, 'r') as f: + assign_args = _json.load(f) + logger.write_dict(assign_args) + assign_args["logger"] = logger + assign_args["modeller"] = modeller + run_assignment(**assign_args) + finally: + desktop.close() + except Exception as error: + with open(_join(database_dir, "finish"), 'w') as f: + f.write("FATAL ERROR\n") + logger.write_timestamp("FATAL error execution stopped:") + logger.write(unicode(error) + "\n") + logger.write(_traceback.format_exc(error)) + finally: + _time.sleep(1) + with open(_join(database_dir, "finish"), 'a') as f: + f.write("finish\n") + sys.exit(0) diff --git a/sandag_abm/src/main/python/sdcvm.py b/sandag_abm/src/main/python/sdcvm.py new file mode 100644 index 0000000..aee0e26 --- /dev/null +++ b/sandag_abm/src/main/python/sdcvm.py @@ -0,0 +1,840 @@ +''' +Created on 2010-04-20 + +@author: Kevin +''' + + +# Python libraries +import copy +import csv +import math +import random +import time +from array import array +from optparse import OptionParser + + +# CSTDM libraries +import sdcvm_settings as settings + + +class excelOne(csv.excel): + # define CSV dialect for Excel to avoid blank lines from default \r\n + lineterminator = "\n" + + + + +def logitNestToLogsums(nestDict): + + #print "Evaluating logit tree structure" + # Logit tree evaluation bit + # + # What this does is start with a dictionary where each key corresponds to a node on a + # nested logit tree, including the special code "top" which is the top of the tree + # and the values for utility for each of the alternatives at the bottom of the tree. + # When the dictionary starts out, the nest nodes should have a list of connections; + # each connection is itself a list of [lower node, nest coefficient]. + # + # For instance, a classic mode choice nest would look like: + # nestDict = {'top': [ ['auto', 0.8], ['transit', 0.5], ['walk', 1.0] ] + # 'auto': [ ['sov', 1.0], ['hov', 0.75] ] + # 'transit': [ ['bus', 0.2], ['lrt', 0.2] ] + # 'hov': [ ['hov 2', 0.6], ['hov 3', 0.6] ] + # 'walk': -4.2911 + # 'sov': 1.0109 + # 'hov 2': -1.201 + # 'hov 3': -1.415 + # 'bus': -3.504 + # 'lrt': -2.879 } + # + # The loop then iterates through the keys of the dictionary (nodes). + # - If the key contains only a float (e.g. 'walk' above), this is assumed to be the + # utility or logsum, and nothing more needs to be done. + # - If the key contains any list elements (connections), the nodes they refer to will be checked; + # if the node it refers to contains only a float (e.g. the ['bus', 0.2] connection + # for the transit nest above, where 'bus' contains the float -3.504), then the nested utility + # will be multiplied by the coefficient and replace the list element. (e.g. -3.504 * 0.2 = -.7008) + # if the node it refers to contains a list (e.g. the ['hov', 0.75] connection above), nothing is done. + # - If the key contains all values as floats (not the case right now with the example above, but after + # the first run through, the 'hov' and 'transit' nodes will be in this state), then the logsum is taken + # of all of the floats, and this replaces the node value. + # + # After the first iteration, the mode choice nest would have: + # nestDict = {'top': [ ['auto', 0.8], ['transit', 0.5], -4.2911 ] + # 'auto': [ 1.0109, ['hov', 0.75] ] + # 'transit': [ -0.7008, -0.5758 ] + # 'hov': [ -0.7206, -0.849 ] + # 'walk': -4.2911 + # 'sov': 1.0109 + # 'hov 2': -1.201 + # 'hov 3': -1.415 + # 'bus': -3.504 + # 'lrt': -2.879 } + # + # After the second iteration, the mode choice nest would have: + # nestDict = {'top': [ ['auto', 0.8], ['transit', 0.5], -4.2911 ] + # 'auto': [ 1.0109, ['hov', 0.75] ] + # 'transit': 0.0568 + # 'hov': -0.0896 + # 'walk': -4.2911 + # 'sov': 1.0109 + # 'hov 2': -1.201 + # 'hov 3': -1.415 + # 'bus': -3.504 + # 'lrt': -2.879 } + # + # + # In essence, what happens is that the utilities are passed up; when all of the utilities for a node + # have been calculated, then the logsum is taken at that node. The nest coefficients are always multiplied + # so a value of 1 needs to be specified if no other value is to be used. + # + # Note that this, in the way it works, destroys the connection information, replacing it by logsums + # at the node location instead. So a copy (not a reference, which nestDict = keepDict would do) is needed + # if the connection information needs to be used again. + + x = 0 + nodeList = nestDict.keys() + + # Do this until the top node has been resolved into a float + while isinstance(nestDict["top"], list) is True: + #print 40 * "." + for node in nodeList: + #print node, nestDict[node] + if isinstance(nestDict[node], float): # if it's already only a float, it's a utility or logsum; do nothing + pass + else: + countFloat = 0 + countSub = 0 + + for sn in range(len(nestDict[node])): + if isinstance(nestDict[node][sn], float): + countFloat = countFloat + 1 + elif isinstance(nestDict[node][sn], list): + subName = nestDict[node][sn][0] + if isinstance(nestDict[subName], float): # if the value this refers to is a float + #print "... ", node, subName, nestDict[subName], nestDict[node][sn][1] + nestDict[node][sn] = nestDict[subName] * nestDict[node][sn][1] + + countSub = countSub + 1 + + #print node, countFloat, countSub + if countFloat == len(nestDict[node]): # all the values are floats; take their logsum + expsum = 0 + for element in nestDict[node]: + expsum = expsum + math.exp(element) + if expsum > 0: + nestDict[node] = math.log(expsum) + else: + nestDict[node] = -99999.9 + + if x > 250: # Prevent nesting dictionary errors + print 250 * "!" + print nestDict + raise RuntimeError("Can't resolve nesting structure!") + x = x + 1 + return nestDict + + + +#def zonalProperties(tazList=None, fileName = cvmZonalProperties): +def zonalProperties(fileName, tazList=None): + #=========================================================================== + # Returns a dictionary of zonal properties, which are anything that applies + # to a zone under all circumstances + # + # The dictionary uses the property names as keys (e.g. "PSE" or "Ag Employment") + # and each key leads to a list of properties, in the same order as the tazList + # + # Reads the zonal property file by default, but can also read in another file + # in the same format if specified. + # + # If the tazList argument is blank, reads in all TAZ and returns both the + # props dictionary and the tazList containing all zones. + # + #=========================================================================== + + print " Reading zonal property file", fileName + fin = open(fileName, "rU") + inFile = csv.reader(fin) + header = inFile.next() + + + tempTazDict = {} + tempTazList = [] + for row in inFile: + try: + taz = int(row[header.index("TAZ")]) + except ValueError: + print 120 * "#" + print "Couldn't process a zone in zonal properties file." + raise + + tempTazList.append(taz) + list = [] + for thing in row: + try: + list.append(float(thing)) + except ValueError: + list.append(thing) + tempTazDict[taz] = list + + if tazList is None: + tazList = tempTazList + returnBoth = True + else: + returnBoth = False + + propsDict = {} + for thing in header: + propsDict[thing] = [] + for zone in tazList: + for n in range(len(header)): + propsDict[header[n]].append(tempTazDict[zone][n]) + + if returnBoth == True: + return tazList, propsDict + else: + return propsDict + + + +def hdf5Skim(fromList, toList, fromZoneDict, toZoneDict, table, skimDict, skimList): + # Reads a skim matrix; the from are the rows and the to are the columns + # so skim references are skim[from][to]. + # In the application of the CVM, the from and to are the same, so the matrix is + # symmetric (in that the 15th cell in the 4th row and 4th cell in 15th row refer + # to the same two zones; one-way roads and congestion means that they won't have + # symmetrical costs) + + + # Create blank skims to hold all of the data + + for s in skimList: + skimDict[s] = [] + for c in range(len(fromList)): + for s in skimList: + row = len(toList) * [99999.9] + row = array('f', row) + skimDict[s].append(row) + + # Read in the table row by row + x = 0 + for row in table.iterrows(): + if fromZoneDict.has_key(row['origin']): + iTaz = fromZoneDict[row['origin']] + if toZoneDict.has_key(row['destination']): + jTaz = toZoneDict[row['destination']] + for s in skimList: + try: + skimDict[s][iTaz][jTaz] = row[s] + except: + print "Skim reading error!", iTaz, jTaz + + x = x + 1 + if x % 500000 == 0: + pass + print " read", x/1000000.0, "million rows." + + return skimDict + + +def csvSkim(fromList, toList, fromZoneDict, toZoneDict, skimFile, skimDict, skimName): + # Reads a skim matrix; the from are the rows and the to are the columns + # so skim references are skim[from][to]. + # In the application of the CVM, the from and to are the same, so the matrix is + # symmetric (in that the 15th cell in the 4th row and 4th cell in 15th row refer + # to the same two zones; one-way roads and congestion means that they won't have + # symmetrical costs) + # Uses TransCad GISDK output which is in "row format", i.e. each row is all destinations for a given origin. + + + # Create blank skims to hold all of the data + print skimFile + skimDict[skimName] = [] + for c in range(len(fromList)): + row = len(toList) * [99999.9] + row = array('f', row) + skimDict[skimName].append(row) + + + + # Open skim file and read header + fin = open(skimFile, "r") + inFile = csv.reader(fin) +# header = inFile.next() +# +# for i in range(len(skimList)): #Replace column names in skim list with index of same-named header +# try: +# skimList[i] = header.index(skimList[i]) +# except ValueError: +# print "Skim name", skimList[i], "nots found in skim file", skimFile +# print "Header:", header +# raise ValueError + + # Read in the table row by row + x = 0 + err = 0 + for row in inFile: + + if fromZoneDict.has_key(int(row[0])): #Orig + iTaz = fromZoneDict[int(row[0])] +# if skimName == "Time_Mid": + + while row.count("") > 0: + row[row.index("")] = "0" + err = err + 1 + floatrow = map(float, row[1:]) + skimDict[skimName][iTaz] = array("f", floatrow) + +# else: +# for jTaz in toList: +# if skimName == "Light_Mid": +# skimDict[skimName][iTaz][jTaz-1] = float(row[jTaz]) +# else: +# skimDict[skimName][iTaz][jTaz-1] = float(row[jTaz]) * -0.3 + + x = x + 1 + if x % 500 == 0: + pass + print " read", x, "rows." + print "Replaced", err, "null values." + return skimDict + + + + +def bigrun(): + ts = time.clock() + + # =============================================================================== + # Set Parser Options + # =============================================================================== + parser = OptionParser() + parser.add_option("-s", "--scale", + action="store", dest="scale", default=1.0, + help="scale factor for multiple runs") + parser.add_option("-p", "--path", + action="store", dest="path", + help="project scenario path") + (options, args) = parser.parse_args() + # =============================================================================== + # Input File Names + # =============================================================================== + cvmInputPath = options.path + "/input/" + + cvmZonalProperties = cvmInputPath + "Zonal Properties CVM.csv" + + skimPath = options.path + "/output/" + + skimFileDict = {"Light_Mid": [skimPath + "impldt_MD_DU.TXT"], + "Medium_Mid": [skimPath + "impmhdt_MD_DU.TXT"], + "Heavy_Mid": [skimPath + "imphhdt_MD_DU.TXT"], + "Time_Mid": [skimPath + "impldt_MD_Time.TXT"]} + # =============================================================================== + # Read in scale factor + # =============================================================================== +# fin = open(settings.scaleFactorSource, "r") +# for row in fin: +# if len(row) > 15: # key word has 15 chars, so don't need to look at shorter lines +# if row[0:15] == "cvm.scaleFactor": +# s = row.index("=") +# scale = float(row[s+1:]) +# scaleName = row + + scale = float(options.scale) + print 40*"-" + print "Scaling tour gen with scale factor", scale + print 40*"-" + print + + + testZones = [1578, 88, 971, 2178, 3798, 2711, 4286] + fout = open("AccessVals.csv", "w") + outFileTest = csv.writer(fout, excelOne) + outFileTest.writerow(["I", "J", "AccType", "Cost", "Attr", "AccVal"]) + + + # =============================================================================== + # Produce accessibilities and other CVM-specific derived attributes + # =============================================================================== + # Read in zonal properties file + tazList, zonals = zonalProperties(fileName=cvmZonalProperties) + tazDict = {} + #tazList = tazList[:25] + for t in range(len(tazList)): + tazDict[tazList[t]] = t + + # Calculate accessibilities + print "Calculating accessibilities", round(time.clock(), 2) + + cvmZonals = {} # This is a zonal properties style dictionary, indexed by thing and containing a list in order of properties + accDict = settings.cvmAccDict # Dictionary for creating accessibilities; [skim, property, lambda] + accList = accDict.keys() + + + skimList = [] + for accType in accList: + cvmZonals[accType] = [] + if skimList.count(accDict[accType][0]) == 0: + skimList.append(accDict[accType][0]) + cvmZonals["LnJobs30"] = [] + cvmZonals["REZone"] = [] + + # Calculate percentage employment by industry; binary over 3000 flag + sectors = ["SV", "IN", "RE", "TH", "WH", "GO"] + for sect in sectors: + cvmZonals["Pct" + sect] = [] + cvmZonals["Over3K_" + sect] = [] + for taz in tazList: + idx = tazDict[taz] + for sect in sectors: + cvmZonals["Pct" + sect].append(zonals["CVM_" + sect][idx] / (zonals["TotEmp"][idx] + 0.0001)) + if zonals["CVM_" + sect][idx] > 3000: + cvmZonals["Over3K_" + sect].append(1) + else: + cvmZonals["Over3K_" + sect].append(0) + if cvmZonals["PctRE"][idx] > 0.5: + cvmZonals["REZone"].append(1) + else: + cvmZonals["REZone"].append(0) + + # Calculate employment and population density and cap if necessary + cvmZonals["PopDensCap"] = [] + cvmZonals["EmpDensCap"] = [] + for taz in tazList: + idx = tazDict[taz] + pop = zonals["Pop"][idx] + emp = zonals["TotEmp"][idx] + area = zonals["Area_SqMi"][idx] + if area > 0: + cvmZonals["PopDensCap"].append(min(pop/area, 50000)) + cvmZonals["EmpDensCap"].append(min(emp/area, 100000)) + else: + cvmZonals["PopDensCap"].append(0) + cvmZonals["EmpDensCap"].append(0) + + + # Read in skims + + print "Reading in CVM skims. Time:", round(time.clock()-ts, 2) + skimDict = {} + + for skimName in skimFileDict.keys(): + print "...", skimName, round(time.clock()-ts, 2) + skimList.append(skimName) + skimDict = csvSkim(tazList, tazList, tazDict, tazDict, + skimFileDict[skimName][0], skimDict, skimName) + + print skimDict.keys() + print len(tazDict.keys()) + print len(tazList) + #print tazDict + + print "Skims read in. Time:", round(time.clock()-ts, 2) + idx = 0 + for iTaz in tazList: + currAcc = len(accList) * [0] + jobs30 = 0 +# maxCost = [999999, -1, -1] + for jTaz in tazList: + iIdx = tazDict[iTaz] + jIdx = tazDict[jTaz] + for accType in accList: + skimType = accDict[accType][0] + try: + cost = skimDict[skimType][iIdx][jIdx] + except: + print skimType, iTaz, jTaz, iIdx, jIdx + print len(skimDict[skimType]) + print len(skimDict[skimType][0]) + crash +# if accType == "Acc_LE" and cost < maxCost[0]: +# maxCost[0] = cost +# maxCost[1] = jTaz +# maxCost[2] = jIdx + attr = zonals[accDict[accType][1]][jIdx] + lam = accDict[accType][2] + accVal = attr * math.exp(cost * lam) + #print accType, accList + currAcc[accList.index(accType)] = currAcc[accList.index(accType)] + accVal + if testZones.count(iTaz) > 0: + outFileTest.writerow([iTaz, jTaz, accType, cost, attr, accVal]) + + + cost = skimDict["Time_Mid"][iIdx][jIdx] + if cost < 30: + jobs30 = jobs30 + zonals["TotEmp"][jIdx] + + if idx % 250000 == 0: + print "Processed", idx, "OD pairs, most recently", iTaz, jTaz, round(time.clock()-ts,2) + + idx = idx + 1 +# if idx < 2000000: +# print iTaz, iIdx, maxCost + for c in range(len(accList)): + cvmZonals[accList[c]].append(currAcc[c]) + if jobs30 > 0: + cvmZonals["LnJobs30"].append(math.log(jobs30)) + else: + cvmZonals["LnJobs30"].append(0) + + + # First set is ship/no ship, second set is tours/emp + rangeDict = {'FA': [[0.01, 0.05], [1.22, 2.09]], + 'IN': [[0.37, 0.59], [0.13, 0.52]], + 'WH': [[0.35, 0.50], [0.17, 0.47]], + 'RE': [[0.10, 0.48], [0.33, 0.65]], + 'SV': [[0.10, 0.33], [0.08, 0.33]], + 'GO': [[0.10, 0.33], [0.08, 0.33]], + 'TH': [[0.12, 0.55], [0.25, 0.55]]} + + + adjDict = {'FA': [[-3.4677, -0.9635, -0.6686, -0.3527, 0.0091],[5.0449, 1.6675, 2.3762, 2.0193, 2.0415]], + 'IN': [[-0.6544, -1.8124, -1.3965, -1.2595, 1.094], [-0.2966, 0.9763, 0.9086, 1.0257, 1.1646]], + 'RE': [[-0.456, -1.4629, -1.6433, -0.666, 1.2942], [-0.1883, 0.4861, 1.1003, 0.8668, 0.8273]], + 'SV': [[-0.6344, -0.5504, -0.2762, -0.0793, 0.0627], [0.6254, 1.8833, 2.5968, 2.3156, 2.2625]], + 'GO': [[-0.6344, -0.5504, -0.2762, -0.0793, 0.0627], [0.6254, 1.8833, 2.5968, 2.3156, 2.2625]], + 'TH': [[-1.9161, -1.623, -1.5503, -1.1891, 0.0705], [0.5195, 0.3715, 0.8332, 0.6878, 0.3449]], + 'WH': [[0.1322, -1.0171, -1.1068, -0.8744, 1.2775], [-1.3517, 0.5526, 1.1136, 0.7629, 0.794]]} + + # Scale to match proportions for SANDAG + adjSandagDict = settings.genCalibDict + + + +# cout = open("e:/sjvitm_sdcvm_calibration.csv", "w") +# calibOut = csv.writer(cout, excelOne) +# calibOut.writerow(['Sector', 'Model', 'Iteration', 'Below', 'Within', 'Above', 'Score', 'Average', 'Param', 'Tours']) + + for iter in range(1): + print 15 * "-", "Iteration", iter, 15 * "-" + + # =========================================================================== + # Big loop: iterate through each industry and create generation + # =========================================================================== + for sector in settings.cvmSectors: + print "Calculating tour generation for sector", sector, round(time.clock()-ts, 2) + # Read in control file for this sector + fin = open(cvmInputPath + sector + ".csv", "r") + inFile = csv.reader(fin) + + paramDict = {} + paramDict["ShipNoShip"] = {} + paramDict["GenPerEmployee"] = {} + paramDict["TourTOD"] ={} + paramDict["VehicleTourType"] = {} + + paramDict["TourTOD_nest"] = {} + paramDict["VehicleTourType_nest"] = {} + + for row in inFile: + model = row[0] + if paramDict.has_key(model): + alt = row[1] + type = row[2] + nest = row[3] + param = float(row[5]) + if nest == "nest": + # put into nesting dictionary + if paramDict[model+"_nest"].has_key(type): + pass + else: + paramDict[model+"_nest"][type] = [] + + if param == 0: + paramDict[model+"_nest"][type].append([alt, 1]) + else: + paramDict[model+"_nest"][type].append([alt, param]) + + else: + if paramDict[model].has_key(alt): + pass + else: + paramDict[model][alt] = [] + parSet = (type, param) + paramDict[model][alt].append(parSet) + + #print paramDict + + # add to CVM zonals file / clear out values + for timePer in settings.cvmTimes: + cvmZonals[sector + "_" + timePer] = [] + cvmZonals[sector + "_Ship"] = [] + cvmZonals[sector + "_ToursEmp"] = [] + + + # Medium loop: iterate through each TAZ + for tazNum in tazList: + taz = tazDict[tazNum] + lu = int(round(float(zonals["CVM_LU_Type"][taz])))-1 + + # =================================================================== + # Phase One: Pass logsums up nested logit structure + # =================================================================== + + # --------------------------------- Tour vehicle type / purpose nest + + model = "VehicleTourType" + #print "Processing:", model, round(time.clock(), 2) + + altList = paramDict[model].keys() + utilDict = {} + + # Begin by calculating the utilities for each alternative + for alt in altList: + util = 0 + for name, par in paramDict[model][alt]: + if name == '': + util = util + par + val = "const" + else: + if cvmZonals.has_key(name): + util = util + cvmZonals[name][taz] * par + val = cvmZonals[name][taz] + elif zonals.has_key(name): + util = util + zonals[name][taz] * par + val = zonals[name][taz] + else: + raise LookupError("Couldn't find value " + name + " in zonal properties files, for alternative " + alt) + utilDict[alt] = util +# if tazNum < 20: +# print alt, util, name, par, val +# if tazNum < 20: +# print 20 * "-" + + # Add the parameters to the nested model and pass it to the logsumerizer + modNest = "VehicleTourType_nest" + + for alt in altList: + paramDict[modNest][alt] = utilDict[alt] + + nestDict = copy.deepcopy(paramDict[modNest]) + #print taz, nestDict + vehAndPurpNest = logitNestToLogsums(nestDict) + CUPurpVeh = vehAndPurpNest["top"] + #print CUPurpVeh + + + # ------------------------------------------------------ Time Of Day + model = "TourTOD" + #print "Processing:", model, round(time.clock(), 2) + + altList = paramDict[model].keys() + utilDict = {} + + # Begin by calculating the utilities for each alternative + for alt in altList: + util = 0 + for name, par in paramDict[model][alt]: + if name == '': + util = util + par + val = "const" + else: + if cvmZonals.has_key(name): + util = util + cvmZonals[name][taz] * par + val = cvmZonals[name][taz] + elif zonals.has_key(name): + util = util + zonals[name][taz] * par + val = zonals[name][taz] + elif name == "CUPurpVeh": + util = util + CUPurpVeh * par + val = CUPurpVeh + else: + raise LookupError("Couldn't find value " + name + " in zonal properties files, for alternative " + alt) + utilDict[alt] = util + #print alt, util, name, par, val + #print 20 * "-" + + # Add the parameters to the nested model and pass it to the logsumerizer + modNest = "TourTOD_nest" + + for alt in altList: + paramDict[modNest][alt] = utilDict[alt] + + nestDict = copy.deepcopy(paramDict[modNest]) + #print nestDict + tourTODNest = logitNestToLogsums(nestDict) + CUTimeOD = tourTODNest["top"] + #print tourTODNest + #print CUTimeOD + + + # ----------------------------------------------- Trips per employee + model = "GenPerEmployee" + #print "Processing:", model, round(time.clock(), 2) + + altList = paramDict[model].keys() + utilDict = {} + # Begin by calculating the utilities for each alternative + for alt in altList: + util = 0 + for name, par in paramDict[model][alt]: + if name == '': + util = util + par + val = "const" + else: + if cvmZonals.has_key(name): + util = util + cvmZonals[name][taz] * par + val = cvmZonals[name][taz] + elif zonals.has_key(name): + util = util + zonals[name][taz] * par + val = zonals[name][taz] + elif name == "CUTimeOD": + util = util + CUTimeOD * par + val = CUTimeOD + else: + raise LookupError("Couldn't find value " + name + " in zonal properties files, for alternative " + alt) + utilDict[alt] = util + #print alt, util, name, par, val + #print 20 * "-" + + # Calibration Adjustments; form: xn, xn-1, fn, fn-1 + utilDict["Gen"] = utilDict["Gen"] + adjDict[sector][1][lu] + + genUtil = utilDict["Gen"] + CUGen = math.log(math.exp(genUtil) + math.exp(0)) # 0 is utility for no tours + + # ---------------------------------------------------- Ship / No Ship + model = "ShipNoShip" + #print "Processing:", model, round(time.clock(), 2) + + altList = paramDict[model].keys() + utilDict = {} + + # Begin by calculating the utilities for each alternative + for alt in altList: + util = 0 + for name, par in paramDict[model][alt]: + if name == '': + util = util + par + val = "const" + else: + if cvmZonals.has_key(name): + util = util + cvmZonals[name][taz] * par + val = cvmZonals[name][taz] + elif zonals.has_key(name): + util = util + zonals[name][taz] * par + val = zonals[name][taz] + elif name == "CUGen": + util = util + CUGen * par + val = CUGen + else: + raise LookupError("Couldn't find value " + name + " in zonal properties files, for alternative " + alt) + utilDict[alt] = util + #print alt, util, name, par, val + # Calibration Adjustments; form: xn, xn-1, fn, fn-1 + utilDict["Ship"] = utilDict["Ship"] + adjDict[sector][0][lu] + + + # =================================================================== + # Phase The Second: Calculate tours by time period + # =================================================================== + + # Get base employment (total employment for fleet allocators) + if sector == "FA": + baseEmp = zonals["TotEmp"][taz] + else: + baseEmp = zonals["CVM_"+sector][taz] + + #print "Base Employment:", baseEmp + + # Ship/No Ship proportions + + uShip = utilDict["Ship"] + uNoShip = utilDict["NoShip"] + + propShip = math.exp(uShip) / (math.exp(uShip) + math.exp(uNoShip)) + + shipEmp = baseEmp * propShip + +# tempOut.writerow([sector, tazList[taz], 'ShipNoShip', 'PropShip', propShip]) + cvmZonals[sector + "_Ship"].append(propShip) + #print "Shipping employees:", shipEmp, propShip + + # Generation: tours per employee + toursPerEmp = (10 * math.exp(genUtil)) / (1 + math.exp(genUtil)) + toursAllDay = shipEmp * toursPerEmp + + # Scale for SANDAG behaviours + toursAllDay = toursAllDay * adjSandagDict[sector][lu] + + + #print "Tours per employee:", toursPerEmp, toursAllDay +# tempOut.writerow([sector, tazList[taz], 'Generation', 'ToursPerEmp', toursPerEmp]) + cvmZonals[sector + "_ToursEmp"].append(toursPerEmp) + + # Time period: calculate probabilities of time period + linkDict = paramDict["TourTOD_nest"] + utilDict = tourTODNest + + #print linkDict + #print utilDict + + #print 20 * "-" + probDict = {} + + # First calculate probabilities for each node with subnodes + for node in linkDict.keys(): + if isinstance(linkDict[node], float): + pass + else: + #print node + expSum = 0 + for subNode in linkDict[node]: + expSum = expSum + math.exp(utilDict[subNode[0]] * subNode[1]) + #print subNode[0], utilDict[subNode[0]], subNode[1], expSum + + for subNode in linkDict[node]: + probDict[subNode[0]] = math.exp(utilDict[subNode[0]] * subNode[1]) / expSum + #print probDict + + # Now go down from top node and scale probabilities of any subnests by the nest prob + # (note: this only goes down one level; this works for the existing time of day nests, but needs to be changed for reuse + for node, coeff in linkDict["top"]: + if isinstance(linkDict[node], float): + pass + else: + for subNode, subcoeff in linkDict[node]: + probDict[subNode] = probDict[subNode] * probDict[node] + #print probDict + + + # Divide into time periods and write out + for timePer in settings.cvmTimes: + + try: + tours = probDict[timePer] * toursAllDay * scale + except: + print "Error in scaling tours:", probDict[timePer], toursAllDay, scale + tours = 0 + cvmZonals[sector + "_" + timePer].append(round(tours, 2)) + + +# ========================================================================== +# Output CVM Gen and Accessibility file +# ========================================================================== + print "Writing the data out...", round(time.clock(),2) + fout = open(cvmInputPath + "CVMToursAccess.csv", "w") + outFile = csv.writer(fout, excelOne) + + header = ["Taz"] + keyList = cvmZonals.keys() + keyList.sort() + header.extend(keyList) + outFile.writerow(header) + + for c in range(len(tazList)): + rowOut = [tazList[c]] + for keyType in keyList: + rowOut.append(cvmZonals[keyType][c]) + outFile.writerow(rowOut) + fout.close() + +# tout.close() +# cout.close() + print "DonE!" + +if __name__ == '__main__': + bigrun() diff --git a/sandag_abm/src/main/python/sdcvm_settings.py b/sandag_abm/src/main/python/sdcvm_settings.py new file mode 100644 index 0000000..e5c1192 --- /dev/null +++ b/sandag_abm/src/main/python/sdcvm_settings.py @@ -0,0 +1,43 @@ +# Created on 2012-10-16 +# +# @author: Kevin + + +# =============================================================================== +# SDCVM properties +# =============================================================================== +cvmModes = ["Light", "Medium", "Heavy"] +cvmTimes = ["OE", "AM", "MD", "PM", "OL"] +# cvmTimes = ["OL"] +cvmSectors = ["GO", "SV", "IN", "RE", "TH", "WH", "FA"] # sectors to run; actual industries are hardcoded into sdcvm.py +# cvmSectors = ["WH"] # sectors to run; actual industries are hardcoded into sdcvm.py + +opCostScale = 1.0 # Scale factor for operating cost + +maxTaz = 4996 # highest taz number; assumes skims are 1-maxTaz without gaps + + +# Costs defined as [time, distance, money]. Not used right now. +cvmCostDict = {"Light": [-0.313, -0.138 * opCostScale, -1], + "Medium": [-0.313, -0.492 * opCostScale, -1], + "Heavy": [-0.302, -0.580 * opCostScale, -1]} + +# Dictionary for creating accessibilities; [skim, property, lambda] +cvmAccDict = {"Acc_LE": ["Light_Mid", "TotEmp", 3.0], + "Acc_LP": ["Light_Mid", "Pop", 3.0], + "Acc_ME": ["Medium_Mid", "TotEmp", 2.0], + "Acc_MP": ["Medium_Mid", "Pop", 2.0], + "Acc_HE": ["Heavy_Mid", "TotEmp", 1.0], + "Acc_HP": ["Heavy_Mid", "Pop", 1.0] + } + +# Calibration adjustment scale factors for tour generation +# Factors by land use type: +# [Low dens, Residential, Retail/Comm, Industrial, Emp Node] +genCalibDict = {'FA': [0.4931, 1.8562, 2.3996, 1.7171, 2.4541], + 'GO': [11.8418, 4.5588, 4.1018, 5.1797, 14.1177], + 'IN': [0.6712, 0.7201, 0.7671, 0.7934, 0.2481], + 'RE': [0.6764, 1.2354, 1.7748, 1.2966, 0.1446], + 'SV': [4.1374, 2.2546, 2.6429, 3.2391, 4.2139], + 'TH': [0.7609, 0.4813, 0.4271, 1.1211, 0.5308], + 'WH': [1.2189, 0.5536, 0.5035, 0.4371, 0.2212]} diff --git a/sandag_abm/src/main/python/sdcvm_settings.pyc b/sandag_abm/src/main/python/sdcvm_settings.pyc new file mode 100644 index 0000000..83196f8 Binary files /dev/null and b/sandag_abm/src/main/python/sdcvm_settings.pyc differ diff --git a/sandag_abm/src/main/python/sdcvm_summarize.py b/sandag_abm/src/main/python/sdcvm_summarize.py new file mode 100644 index 0000000..16f802a --- /dev/null +++ b/sandag_abm/src/main/python/sdcvm_summarize.py @@ -0,0 +1,99 @@ +import csv, time +import sdcvm +# CSTDM libraries +import sdcvm_settings as settings +from optparse import OptionParser + +# External libraries +ts = time.clock() + + +class excelOne(csv.excel): + # define CSV dialect for Excel to avoid blank lines from default \r\n + lineterminator = "\n" + +# =============================================================================== +# Set Parser Options +# =============================================================================== +parser = OptionParser() +parser.add_option("-p", "--path", + action="store", dest="path", + help="project scenario path") +(options, args) = parser.parse_args() +# =============================================================================== +# Input File Names +# =============================================================================== +cvmInputPath = options.path + "/input/" +cvmZonalProperties = cvmInputPath + "Zonal Properties CVM.csv" +skimPath = options.path + "/output/" +cvmPath = options.path + "/output/" + +tazList = range(1, settings.maxTaz+1) +tazList, zonals = sdcvm.zonalProperties(fileName=cvmZonalProperties) +tazDict = {} +# tazList = tazList[:25] +for t in range(len(tazList)): + tazDict[tazList[t]] = t + +# Read in skims + +print "Reading in CVM skims. Time:", round(time.clock()-ts, 2) +skimDict = {} +skimList = [] + + +print "... Midday distance", round(time.clock()-ts, 2) +skimList.append("Dist_Mid") +skimDict = sdcvm.csvSkim(tazList, tazList, tazDict, tazDict, + skimPath + "impldt_MD_Dist.TXT", skimDict, "Dist_Mid") + + +bigDict = {} +for ind in settings.cvmSectors: + for tim in settings.cvmTimes: + print ind, tim, round(time.clock()-ts, 2) + fin = open(cvmPath + "Trip_" + ind + "_" + tim + ".csv", "r") + inFile = csv.reader(fin) + header = inFile.next() + for row in inFile: + mode = row[header.index("Mode")] + trip = int(row[header.index("Trip")]) + purp = row[header.index("TourType")] + toll = row[header.index("TripMode")] + tollAv = row[header.index("TollAvailable")] + home = int(row[header.index("HomeZone")]) + iTaz = int(row[header.index("I")]) + jTaz = int(row[header.index("J")]) + tim = row[header.index("TripTime")] + + iIdx = tazList.index(iTaz) + jIdx = tazList.index(jTaz) + newjIdx = jIdx # new index created to add 12 to include external zones 1-12 in the skim matrix + + key = (ind, mode, purp, toll, tollAv, tim, home) + if bigDict.has_key(key): + pass + else: + bigDict[key] = [0, 0, 0, 0] + + bigDict[key][1] = bigDict[key][1] + 1 + bigDict[key][2] = bigDict[key][2] + skimDict["Dist_Mid"][iIdx][newjIdx] + if trip == 1: + bigDict[key][0] = bigDict[key][0] + 1 + if iTaz == jTaz: + bigDict[key][3] = bigDict[key][3] + 1 + +fout = open(cvmPath + "Gen and trip sum.csv", "w") +outFile = csv.writer(fout, excelOne) + +keyList = bigDict.keys() +keyList.sort() +header = ["Industry", "Mode", "Purpose", "Toll", "TollAv", "Time", "TAZ", "Tours", "Trips", "Dist", "Intra"] +outFile.writerow(header) + + +for key in keyList: + outRow = list(key) + outRow.extend(bigDict[key]) + outFile.writerow(outRow) +fout.close() diff --git a/sandag_abm/src/main/python/serverswap.py b/sandag_abm/src/main/python/serverswap.py new file mode 100644 index 0000000..5da8c6d --- /dev/null +++ b/sandag_abm/src/main/python/serverswap.py @@ -0,0 +1,92 @@ +# Rick.Curry@sandag.org +# July 12, 2016 + +import os +import socket +import csv +from optparse import OptionParser + + +def swap_servers(infile, outfile, searchitem, sep_str, swap_value, skip_lines): + found = 0 + print infile, outfile + print searchitem, sep_str, swap_value + lines = [] + with open(infile) as propInFile: + for line in propInFile: + if line.find(searchitem) > -1: + if found == skip_lines: + line = line.split(sep_str, 1)[0] + sep_str + swap_value + "\n" + else: + found += 1 + lines.append(line) + with open(outfile, 'w') as propOutFile: + for line in lines: + propOutFile.write(line) + + +# Set Parser Options +parser = OptionParser() +parser.add_option("-p", "--path", + action="store", dest="path", + help="project scenario path") +(options, args) = parser.parse_args() + +# Set Paths +dst_dir_bin = options.path + "/bin/" +dst_dir_conf = options.path + "/conf/" + +# Get IP Address +ip = socket.gethostbyname(socket.gethostname()) +print str(ip) + +# Read Server Info +fileServer = options.path + "/conf/server-config-local.csv" +if not os.path.exists(fileServer): + fileServer = "T:/ABM/release/ABM/config/server-config.csv" +print fileServer +logFile = options.path + "/logFiles/serverswap.log" +if os.path.exists(logFile): + os.remove(logFile) +dictServer = csv.DictReader(open(fileServer)) + +# Check for Matching IP Address and Stop on Row +match = 'false' +for row in dictServer: + print row + if row['ActualIP'] == str(ip): + match = 'true' + print match + serverName = row['ServerName'] + print serverName + modelIP = row['ModelIP'] + break + +# Write error log if IP address not found +logWriteFile = open(logFile, "w") +if match == 'false': + logWriteFile.write('Using server-config file in: ' + fileServer + "\n") + logWriteFile.write('FATAL, Head Node not found - check for ' + str(ip)) + print 'Head Node not found' +else: + # Update Files in serverswap_files.csv + logWriteFile.write('Using server-config file in: ' + fileServer + "\n") + logWriteFile.write('MATCH, Head Node found - ' + str(ip)) + skip = 0 + fileUpdate = options.path + "/conf/serverswap_files.csv" + print fileUpdate + filesToUpdate = csv.DictReader(open(fileUpdate)) + for update in filesToUpdate: + print update + # Special section for StopABM.cmd which does not have a property=value format + if update['property'] == 'pskill': + refValue = row[update['refValue']] + ' java.exe' + print row[update['refValue']] + print refValue + swap_servers(options.path + update['fileName'], options.path + update['fileName'], + update['property'], update['separator'], refValue, skip) + skip += 1 + else: + # General section for file updates + swap_servers(options.path + update['fileName'], options.path + update['fileName'], + update['property'], update['separator'], row[update['refValue']], 0) diff --git a/sandag_abm/src/main/r/INRIX_OutlierAnalysis_Final.R b/sandag_abm/src/main/r/INRIX_OutlierAnalysis_Final.R new file mode 100644 index 0000000..6b1b3a7 --- /dev/null +++ b/sandag_abm/src/main/r/INRIX_OutlierAnalysis_Final.R @@ -0,0 +1,532 @@ +### +# OBJECTIVE: +# outlier analysis for SANDAG INRIX travel time data +# travel time and speed plots +# std dev and mean + +# INPUTS: +# inrix data - "2012_10.csv" +# inrix to tcoved correspondence (created by Fehr and Peers) - "inrix_2012hwy.txt" (also an input to regression analysis script) + +# OUTPUTS: +# travel time SD/ mean travel time in 15 mins - "inrix2012_nooutliers_traveltime.dbf" (input to regression analysis script) + +# INRIX DATA: +# october 2012 inrix data is used. +# the inrix data are in 1-mins increment and available for freeways, major/minor arterials, collectors and ramps. + +# INRIX TO MODEL NETWORK CORRESPONDENCE: +# Doubtful if ramps are in the data, perhaps correspondence to ramps isn't correct. +# fehr and peers established an initial correspondence between the model network segments and INRIX TMC segments. +# the correspondence included one record for each model link-to-inrix segments. Some model links may corresponds to multiple TMCs, +# a TMC proportion which is proportion of the TMC feature covered by the corresponding model network feature was also provided. +# The records that may not represent true correspondence, due to high frequency of link join, were flagged in the correspondence. + +# DATA PROCESSING: +# While preparing the data, the records that were flagged in the correspondence file were removed. +# Then, a TMC segment was assigned with one model link by finding the record with the highest TMC proportion. The characteristics of that model link were attached to the TMC segment. +# The analysis was restricted to weekdays. weekend’s data points were eliminated from the dataset +# plots of speeds and travel times are created +# outlier analysis using adjusted boxplot +# removed data points in period 4:15 am - 4:30 am (unexpected variation). also, removed based on reference_speed (if "reference_speed-speed>5") +# comparison of before and after outlier analysis plots +# travel time variability (standard deviation) is calculated for every 15 minutes time interval +# travel time unit = travel time per sec per mile (=travel_time_sec/seg.length) +# seg.length:=speed*travel_time_minutes/60 +# for a tmc segment (travel time sd/travel time mean) is calculated over all weekdays in 15-mins bins + +# OTHER SCRIPTS USED: +# utilfunc.R + +# by: nagendra.dhakar@rsginc.com +# for: SANDAG SHRP C04 - Tolling and Reliability +### + +library(foreign) +library (stringr) +library(xtable) +library(reshape) +library(reshape2) +library(XLConnect) +library(descr) +library(Hmisc) +library(data.table) +library(plyr) +library(gtools) +library(vioplot) +library(lattice) +library(grid) +library(timeDate) +library(ggplot2) +library(robustbase) +library(readr) + +# -------------------- 0. SOURCE FILES AND CONFIG SETTINGS ----------------------- + +# workspace and source files +setwd("E:/Projects/Clients/SANDAG/Data_2015") +source("utilfunc.R") + +# input files +inrix_2012_file = "./INRIX/2012_10/2012_10.csv" +inrix_2014_file = "./INRIX/2014_10/october_2014.csv" +inrixhwycorresp_file = "./TMC/inrix_2012hwy.txt" + +# config settings +year = "2012" # data year +interval<-15 # time bin interval in minutes +bptype<-"adjusted" # box plot - original or adjusted +field="travel.time.sec.per.mile" +ByDOW<-FALSE # by day of week - false, analysis is performed for all weekdays +OUTLIER<-TRUE # outlier analysis or confidence score (CS) removal + +# -------------------- 1. LOAD DATA ---------------------- + +# read and load inrix data +if (year=="2012"){ + # read and load 2012 data + outputsDir="./INRIX/2012_10/" + readSaveRdata(inrix_2012_file,"inrix_2012") + inrix_2012 <- assignLoad(paste0(inrix_2012_file,".Rdata")) +} else{ + # read and load 2014 data + outputsDir="./INRIX/2014_10/" + readSaveRdata(inrix_2014_file,"inrix_2014") + inrix_2014 <- assignLoad(paste0(inrix_2014_file,".Rdata")) +} + +# read and load inrix to hwy correspondence data +readSaveRdata(inrixhwycorresp_file,"inrixhwycorresp") +inrixhwycorresp <- assignLoad(paste0(inrixhwycorresp_file,".Rdata")) + +# -------------------- 2. CLEAN/PROCESS DATA -------------- + +# add a new field tmc_code without first character ('-' or '+') +inrixhwycorresp[,tmc_code:=substr(TMC,2,nchar(TMC))] + +# remove the segments that are flagged +inrixhwycorresp<-subset(inrixhwycorresp,FLAG==0) + +# get unique tmc_code with variables corresponding to maximum of TMCProp +df.orig <-inrixhwycorresp +df.agg<-aggregate(TMCProp~tmc_code,inrixhwycorresp,max) +df.max <- merge(df.agg, df.orig) + +# facility type - keep only two columns +#tmc_ifc <-df.max[,c("tmc_code","IFC","HWYCOV_ID"),] +tmc_ifc <-df.max[,c("tmc_code","TMC_Len","IFC","HWYCOV_ID","NM","LENGTH","ISPD","ABLNO","ABLNA","ABLNP","BALNO","BALNA","BALNP","ABCNT","BACNT","IHOV","ABAU","BAAU"),] +tmc_ifc$LENGTH<-as.numeric(gsub(",","",tmc_ifc$LENGTH)) +tmc_ifc$HWYCOV_ID<-as.numeric(gsub(",","",tmc_ifc$HWYCOV_ID)) + +# for plots +tmc_ifc_temp <-df.max[,c("tmc_code","IFC"),] + +# merge INRIX travel time data with hwyinrix correspondence file +inrix_2012_ifc<-merge(inrix_2012,tmc_ifc,by="tmc_code") + +# set data +alldata<-inrix_2012_ifc + +# determine Day Of Week (DOW): weekday (1) or weekend (0) +alldata[,DOW:=ifelse(isWeekday(as.Date(measurement_tstamp)),1,0)] + +# keep only weekdays +alldata<-alldata[DOW==1] + +# calculate time stamp +alldata[,date:=substr(measurement_tstamp,0,10)] +alldata[,hour:=as.numeric(substr(measurement_tstamp, 12, 13))] +alldata[,min:=as.numeric(substr(measurement_tstamp, 15, 16))] +alldata[,totalmin:=hour*60+min] +alldata[,totalhour:=hour+(min/60)] + +#travel time +alldata[,travel_time_sec:=travel_time_minutes*60] + +# determine time of day (TOD) +alldata[totalmin>=0 & totalmin<=209,tod:='EV1'] +alldata[totalmin>=210 & totalmin<=359,tod:='EA'] #1-early AM +alldata[totalmin>=360 & totalmin<=539,tod:='AM'] #2-AM peak +alldata[totalmin>=540 & totalmin<=929,tod:='MD'] #3-Midday +alldata[totalmin>=930 & totalmin<=1139,tod:='PM'] #4-PM Peak +alldata[totalmin>=1140 & totalmin<=1440,tod:='EV2'] + +# create time intervals +alldata[,todcat:=findInterval(totalmin,seq(0,1440,by=interval))] + +# --------------- 3. ANALYSIS (OUTLIER DETECTION) ------------------- + +if (OUTLIER) { + # ---------------- outlier analysis -------------------- + # create a columns "outlier" with default set to 0 + alldata[,outlier:=0] + + # find tmc segments + segmentslist<-unique(alldata$tmc_code) + + if (length(segmentslist)==0) { + stop("no tmc segments in the dataset") + } + + # create dataframes by tmc_code + alldata_bytmc<-by(alldata,alldata$tmc_code, function(x) x) + + if (length(segmentslist)>length(alldata_bytmc)) { + warning("not all tmc segments have dataframe") + } + + # identify outliers for each dataframe + lapply(alldata_bytmc, detectoutliers) + + # combine dataframes into one dataset + alldata.outliers<-do.call(rbind,alldata_bytmc) + + # calculate length (mile) + alldata.outliers[,seg.length:=speed*travel_time_minutes/60] + alldata.outliers[,travel.time.sec.per.mile:=travel_time_sec/seg.length] + + #free-up memory + #rm(alldata) + rm(inrix_2012) + gc() + + if (sum(alldata.outliers$outlier)==0) { + stop("no outliers are detected") + } + + outliers_byIFC<-c(0,0,0,0,0,0,0,0,0) + outliers_byIFC[1]<-sum(alldata.outliers[IFC==1]$outlier) + outliers_byIFC[2]<-sum(alldata.outliers[IFC==2]$outlier) + outliers_byIFC[3]<-sum(alldata.outliers[IFC==3]$outlier) + outliers_byIFC[4]<-sum(alldata.outliers[IFC==4]$outlier) + outliers_byIFC[5]<-sum(alldata.outliers[IFC==5]$outlier) + outliers_byIFC[6]<-sum(alldata.outliers[IFC==6]$outlier) + outliers_byIFC[7]<-sum(alldata.outliers[IFC==7]$outlier) + outliers_byIFC[8]<-sum(alldata.outliers[IFC==8]$outlier) + outliers_byIFC[9]<-sum(alldata.outliers[IFC==9]$outlier) + + # also remove data points in period 4:15 am - 4:30 am. also, remove based on reference_speed + alldata.nooutliers<-alldata.outliers[todcat==18 & reference_speed-speed>5,outlier:=1] + + # remove outliers + alldata.nooutliers<-alldata.outliers[outlier==0] + +} else { + # filter out data points based on confidence score + # lose about 19% of the data points + alldata.nooutliers <- alldata[alldata$confidence_score>10] + alldata.nooutliers[,seg.length:=speed*travel_time_minutes/60] + alldata.nooutliers[,travel.time.sec.per.mile:=travel_time_sec/seg.length] +} + +# free-up memory +rm(alldata_bytmc) +rm(alldata) +rm(alldata.outliers) +rm(inrix_2012_ifc) +gc() + +alldata.nooutliers$dayofweek<-dayOfWeek(as.timeDate(alldata.nooutliers$date)) + +# ---------------- 4. OUTPUT ---------------------- +if (OUTLIER){ + # write out the new dataset + write.table(alldata.nooutliers,"inrix_2012_nooutliers_15mins.txt",sep=",",row.names=F,quote=F) +} else { + # write out the new dataset - no confidence score 10 + write.table(alldata.nooutliers,"inrix_2012_noCS10_15mins.txt",sep=",",row.names=F,quote=F) +} + + +if (FALSE){ + # for test + withnooutliers_file="./inrix_2012_nooutliers.txt" + readSaveRdata(withnooutliers_file,"inrix_2012_nooutliers") + inrix_2012_nooutliers <- assignLoad(paste0(withnooutliers_file,".Rdata")) + alldata.nooutliers <- inrix_2012_nooutliers + + alldata.nooutliers[,seg.length:=speed*travel_time_minutes/60] + alldata.nooutliers[,travel.time.sec.per.mile:=travel_time_sec/seg.length] + + # for test + withoutliers_file="./inrix_2012_outliers.txt" + readSaveRdata(withoutliers_file,"inrix_2012_outliers") + inrix_2012_outliers <- assignLoad(paste0(withoutliers_file,".Rdata")) + + inrix_2012_outliers[,seg.length:=speed*travel_time_minutes/60] + inrix_2012_outliers[,travel.time.sec.per.mile:=travel_time_sec/seg.length] + + alldata.outliers=inrix_2012_outliers + alldata.nooutliers=inrix_2012_outliers[outlier==0] + +} + +# ----------------- 5. Statistics ----------------- + +# for raw data set - outliers are included (though identified) +if (FALSE){ + # calculate SD - all data points + #temp<-cast(alldata.outliers,tmc_code~todcat,sd,value=field) + temp<-dcast(alldata.outliers,tmc_code+date+todcat~field,fun.aggregate=sd) + + alldata.outliers.sd<-temp[complete.cases(temp),] # keeps only complete values - no missing values + temp=alldata.outliers.sd + temp<-merge(temp,tmc_ifc,by="tmc_code") + + #output SD file + #outfile=paste("inrix2012_outliers_",field,"_sd.txt") + #write.table(temp,outfile,sep="\t",row.names=F,quote=F) + + outfile=paste("inrix2012_outliers_",field,"_sd.dbf") + write.dbf(temp,outfile) +} + +# save data +if (OUTLIER) { + # outlier method + save(alldata.nooutliers,file = "alldatanooutliers.Rdata") +} else { + # confidence score 10 method + save(alldata.nooutliers,file = "alldatanoCS10.Rdata") +} + +# load data +if (OUTLIER) { + # outlier method + alldata.nooutliers <- assignLoad("alldatanooutliers.Rdata") +} else { + # confidence score 10 method + alldata.nooutliers <- assignLoad("alldatanoCS10.Rdata") +} + +# std. dev of all data points +if (!ByDOW){ + # std dev for all weekdays + alldata.nooutliers.sd<-cast(alldata.nooutliers,tmc_code~todcat,sd,value=field) + + # reshape the dataset + alldata.nooutliers.sd.melt<-melt(alldata.nooutliers.sd,id="tmc_code") + setnames(alldata.nooutliers.sd.melt,"value","sd") + + # field name got changed to "value" due to cast in the previous step - set back to field name + setnames(alldata.nooutliers,"value",field) +} + +if (FALSE) { + # avg speed for Wu - 05/09/2016 + alldata.nooutliers.mean<-aggregate(alldata.nooutliers$speed,by=list(alldata.nooutliers$tmc_code, alldata.nooutliers$todcat),FUN = mean, na.rm=TRUE, na.action = na.pass) + tmc_length<-aggregate(alldata.nooutliers$seg.length,by=list(alldata.nooutliers$tmc_code),FUN = mean, na.rm=TRUE, na.action = na.pass) + + setnames(alldata.nooutliers.mean,c("Group.1","Group.2","x"),c("tmc_code","todcat","avg_speed")) + setnames(tmc_length,c("Group.1","x"),c("tmc_code","avg_tmc_length")) + + alldata.nooutliers.mean.hwycov<-merge(alldata.nooutliers.mean,tmc_ifc,by="tmc_code") + alldata.nooutliers.mean.hwycov<-merge(alldata.nooutliers.mean.hwycov,tmc_length,by="tmc_code") + + alldata.nooutliers.mean.hwycov$TMC_Len<-as.numeric(gsub(",","",alldata.nooutliers.mean.hwycov$TMC_Len)) + write.table(alldata.nooutliers.mean.hwycov,"inrix_2012_avgspeed_wu.csv",sep=",",row.names=F,quote=F) + +} + +# std. dev of all datapoints of a weekday (ex. all monday, all tuesday,.., all friday) - not used +if (ByDOW) { + alldata.nooutliers.sd<-dcast(alldata.nooutliers,tmc_code+todcat~dayofweek,value.var=field,fun.aggregate=sd,na.rm=TRUE) + + if (FALSE){ + + if (field=="speed"){ + alldata.nooutliers.sd<-aggregate(alldata.nooutliers$speed,by=list(alldata.nooutliers$tmc_code,alldata.nooutliers$dayofweek,alldata.nooutliers$todcat),FUN = sd) + } else { + alldata.nooutliers.sd<-aggregate(alldata.nooutliers$travel.time.sec.per.mile,by=list(alldata.nooutliers$tmc_code,alldata.nooutliers$dayofweek,alldata.nooutliers$todcat),FUN = sd) + } + } + # reshape the dataset - not needed in aggregate method + alldata.nooutliers.sd.melt<-melt(alldata.nooutliers.sd,id=c("tmc_code","todcat")) + setnames(alldata.nooutliers.sd.melt,c("variable","value"),c("dayofweek","sd")) + +} + +#alldata.nooutliers.sd<-alldata.nooutliers.sd[complete.cases(alldata.nooutliers.sd),] + +# For Shift Variables - now they are calculated in regression analysis script +# calculate mean + +# all data points +if (!ByDOW){ + # calculate mean + alldata.nooutliers.mean<-dcast(alldata.nooutliers,tmc_code~todcat,value.var=field,fun.aggregate=mean,na.rm=TRUE) + alldata.nooutliers.mean.melt<-melt(alldata.nooutliers.mean,id="tmc_code") + setnames(alldata.nooutliers.mean.melt,c("variable","value"),c("todcat","mean")) +} + +# data points by weekday +if (ByDOW){ + alldata.nooutliers.mean<-dcast(alldata.nooutliers,tmc_code+todcat~dayofweek,value.var=field,fun.aggregate=mean,na.rm=TRUE) + alldata.nooutliers.mean.melt<-melt(alldata.nooutliers.mean,id=c("tmc_code","todcat")) + + # set column names + setnames(alldata.nooutliers.mean.melt,c("variable","value"),c("dayofweek","mean")) + +} + +# five model time periods +alldata.nooutliers.mean.melt$todcat.int <- as.integer(alldata.nooutliers.mean.melt$todcat) + +alldata.nooutliers.mean.melt$tod<-ifelse(alldata.nooutliers.mean.melt$todcat.int>0 & alldata.nooutliers.mean.melt$todcat.int<=14,'EV','') +alldata.nooutliers.mean.melt$tod<-ifelse(alldata.nooutliers.mean.melt$todcat.int>14 & alldata.nooutliers.mean.melt$todcat.int<=24,'EA',alldata.nooutliers.mean.melt$tod) +alldata.nooutliers.mean.melt$tod<-ifelse(alldata.nooutliers.mean.melt$todcat.int>24 & alldata.nooutliers.mean.melt$todcat.int<=36,'AM',alldata.nooutliers.mean.melt$tod) +alldata.nooutliers.mean.melt$tod<-ifelse(alldata.nooutliers.mean.melt$todcat.int>36 & alldata.nooutliers.mean.melt$todcat.int<=62,'MD',alldata.nooutliers.mean.melt$tod) +alldata.nooutliers.mean.melt$tod<-ifelse(alldata.nooutliers.mean.melt$todcat.int>62 & alldata.nooutliers.mean.melt$todcat.int<=76,'PM',alldata.nooutliers.mean.melt$tod) +alldata.nooutliers.mean.melt$tod<-ifelse(alldata.nooutliers.mean.melt$todcat.int>76 & alldata.nooutliers.mean.melt$todcat.int<=96,'EV',alldata.nooutliers.mean.melt$tod) + +if (FALSE) +{ + # max time by tmc_code and dayofweek + #MaxTime.AM<-do.call(rbind,lapply(split(MeanTime.AM,list(MeanTime.AM$tmc_code,MeanTime.AM$dayofweek)), function(x) x[which.max(x$mean),])) + #MaxTime.AM<-MaxTime.AM[,c("tmc_code","dayofweek","todcat")] + #setnames(MaxTime.AM,"todcat","MaxAMtod") + + MaxTime.AM<-do.call(rbind,lapply(split(MeanTime.AM,list(MeanTime.AM$tmc_code)), function(x) x[which.max(x$mean),])) + MaxTime.AM<-MaxTime.AM[,c("tmc_code","todcat.int")] + setnames(MaxTime.AM,"todcat.int","MaxAMtod") + + #MaxTime.PM<-do.call(rbind,lapply(split(MeanTime.PM,list(MeanTime.PM$tmc_code,MeanTime.PM$dayofweek)), function(x) x[which.max(x$mean),])) + #MaxTime.PM<-MaxTime.PM[,c("tmc_code","dayofweek","todcat")] + #setnames(MaxTime.PM,"todcat","MaxPMtod") + + MaxTime.PM<-do.call(rbind,lapply(split(MeanTime.PM,list(MeanTime.PM$tmc_code)), function(x) x[which.max(x$mean),])) + MaxTime.PM<-MaxTime.PM[,c("tmc_code","todcat.int")] + setnames(MaxTime.PM,"todcat.int","MaxPMtod") + + # merge + #temp<-merge(alldata.nooutliers.sd.melt,MaxTime.AM,by=c("tmc_code","dayofweek"), all.x=TRUE) + #temp1<-merge(temp,MaxTime.PM,by=c("tmc_code","dayofweek"), all.x=TRUE) + + temp<-merge(alldata.nooutliers.sd.melt,MaxTime.AM,by="tmc_code", all.x=TRUE) + temp1<-merge(temp,MaxTime.PM,by="tmc_code", all.x=TRUE) +} + +# merge sd and mean values +temp<-merge(alldata.nooutliers.sd.melt,alldata.nooutliers.mean.melt,by=c("tmc_code","todcat")) +temp$sdpermean<-temp$sd/temp$mean + +# estimation dataset +data.est <- temp +data.est <- data.est[,c("tmc_code","todcat","sd","mean","todcat.int","tod","sdpermean")] + +# save data +if (OUTLIER) { + save(data.est,file = "data.est.nooutliers.Rdata") +} else { + save(data.est,file = "data.est.noCS10.Rdata") +} + +# load data +if (OUTLIER) { + data.est <- assignLoad("data.est.nooutliers.Rdata") +} else { + data.est <- assignLoad("data.est.noCS10.Rdata") +} + +data.est<-na.omit(data.est) + +# don't merge attributes here +#data.est<-merge(data.est,tmc_ifc,by="tmc_code") + +if (OUTLIER) { + # output without outliers SD file - in DBF format + outfile="inrix2012_nooutliers_traveltime.dbf" +} else { + outfile="inrix2012_noCS10_traveltime.dbf" +} + +# write to dbf file +write.dbf(data.est,outfile) + +# output without outliers SD file - in text format +if (FALSE){ + outfile=paste("inrix2012_nooutliers_",field,"_sd.txt") + write.table(temp,outfile,sep="\t",row.names=F,quote=F) +} + +rm(alldata.nooutliers.mean) +gc() + +# ----------------- 6. Plots ----------------- + +# arrange data +alldata.outliers.sd.melt<-melt(alldata.outliers.sd,id="tmc_code") +alldata.nooutliers.sd.melt<-melt(alldata.nooutliers.sd,id="tmc_code") + +# determine time of day (TOD) + +alldata.outliers.sd.melt$tod<-ifelse(alldata.outliers.sd.melt$todcat>=0 & alldata.outliers.sd.melt$todcat<=7,'EV1','') +alldata.outliers.sd.melt$tod<-ifelse(alldata.outliers.sd.melt$todcat>=7 & alldata.outliers.sd.melt$todcat<=12,'EA',alldata.outliers.sd.melt$tod) +alldata.outliers.sd.melt$tod<-ifelse(alldata.outliers.sd.melt$todcat>=12 & alldata.outliers.sd.melt$todcat<=18,'AM',alldata.outliers.sd.melt$tod) +alldata.outliers.sd.melt$tod<-ifelse(alldata.outliers.sd.melt$todcat>=18 & alldata.outliers.sd.melt$todcat<=31,'MD',alldata.outliers.sd.melt$tod) +alldata.outliers.sd.melt$tod<-ifelse(alldata.outliers.sd.melt$todcat>=31 & alldata.outliers.sd.melt$todcat<=38,'PM',alldata.outliers.sd.melt$tod) +alldata.outliers.sd.melt$tod<-ifelse(alldata.outliers.sd.melt$todcat>=38 & alldata.outliers.sd.melt$todcat<=48,'EV2',alldata.outliers.sd.melt$tod) + +alldata.nooutliers.sd.melt$tod<-ifelse(alldata.nooutliers.sd.melt$todcat>=0 & alldata.nooutliers.sd.melt$todcat<7,'EV1','') +alldata.nooutliers.sd.melt$tod<-ifelse(alldata.nooutliers.sd.melt$todcat>=7 & alldata.nooutliers.sd.melt$todcat<12,'EA',alldata.nooutliers.sd.melt$tod) +alldata.nooutliers.sd.melt$tod<-ifelse(alldata.nooutliers.sd.melt$todcat>=12 & alldata.nooutliers.sd.melt$todcat<18,'AM',alldata.nooutliers.sd.melt$tod) +alldata.nooutliers.sd.melt$tod<-ifelse(alldata.nooutliers.sd.melt$todcat>=18 & alldata.nooutliers.sd.melt$todcat<31,'MD',alldata.nooutliers.sd.melt$tod) +alldata.nooutliers.sd.melt$tod<-ifelse(alldata.nooutliers.sd.melt$todcat>=31 & alldata.nooutliers.sd.melt$todcat<38,'PM',alldata.nooutliers.sd.melt$tod) +alldata.nooutliers.sd.melt$tod<-ifelse(alldata.nooutliers.sd.melt$todcat>=38 & alldata.nooutliers.sd.melt$todcat<=48,'EV2',alldata.nooutliers.sd.melt$tod) + +# arrange data +alldata.outliers.sd.melt<-merge(alldata.outliers.sd.melt,tmc_ifc_temp,by="tmc_code") +alldata.nooutliers.sd.melt<-merge(alldata.nooutliers.sd.melt,tmc_ifc_temp,by="tmc_code") + +# segment by facility type (IFC) +alldata.outliers.sd.melt.byifc<-by(alldata.outliers.sd.melt,alldata.outliers.sd.melt$IFC, function(x) x) +alldata.nooutliers.sd.melt.byifc<-by(alldata.nooutliers.sd.melt,alldata.nooutliers.sd.melt$IFC, function(x) x) + +# make plots +for (p in 1:length(alldata.outliers.sd.melt.byifc)) { + + plot1<-myplot_sd(alldata.outliers.sd.melt.byifc[[p]],"raw",outliers_byIFC[p],field) + plot2<-myplot_sd(alldata.nooutliers.sd.melt.byifc[[p]],"nooutliers",outliers_byIFC[p],field) + + # save as JPEG + print(multiplot(plot1,plot2),cols=1) + dev.copy(jpeg,filename=paste(outputsDir,field, "_SD_","IFC_",p,".jpeg", sep = ""),width=1280, height=1280) + dev.off() + +} + +#debug +#myplot_sd(alldata.nooutliers.sd.melt.byifc[["9"]]) + +myplot_sd(alldata.outliers.sd.melt,"SD_per_mile_outliers.jpeg") +myplot_sd(alldata.nooutliers.sd.melt,"SD_per_mile_nooutliers.jpeg") + +# ---------------- 5. PLTOS ---------------------- +if(FALSE) { + alldata.outliers.day<-alldata.outliers[date=="2012-10-01"] + + alldata.outliers.day[outlier==0, color.codes:="#000000"] #black + alldata.outliers.day[outlier==1, color.codes:="#FF0000"] #red + + alldata.outliers.day[outlier==0, color.names:="valid"] + alldata.outliers.day[outlier==1, color.names:="outlier"] + + # all freeways of a day data points + alldata.facility.type<-by(alldata.outliers.day,alldata.outliers.day$IFC, function(x) x) + + lapply(alldata.facility.type, myplot1) + + alldata.nooutliers.day<-alldata.nooutliers[date=="2012-10-01"] + + alldata.nooutliers.day[outlier==0, color.codes:="#000000"] #black + alldata.nooutliers.day[outlier==1, color.codes:="#FF0000"] #red + + alldata.nooutliers.day[outlier==0, color.names:="valid"] + alldata.nooutliers.day[outlier==1, color.names:="outlier"] + + alldata.facility.type<-by(alldata.nooutliers.day,alldata.nooutliers.day$IFC, function(x) x) + + lapply(alldata.facility.type, myplot1) +} + + diff --git a/sandag_abm/src/main/r/RegressionAnalysis_Final.R b/sandag_abm/src/main/r/RegressionAnalysis_Final.R new file mode 100644 index 0000000..830bb36 --- /dev/null +++ b/sandag_abm/src/main/r/RegressionAnalysis_Final.R @@ -0,0 +1,953 @@ +### +# OBJECTIVE: +# Regression analysis for SANDAG INRIX travel time data +# +# INPUTS: +# travel time SD/ mean travel time in 15 mins (*.dbf) - "inrix2012_nooutliers_traveltime.dbf" (output of inrix outlier analysis) +# inrix to tcoved correspondence (created by Fehr and Peers) - "inrix_2012hwy.txt" +# ABM assignment results by 5 time periods - "hwyload_EA.csv", "hwyload_AM.csv", "hwyload_MD.csv", "hwyload_PM.csv", "hwyload_EV.csv" +# Major interchange distance from SANDAG ABM output folder - "MajorInterchangeDistance.csv" +# other inputs (not used in final analysis) - "InterchangeDistance.csv", "LaneChangeDistance.csv", "FreewayRampMeters.csv" + +# DATA: +# IFC in the roadway network database is re-categorized into four facility classes +# Facility Class IFC Description +# Freeway 1 Freeways +# Arterial 2,3 Major arterials, prime arterials +# Ramp 8,9 Local ramps, freeway ramps +# Other 4,5,6,7 Collectors and local streets +# 80% for estimation (regression analysis) and 20% kept for validation +# low sample size for ramps and others - only freeway and arterial estimations are used + +# REGRESSION VARIABLES (final): +# +# Dependent Variable: +# Travel time per mile Std. Dev. per mean travel time in 15 mins time slices +# +# Independent Variables: +# Number of lanes categories (one, two, three, four, five and more) +# Level of service (LOS) +# LOSC+ = (V/C-0.69)* if (V/C>=0.70) +# LOSD+ = (V/C-0.79)* if (V/C>=0.80) +# LOSE+ = (V/C-0.89)* if (V/C>=0.90) +# LOSF_LOW = (V/C-0.99)* if (V/C>=1.00) +# LOSF_MED = (V/C-1.09)* if (V/C>=1.10) +# LOSF_HIGH = (V/C-1.19)* if (V/C>=1.20) +# Speed +# ISPD70 (1 if posted speed is 70mph, 0 otherwise) for Freeways +# Posted speed categories (ISPD<35, ISPD=35, ISPD=40, ISPD=45, ISPD=50, ISPD>50) for Arterials +# Shift variables (BeforeAM.Shift, AfterAM.Shift, BeforePM.Shift, AfterPM.Shift) +# Control type (none, signal, stop, railroad, ramp meter) +# Upstream and downstream major interchange distance - from midpoint of a freeway segment. inverse distances are used in estimation + +# IMPLEMENTATION (in SANDAG ABM): +# +# By facility type and by 5 time periods +# Estimations for freeways and arterials +# Ramp and other facility types are applied with arterial estimation +# Two reliability components +# LOS +# Static (speed, distance to/from interchanges, intersection type etc.) +# Sum of the two reliability components is multiplied by mean travel time and link length +# Variable calculations are automated including distance to/from interchanges +# Reliability fields are added to highway network +# LOS: include only coefficients +# Static: sum of remaining (un)reliability including the intercept +# Skimming: +# Standard deviation is not additive but variance is +# A link (un)reliability = (MSA Cost – MSA Time) +# Skimmed variance (square of link (un)reliability) +# Final skims are square root of the skimmed value + +# OTHER SCRIPTS USED: +# utilfunc.R + +# by: nagendra.dhakar@rsginc.com +# for: SANDAG SHRP C04 - Tolling and Reliability +#---------------------------------------------------- + +library(foreign) +library(stringr) +library(xtable) +library(reshape) +library(XLConnect) +library(descr) +library(Hmisc) +library(data.table) +library(plyr) +library(gtools) +library(vioplot) +library(lattice) +library(grid) +library(timeDate) +library(ggplot2) +library(robustbase) +library(readr) + +# -------------------- 0. SOURCE FILES AND CONFIG SETTINGS ----------------------- + +# workspace and source files +setwd("E:/Projects/Clients/SANDAG") +source("./Data_2015/utilfunc.R") + +# method of outlier removal - outlier analysis (this is used) or confidence interval 10 +OUTLIER=TRUE + +# input files +inrixhwycorresp.file = "./Data_2015/TMC/inrix_2012hwy.txt" +AssignResultsEA.file = "./SandagReliability/ModelData/OldApp_OldPopSyn/AssignmentResults/hwyload_EA.csv" +AssignResultsAM.file = "./SandagReliability/ModelData/OldApp_OldPopSyn/AssignmentResults/hwyload_AM.csv" +AssignResultsMD.file = "./SandagReliability/ModelData/OldApp_OldPopSyn/AssignmentResults/hwyload_MD.csv" +AssignResultsPM.file = "./SandagReliability/ModelData/OldApp_OldPopSyn/AssignmentResults/hwyload_PM.csv" +AssignResultsEV.file = "./SandagReliability/ModelData/OldApp_OldPopSyn/AssignmentResults/hwyload_EV.csv" +InterchangeDistance.file = "./Data_2015/InterchangeDistance.csv" +InterchangeDistanceHOV.file = "./Data_2015/InterchangeDistance_HOV.csv" +MajorInterchangeDistance.file = "./Data_2015/MajorInterchangeDistance.csv" +LaneChangeDistance.file = "./Data_2015/LaneChangeDistance.csv" +FreewayRampMeters.file = "./Data_2015/FreewayRampMeters.csv" + +# travel time SD input file +if (OUTLIER) { + StdDev.file = "./Data_2015/inrix2012_nooutliers_traveltime.dbf" +} else { + StdDev.file = "./Data_2015/inrix2012_noCS10_traveltime.dbf" +} + +# outputs directory +outputsDir="./Data_2015/Results" + +# -------------------- 1. LOAD DATA ---------------------- +# load SD file, assignment results, interchange distance etc. +StdDev<- read.dbf(StdDev.file) +AssignResultsEA <- read.csv(AssignResultsEA.file) +AssignResultsAM <- read.csv(AssignResultsAM.file) +AssignResultsMD <- read.csv(AssignResultsMD.file) +AssignResultsPM <- read.csv(AssignResultsPM.file) +AssignResultsEV <- read.csv(AssignResultsEV.file) +InterchangeDistance <- read.csv(InterchangeDistance.file) +InterchangeDistanceHOV <- read.csv(InterchangeDistanceHOV.file) +MajorInterchangeDistance <- read.csv(MajorInterchangeDistance.file) +LaneChangeDistance <- read.csv(LaneChangeDistance.file) # LinkID,Length,LaneIncrease,LaneDrop,DeadEnd,RegionEnd,DownstreamDistance,ihov,BaseThruLanes,DownThruLanes,DownLinks,QueryDown +FreewayRampMeters <- read.csv(FreewayRampMeters.file) # LinkID,Length,IsRampMeter,QueryNode + +# -------------------- 2. SET UP DATA -------------- + +# read and load inrix to hwy correspondence data +readSaveRdata(inrixhwycorresp.file,"inrixhwycorresp") +inrixhwycorresp <- assignLoad(paste0(inrixhwycorresp.file,".Rdata")) + +# add a new field tmc_code without first character ('-' or '+') +inrixhwycorresp[,tmc_code:=substr(TMC,2,nchar(TMC))] + +# remove the segments that are flagged +inrixhwycorresp<-subset(inrixhwycorresp,FLAG==0) + +# get unique tmc_code with variables corresponding to maximum of TMCProp +df.orig <-inrixhwycorresp +df.agg<-aggregate(TMCProp~tmc_code,inrixhwycorresp,max) +df.max <- merge(df.agg, df.orig) + +# Note: there could be cases where one hwcov_id is associated with multiple tmc_code + +# facility type - different capacity fields for mid-link capacity (period fields) +tmc_ifc <-df.max[,c("tmc_code","IFC","HWYCOV_ID","NM","LENGTH","ISPD","ABLNO","ABLNA","ABLNP", + "BALNO","BALNA","BALNP","ABCPO","ABCPA","ABCPP","BACPO","BACPA","BACPP", + "ABCXO","ABCXA","ABCXP","BACXO","BACXA","BACXP","ABCNT","BACNT", + "ABTL","ABRL","ABLL","BATL","BARL","BALL","ABGC","BAGC","IHOV","ABAU","BAAU"),] + +tmc_ifc$LENGTH<-as.numeric(gsub(",","",tmc_ifc$LENGTH)) +tmc_ifc$HWYCOV_ID<-as.numeric(gsub(",","",tmc_ifc$HWYCOV_ID)) + +# merge attributes to INRIX data +StdDev<-merge(StdDev,tmc_ifc,by="tmc_code") + +# ---------------------------------------------------- + +# write to file +if (FALSE) { + write.table(tmc_ifc,"./Data_2015/tmc_hwycov_atrributes.csv",sep=",",row.names=F,quote=F) +} + +# ID1 in the results is the same as HWYCOV_ID in the link file +AssignResultsEA <- AssignResultsEA[,c("ID1","AB_Time","BA_Time","AB_Flow","BA_Flow","AB_Speed","BA_Speed")] +AssignResultsAM <- AssignResultsAM[,c("ID1","AB_Time","BA_Time","AB_Flow","BA_Flow","AB_Speed","BA_Speed")] +AssignResultsMD <- AssignResultsMD[,c("ID1","AB_Time","BA_Time","AB_Flow","BA_Flow","AB_Speed","BA_Speed")] +AssignResultsPM <- AssignResultsPM[,c("ID1","AB_Time","BA_Time","AB_Flow","BA_Flow","AB_Speed","BA_Speed")] +AssignResultsEV <- AssignResultsEV[,c("ID1","AB_Time","BA_Time","AB_Flow","BA_Flow","AB_Speed","BA_Speed")] + +# use 80% for estimation and 20% for validation - sample segments by facility type + +# create new facility type - freeways, arterials, ramps, and others +StdDev$IFC_Est <- ifelse(StdDev$IFC==1,1,0) # freeways +StdDev$IFC_Est <- ifelse(StdDev$IFC==2 | StdDev$IFC==3,2,StdDev$IFC_Est) # arterials - major and prime +StdDev$IFC_Est <- ifelse(StdDev$IFC==8 | StdDev$IFC==9,3,StdDev$IFC_Est) # ramps - local ramps and freeways ramps +StdDev$IFC_Est <- ifelse(StdDev$IFC>=4 & StdDev$IFC<=7,4,StdDev$IFC_Est) # others - collectors and local streets + +Sample.Rate<-0.8 + +# Freeways +StdDev.Freeways <- subset(StdDev, IFC_Est==1) +StdDev.Freeways.Seg <- unique(StdDev.Freeways$tmc_code) +StdDev.Freeways.Seg<-as.data.frame(StdDev.Freeways.Seg) + +sample_size <- floor(Sample.Rate *nrow(StdDev.Freeways.Seg)) +set.seed(123) +Est.Ind <- sample(seq_len(nrow(StdDev.Freeways.Seg)), size = sample_size) +StdDev.Freeways.Seg.Est <- StdDev.Freeways.Seg[Est.Ind,] +StdDev.Freeways.Seg.Val <- StdDev.Freeways.Seg[-Est.Ind,] + +# Arterials +StdDev.Arterials <- subset(StdDev, IFC_Est==2) +StdDev.Arterials.Seg <- unique(StdDev.Arterials$tmc_code) +StdDev.Arterials.Seg<-as.data.frame(StdDev.Arterials.Seg) + +sample_size <- floor(Sample.Rate *nrow(StdDev.Arterials.Seg)) +set.seed(123) +Est.Ind <- sample(seq_len(nrow(StdDev.Arterials.Seg)), size = sample_size) +StdDev.Arterials.Seg.Est <- StdDev.Arterials.Seg[Est.Ind,] +StdDev.Arterials.Seg.Val <- StdDev.Arterials.Seg[-Est.Ind,] + +# Ramps +StdDev.Ramps <- subset(StdDev, IFC_Est==3) +StdDev.Ramps.Seg <- unique(StdDev.Ramps$tmc_code) +StdDev.Ramps.Seg<-as.data.frame(StdDev.Ramps.Seg) + +sample_size <- floor(Sample.Rate *nrow(StdDev.Ramps.Seg)) +set.seed(123) +Est.Ind <- sample(seq_len(nrow(StdDev.Ramps.Seg)), size = sample_size) +StdDev.Ramps.Seg.Est <- StdDev.Ramps.Seg[Est.Ind,] +StdDev.Ramps.Seg.Val <- StdDev.Ramps.Seg[-Est.Ind,] + +# Others +StdDev.Others <- subset(StdDev, IFC_Est==4) +StdDev.Others.Seg <- unique(StdDev.Others$tmc_code) +StdDev.Others.Seg<-as.data.frame(StdDev.Others.Seg) + +sample_size <- floor(Sample.Rate *nrow(StdDev.Others.Seg)) +set.seed(123) +Est.Ind <- sample(seq_len(nrow(StdDev.Others.Seg)), size = sample_size) +StdDev.Others.Seg.Est <- StdDev.Others.Seg[Est.Ind,] +StdDev.Others.Seg.Val <- StdDev.Others.Seg[-Est.Ind,] + +# ------------------ Estimation Dataset -------------------------------------- + +StdDev.Freeways.Seg.Est<-as.data.frame(StdDev.Freeways.Seg.Est) +StdDev.Arterials.Seg.Est<-as.data.frame(StdDev.Arterials.Seg.Est) +StdDev.Ramps.Seg.Est<-as.data.frame(StdDev.Ramps.Seg.Est) +StdDev.Others.Seg.Est<-as.data.frame(StdDev.Others.Seg.Est) + +setnames(StdDev.Freeways.Seg.Est,"StdDev.Freeways.Seg.Est","tmc_code") +setnames(StdDev.Arterials.Seg.Est,"StdDev.Arterials.Seg.Est","tmc_code") +setnames(StdDev.Ramps.Seg.Est,"StdDev.Ramps.Seg.Est","tmc_code") +setnames(StdDev.Others.Seg.Est,"StdDev.Others.Seg.Est","tmc_code") + +# combine dataframes into one +StdDev.Seg.Est <- do.call(rbind,list(StdDev.Freeways.Seg.Est,StdDev.Arterials.Seg.Est,StdDev.Ramps.Seg.Est,StdDev.Others.Seg.Est)) + +# merge data +StdDev.Est<-merge(StdDev,StdDev.Seg.Est,by="tmc_code") + +# ---------------------------- Validation Dataset ------------------------------ + +StdDev.Freeways.Seg.Val<-as.data.frame(StdDev.Freeways.Seg.Val) +StdDev.Arterials.Seg.Val<-as.data.frame(StdDev.Arterials.Seg.Val) +StdDev.Ramps.Seg.Val<-as.data.frame(StdDev.Ramps.Seg.Val) +StdDev.Others.Seg.Val<-as.data.frame(StdDev.Others.Seg.Val) + +setnames(StdDev.Freeways.Seg.Val,"StdDev.Freeways.Seg.Val","tmc_code") +setnames(StdDev.Arterials.Seg.Val,"StdDev.Arterials.Seg.Val","tmc_code") +setnames(StdDev.Ramps.Seg.Val,"StdDev.Ramps.Seg.Val","tmc_code") +setnames(StdDev.Others.Seg.Val,"StdDev.Others.Seg.Val","tmc_code") + +# combine dataframes into one +StdDev.Seg.Val <- do.call(rbind,list(StdDev.Freeways.Seg.Val,StdDev.Arterials.Seg.Val,StdDev.Ramps.Seg.Val,StdDev.Others.Seg.Val)) + +# merge data +StdDev.Val<-merge(StdDev,StdDev.Seg.Val,by="tmc_code") + +# ------------------- Add Interchange Distance ----------------------- +if (FALSE) { + # Interchange distance + InterchangeDistance <-InterchangeDistance[,c("LinkID","upstream.distance","downstream.distance")] + InterchangeDistanceHOV <-InterchangeDistanceHOV[,c("LinkID","Length","upstream.distance","downstream.distance")] + + temp<-merge(InterchangeDistance,InterchangeDistanceHOV,by="LinkID",all.x = TRUE) + temp$upstream.distance <- ifelse(!is.na(temp$Length),temp$upstream.distance.y,temp$upstream.distance.x) + temp$downstream.distance<-ifelse(!is.na(temp$Length),temp$downstream.distance.y,temp$downstream.distance.x) + + InterchangeDistance<-temp + InterchangeDistance <-InterchangeDistance[,c("LinkID","upstream.distance","downstream.distance")] + + temp<-merge(StdDev.Est,InterchangeDistance,by.x ="HWYCOV_ID",by.y = "LinkID",all.x=TRUE) + + StdDev.Est<-temp +} + +# Major Interchange distance +MajorInterchangeDistance <-MajorInterchangeDistance[,c("LinkID","upstream.distance","downstream.distance")] + +temp<-merge(MajorInterchangeDistance,InterchangeDistanceHOV,by="LinkID",all.x = TRUE) +temp$majorupstream.distance <- ifelse(!is.na(temp$Length),temp$upstream.distance.y,temp$upstream.distance.x) +temp$majordownstream.distance<-ifelse(!is.na(temp$Length),temp$downstream.distance.y,temp$downstream.distance.x) + +MajorInterchangeDistance<-temp +MajorInterchangeDistance <-MajorInterchangeDistance[,c("LinkID","majorupstream.distance","majordownstream.distance")] + +temp<-merge(StdDev.Est,MajorInterchangeDistance,by.x ="HWYCOV_ID",by.y = "LinkID",all.x=TRUE) + +StdDev.Est<-temp + +# FF Time (seconds) +StdDev.Est$FF_Time <- as.numeric(StdDev.Est$LENGTH)*(1/5280)*(1/StdDev.Est$ISPD)*60 +#test <- subset(StdDev.Est, is.na(StdDev.Est$FF_Time)) # just to see if there are any NA values + +# model tod +StdDev.Est$tod.model<-ifelse(StdDev.Est$todcat>0 & StdDev.Est$todcat<=14,'EV','') #3.5 hours +StdDev.Est$tod.model<-ifelse(StdDev.Est$todcat>14 & StdDev.Est$todcat<=24,'EA',StdDev.Est$tod.model) #2.5 hours +StdDev.Est$tod.model<-ifelse(StdDev.Est$todcat>24 & StdDev.Est$todcat<=36,'AM',StdDev.Est$tod.model) #3 hours +StdDev.Est$tod.model<-ifelse(StdDev.Est$todcat>36 & StdDev.Est$todcat<=62,'MD',StdDev.Est$tod.model) #6.5 hours +StdDev.Est$tod.model<-ifelse(StdDev.Est$todcat>62 & StdDev.Est$todcat<=76,'PM',StdDev.Est$tod.model) #3.5 hours +StdDev.Est$tod.model<-ifelse(StdDev.Est$todcat>76 & StdDev.Est$todcat<=96,'EV',StdDev.Est$tod.model) #5 hours + +# convert to integer - mid link (*CPO, *CPA, *CPP) and intersection (*CXO, *CXA, *CXP) capacities +StdDev.Est$ABCPO<-as.integer(gsub(",","",StdDev.Est$ABCPO)) +StdDev.Est$ABCPA<-as.integer(gsub(",","",StdDev.Est$ABCPA)) +StdDev.Est$ABCPP<-as.integer(gsub(",","",StdDev.Est$ABCPP)) +StdDev.Est$BACPO<-as.integer(gsub(",","",StdDev.Est$BACPO)) +StdDev.Est$BACPA<-as.integer(gsub(",","",StdDev.Est$BACPA)) +StdDev.Est$BACPP<-as.integer(gsub(",","",StdDev.Est$BACPP)) +StdDev.Est$ABCXO<-as.integer(gsub(",","",StdDev.Est$ABCXO)) +StdDev.Est$ABCXA<-as.integer(gsub(",","",StdDev.Est$ABCXA)) +StdDev.Est$ABCXP<-as.integer(gsub(",","",StdDev.Est$ABCXP)) +StdDev.Est$BACXO<-as.integer(gsub(",","",StdDev.Est$BACXO)) +StdDev.Est$BACXA<-as.integer(gsub(",","",StdDev.Est$BACXA)) +StdDev.Est$BACXP<-as.integer(gsub(",","",StdDev.Est$BACXP)) + +# set initial values to 0 +StdDev.Est$NumLanes <-0 +StdDev.Est$ICNT <-0 # intersection control +StdDev.Est$Flow <-0 +StdDev.Est$CAP.MidLink <-0 # mid-link capacity for freeways and ramps +StdDev.Est$CAP.IntAppr <-0 # intersection-approach capacity for arterials and others +StdDev.Est$AuxLanes <-0 +StdDev.Est$ThruLanes <-0 +StdDev.Est$LeftLanes <-0 +StdDev.Est$RightLanes <-0 +StdDev.Est$GCRatio <-0 +Default.Cap<-9999999 # set a very high + +# TMC Codes +# External (between interchanges): '+' (NB or WB - positive direction), '-' (SB or EB - negative direction) +# Internal (within interchanges): 'P' (NB or WB), 'N' (SB or EB) + +# -------------------------------- ESTIMATION --------------------------------- +# This section estimates regression equations using estimation dataset (StdDev.Est) + +# the below is how SANDAG ABM (gisdk) converts capacities from three periods to 5 model periods: +# set capacity fields +# tod_fld ={{"ABCP_EA"},{"ABCP_AM"},{"ABCP_MD"},{"ABCP_PM"},{"ABCP_EV"}, //BA link capacity +# {"BACP_EA"},{"BACP_AM"},{"BACP_MD"},{"BACP_PM"},{"BACP_EV"}, //AB link capacity +# {"ABCX_EA"},{"ABCX_AM"},{"ABCX_MD"},{"ABCX_PM"},{"ABCX_EV"}, //BA intersection capacity +# {"BACX_EA"},{"BACX_AM"},{"BACX_MD"},{"BACX_PM"},{"BACX_EV"}} //AB intersection capacity + +# org_fld ={"ABCPO","ABCPA","ABCPO","ABCPP","ABCPO", +# "BACPO","BACPA","BACPO","BACPP","BACPO", +# "ABCXO","ABCXA","ABCXO","ABCXP","ABCXO", +# "BACXO","BACXA","BACXO","BACXP","BACXO"} + +# factor ={"3/12","1","6.5/12","3.5/3","8/12", +# "3/12","1","6.5/12","3.5/3","8/12", +# "3/12","1","6.5/12","3.5/3","8/12", +# "3/12","1","6.5/12","3.5/3","8/12"} +# +# the capacity calculations below are consistent with the ABM gisdk + +# MERGE assignment results to the estimation data + +setnames(StdDev.Est,"HWYCOV_ID","ID1") +nrow(StdDev.Est) + +# EA Period +temp2 <- merge(StdDev.Est,AssignResultsEA,by="ID1", all.x=TRUE) +temp2$Flow <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BA_Flow,temp2$AB_Flow),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$AB_Flow,temp2$BA_Flow)),temp2$Flow) +temp2$CAP.MidLink <- (ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACPO*3/12,temp2$ABCPO*3/12),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCPO*3/12,temp2$BACPO*3/12)),temp2$CAP.MidLink)) +temp2$CAP.IntAppr <- (ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXO*3/12,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXO*3/12,Default.Cap)),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXO*3/12,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXO*3/12,Default.Cap))),temp2$CAP.IntAppr)) +temp2$NumLanes <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALNO,temp2$ABLNO),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLNO,temp2$BALNO)),temp2$NumLanes) +temp2$ICNT <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACNT,temp2$ABCNT),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCNT,temp2$BACNT)),temp2$ICNT) +temp2$AuxLanes <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAAU,temp2$ABAU),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABAU,temp2$BAAU)),temp2$AuxLanes) +temp2$ThruLanes <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BATL,temp2$ABTL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABTL,temp2$BATL)),temp2$ThruLanes) +temp2$LeftLanes <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALL,temp2$ABLL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLL,temp2$BALL)),temp2$LeftLanes) +temp2$RightLanes <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BARL,temp2$ABRL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABRL,temp2$BARL)),temp2$RightLanes) +temp2$GCRatio <- ifelse(temp2$tod.model=='EA', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAGC,temp2$ABGC),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABGC,temp2$BAGC)),temp2$GCRatio) + +temp2<-temp2[,-c(61:66)] +nrow(temp2) + +# AM Period +temp2 <- merge(temp2,AssignResultsAM,by="ID1", all.x=TRUE) +temp2$Flow <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BA_Flow,temp2$AB_Flow),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$AB_Flow,temp2$BA_Flow)),temp2$Flow) +temp2$CAP.MidLink <- (ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACPA,temp2$ABCPA),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCPA,temp2$BACPA)),temp2$CAP.MidLink)) # AM capacity is for 3 hours +temp2$CAP.IntAppr <- (ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXA,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXA,Default.Cap)),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXA,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXA,Default.Cap))),temp2$CAP.IntAppr)) +temp2$NumLanes <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALNA,temp2$ABLNA),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLNA,temp2$BALNA)),temp2$NumLanes) +temp2$ICNT <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACNT,temp2$ABCNT),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCNT,temp2$BACNT)),temp2$ICNT) +temp2$AuxLanes <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAAU,temp2$ABAU),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABAU,temp2$BAAU)),temp2$AuxLanes) +temp2$ThruLanes <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BATL,temp2$ABTL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABTL,temp2$BATL)),temp2$ThruLanes) +temp2$LeftLanes <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALL,temp2$ABLL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLL,temp2$BALL)),temp2$LeftLanes) +temp2$RightLanes <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BARL,temp2$ABRL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABRL,temp2$BARL)),temp2$RightLanes) +temp2$GCRatio <- ifelse(temp2$tod.model=='AM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAGC,temp2$ABGC),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABGC,temp2$BAGC)),temp2$GCRatio) + +temp2<-temp2[,-c(61:66)] +nrow(temp2) + +# MD Period +temp2 <- merge(temp2,AssignResultsMD,by="ID1", all.x=TRUE) +temp2$Flow <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BA_Flow,temp2$AB_Flow),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$AB_Flow,temp2$BA_Flow)),temp2$Flow) # the flow is for 9 am - 3:30 pm +temp2$CAP.MidLink <- (ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACPO*6.5/12,temp2$ABCPO*6.5/12),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCPO*6.5/12,temp2$BACPO*6.5/12)),temp2$CAP.MidLink)) +temp2$CAP.IntAppr <- (ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXO*6.5/12,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXO*6.5/12,Default.Cap)),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXO*6.5/12,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXO*6.5/12,Default.Cap))),temp2$CAP.IntAppr)) +temp2$NumLanes <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALNO,temp2$ABLNO),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLNO,temp2$BALNO)),temp2$NumLanes) +temp2$ICNT <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACNT,temp2$ABCNT),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCNT,temp2$BACNT)),temp2$ICNT) +temp2$AuxLanes <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAAU,temp2$ABAU),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABAU,temp2$BAAU)),temp2$AuxLanes) +temp2$ThruLanes <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BATL,temp2$ABTL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABTL,temp2$BATL)),temp2$ThruLanes) +temp2$LeftLanes <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALL,temp2$ABLL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLL,temp2$BALL)),temp2$LeftLanes) +temp2$RightLanes <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BARL,temp2$ABRL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABRL,temp2$BARL)),temp2$RightLanes) +temp2$GCRatio <- ifelse(temp2$tod.model=='MD', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAGC,temp2$ABGC),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABGC,temp2$BAGC)),temp2$GCRatio) + +temp2<-temp2[,-c(61:66)] +nrow(temp2) + +# PM Period +temp2 <- merge(temp2,AssignResultsPM,by="ID1", all.x=TRUE) +temp2$Flow <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BA_Flow,temp2$AB_Flow),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$AB_Flow,temp2$BA_Flow)),temp2$Flow) # flow is from 3:30 pm to 7 pm +temp2$CAP.MidLink <- (ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACPP*3.5/3,temp2$ABCPP*3.5/3),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCPP*3.5/3,temp2$BACPP*3.5/3)),temp2$CAP.MidLink)) # PM capacity is for 3 hours +temp2$CAP.IntAppr <- (ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXP*3.5/3,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXP*3.5/3,Default.Cap)),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXP*3.5/3,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXP*3.5/3,Default.Cap))),temp2$CAP.IntAppr)) +temp2$NumLanes <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALNP,temp2$ABLNP),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLNP,temp2$BALNP)),temp2$NumLanes) +temp2$ICNT <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACNT,temp2$ABCNT),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCNT,temp2$BACNT)),temp2$ICNT) +temp2$AuxLanes <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAAU,temp2$ABAU),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABAU,temp2$BAAU)),temp2$AuxLanes) +temp2$ThruLanes <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BATL,temp2$ABTL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABTL,temp2$BATL)),temp2$ThruLanes) +temp2$LeftLanes <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALL,temp2$ABLL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLL,temp2$BALL)),temp2$LeftLanes) +temp2$RightLanes <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BARL,temp2$ABRL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABRL,temp2$BARL)),temp2$RightLanes) +temp2$GCRatio <- ifelse(temp2$tod.model=='PM', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAGC,temp2$ABGC),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABGC,temp2$BAGC)),temp2$GCRatio) + +temp2<-temp2[,-c(61:66)] +nrow(temp2) + +# EV Period +temp2 <- merge(temp2,AssignResultsPM,by="ID1", all.x=TRUE) +temp2$Flow <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BA_Flow,temp2$AB_Flow),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$AB_Flow,temp2$BA_Flow)),temp2$Flow) # flow is from 7 pm to 3:30 am +temp2$CAP.MidLink <- (ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code), ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACPO*8/12,temp2$ABCPO*8/12),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCPO*8/12,temp2$BACPO*8/12)),temp2$CAP.MidLink)) # OP capacity is for 18 hours +temp2$CAP.IntAppr <- (ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXO*8/12,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXO*8/12,Default.Cap)),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,ifelse(temp2$BACNT==1,temp2$BACXO*8/12,Default.Cap),ifelse(temp2$ABCNT==1,temp2$ABCXO*8/12,Default.Cap))),temp2$CAP.IntAppr)) +temp2$NumLanes <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALNO,temp2$ABLNO),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLNO,temp2$BALNO)),temp2$NumLanes) +temp2$ICNT <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BACNT,temp2$ABCNT),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABCNT,temp2$BACNT)),temp2$ICNT) +temp2$AuxLanes <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAAU,temp2$ABAU),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABAU,temp2$BAAU)),temp2$AuxLanes) +temp2$ThruLanes <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BATL,temp2$ABTL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABTL,temp2$BATL)),temp2$ThruLanes) +temp2$LeftLanes <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BALL,temp2$ABLL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABLL,temp2$BALL)),temp2$LeftLanes) +temp2$RightLanes <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BARL,temp2$ABRL),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABRL,temp2$BARL)),temp2$RightLanes) +temp2$GCRatio <- ifelse(temp2$tod.model=='EV', ifelse(grepl("\\+",temp2$tmc_code) | grepl("P",temp2$tmc_code),ifelse(is.na(temp2$AB_Flow) | temp2$AB_Flow==0,temp2$BAGC,temp2$ABGC),ifelse(is.na(temp2$BA_Flow) | temp2$BA_Flow==0,temp2$ABGC,temp2$BAGC)),temp2$GCRatio) + +temp2<-temp2[,-c(61:66)] + +nrow(temp2) + +# intersection approach capacity, when not available set to 0 +#temp2$CAP.IntAppr<-ifelse(temp2$CAP.IntAppr==9999999,0,temp2$CAP.IntAppr) +temp2$CAP.IntAppr<-ifelse(temp2$CAP.IntAppr==9999999,temp2$CAP.MidLink,temp2$CAP.IntAppr) + +# values of greater and equal to 7 are for non-availability for some reasons, set them to 0 +temp2$ThruLanes <-ifelse(temp2$ThruLanes>=7,0,temp2$ThruLanes) +temp2$LeftLanes <-ifelse(temp2$LeftLanes>=7,0,temp2$LeftLanes) +temp2$RightLanes <-ifelse(temp2$RightLanes>=7,0,temp2$RightLanes) + +# recalculate GC ratio as per createhwynet.rsc (line 1045) +temp2$GCRatio<-ifelse(temp2$GCRatio>10,temp2$GCRatio/100,temp2$GCRatio) +temp2$GCRatio<-ifelse(temp2$GCRatio>1,1,temp2$GCRatio) + +# ----------------------- Create Variables for Regression Models ----------------------------- +EstDataSet<-temp2 + +# NOTE: Link ID (HWYCOV_ID)=29412 29413 31194 31202,40479 are not in the model network. So remove those for now +EstDataSet<-subset(EstDataSet, !is.na(EstDataSet$Flow)) + +# Capacity by facility type (12/07/2015) +# freeways and ramps - mid link capacity +# arterials and others - intersection approach +#EstDataSet$CAP<-ifelse(EstDataSet$IFC_Est==1 | EstDataSet$IFC_Est==3, EstDataSet$CAP.MidLink, EstDataSet$CAP.IntAppr) + +EstDataSet$CAP<-EstDataSet$CAP.MidLink # mid link capacity for all +EstDataSet$VOC <- EstDataSet$Flow/EstDataSet$CAP + +# control type - 0-none, 1-signal, 2-stop, 3-railroad +EstDataSet$ICNT.Est <-ifelse(EstDataSet$ICNT==1,"Signal","None") # signal +EstDataSet$ICNT.Est <-ifelse(EstDataSet$ICNT==2 | EstDataSet$ICNT==3,"Stop",EstDataSet$ICNT.Est) # all-way and two way stop +EstDataSet$ICNT.Est <-ifelse(EstDataSet$ICNT>3,"RailRoad",EstDataSet$ICNT.Est) # other-primarily rail-road crossing +#set the order of factors +EstDataSet$ICNT.Est<-factor(EstDataSet$ICNT.Est, levels = c("None","Signal", "Stop", "RailRoad")) + +# for descriptives +EstDataSet$ICNT.Signal <-ifelse(EstDataSet$ICNT==1,1,0) # signal +EstDataSet$ICNT.Stop <-ifelse(EstDataSet$ICNT==2 | EstDataSet$ICNT==3,1,0) # all-way and two way stop +EstDataSet$ICNT.RailRoad <-ifelse(EstDataSet$ICNT>3,1,0) # other-primarily rail-road crossing +EstDataSet$ICNT.RampMeter <-ifelse(EstDataSet$ICNT==4 | EstDataSet$ICNT==5,1,0) # Ramp meter, ramp meter with HOV bypass (12/07/2015) + +# Major and Minor Arterial - this would be used only for arterials +EstDataSet$MajorArterial <-ifelse(EstDataSet$IFC==2,1,0) + +# I-15 (managed lanes) and SR-125 +EstDataSet$I15<-ifelse(EstDataSet$IFC==1 & EstDataSet$IHOV==2 & str_sub(EstDataSet$NM,1,4)=="I-15",1,0) # I15 +#EstDataSet$SR125<-ifelse(EstDataSet$IFC==1 & EstDataSet$ihov==4,1,0) # No SR125 facility in the dataset + +# LOS variables - additive and multiplicative (12/07/2015) +EstDataSet$LOSC.Up <- ifelse(EstDataSet$VOC>=0.70,EstDataSet$VOC-0.69,0) # LOS C+ +EstDataSet$LOSD.Up <- ifelse(EstDataSet$VOC>=0.80,EstDataSet$VOC-0.79,0) # LOS D+ +EstDataSet$LOSE.Up <- ifelse(EstDataSet$VOC>=0.90,EstDataSet$VOC-0.89,0) # LOS E+ +EstDataSet$LOSF.Low.Up <- ifelse(EstDataSet$VOC>=1.00,EstDataSet$VOC-0.99,0) # LOS F Low+ +EstDataSet$LOSF.Med.Up <- ifelse(EstDataSet$VOC>=1.10,EstDataSet$VOC-1.09,0) # LOS F Med+ +EstDataSet$LOSF.High.Up <- ifelse(EstDataSet$VOC>=1.20,EstDataSet$VOC-1.19,0) # LOS F High+ + +# LOS variables - additive and multiplicative - capping VOC +#EstDataSet$LOSC.Up <- ifelse(EstDataSet$VOC>=0.70 & EstDataSet$VOC<=1.00,EstDataSet$VOC-0.69,0) # LOS C+ +#EstDataSet$LOSD.Up <- ifelse(EstDataSet$VOC>=0.80 & EstDataSet$VOC<=1.00,EstDataSet$VOC-0.79,0) # LOS D+ +#EstDataSet$LOSE.Up <- ifelse(EstDataSet$VOC>=0.90 & EstDataSet$VOC<=1.00,EstDataSet$VOC-0.89,0) # LOS E+ +#EstDataSet$LOSF.Low.Up <- ifelse(EstDataSet$VOC>=1.00,EstDataSet$VOC-0.99,0) # LOS F Low+ +#EstDataSet$LOSF.Med.Up <- ifelse(EstDataSet$VOC>=1.10,EstDataSet$VOC-1.09,0) # LOS F Med+ +#EstDataSet$LOSF.High.Up <- ifelse(EstDataSet$VOC>=1.20,EstDataSet$VOC-1.19,0) # LOS F High+ + +# LOS categories - for descriptives only +EstDataSet$LOS.Cat <-"LOSB" +EstDataSet$LOS.Cat <- ifelse(EstDataSet$VOC>=0.70 & EstDataSet$VOC<0.80,"LOSC",EstDataSet$LOS.Cat) +EstDataSet$LOS.Cat <- ifelse(EstDataSet$VOC>=0.80 & EstDataSet$VOC<0.90,"LOSD",EstDataSet$LOS.Cat) +EstDataSet$LOS.Cat <- ifelse(EstDataSet$VOC>=0.90 & EstDataSet$VOC<1.00,"LOSE",EstDataSet$LOS.Cat) +EstDataSet$LOS.Cat <- ifelse(EstDataSet$VOC>=1.00 & EstDataSet$VOC<1.10,"LOSF.Low",EstDataSet$LOS.Cat) +EstDataSet$LOS.Cat <- ifelse(EstDataSet$VOC>=1.10 & EstDataSet$VOC<1.20,"LOSF.Med",EstDataSet$LOS.Cat) +EstDataSet$LOS.Cat <- ifelse(EstDataSet$VOC>=1.20,"LOSF.High",EstDataSet$LOS.Cat) +EstDataSet$LOS.Cat<-factor(EstDataSet$LOS.Cat, levels = c("LOSB","LOSC","LOSD", "LOSE", "LOSF.Low","LOSF.Med","LOSF.High")) + +# NumLanes +EstDataSet$NumLanesCat <- ifelse(EstDataSet$NumLanes==1,"OneLane","NoLane") +EstDataSet$NumLanesCat <- ifelse(EstDataSet$NumLanes==2,"TwoLane",EstDataSet$NumLanesCat) +EstDataSet$NumLanesCat <- ifelse(EstDataSet$NumLanes==3,"ThreeLane",EstDataSet$NumLanesCat) +EstDataSet$NumLanesCat <- ifelse(EstDataSet$NumLanes==4,"FourLanes",EstDataSet$NumLanesCat) +EstDataSet$NumLanesCat <- ifelse(EstDataSet$NumLanes>=5,"FiveLanes+",EstDataSet$NumLanesCat) +#set order of factors +EstDataSet$NumLanesCat<-factor(EstDataSet$NumLanesCat, levels = c("NoLane","OneLane", "TwoLane", "ThreeLane","FourLanes", "FiveLanes+")) + +# for descriptives +EstDataSet$OneLane <- ifelse(EstDataSet$NumLanes==1,1,0) +EstDataSet$TwoLane <- ifelse(EstDataSet$NumLanes==2,1,0) +EstDataSet$ThreeLane <- ifelse(EstDataSet$NumLanes==3,1,0) +EstDataSet$FourLane <- ifelse(EstDataSet$NumLanes==4,1,0) +EstDataSet$FiveMoreLane <- ifelse(EstDataSet$NumLanes>=5,1,0) + +# calculate reference bins (shift variables) - two peaks (AM and PM) and one low (MD) - generic, for all facility types +#Pre-AM: AM Peak to start of day +#Post-AM: AM Peak to MD low +#Pre-PM: PM Peak to MD low (backward) +#Post-PM: PM Peak to end of day +if (TRUE) { + EstDataSet.mean.mean<-cast(EstDataSet,todcat~IFC_Est,mean,value="mean") + EstDataSet.mean.mean<-aggregate(EstDataSet$mean,by=list(EstDataSet$todcat),FUN=mean) + + temp<-subset(EstDataSet.mean.mean,EstDataSet.mean.mean$Group.1>=25 & EstDataSet.mean.mean$Group.1<=36) + Peak_AM <- temp[which.max(temp$x),1] #32 + + temp<-subset(EstDataSet.mean.mean,EstDataSet.mean.mean$Group.1>=37 & EstDataSet.mean.mean$Group.1<=62) + Low_MD <- temp[which.min(temp$x),1] #41 + + temp<-subset(EstDataSet.mean.mean,EstDataSet.mean.mean$Group.1>=63 & EstDataSet.mean.mean$Group.1<=76) + Peak_PM <- temp[which.max(temp$x),1] #70 + + # calculate before and after variables for AM and PM periods + EstDataSet$BeforeAM <-ifelse(EstDataSet$todcat<=Peak_AM,Peak_AM-EstDataSet$todcat,99) + EstDataSet$BeforePM <-ifelse(EstDataSet$todcat>=Low_MD & EstDataSet$todcat <= Peak_PM,Peak_PM-EstDataSet$todcat,99) + + EstDataSet$AfterAM <-ifelse(EstDataSet$todcat>=Peak_AM & EstDataSet$todcat=Peak_PM,EstDataSet$todcat-Peak_PM,99) + +} + +EstDataSet$IsBeforeAM<- ifelse(EstDataSet$BeforeAM<99,1,0) +EstDataSet$IsAfterAM<- ifelse(EstDataSet$AfterAM<99,1,0) +EstDataSet$IsBeforePM<- ifelse(EstDataSet$BeforePM<99,1,0) +EstDataSet$IsAfterPM<- ifelse(EstDataSet$AfterPM<99,1,0) + +# apply shift +EstDataSet$IsBeforeAM.Shift<- EstDataSet$IsBeforeAM*EstDataSet$BeforeAM +EstDataSet$IsAfterAM.Shift<- EstDataSet$IsAfterAM*EstDataSet$AfterAM +EstDataSet$IsBeforePM.Shift<- EstDataSet$IsBeforePM*EstDataSet$BeforePM +EstDataSet$IsAfterPM.Shift<- EstDataSet$IsAfterPM*EstDataSet$AfterPM + +# piecewise functions for shift variables +# Before AM: 32 (Peak_AM) to 29, 29 to 26, 26 to 20, 20 to 1 +# After AM: 32 to 36, 36 to 39, 39 to 41 (Low_MD) +# Before PM: 70 (Peak_PM) to 66, 66 to 62, 62 to 58, 58 to 41 (Low_MD) +# After PM: 70 (Peak_PM) to 71, 71 to 79, 79 to 96 + +EstDataSet$BeforeAM.Step1<-ifelse(EstDataSet$IsBeforeAM==1, EstDataSet$BeforeAM,0) +EstDataSet$BeforeAM.Step2<-ifelse(EstDataSet$IsBeforeAM==1 & EstDataSet$todcat<29,EstDataSet$BeforeAM-(Peak_AM-29),0) +EstDataSet$BeforeAM.Step3<-ifelse(EstDataSet$IsBeforeAM==1 & EstDataSet$todcat<26,EstDataSet$BeforeAM-(Peak_AM-26),0) +EstDataSet$BeforeAM.Step4<-ifelse(EstDataSet$IsBeforeAM==1 & EstDataSet$todcat<20,EstDataSet$BeforeAM-(Peak_AM-20),0) + +EstDataSet$AfterAM.Step1<-ifelse(EstDataSet$IsAfterAM==1, EstDataSet$AfterAM,0) +EstDataSet$AfterAM.Step2<-ifelse(EstDataSet$IsAfterAM==1 & EstDataSet$todcat>36,EstDataSet$AfterAM-(36-Peak_AM),0) +EstDataSet$AfterAM.Step3<-ifelse(EstDataSet$IsAfterAM==1 & EstDataSet$todcat>39,EstDataSet$AfterAM-(39-Peak_AM),0) + +EstDataSet$BeforePM.Step1<-ifelse(EstDataSet$IsBeforePM==1, EstDataSet$BeforePM,0) +EstDataSet$BeforePM.Step2<-ifelse(EstDataSet$IsBeforePM==1 & EstDataSet$todcat<66,EstDataSet$BeforePM-(Peak_PM-66),0) +EstDataSet$BeforePM.Step3<-ifelse(EstDataSet$IsBeforePM==1 & EstDataSet$todcat<62,EstDataSet$BeforePM-(Peak_PM-62),0) +EstDataSet$BeforePM.Step4<-ifelse(EstDataSet$IsBeforePM==1 & EstDataSet$todcat<58,EstDataSet$BeforePM-(Peak_PM-58),0) + +EstDataSet$AfterPM.Step1<-ifelse(EstDataSet$IsAfterPM==1, EstDataSet$AfterPM,0) +EstDataSet$AfterPM.Step2<-ifelse(EstDataSet$IsAfterPM==1 & EstDataSet$todcat>71,EstDataSet$AfterPM-(71-Peak_PM),0) +EstDataSet$AfterPM.Step3<-ifelse(EstDataSet$IsAfterPM==1 & EstDataSet$todcat>79,EstDataSet$AfterPM-(79-Peak_PM),0) + +if (TRUE){ + # calculate mean SD in time slices for the four variables + BeforeAM.sd.mean<-cast(EstDataSet,BeforeAM~IFC_Est,mean,value="sd") + BeforePM.sd.mean<-cast(EstDataSet,BeforePM~IFC_Est,mean,value="sd") + AfterAM.sd.mean<-cast(EstDataSet,AfterAM~IFC_Est,mean,value="sd") + AfterPM.sd.mean<-cast(EstDataSet,AfterPM~IFC_Est,mean,value="sd") + EstDataSet.sd.mean<-cast(EstDataSet,todcat~IFC_Est,mean,value="sd") + + setnames(BeforeAM.sd.mean, c("1","2","3","4"), c("Freeways.SD","Arterials.SD","Ramps.SD", "Others.SD")) + setnames(BeforePM.sd.mean, c("1","2","3","4"), c("Freeways.SD","Arterials.SD","Ramps.SD", "Others.SD")) + setnames(AfterAM.sd.mean, c("1","2","3","4"), c("Freeways.SD","Arterials.SD","Ramps.SD", "Others.SD")) + setnames(AfterPM.sd.mean, c("1","2","3","4"), c("Freeways.SD","Arterials.SD","Ramps.SD", "Others.SD")) + setnames(EstDataSet.sd.mean, c("1","2","3","4"), c("Freeways.SD","Arterials.SD","Ramps.SD", "Others.SD")) + + if (OUTLIER) { + # outlier method + write.table(BeforeAM.sd.mean,"BeforeAM_SDMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(BeforePM.sd.mean,"BeforePM_SDMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(AfterAM.sd.mean,"AfterAM_SDMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(AfterPM.sd.mean,"AfterPM_SDMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(EstDataSet.sd.mean,"EstDataSet_SDMean_nooutlier.csv",sep = ",",row.names = FALSE) + + } else { + # confidence score 10 method + write.table(BeforeAM.sd.mean,"BeforeAM_SDMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(BeforePM.sd.mean,"BeforePM_SDMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(AfterAM.sd.mean,"AfterAM_SDMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(AfterPM.sd.mean,"AfterPM_SDMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(EstDataSet.sd.mean,"EstDataSet_SDMean_noCS10.csv",sep = ",",row.names = FALSE) + + } +} + +if (TRUE){ + # calculate mean SD in time slices for the four variables + BeforeAM.mean.mean<-cast(EstDataSet,BeforeAM~IFC_Est,mean,value="mean") + BeforePM.mean.mean<-cast(EstDataSet,BeforePM~IFC_Est,mean,value="mean") + AfterAM.mean.mean<-cast(EstDataSet,AfterAM~IFC_Est,mean,value="mean") + AfterPM.mean.mean<-cast(EstDataSet,AfterPM~IFC_Est,mean,value="mean") + EstDataSet.mean.mean<-cast(EstDataSet,todcat~IFC_Est,mean,value="mean") + + setnames(BeforeAM.mean.mean, c("1","2","3","4"), c("Freeways.Mean","Arterials.Mean","Ramps.Mean", "Others.Mean")) + setnames(BeforePM.mean.mean, c("1","2","3","4"), c("Freeways.Mean","Arterials.Mean","Ramps.Mean", "Others.Mean")) + setnames(AfterAM.mean.mean, c("1","2","3","4"), c("Freeways.Mean","Arterials.Mean","Ramps.Mean", "Others.Mean")) + setnames(AfterPM.mean.mean, c("1","2","3","4"), c("Freeways.Mean","Arterials.Mean","Ramps.Mean", "Others.Mean")) + setnames(EstDataSet.mean.mean, c("1","2","3","4"), c("Freeways.Mean","Arterials.Mean","Ramps.Mean", "Others.Mean")) + + if (OUTLIER) { + # outlier method + write.table(BeforeAM.mean.mean,"BeforeAM_MeanMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(BeforePM.mean.mean,"BeforePM_MeanMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(AfterAM.mean.mean,"AfterAM_MeanMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(AfterPM.mean.mean,"AfterPM_MeanMean_nooutlier.csv",sep = ",",row.names = FALSE) + write.table(EstDataSet.mean.mean,"EstDataSet_MeanMean_nooutlier.csv",sep = ",",row.names = FALSE) + + } else { + # confidence score 10 method + write.table(BeforeAM.mean.mean,"BeforeAM_MeanMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(BeforePM.mean.mean,"BeforePM_MeanMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(AfterAM.mean.mean,"AfterAM_MeanMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(AfterPM.mean.mean,"AfterPM_MeanMean_noCS10.csv",sep = ",",row.names = FALSE) + write.table(EstDataSet.mean.mean,"EstDataSet_MeanMean_noCS10.csv",sep = ",",row.names = FALSE) + + } +} + +# InterchangeDistance +#EstDataSet$Upstream <- EstDataSet$upstream.distance +#EstDataSet$Downstream <- EstDataSet$downstream.distance +EstDataSet$MajorUpstream <- EstDataSet$majorupstream.distance +EstDataSet$MajorDownstream <- EstDataSet$majordownstream.distance + +if (FALSE){ + EstDataSet$AllInt.UpDist<-ifelse(EstDataSet$upstream.distance<0.5,"Short","Long") + EstDataSet$AllInt.UpDist<-ifelse(EstDataSet$upstream.distance>=0.5 & EstDataSet$upstream.distance<=2,"Med",EstDataSet$AllInt.UpDist) + EstDataSet$AllInt.DownDist<-ifelse(EstDataSet$downstream.distance<0.5,"Short","Long") + EstDataSet$AllInt.DownDist<-ifelse(EstDataSet$downstream.distance>=0.5 & EstDataSet$downstream.distance<=2,"Med",EstDataSet$AllInt.DownDist) + + EstDataSet$AllInt.UpDist<-factor(EstDataSet$AllInt.UpDist, levels = c("Short","Med", "Long")) + EstDataSet$AllInt.DownDist<-factor(EstDataSet$AllInt.DownDist, levels = c("Short","Med", "Long")) + + EstDataSet$MajInt.UpDist<-ifelse(EstDataSet$majorupstream.distance<0.5,"Short","Long") + EstDataSet$MajInt.UpDist<-ifelse(EstDataSet$majorupstream.distance>=0.5 & EstDataSet$majorupstream.distance<=2,"Med",EstDataSet$MajInt.UpDist) + EstDataSet$MajInt.DownDist<-ifelse(EstDataSet$majordownstream.distance<0.5,"Short","Long") + EstDataSet$MajInt.DownDist<-ifelse(EstDataSet$majordownstream.distance>=0.5 & EstDataSet$majordownstream.distance<=2,"Med",EstDataSet$MajInt.DownDist) + + EstDataSet$MajInt.UpDist<-factor(EstDataSet$MajInt.UpDist, levels = c("Short","Med", "Long")) + EstDataSet$MajInt.DownDist<-factor(EstDataSet$MajInt.DownDist, levels = c("Short","Med", "Long")) +} + +EstDataSet$MajorUpstream.Inverse <- (1/EstDataSet$MajorUpstream) +EstDataSet$MajorDownstream.Inverse <- (1/EstDataSet$MajorDownstream) + +EstDataSet$AuxLanesBinary <- ifelse(EstDataSet$AuxLanes>0,1,0) +EstDataSet$ISPD70 <- ifelse(EstDataSet$ISPD==70,1,0) + +# subset by facility type - four for now (freeways, arterials, ramps, and others) +EstDataSet.freeways <- subset(EstDataSet,IFC_Est==1) +EstDataSet.arterials <- subset(EstDataSet,IFC_Est==2) +EstDataSet.ramps <- subset(EstDataSet,IFC_Est==3) +EstDataSet.others <- subset(EstDataSet,IFC_Est==4) + +# ----------------------------- 1.FREEWAYS ----------------------------- +# remove 1-lane freeways +EstDataSet.freeways <- subset(EstDataSet.freeways,NumLanes>1) + +# add lane change distance (12/7/2015) +LaneChangeDistance <-LaneChangeDistance[,c("LinkID","LaneIncrease","LaneDrop","DeadEnd","RegionEnd","DownstreamDistance")] +temp<-merge(EstDataSet.freeways,LaneChangeDistance,by.x ="ID1",by.y = "LinkID",all.x=TRUE) + +EstDataSet.freeways<-temp +EstDataSet.freeways$Down.Lane.Increase<-0 +EstDataSet.freeways$Down.Lane.Drop<-0 + +EstDataSet.freeways$Down.Lane.Increase<-ifelse(!is.na(EstDataSet.freeways$LaneIncrease) & EstDataSet.freeways$LaneIncrease>0,EstDataSet.freeways$DownstreamDistance,0) +EstDataSet.freeways$Down.Lane.Drop<-ifelse(!is.na(EstDataSet.freeways$LaneDrop) & EstDataSet.freeways$LaneDrop>0,EstDataSet.freeways$DownstreamDistance,0) + +EstDataSet.freeways$Down.Lane.Increase.Inv<-ifelse(!is.na(EstDataSet.freeways$LaneIncrease) & EstDataSet.freeways$LaneIncrease>0,1/EstDataSet.freeways$DownstreamDistance,0) +EstDataSet.freeways$Down.Lane.Drop.Inv<-ifelse(!is.na(EstDataSet.freeways$LaneDrop) & EstDataSet.freeways$LaneDrop>0,1/EstDataSet.freeways$DownstreamDistance,0) + +# add upstream/downstream node ramp meter (12/16/2015) - only within the periods of 7am-9am and 4pm-6pm +FreewayRampMeters <-FreewayRampMeters[,c("LinkID","IsRampMeterUp","IsRampMeterDown")] +temp<-merge(EstDataSet.freeways,FreewayRampMeters,by.x ="ID1",by.y = "LinkID",all.x=TRUE) +EstDataSet.freeways<-temp + +EstDataSet.freeways$DownNode.RampMeter<-0 +EstDataSet.freeways$DownNode.RampMeter<-ifelse(!is.na(EstDataSet.freeways$IsRampMeterDown) & EstDataSet.freeways$IsRampMeterDown==1 + & ((EstDataSet.freeways$todcat>=28 & EstDataSet.freeways$todcat<=36) + | (EstDataSet.freeways$todcat>=64 & EstDataSet.freeways$todcat<=72)),1,0) + +# Regression model +if (FALSE) { + model.freeways = lm(sdpermean~LOSC.Up+LOSD.Up+LOSE.Up+LOSF.Low.Up+LOSF.Med.Up+LOSF.High.Up+ISPD70+BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+AfterAM.Step2+AfterAM.Step3+BeforePM.Step1+BeforePM.Step2+BeforePM.Step3+BeforePM.Step4 + +AfterPM.Step1+AfterPM.Step2+AfterPM.Step3 + +MajorUpstream.Inverse+MajorDownstream.Inverse, data=EstDataSet.freeways) +} + +# significant - remove ISPD70 +model.freeways = lm(sdpermean~LOSC.Up+LOSD.Up+LOSE.Up+LOSF.Low.Up+LOSF.High.Up+ISPD70+BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+BeforePM.Step1+BeforePM.Step2+BeforePM.Step3 + +AfterPM.Step1+AfterPM.Step3 + +MajorUpstream.Inverse+MajorDownstream.Inverse, data=EstDataSet.freeways) + +# no shift vars +model.freeways = lm(sdpermean~LOSC.Up+LOSD.Up+LOSE.Up+LOSF.Low.Up+LOSF.High.Up+ISPD70 + +MajorUpstream.Inverse+MajorDownstream.Inverse, data=EstDataSet.freeways) + + +summary(model.freeways) + +# ---------------------------- 2.ARTERIALS ----------------------------- +# Arterials - segment speed (12/7/2015) +EstDataSet.arterials$ISPD.Cat<-"" +EstDataSet.arterials$ISPD.Cat <- ifelse(EstDataSet.arterials$ISPD<35,"ISPD35Less",EstDataSet.arterials$ISPD.Cat) +EstDataSet.arterials$ISPD.Cat <- ifelse(EstDataSet.arterials$ISPD==35,"ISPD35",EstDataSet.arterials$ISPD.Cat) +EstDataSet.arterials$ISPD.Cat <- ifelse(EstDataSet.arterials$ISPD==40,"ISPD40",EstDataSet.arterials$ISPD.Cat) +EstDataSet.arterials$ISPD.Cat <- ifelse(EstDataSet.arterials$ISPD==45,"ISPD45",EstDataSet.arterials$ISPD.Cat) +EstDataSet.arterials$ISPD.Cat <- ifelse(EstDataSet.arterials$ISPD==50,"ISPD50",EstDataSet.arterials$ISPD.Cat) +EstDataSet.arterials$ISPD.Cat <- ifelse(EstDataSet.arterials$ISPD>50,"ISPD50More",EstDataSet.arterials$ISPD.Cat) +#set order of factors +EstDataSet.arterials$ISPD.Cat<-factor(EstDataSet.arterials$ISPD.Cat, levels = c("ISPD35Less","ISPD35", "ISPD40", "ISPD45","ISPD50", "ISPD50More")) + +EstDataSet.arterials<-subset(EstDataSet.arterials,!is.na(EstDataSet.arterials$VOC)) +# Regression model +if (FALSE) { + model.arterials = lm(sdpermean~NumLanesCat+LOSC.Up+LOSD.Up+LOSE.Up+LOSF.Low.Up+LOSF.Med.Up+LOSF.High.Up + +ISPD.Cat+BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+AfterAM.Step2+AfterAM.Step3+BeforePM.Step1+BeforePM.Step2+BeforePM.Step3+BeforePM.Step4 + +AfterPM.Step1+AfterPM.Step2+AfterPM.Step3+ICNT.Est, data=EstDataSet.arterials) +} + +model.arterials = lm(sdpermean~NumLanesCat+LOSC.Up+LOSF.Low.Up + +ISPD.Cat+BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+BeforePM.Step1+BeforePM.Step3 + +AfterPM.Step1+AfterPM.Step2+AfterPM.Step3+ICNT.Est, data=EstDataSet.arterials) +# no shift vars +model.arterials = lm(sdpermean~NumLanesCat+LOSC.Up+LOSF.Low.Up + +ISPD.Cat + +ICNT.Est, data=EstDataSet.arterials) + +# different measures of capacity +model.arterials = lm(sdpermen~GCRatio+RightLanes+LeftLanes + +ISPD.Cat+BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+BeforePM.Step1+BeforePM.Step3 + +AfterPM.Step1+AfterPM.Step2+AfterPM.Step3+ICNT.Est, data=EstDataSet.arterials) + +summary(model.arterials) + +# significant - aggregate from lower LOS + +# ---------------------------- 3.RAMPS --------------------------------- +model.ramps = lm(sdpermean~LOSC.Up+LOSD.Up+LOSE.Up+LOSF.Low.Up+LOSF.Med.Up+LOSF.High.Up + +BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+AfterAM.Step2+AfterAM.Step3+BeforePM.Step1+BeforePM.Step2+BeforePM.Step3+BeforePM.Step4 + +AfterPM.Step1+AfterPM.Step2+AfterPM.Step3+ICNT.RampMeter, data=EstDataSet.ramps) + +# only significant - don't include after LOSE.Up +model.ramps = lm(sdpermean~LOSC.Up+LOSE.Up + +BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+AfterAM.Step2+AfterAM.Step3+BeforePM.Step1+BeforePM.Step2+BeforePM.Step4 + +AfterPM.Step1+AfterPM.Step3+ICNT.RampMeter, data=EstDataSet.ramps) + +# no shift vars +model.ramps = lm(sdpermean~LOSC.Up+LOSE.Up + +ICNT.RampMeter, data=EstDataSet.ramps) + + +summary(model.ramps) + +# ---------------------------- 4.OTHERS -------------------------------- +# combine twolane and threelanes for others +EstDataSet.others$NumLanesCat <- ifelse(EstDataSet.others$NumLanes==1,"OneLane","NoLane") +EstDataSet.others$NumLanesCat <- ifelse(EstDataSet.others$NumLanes>=2,"TwoLane+",EstDataSet.others$NumLanesCat) +EstDataSet.others$NumLanesCat<-factor(EstDataSet.others$NumLanesCat, levels = c("NoLane","OneLane", "TwoLane+")) + +EstDataSet.others$OneLane <- ifelse(EstDataSet.others$NumLanes==1,1,0) +EstDataSet.others$TwoLane <- ifelse(EstDataSet.others$NumLanes>=2,1,0) +EstDataSet.others$ThreeLane <- 0 + +# Regression model +model.others = lm(sdpermean~LOSC.Up+LOSD.Up+LOSE.Up+LOSF.Low.Up+LOSF.Med.Up+LOSF.High.Up + +ISPD+BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+AfterAM.Step2+AfterAM.Step3+BeforePM.Step1+BeforePM.Step2+BeforePM.Step3+BeforePM.Step4 + +AfterPM.Step1+AfterPM.Step2+AfterPM.Step3, data=EstDataSet.others) + +model.others = lm(sdpermean~ISPD+BeforeAM.Step1+BeforeAM.Step2+BeforeAM.Step3+BeforeAM.Step4 + +AfterAM.Step1+BeforePM.Step1+BeforePM.Step3 + +AfterPM.Step1+AfterPM.Step2+AfterPM.Step3, data=EstDataSet.others) + +# no shift vars +model.others = lm(sdpermean~ISPD, data=EstDataSet.others) + +# view results +summary(model.others) + +# ---------------------------------- Correlation Matrix ------------------------------------- +library(Hmisc) +library(corrplot) + +# Freeways +# keep only a few variables +temp1<-EstDataSet.freeways[,c("sd","sdpermean", + "ISPD70","VOC","LOSC.Up","LOSD.Up","LOSE.Up","LOSF.Low.Up","LOSF.Med.Up","LOSF.High.Up", + "BeforeAM.Step1","BeforeAM.Step2","BeforeAM.Step3","BeforeAM.Step4","AfterAM.Step1","AfterAM.Step2","AfterAM.Step3", + "BeforePM.Step1","BeforePM.Step2","BeforePM.Step3","BeforePM.Step4","AfterPM.Step1","AfterPM.Step2","AfterPM.Step3", + "MajorUpstream.Inverse","MajorDownstream.Inverse")] +mcor<-rcorr(as.matrix(temp1)) +# make plot and write the correlations to a csv file +corrplot(mcor$r,type="upper",tl.col="black",tl.srt=45) +write.table(mcor$r,"correlation_freeways.csv",row.names = FALSE, sep = ",") + +# Arterials +temp2<-EstDataSet.arterials[,c("sd","sdpermean","NumLanes","OneLane","TwoLane","ThreeLane","FourLane", + "AuxLanesBinary","ISPD","VOC","LOSC","LOSD","LOSE", + "LOSF_Low","LOSF_Med","LOSF_High","ICNT.Signal","ICNT.Stop","ICNT.RailRoad", + "IsBeforeAM.Shift","IsAfterAM.Shift","IsBeforePM.Shift","IsAfterPM.Shift")] +mcor<-rcorr(as.matrix(temp2)) +# make plot and write the correlations to a csv file +corrplot(mcor$r,type="upper",tl.col="black",tl.srt=45) +write.table(mcor$r,"correlation_arterials.csv",row.names = TRUE, sep = ",") + +# Ramps +temp3<-EstDataSet.ramps[,c("sd","sdpermean","NumLanes","OneLane","TwoLane","ThreeLane","ISPD","VOC", + "IsBeforeAM.Shift","IsAfterAM.Shift","IsBeforePM.Shift","IsAfterPM.Shift")] +mcor<-rcorr(as.matrix(temp3)) +# make plot and write the correlations to a csv file +corrplot(mcor$r,type="upper",tl.col="black",tl.srt=45) +write.table(mcor$r,"correlation_ramps.csv",row.names = TRUE, sep = ",") + +# Others +temp4<-EstDataSet.others[,c("sd","sdpermean","NumLanes","OneLane","TwoLane","ISPD","VOC","LOSC","LOSD","LOSE", + "LOSF_Low","LOSF_Med", + "IsBeforeAM.Shift","IsAfterAM.Shift","IsBeforePM.Shift","IsAfterPM.Shift")] +mcor<-rcorr(as.matrix(temp4)) +# make plot and write the correlations to a csv file +corrplot(mcor$r,type="upper",tl.col="black",tl.srt=45) +write.table(mcor$r,"correlation_others.csv",row.names = TRUE, sep = ",") + +# ----------------------- PLOTS ------------ +p1<-plot(EstDataSet.freeways$VOC,EstDataSet.freeways$sdpermean,type="p") +p2<-plot(EstDataSet.arterials$VOC,EstDataSet.arterials$sdpermean,type="p") +p3<-plot(EstDataSet.ramps$VOC,EstDataSet.ramps$sdpermean,type="p") +p4<-plot(EstDataSet.others$VOC,EstDataSet.others$sdpermean,type="p") + +# Shift variable plot +EstDataSet.sdmean<-cast(EstDataSet,todcat~IFC_Est,mean,value="sd") +EstDataSet.meanmean<-cast(EstDataSet,todcat~IFC_Est,mean,value="mean") +setnames(EstDataSet.sdmean,c("1","2","3","4"),c("Freeways","Arterials","Ramps","Others")) +setnames(EstDataSet.meanmean,c("1","2","3","4"),c("Freeways","Arterials","Ramps","Others")) + +EstDataSet.sdmean$tod.model<-ifelse(EstDataSet.sdmean$todcat>0 & EstDataSet.sdmean$todcat<=14,'EV1','') +EstDataSet.sdmean$tod.model<-ifelse(EstDataSet.sdmean$todcat>14 & EstDataSet.sdmean$todcat<=24,'EA',EstDataSet.sdmean$tod.model) +EstDataSet.sdmean$tod.model<-ifelse(EstDataSet.sdmean$todcat>24 & EstDataSet.sdmean$todcat<=36,'AM',EstDataSet.sdmean$tod.model) +EstDataSet.sdmean$tod.model<-ifelse(EstDataSet.sdmean$todcat>36 & EstDataSet.sdmean$todcat<=62,'MD',EstDataSet.sdmean$tod.model) +EstDataSet.sdmean$tod.model<-ifelse(EstDataSet.sdmean$todcat>62 & EstDataSet.sdmean$todcat<=76,'PM',EstDataSet.sdmean$tod.model) +EstDataSet.sdmean$tod.model<-ifelse(EstDataSet.sdmean$todcat>76 & EstDataSet.sdmean$todcat<=96,'EV2',EstDataSet.sdmean$tod.model) + +EstDataSet.meanmean$tod.model<-ifelse(EstDataSet.meanmean$todcat>0 & EstDataSet.meanmean$todcat<=14,'EV1','') +EstDataSet.meanmean$tod.model<-ifelse(EstDataSet.meanmean$todcat>14 & EstDataSet.meanmean$todcat<=24,'EA',EstDataSet.meanmean$tod.model) +EstDataSet.meanmean$tod.model<-ifelse(EstDataSet.meanmean$todcat>24 & EstDataSet.meanmean$todcat<=36,'AM',EstDataSet.meanmean$tod.model) +EstDataSet.meanmean$tod.model<-ifelse(EstDataSet.meanmean$todcat>36 & EstDataSet.meanmean$todcat<=62,'MD',EstDataSet.meanmean$tod.model) +EstDataSet.meanmean$tod.model<-ifelse(EstDataSet.meanmean$todcat>62 & EstDataSet.meanmean$todcat<=76,'PM',EstDataSet.meanmean$tod.model) +EstDataSet.meanmean$tod.model<-ifelse(EstDataSet.meanmean$todcat>76 & EstDataSet.meanmean$todcat<=96,'EV2',EstDataSet.meanmean$tod.model) + +EstDataSet.sdmean$tod.model<-factor(EstDataSet.sdmean$tod.model, levels = c("EV1","EA", "AM", "MD", "PM", "EV2")) +EstDataSet.meanmean$tod.model<-factor(EstDataSet.meanmean$tod.model, levels = c("EV1","EA", "AM", "MD", "PM", "EV2")) + + +Peak_AM <- 32 +Low_MD <- 60 +Peak_PM <-76 + +EstDataSet.sdmean$shift.period<-ifelse(EstDataSet.sdmean$todcat<=Peak_AM,1,0) #blue +EstDataSet.sdmean$shift.period<-ifelse(EstDataSet.sdmean$todcat>=Peak_AM & EstDataSet.sdmean$todcat<=Low_MD,2,EstDataSet.sdmean$shift.period) # darkgreen +EstDataSet.sdmean$shift.period<-ifelse(EstDataSet.sdmean$todcat>=Low_MD & EstDataSet.sdmean$todcat<=Peak_PM,3,EstDataSet.sdmean$shift.period) # darkorange4 +EstDataSet.sdmean$shift.period<-ifelse(EstDataSet.sdmean$todcat>=Peak_PM,4,EstDataSet.sdmean$shift.period) #chocolate4 + +EstDataSet.meanmean$shift.period<-ifelse(EstDataSet.meanmean$todcat<=Peak_AM,1,0) #blue +EstDataSet.meanmean$shift.period<-ifelse(EstDataSet.meanmean$todcat>=Peak_AM & EstDataSet.meanmean$todcat<=Low_MD,2,EstDataSet.meanmean$shift.period) # darkgreen +EstDataSet.meanmean$shift.period<-ifelse(EstDataSet.meanmean$todcat>=Low_MD & EstDataSet.meanmean$todcat<=Peak_PM,3,EstDataSet.meanmean$shift.period) # darkorange4 +EstDataSet.meanmean$shift.period<-ifelse(EstDataSet.meanmean$todcat>=Peak_PM,4,EstDataSet.meanmean$shift.period) #chocolate4 + +#colors +EstDataSet.sdmean$shift.period.color<-ifelse(EstDataSet.sdmean$todcat<=Peak_AM,"#0000FF",0) +EstDataSet.sdmean$shift.period.color<-ifelse(EstDataSet.sdmean$todcat>=Peak_AM & EstDataSet.sdmean$todcat<=Low_MD,"#006400",EstDataSet.sdmean$shift.period.color) +EstDataSet.sdmean$shift.period.color<-ifelse(EstDataSet.sdmean$todcat>=Low_MD & EstDataSet.sdmean$todcat<=Peak_PM,"#BB4500",EstDataSet.sdmean$shift.period.color) +EstDataSet.sdmean$shift.period.color<-ifelse(EstDataSet.sdmean$todcat>=Peak_PM,"#BB4513",EstDataSet.sdmean$shift.period.color) + +EstDataSet.meanmean$shift.period.color<-ifelse(EstDataSet.meanmean$todcat<=Peak_AM,"#0000FF",0) +EstDataSet.meanmean$shift.period.color<-ifelse(EstDataSet.meanmean$todcat>=Peak_AM & EstDataSet.meanmean$todcat<=Low_MD,"#006400",EstDataSet.meanmean$shift.period.color) +EstDataSet.meanmean$shift.period.color<-ifelse(EstDataSet.meanmean$todcat>=Low_MD & EstDataSet.meanmean$todcat<=Peak_PM,"#BB4500",EstDataSet.meanmean$shift.period.color) +EstDataSet.meanmean$shift.period.color<-ifelse(EstDataSet.meanmean$todcat>=Peak_PM,"#BB4513",EstDataSet.meanmean$shift.period.color) + +#plot +p1<-ggplot(data=EstDataSet.sdmean,aes(x=todcat,y=Freeways)) + geom_point() + geom_line(aes(colour=EstDataSet.sdmean$shift.period.color)) + theme_bw() +p2<-ggplot(data=EstDataSet.meanmean,aes(x=todcat,y=Freeways)) + geom_point() + geom_line(aes(colour=EstDataSet.meanmean$shift.period.color)) + theme_bw() %+replace% theme(panel.background = element_rect(fill = NA)) + +p<-p + facet_grid( . ~ tod.model, scales="free_x", space="free") + +#p<-p + geom_line(colour=EstDataSet.sdmean$shift.period) +#p<-p + scale_colour_manual(breaks=EstDataSet.sdmean$shift.period, values = unique(as.character(EstDataSet.sdmean$shift.period.color))) + +p<-p + theme_bw() + theme(panel.margin.x=unit(0,"lines"),panel.margin.y=unit(0.25,"lines"), + plot.title = element_text(lineheight=.8, face="bold", vjust=2)) +p<-p+expand_limits(y = 0) + +p<-p+scale_x_continuous(breaks = seq(0,96, by = 1), expand=c(0,0))+scale_y_continuous(expand = c(0, 0)) + +p<-p + labs(x="Time of Day Bins",y="Travel Time SD", title="Travel Time Reliability") +p<-p+theme(plot.title = element_text(lineheight=.8, face="bold", vjust=2)) + diff --git a/sandag_abm/src/main/r/summarize_SR125data.R b/sandag_abm/src/main/r/summarize_SR125data.R new file mode 100644 index 0000000..7629531 --- /dev/null +++ b/sandag_abm/src/main/r/summarize_SR125data.R @@ -0,0 +1,141 @@ +library(stringr) +library(xtable) +library(foreign) +library(data.table) + +setwd("C:/Projects/SANDAG_PricingAndReliability/data/toll facility data") + +tripdata <- read.csv("RequestedNumbers.csv",header=TRUE) +nrow(tripdata) +tripdata<-data.table(tripdata) + +#start time +tripdata[, starthour := as.numeric(substr(descr,1,2))] +tripdata[, startmin := as.numeric(substr(descr,4,5))] +tripdata[,starttime:=as.numeric(starthour*60+startmin)] + +# end time +tripdata[, endhour := as.numeric(substr(descr,9,10))] +tripdata[, endmin := as.numeric(substr(descr,12,13))] +tripdata[,endtime:=as.numeric(endhour*60+endmin)] + +tripdata[,midtime:=(starttime+endtime)/2] + +# time periods (mins from midnight) +#Early AM (EA) 210 - 359 +#AM Peak (AM) 360 - 539 +#Midday (MD) 540 - 929 +#PM Peak (PM) 930 - 1139 +#Evening (EV) 1140 - 1440 and 0 - 209 + +tripdata$tod=5 # 5-evening +tripdata[midtime>=210 & midtime<=359,tod:=1] #1-early AM +tripdata[midtime>=360 & midtime<=539,tod:=2] #2-AM peak +tripdata[midtime>=540 & midtime<=929,tod:=3] #3-Midday +tripdata[midtime>=930 & midtime<=1139,tod:=4] #4-PM Peak + +tripdata$ea<-ifelse(tripdata$tod==1,1,0) +tripdata$am<-ifelse(tripdata$tod==2,1,0) +tripdata$md<-ifelse(tripdata$tod==3,1,0) +tripdata$pm<-ifelse(tripdata$tod==4,1,0) +tripdata$ev<-ifelse(tripdata$tod==5,1,0) + +#ea trips +tripdata[,ea_FT2Axle:=FT2Axle*ea] +tripdata[,ea_CashCC2Axle:=CashCC2Axle*ea] +tripdata[,ea_FT3PlusAxle:=FT3PlusAxle*ea] +tripdata[,ea_CashCC3PlusAxle:=CashCC3PlusAxle*ea] + +#am trips +tripdata[,am_FT2Axle:=FT2Axle*am] +tripdata[,am_CashCC2Axle:=CashCC2Axle*am] +tripdata[,am_FT3PlusAxle:=FT3PlusAxle*am] +tripdata[,am_CashCC3PlusAxle:=CashCC3PlusAxle*am] + +#md trips +tripdata[,md_FT2Axle:=FT2Axle*md] +tripdata[,md_CashCC2Axle:=CashCC2Axle*md] +tripdata[,md_FT3PlusAxle:=FT3PlusAxle*md] +tripdata[,md_CashCC3PlusAxle:=CashCC3PlusAxle*md] + +#pm trips +tripdata[,pm_FT2Axle:=FT2Axle*pm] +tripdata[,pm_CashCC2Axle:=CashCC2Axle*pm] +tripdata[,pm_FT3PlusAxle:=FT3PlusAxle*pm] +tripdata[,pm_CashCC3PlusAxle:=CashCC3PlusAxle*pm] + +#ev trips +tripdata[,ev_FT2Axle:=FT2Axle*ev] +tripdata[,ev_CashCC2Axle:=CashCC2Axle*ev] +tripdata[,ev_FT3PlusAxle:=FT3PlusAxle*ev] +tripdata[,ev_CashCC3PlusAxle:=CashCC3PlusAxle*ev] + +#ea +trips_FT2Axle<-aggregate(x=tripdata$ea_FT2Axle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC2Axle<-aggregate(x=tripdata$ea_CashCC2Axle,by=list(key=tripdata$key),FUN=sum) +trips_FT3PlusAxle<-aggregate(x=tripdata$ea_FT3PlusAxle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC3PlusAxle<-aggregate(x=tripdata$ea_CashCC3PlusAxle,by=list(key=tripdata$key),FUN=sum) + +trips_ea<-data.frame(key=trips_FT2Axle$key,FT2Axle=trips_FT2Axle$x) +trips_ea$CashCC2Axle<-trips_CashCC2Axle$x +trips_ea$FT3PlusAxle<-trips_FT3PlusAxle$x +trips_ea$CashCC3PlusAxle<-trips_CashCC3PlusAxle$x + +#am +trips_FT2Axle<-aggregate(x=tripdata$am_FT2Axle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC2Axle<-aggregate(x=tripdata$am_CashCC2Axle,by=list(key=tripdata$key),FUN=sum) +trips_FT3PlusAxle<-aggregate(x=tripdata$am_FT3PlusAxle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC3PlusAxle<-aggregate(x=tripdata$am_CashCC3PlusAxle,by=list(key=tripdata$key),FUN=sum) + +trips_am<-data.frame(key=trips_FT2Axle$key,FT2Axle=trips_FT2Axle$x) +trips_am$CashCC2Axle<-trips_CashCC2Axle$x +trips_am$FT3PlusAxle<-trips_FT3PlusAxle$x +trips_am$CashCC3PlusAxle<-trips_CashCC3PlusAxle$x + +#md +trips_FT2Axle<-aggregate(x=tripdata$md_FT2Axle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC2Axle<-aggregate(x=tripdata$md_CashCC2Axle,by=list(key=tripdata$key),FUN=sum) +trips_FT3PlusAxle<-aggregate(x=tripdata$md_FT3PlusAxle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC3PlusAxle<-aggregate(x=tripdata$md_CashCC3PlusAxle,by=list(key=tripdata$key),FUN=sum) + +trips_md<-data.frame(key=trips_FT2Axle$key,FT2Axle=trips_FT2Axle$x) +trips_md$CashCC2Axle<-trips_CashCC2Axle$x +trips_md$FT3PlusAxle<-trips_FT3PlusAxle$x +trips_md$CashCC3PlusAxle<-trips_CashCC3PlusAxle$x + +#pm +trips_FT2Axle<-aggregate(x=tripdata$pm_FT2Axle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC2Axle<-aggregate(x=tripdata$pm_CashCC2Axle,by=list(key=tripdata$key),FUN=sum) +trips_FT3PlusAxle<-aggregate(x=tripdata$pm_FT3PlusAxle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC3PlusAxle<-aggregate(x=tripdata$pm_CashCC3PlusAxle,by=list(key=tripdata$key),FUN=sum) + +trips_pm<-data.frame(key=trips_FT2Axle$key,FT2Axle=trips_FT2Axle$x) +trips_pm$CashCC2Axle<-trips_CashCC2Axle$x +trips_pm$FT3PlusAxle<-trips_FT3PlusAxle$x +trips_pm$CashCC3PlusAxle<-trips_CashCC3PlusAxle$x + +#ev +trips_FT2Axle<-aggregate(x=tripdata$ev_FT2Axle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC2Axle<-aggregate(x=tripdata$ev_CashCC2Axle,by=list(key=tripdata$key),FUN=sum) +trips_FT3PlusAxle<-aggregate(x=tripdata$ev_FT3PlusAxle,by=list(key=tripdata$key),FUN=sum) +trips_CashCC3PlusAxle<-aggregate(x=tripdata$ev_CashCC3PlusAxle,by=list(key=tripdata$key),FUN=sum) + +trips_ev<-data.frame(key=trips_FT2Axle$key,FT2Axle=trips_FT2Axle$x) +trips_ev$CashCC2Axle<-trips_CashCC2Axle$x +trips_ev$FT3PlusAxle<-trips_FT3PlusAxle$x +trips_ev$CashCC3PlusAxle<-trips_CashCC3PlusAxle$x + +#all +trips_FT2Axle<-aggregate(x=tripdata$FT2Axle,by=list(tod=tripdata$tod),FUN=sum) +trips_CashCC2Axle<-aggregate(x=tripdata$CashCC2Axle,by=list(tod=tripdata$tod),FUN=sum) +trips_FT3PlusAxle<-aggregate(x=tripdata$FT3PlusAxle,by=list(tod=tripdata$tod),FUN=sum) +trips_CashCC3PlusAxle<-aggregate(x=tripdata$CashCC3PlusAxle,by=list(tod=tripdata$tod),FUN=sum) + +trips_all<-data.frame(tod=trips_FT2Axle$tod,FT2Axle=trips_FT2Axle$x) +trips_all$CashCC2Axle<-trips_CashCC2Axle$x +trips_all$FT3PlusAxle<-trips_FT3PlusAxle$x +trips_all$CashCC3PlusAxle<-trips_CashCC3PlusAxle$x + +write.table(trips_all,"sr125_summary.csv",row.names=F,quote=F,sep = ",") + +rm(tripdata) \ No newline at end of file diff --git a/sandag_abm/src/main/r/utilfunc.R b/sandag_abm/src/main/r/utilfunc.R new file mode 100644 index 0000000..1aead08 --- /dev/null +++ b/sandag_abm/src/main/r/utilfunc.R @@ -0,0 +1,256 @@ + +#read a file, save to Rdata, and remove from workspace +readSaveRdata <- function(filename,objname) { + assign(objname,fread(filename)) + save(list=objname,file=paste0(filename,".Rdata")) + rm(list=objname) +} + +#load an RData object to an object name +assignLoad <- function(filename) { + load(filename) + get(ls()[ls() != "filename"]) +} + +regressionmodel<-function(myDF) { + +model = lm(SpeedStdDev~NumLanes+VOC+CongSpeed+Ratio.FFTime.CongTime+IFC, data=myDF) +summary(model) + +} + +detectoutliers<-function(myDF) { + # Detects outliers in a dataset + # + # Args: + # myDF: dataframe in list of dataframes + # type: box plot to use - original or adjusted + # + # Returns: + # mydata with outlier=1 for outliers + type<-"adjusted" + + if (type=="original") { + values<-boxplot(travel_time_sec ~ todcat, myDF, main = "Original Boxplot") + } else { + values<-adjbox(travel_time_sec ~ todcat, myDF, main = "Adjusted Boxplot") + } + + if (length(table(myDF$todcat))<48) { + warning(paste("tmc segment ", myDF$tmc_code[1], " is missing some data")) + } + + for (cat in 1:length(unique(myDF$todcat))) { + limit_lower<-values[["stats"]][1,cat] + limit_upper<-values[["stats"]][5,cat] + myDF[todcat==cat & (travel_time_seclimit_upper), outlier:=1] + } + +} + +myplot_sd<-function(myDF,datatype,numoutliers,field) { + # Plots data points by facility type + # + # Args: + # myDF: dataframe in list of dataframes + # outputsDir: directory to save the plot + # + # Returns: + # Nothing. saves a plot in JPEG format in OutputsDir + + # to change the order of variables in plot + outputsDir="./INRIX/2012_10/" + + # include only segments that have data for the entire period + if (length(table(myDF$todcat))==48) { + + myDF$tod<-factor(myDF$tod, levels = c("EV1","EA", "AM", "MD", "PM", "EV2")) + IFC<-myDF$IFC[1] + + #p<-ggplot(data=myDF,aes(todcat,value, colour=tmc_code),na.rm=TRUE) + geom_point() + #p<-ggplot(data=myDF,aes(todcat,value),na.rm=TRUE) + geom_point() + + p<-ggplot(data=myDF,aes(todcat,value, group=tmc_code),na.rm=TRUE) + geom_line()+ geom_point() + + # add grids for TOD + p<-p + facet_grid(. ~ tod, scales="free_x", space="free") + + # set space between facets + p<-p + theme_bw() + theme(panel.margin.x=unit(0,"lines"),panel.margin.y=unit(0.25,"lines"), + plot.title = element_text(lineheight=.8, face="bold", vjust=2)) + + # set consistent axis and force axis to start at 0 + p<-p+expand_limits(y = 0) + p<-p+scale_x_continuous(breaks = seq(0,48, by = 1), expand=c(0,0))+scale_y_continuous(expand = c(0, 0)) + + # add title + if (datatype=="raw") { + outfile = paste(field, "_SD_rawdata_",IFC,".jpeg") + maintitle<-paste(field," SD by TOD (raw data)") + } else { + outfile = paste("SD_per_mile_nooutliers_",IFC,".jpeg") + maintitle<-paste(field, " SD by TOD (", numoutliers, " outliers removed)") + } + + p<-p + labs(x="Time of Day Category (30 mins interval)",y=paste(field, " SD"), title=maintitle) + p<-p+theme(plot.title = element_text(lineheight=.8, face="bold", vjust=2)) + + #print(p) + + return(p) + + # save as JPEG + #dev.copy(jpeg,filename=paste(outputsDir,outfile, sep = ""),width=1280, height=1280) + #dev.off() + + } + +} + +myplot1<-function(myDF) { + # Plots data points by facility type + # + # Args: + # myDF: dataframe in list of dataframes + # outputsDir: directory to save the plot + # + # Returns: + # Nothing. saves a plot in JPEG format in OutputsDir + + # to change the order of variables in plot + outputsDir="./INRIX/2012_10/" + myDF$tod<-factor(myDF$tod, levels = c("EV1","EA", "AM", "MD", "PM", "EV2")) + IFC<-myDF$IFC[1] + + p<-ggplot(data=myDF,aes(totalhour,speed, colour=color.names)) + geom_point() + p<-p + scale_colour_manual(breaks=myDF$color.names, values = unique(as.character(myDF$color.codes))) + + # add grids for TOD + p<-p + facet_grid(. ~ tod, scales="free_x", space="free") + + # set space between facets + p<-p + theme_bw() + theme(panel.margin.x=unit(0,"lines"),panel.margin.y=unit(0.25,"lines"), + plot.title = element_text(lineheight=.8, face="bold", vjust=2)) + + # set consistent axis and force axis to start at 0 + p<-p+expand_limits(y = 0) + p<-p+scale_x_continuous(breaks = seq(0,24, by = 2), expand=c(0,0))+scale_y_continuous(expand = c(0, 0)) + + numoutliers<-sum(myDF$outlier) + # add title + maintitle<-paste("Speed by TOD (outliers=",numoutliers,")") + p<-p + labs(x="Time of Day (hour)",y="Speed (mph)", title=maintitle) + p<-p+theme(plot.title = element_text(lineheight=.8, face="bold", vjust=2)) + + print(p) + # save as JPEG + dev.copy(jpeg,filename=paste(outputsDir,"Speed_IFC_", IFC, "_outliers30mins.jpeg", sep = ""),width=1280, height=1280) + dev.off() + +} + +myplot<- function(indata,datatype,analysistype,xlbl,ylbl,plottitle,ymax) { + # Makes a scatter plot + # + # Args: + # indata: dataset with datapoints + # datatype: all weekdays or one + # analysistype: travel time or speed analysis + # xlbl: x-axis label + # ylbl: y-axis label + # plottitle: plot title + # ymax: y-axis limit + # + # Returns: + # a scatter plot of datapoints in indata + + # setup a plot + if (analysistype == "Time") { + p<-ggplot(data=indata,aes(x=totalhour,y=travel_time_sec)) + geom_point(colour='black',size=2) + #ymax<-max(indata$travel_time_sec)+100 # add 100sec to have some space on top + ybreak <-200 # 200 seconds + } else { + p<-ggplot(data=indata,aes(x=totalhour,y=speed)) + geom_point(colour='black',size=2) + #ymax<-max(indata$speed)+10 # add 10 mph to have some space on top + ybreak <-20 # 20 mph + } + + # set different colors for outliers + p<-p + scale_colour_hue(breaks=indata$outlier) + + # add grids for TOD + if (datatype=="All") { + p<-p + facet_grid(wday ~ tod, scales="free_x", space="free") + } else { + p<-p + facet_grid(day ~ tod, scales="free_x", space="free") + } + + # set space between facets + p<-p + theme_bw() + theme(panel.margin.x=unit(0,"lines"),panel.margin.y=unit(0.25,"lines"), + plot.title = element_text(lineheight=.8, face="bold", vjust=2)) + + # set consistent axis and force axis to start at 0 + p<-p+expand_limits(y = 0) + + # modify x and y axis + if (analysistype == "Time") { + p<-p+scale_x_continuous(breaks = seq(0,24, by = 2), expand=c(0,0))+scale_y_continuous(expand = c(0, 0)) #breaks=seq(0,1000, by = ybreak), + } else { + p<-p+scale_x_continuous(breaks = seq(0,24, by = 2), expand=c(0,0))+scale_y_continuous(breaks=seq(0,100, by = 20), expand = c(0, 0)) #breaks=seq(0,100, by = ybreak), + } + + # add title + p<-p + labs(x=xlbl,y=ylbl, title=plottitle) + p<-p+theme(plot.title = element_text(lineheight=.8, face="bold", vjust=2)) + + return(p) +} + +# function to add multiple plots in a print area +multiplot <- function(..., plotlist=NULL, file, cols=1, layout=NULL) { + # Combines multiple plots in one print area + # + # Args: + # ...: plots seperated by commas. Provide as many plots as you want. + # plotlist: + # file: + # cols: number of columns in the plot area + # layout: if NULL then 'cols' is used to determine layout + # + # Returns: + # None. Displays the multiplot + + library(grid) + + # Make a list from the ... arguments and plotlist + plots <- c(list(...), plotlist) + + numPlots = length(plots) + + # If layout is NULL, then use 'cols' to determine layout + if (is.null(layout)) { + # Make the panel + # ncol: Number of columns of plots + # nrow: Number of rows needed, calculated from # of cols + layout <- matrix(seq(1, cols * ceiling(numPlots/cols)), + ncol = cols, nrow = ceiling(numPlots/cols)) + } + + if (numPlots==1) { + print(plots[[1]]) + + } else { + # Set up the page + grid.newpage() + pushViewport(viewport(layout = grid.layout(nrow(layout), ncol(layout)))) + + # Make each plot, in the correct location + for (i in 1:numPlots) { + # Get the i,j matrix positions of the regions that contain this subplot + matchidx <- as.data.frame(which(layout == i, arr.ind = TRUE)) + + print(plots[[i]], vp = viewport(layout.pos.row = matchidx$row, + layout.pos.col = matchidx$col)) + } + } +} \ No newline at end of file diff --git a/sandag_abm/src/main/r/visualizer/Master.R b/sandag_abm/src/main/r/visualizer/Master.R new file mode 100644 index 0000000..bfc4337 --- /dev/null +++ b/sandag_abm/src/main/r/visualizer/Master.R @@ -0,0 +1,94 @@ +############################################################################################################################# +# Master script to render final HTML file from R Markdown file +# Loads all required packages from the dependencies folder +# +# Make sure the 'plyr' is not loaded after 'dplyr' library in the same R session +# Under such case, the group_by features of dplyr library does not work. Restart RStudio and make sure +# plyr library is not loaded while generating dashboard +# For more info on this issue: +# https://stackoverflow.com/questions/26923862/why-are-my-dplyr-group-by-summarize-not-working-properly-name-collision-with +# +############################################################################################################################# + +##### LIST OF ALL INPUT FILES ##### +## 0. Path input data : parameters.csv +## 1. Base scenario summary file names : summaryFilesNames_survey.csv +## 2. Build scenario summary file names : summaryFilesNames.csv +## 3. Model area shapefile : summaryFilesNames.csv +## 4. All REF and ABM summary output files + +### Read Command Line Arguments +args <- commandArgs(trailingOnly = TRUE) +Parameters_File <- args[1] +showWarnings=FALSE + +### Read parameters from Parameters_File +parameters <- read.csv(Parameters_File, header = TRUE) +WORKING_DIR <- trimws(paste(parameters$Value[parameters$Key=="WORKING_DIR"])) +BASE_SUMMARY_DIR <- trimws(paste(parameters$Value[parameters$Key=="BASE_SUMMARY_DIR"])) +BUILD_SUMMARY_DIR <- trimws(paste(parameters$Value[parameters$Key=="BUILD_SUMMARY_DIR"])) +BASE_SCENARIO_NAME <- trimws(paste(parameters$Value[parameters$Key=="BASE_SCENARIO_NAME"])) +BUILD_SCENARIO_NAME <- trimws(paste(parameters$Value[parameters$Key=="BUILD_SCENARIO_NAME"])) +BASE_SAMPLE_RATE <- as.numeric(trimws(paste(parameters$Value[parameters$Key=="BASE_SAMPLE_RATE"]))) +BUILD_SAMPLE_RATE <- as.numeric(trimws(paste(parameters$Value[parameters$Key=="BUILD_SAMPLE_RATE"]))) +R_LIBRARY <- trimws(paste(parameters$Value[parameters$Key=="R_LIBRARY"])) +OUTPUT_HTML_NAME <- trimws(paste(parameters$Value[parameters$Key=="OUTPUT_HTML_NAME"])) +SHP_FILE_NAME <- trimws(paste(parameters$Value[parameters$Key=="SHP_FILE_NAME"])) +IS_BASE_SURVEY <- trimws(paste(parameters$Value[parameters$Key=="IS_BASE_SURVEY"])) + +### Initialization +# Load global variables +.libPaths(R_LIBRARY) +source(paste(WORKING_DIR, "scripts/_SYSTEM_VARIABLES.R", sep = "/")) + +###create directories +dir.create(BASE_DATA_PATH) +dir.create(BUILD_DATA_PATH) + +### Copy summary CSVs +base_CSV_list <- ifelse(IS_BASE_SURVEY=="Yes", "summaryFilesNames_survey.csv", "summaryFilesNames.csv") +summaryFileList_base <- read.csv(paste(SYSTEM_TEMPLATES_PATH, base_CSV_list, sep = '/'), as.is = T) +summaryFileList_base <- as.list(summaryFileList_base$summaryFile) +retVal <- copyFile(summaryFileList_base, sourceDir = BASE_SUMMARY_DIR, targetDir = BASE_DATA_PATH) +if(retVal) q(save = "no", status = 11) +summaryFileList_build <- read.csv(paste(SYSTEM_TEMPLATES_PATH, "summaryFilesNames.csv", sep = '/'), as.is = T) +summaryFileList_build <- as.list(summaryFileList_build$summaryFile) +retVal <- copyFile(summaryFileList_build, sourceDir = BUILD_SUMMARY_DIR, targetDir = BUILD_DATA_PATH) +if(retVal) q(save = "no", status = 11) + +### Load required libraries +SYSTEM_REPORT_PKGS <- c("DT", "flexdashboard", "leaflet", "geojsonio", "htmltools", "htmlwidgets", "kableExtra", + "knitr", "mapview", "plotly", "RColorBrewer", "rgdal", "rgeos", "crosstalk","treemap", "htmlTable", + "rmarkdown", "scales", "stringr", "jsonlite", "pander", "ggplot2", "reshape", "raster", "dplyr") + +lapply(SYSTEM_REPORT_PKGS, library, character.only = TRUE) + +### Read Target and Output SUmmary files +currDir <- getwd() +setwd(BASE_DATA_PATH) +base_csv = list.files(pattern="*.csv") +base_data <- lapply(base_csv, read.csv) +base_csv_names <- unlist(lapply(base_csv, function (x) {gsub(".csv", "", x)})) + +setwd(BUILD_DATA_PATH) +build_csv = list.files(pattern="*.csv") +build_data <- lapply(build_csv, read.csv) +build_csv_names <- unlist(lapply(build_csv, function (x) {gsub(".csv", "", x)})) + +## Read SHP file +setwd(SYSTEM_SHP_PATH) +zone_shp <- shapefile(SHP_FILE_NAME) +zone_shp <- spTransform(zone_shp, CRS("+proj=longlat +ellps=GRS80")) + +setwd(currDir) + +### Generate dashboard +rmarkdown::render(file.path(SYSTEM_TEMPLATES_PATH, "template.Rmd"), + output_dir = RUNTIME_PATH, + intermediates_dir = RUNTIME_PATH, quiet = TRUE) +template.html <- readLines(file.path(RUNTIME_PATH, "template.html")) +idx <- which(template.html == "window.FlexDashboardComponents = [];")[1] +template.html <- append(template.html, "L_PREFER_CANVAS = true;", after = idx) +writeLines(template.html, file.path(OUTPUT_PATH, paste(OUTPUT_HTML_NAME, ".html", sep = ""))) + +# finish \ No newline at end of file diff --git a/sandag_abm/src/main/r/visualizer/SummarizeABM2016.R b/sandag_abm/src/main/r/visualizer/SummarizeABM2016.R new file mode 100644 index 0000000..fb6eb50 --- /dev/null +++ b/sandag_abm/src/main/r/visualizer/SummarizeABM2016.R @@ -0,0 +1,2448 @@ +####################################################### +### Script for summarizing SANDAG ABM Output +### Author: Binny M Paul, binny.paul@rsginc.com, Oct 2017 +### Edited: Khademul Haque, khademul.haque@rsginc.com, Mar 2019 +####################################################### + +##### LIST OF ALL INPUT FILES ##### +## 0. Path input data : summ_inputs_abm.csv +## 1. household data : householdData_3.csv +## 2. person data : personData_3.csv +## 3. Individual tour data : indivTourData_3.csv +## 4. Individual trip data : indivTripData_3.csv +## 5. Joint tour data : jointTripData_3.csv +## 6. Joint trip data : jointTourData_3.csv +## 7. Work school location data : wsLocResults_3.csv +## 8. Auto ownership data : aoResults.csv +## 9. Auto ownership data : aoResults_Pre.csv +## 10. Geographic crosswalk data : geographicXwalk_PMSA.csv +## 11. Distance skim : traffic_skims_MD.omx -> MD_SOVTOLLH_DIST + +start_time <- Sys.time() + +library(plyr) +library(weights) +library(reshape) +library(data.table) +library(omxr) +showWarnings=FALSE + +# Read Command Line Arguments +args <- commandArgs(trailingOnly = TRUE) +inputs_File <- args[1] + +inputs <- read.csv(inputs_File, header = TRUE) +WD <- trimws(paste(inputs$Value[inputs$Key=="WD"])) +ABMOutputDir <- trimws(paste(inputs$Value[inputs$Key=="ABMOutputDir"])) +geogXWalkDir <- trimws(paste(inputs$Value[inputs$Key=="geogXWalkDir"])) +SkimDir <- trimws(paste(inputs$Value[inputs$Key=="SkimDir"])) +MAX_ITER <- trimws(paste(inputs$Value[inputs$Key=="MAX_ITER"])) + +setwd(ABMOutputDir) +#full model run +hh <- fread(paste("householdData_",MAX_ITER,".csv", sep = "")) +per <- fread(paste("personData_",MAX_ITER,".csv", sep = "")) +tours <- fread(paste("indivTourData_",MAX_ITER,".csv", sep = "")) +trips <- fread(paste("indivTripData_",MAX_ITER,".csv", sep = "")) +jtrips <- fread(paste("jointTripData_",MAX_ITER,".csv", sep = "")) +unique_joint_tours <- fread(paste("jointTourData_",MAX_ITER,".csv", sep = "")) +wsLoc <- fread(paste("wsLocResults_",MAX_ITER,".csv", sep = "")) +aoResults <- fread("aoResults.csv") +aoResults_Pre <- fread("aoResults_Pre.csv") + +visitor_trips <- fread(paste("visitorTrips.csv", sep = "")) + +mazCorrespondence <- fread(paste(geogXWalkDir, "geographicXwalk_PMSA.csv", sep = "/"), stringsAsFactors = F) +districtList <- sort(unique(mazCorrespondence$pmsa)) + +SkimFile <- paste(SkimDir, "traffic_skims_MD.omx", sep = "/") +DST_SKM <- read_omx(SkimFile, "MD_SOV_TR_H_DIST") +skimLookUp <- read_lookup(SkimFile, "zone_number") + +pertypeCodes <- data.frame(code = c(1,2,3,4,5,6,7,8,"All"), + name = c("FT Worker", "PT Worker", "Univ Stud", "Non Worker", "Retiree", "Driv Stud", "NonDriv Stud", "Pre-School", "All")) + +#------------------------------------------- +# Prepare files for computing summary statistics +dir.create(WD, showWarnings = FALSE) +setwd(WD) + +aoResults$HHVEH[aoResults$AO == 0] <- 0 +aoResults$HHVEH[aoResults$AO == 1] <- 1 +aoResults$HHVEH[aoResults$AO == 2] <- 2 +aoResults$HHVEH[aoResults$AO == 3] <- 3 +aoResults$HHVEH[aoResults$AO >= 4] <- 4 + +aoResults_Pre$HHVEH[aoResults_Pre$AO == 0] <- 0 +aoResults_Pre$HHVEH[aoResults_Pre$AO == 1] <- 1 +aoResults_Pre$HHVEH[aoResults_Pre$AO == 2] <- 2 +aoResults_Pre$HHVEH[aoResults_Pre$AO == 3] <- 3 +aoResults_Pre$HHVEH[aoResults_Pre$AO >= 4] <- 4 + +hh$HHVEH[hh$autos == 0] <- 0 +hh$HHVEH[hh$autos == 1] <- 1 +hh$HHVEH[hh$autos == 2] <- 2 +hh$HHVEH[hh$autos == 3] <- 3 +hh$HHVEH[hh$autos >= 4] <- 4 + +hh$VEH_NEWCAT[(hh$HVs == 0) & (hh$AVs) == 0] <- 1 +hh$VEH_NEWCAT[(hh$HVs == 1) & (hh$AVs) == 0] <- 2 +hh$VEH_NEWCAT[(hh$HVs == 0) & (hh$AVs) == 1] <- 3 +hh$VEH_NEWCAT[(hh$HVs == 2) & (hh$AVs) == 0] <- 4 +hh$VEH_NEWCAT[(hh$HVs == 0) & (hh$AVs) == 2] <- 5 +hh$VEH_NEWCAT[(hh$HVs == 1) & (hh$AVs) == 1] <- 6 +hh$VEH_NEWCAT[(hh$HVs == 3) & (hh$AVs) == 0] <- 7 +hh$VEH_NEWCAT[(hh$HVs == 0) & (hh$AVs) == 3] <- 8 +hh$VEH_NEWCAT[(hh$HVs == 2) & (hh$AVs) == 1] <- 9 +hh$VEH_NEWCAT[(hh$HVs == 1) & (hh$AVs) == 2] <- 10 +hh$VEH_NEWCAT[(hh$HVs == 4) & (hh$AVs) == 0] <- 11 + +#HH Size +hhsize <- count(per, c("hh_id"), "hh_id>0") +hh$HHSIZ <- hhsize$freq[match(hh$hh_id, hhsize$hh_id)] +hh$HHSIZE[hh$HHSIZ == 1] <- 1 +hh$HHSIZE[hh$HHSIZ == 2] <- 2 +hh$HHSIZE[hh$HHSIZ == 3] <- 3 +hh$HHSIZE[hh$HHSIZ == 4] <- 4 +hh$HHSIZE[hh$HHSIZ >= 5] <- 5 + +#Adults in the HH +adults <- count(per, c("hh_id"), "age>=18 & age<99") +hh$ADULTS <- adults$freq[match(hh$hh_id, adults$hh_id)] + +per$PERTYPE[per$type=="Full-time worker"] <- 1 +per$PERTYPE[per$type=="Part-time worker"] <- 2 +per$PERTYPE[per$type=="University student"] <- 3 +per$PERTYPE[per$type=="Non-worker"] <- 4 +per$PERTYPE[per$type=="Retired"] <- 5 +per$PERTYPE[per$type=="Student of driving age"] <- 6 +per$PERTYPE[per$type=="Student of non-driving age"] <- 7 +per$PERTYPE[per$type=="Child too young for school"] <- 8 + +# Districts are Pseudo MSA +wsLoc$HDISTRICT <- mazCorrespondence$pmsa[match(wsLoc$HomeMGRA, mazCorrespondence$mgra)] +wsLoc$WDISTRICT <- mazCorrespondence$pmsa[match(wsLoc$WorkLocation, mazCorrespondence$mgra)] + +# Get home, work and school location TAZs +wsLoc$HHTAZ <- mazCorrespondence$taz[match(wsLoc$HomeMGRA, mazCorrespondence$mgra)] +wsLoc$WTAZ <- mazCorrespondence$taz[match(wsLoc$WorkLocation, mazCorrespondence$mgra)] +wsLoc$STAZ <- mazCorrespondence$taz[match(wsLoc$SchoolLocation, mazCorrespondence$mgra)] + +wsLoc$oindex<-match(wsLoc$HHTAZ, skimLookUp$Lookup) +wsLoc$dindex<-match(wsLoc$WTAZ, skimLookUp$Lookup) +wsLoc$dindex2<-match(wsLoc$STAZ, skimLookUp$Lookup) +wsLoc$WorkLocationDistance<-DST_SKM[cbind(wsLoc$oindex, wsLoc$dindex)] +wsLoc$WorkLocationDistance[is.na(wsLoc$WorkLocationDistance)] <- 0 + +wsLoc$SchoolLocationDistance<-DST_SKM[cbind(wsLoc$oindex, wsLoc$dindex2)] +wsLoc$SchoolLocationDistance[is.na(wsLoc$SchoolLocationDistance)] <- 0 + +#--------Compute Summary Statistics------- +#***************************************** + +# Auto ownership +autoOwnership_Pre <- count(aoResults_Pre, c("HHVEH")) +write.csv(autoOwnership_Pre, "autoOwnership_Pre.csv", row.names = TRUE) + +autoOwnership <- count(aoResults, c("HHVEH")) +write.csv(autoOwnership, "autoOwnership.csv", row.names = TRUE) + +autoOwnership_AV <- count(hh, c("AVs")) +write.csv(autoOwnership_AV, "autoOwnership_AV.csv", row.names = TRUE) + +autoOwnership_new <- count(hh, c("VEH_NEWCAT")) +write.csv(autoOwnership_new, "autoOwnership_new.csv", row.names = TRUE) + +# Zero auto HHs by TAZ +hh$HHTAZ <- mazCorrespondence$taz[match(hh$home_mgra, mazCorrespondence$mgra)] +hh$ZeroAutoWgt[hh$HHVEH==0] <- 1 +hh$ZeroAutoWgt[is.na(hh$ZeroAutoWgt)] <- 0 +zeroAutoByTaz <- aggregate(hh$ZeroAutoWgt, list(TAZ = hh$HHTAZ), sum) +write.csv(zeroAutoByTaz, "zeroAutoByTaz.csv", row.names = TRUE) + +# Persons by person type +pertypeDistbn <- count(per, c("PERTYPE")) +write.csv(pertypeDistbn, "pertypeDistbn.csv", row.names = TRUE) + +# Telecommute Freuency +teleCommute <- count(per, c("tele_choice")) +write.csv(teleCommute, "teleCommute_frequency.csv", row.names = TRUE) + +# HH Transponder Ownership +transponder <- count(hh, c("transponder")) +write.csv(transponder, "transponder_ownership.csv", row.names = TRUE) + +# Micro-mobility +micro_r1 <- count(trips, c('micro_walkMode')) +micro_r2 <- count(trips, c('micro_trnAcc')) +micro_r3 <- count(trips, c('micro_trnEgr')) +colnames(micro_r1) <- c("micro_mode","trips") +colnames(micro_r2) <- c("micro_mode","trips") +colnames(micro_r3) <- c("micro_mode","trips") + +micro_v1 <- count(visitor_trips, c('micro_walkMode')) +micro_v2 <- count(visitor_trips, c('micro_trnAcc')) +micro_v3 <- count(visitor_trips, c('micro_trnEgr')) +colnames(micro_v1) <- c("micro_mode","trips") +colnames(micro_v2) <- c("micro_mode","trips") +colnames(micro_v3) <- c("micro_mode","trips") + +micromobility <- rbind(micro_r1,micro_r2,micro_r3,micro_v1,micro_v2,micro_v3) +micromobility_summary <- aggregate(trips ~ micro_mode, data=micromobility, FUN = sum) +write.csv(micromobility_summary, "micormobility.csv", row.names = TRUE) + +# Mandatory DC +workers <- wsLoc[wsLoc$WorkLocation > 0 & wsLoc$WorkLocation != 99999,] +students <- wsLoc[wsLoc$SchoolLocation > 0 & wsLoc$SchoolLocation != 88888,] + +# code distance bins +workers$distbin <- cut(workers$WorkLocationDistance, breaks = c(seq(0,50, by=1), 9999), labels = F, right = F) +students$distbin <- cut(students$SchoolLocationDistance, breaks = c(seq(0,50, by=1), 9999), labels = F, right = F) + +distBinCat <- data.frame(distbin = seq(1,51, by=1)) +districtList_df <- data.frame(id = districtList) + +# compute TLFDs by district and total +tlfd_work <- ddply(workers[,c("HDISTRICT", "distbin")], c("HDISTRICT", "distbin"), summarise, work = sum(HDISTRICT>0)) +tlfd_work <- cast(tlfd_work, distbin~HDISTRICT, value = "work", sum) +work_ditbins <- tlfd_work$distbin +tlfd_work <- transpose(tlfd_work[,!colnames(tlfd_work) %in% c("distbin")]) +tlfd_work$id <- row.names(tlfd_work) +tlfd_work <- merge(x = districtList_df, y = tlfd_work, by = "id", all.x = TRUE) +tlfd_work[is.na(tlfd_work)] <- 0 +tlfd_work <- transpose(tlfd_work[,!colnames(tlfd_work) %in% c("id")]) +tlfd_work <- cbind(data.frame(distbin = work_ditbins), tlfd_work) +tlfd_work$Total <- rowSums(tlfd_work[,!colnames(tlfd_work) %in% c("distbin")]) +names(tlfd_work) <- sub("V", "District_", names(tlfd_work)) +tlfd_work_df <- merge(x = distBinCat, y = tlfd_work, by = "distbin", all.x = TRUE) +tlfd_work_df[is.na(tlfd_work_df)] <- 0 + +tlfd_univ <- ddply(students[students$PersonType==3,c("HDISTRICT", "distbin")], c("HDISTRICT", "distbin"), summarise, univ = sum(HDISTRICT>0)) +tlfd_univ <- cast(tlfd_univ, distbin~HDISTRICT, value = "univ", sum) +univ_ditbins <- tlfd_univ$distbin +tlfd_univ <- transpose(tlfd_univ[,!colnames(tlfd_univ) %in% c("distbin")]) +tlfd_univ$id <- row.names(tlfd_univ) +tlfd_univ <- merge(x = districtList_df, y = tlfd_univ, by = "id", all.x = TRUE) +tlfd_univ[is.na(tlfd_univ)] <- 0 +tlfd_univ <- transpose(tlfd_univ[,!colnames(tlfd_univ) %in% c("id")]) +tlfd_univ <- cbind(data.frame(distbin = univ_ditbins), tlfd_univ) +tlfd_univ$Total <- rowSums(tlfd_univ[,!colnames(tlfd_univ) %in% c("distbin")]) +names(tlfd_univ) <- sub("V", "District_", names(tlfd_univ)) +tlfd_univ_df <- merge(x = distBinCat, y = tlfd_univ, by = "distbin", all.x = TRUE) +tlfd_univ_df[is.na(tlfd_univ_df)] <- 0 + +tlfd_schl <- ddply(students[students$PersonType>=6,c("HDISTRICT", "distbin")], c("HDISTRICT", "distbin"), summarise, schl = sum(HDISTRICT>0)) +tlfd_schl <- cast(tlfd_schl, distbin~HDISTRICT, value = "schl", sum) +schl_ditbins <- tlfd_schl$distbin +tlfd_schl <- transpose(tlfd_schl[,!colnames(tlfd_schl) %in% c("distbin")]) +tlfd_schl$id <- row.names(tlfd_schl) +tlfd_schl <- merge(x = districtList_df, y = tlfd_schl, by = "id", all.x = TRUE) +tlfd_schl[is.na(tlfd_schl)] <- 0 +tlfd_schl <- transpose(tlfd_schl[,!colnames(tlfd_schl) %in% c("id")]) +tlfd_schl <- cbind(data.frame(distbin = schl_ditbins), tlfd_schl) +tlfd_schl$Total <- rowSums(tlfd_schl[,!colnames(tlfd_schl) %in% c("distbin")]) +names(tlfd_schl) <- sub("V", "District_", names(tlfd_schl)) +tlfd_schl_df <- merge(x = distBinCat, y = tlfd_schl, by = "distbin", all.x = TRUE) +tlfd_schl_df[is.na(tlfd_schl_df)] <- 0 + +write.csv(tlfd_work_df, "workTLFD.csv", row.names = F) +write.csv(tlfd_univ_df, "univTLFD.csv", row.names = F) +write.csv(tlfd_schl_df, "schlTLFD.csv", row.names = F) + +cat("\n Average distance to workplace (Total): ", mean(workers$WorkLocationDistance, na.rm = TRUE)) +cat("\n Average distance to university (Total): ", mean(students$SchoolLocationDistance[students$PersonType==3], na.rm = TRUE)) +cat("\n Average distance to school (Total): ", mean(students$SchoolLocationDistance[students$PersonType>=6], na.rm = TRUE)) + +## Output avg trip lengths for visualizer +workTripLengths <- ddply(workers[,c("HDISTRICT", "WorkLocationDistance")], c("HDISTRICT"), summarise, work = mean(WorkLocationDistance)) +totalLength <- data.frame("Total", mean(workers$WorkLocationDistance)) +colnames(totalLength) <- colnames(workTripLengths) +workTripLengths <- rbind(workTripLengths, totalLength) + +univTripLengths <- ddply(students[students$PersonType==3,c("HDISTRICT", "SchoolLocationDistance")], c("HDISTRICT"), summarise, univ = mean(SchoolLocationDistance)) +totalLength <- data.frame("Total", mean(students$SchoolLocationDistance[students$PersonType==3])) +colnames(totalLength) <- colnames(univTripLengths) +univTripLengths <- rbind(univTripLengths, totalLength) + +schlTripLengths <- ddply(students[students$PersonType>=6,c("HDISTRICT", "SchoolLocationDistance")], c("HDISTRICT"), summarise, schl = mean(SchoolLocationDistance)) +totalLength <- data.frame("Total", mean(students$SchoolLocationDistance[students$PersonType>=6])) +colnames(totalLength) <- colnames(schlTripLengths) +schlTripLengths <- rbind(schlTripLengths, totalLength) + +mandTripLengths <- cbind(workTripLengths, univTripLengths$univ, schlTripLengths$schl) +colnames(mandTripLengths) <- c("District", "Work", "Univ", "Schl") +write.csv(mandTripLengths, "mandTripLengths.csv", row.names = F) + +# Work from home [for each district and total] +districtWorkers <- ddply(wsLoc[wsLoc$WorkLocation > 0,c("HDISTRICT")], c("HDISTRICT"), summarise, workers = sum(HDISTRICT>0)) +districtWfh <- ddply(wsLoc[wsLoc$WorkLocation==99999,c("HDISTRICT", "WorkLocation")], c("HDISTRICT"), summarise, wfh = sum(HDISTRICT>0)) +wfh_summary <- cbind(districtWorkers, districtWfh$wfh) +colnames(wfh_summary) <- c("District", "Workers", "WFH") +totalwfh <- data.frame("Total", sum(wsLoc$WorkLocation>0), sum(wsLoc$WorkLocation==99999)) +colnames(totalwfh) <- colnames(wfh_summary) +wfh_summary <- rbind(wfh_summary, totalwfh) +write.csv(wfh_summary, "wfh_summary.csv", row.names = F) +write.csv(totalwfh, "wfh_summary_region.csv", row.names = F) + +# County-County Flows +countyFlows <- xtabs(~HDISTRICT+WDISTRICT, data = workers) +countyFlows[is.na(countyFlows)] <- 0 +countyFlows <- addmargins(as.table(countyFlows)) +countyFlows <- as.data.frame.matrix(countyFlows) +colnames(countyFlows)[colnames(countyFlows)=="Sum"] <- "Total" +colnames(countyFlows) <- paste("District", colnames(countyFlows), sep = "_") +rownames(countyFlows)[rownames(countyFlows)=="Sum"] <- "Total" +rownames(countyFlows) <- paste("District", rownames(countyFlows), sep = "_") +write.csv(countyFlows, "countyFlows.csv", row.names = T) + +# Process Tour file +#------------------ +tours$PERTYPE <- tours$person_type +tours$DISTMILE <- tours$tour_distance +tours$HHVEH <- hh$HHVEH[match(tours$hh_id, hh$hh_id)] +tours$ADULTS <- hh$ADULTS[match(tours$hh_id, hh$hh_id)] +tours$AUTOSUFF[tours$HHVEH == 0] <- 0 +tours$AUTOSUFF[tours$HHVEH < tours$ADULTS & tours$HHVEH > 0] <- 1 +tours$AUTOSUFF[tours$HHVEH >= tours$ADULTS & tours$HHVEH > 0] <- 2 + +tours$num_tot_stops <- tours$num_ob_stops + tours$num_ib_stops + +tours$OTAZ <- mazCorrespondence$taz[match(tours$orig_mgra, mazCorrespondence$mgra)] +tours$DTAZ <- mazCorrespondence$taz[match(tours$dest_mgra, mazCorrespondence$mgra)] + +tours$oindex<-match(tours$OTAZ, skimLookUp$Lookup) +tours$dindex<-match(tours$DTAZ, skimLookUp$Lookup) +tours$SKIMDIST<-DST_SKM[cbind(tours$oindex, tours$dindex)] + + +unique_joint_tours$HHVEH <- hh$HHVEH[match(unique_joint_tours$hh_id, hh$hh_id)] +unique_joint_tours$ADULTS <- hh$ADULTS[match(unique_joint_tours$hh_id, hh$hh_id)] +unique_joint_tours$AUTOSUFF[unique_joint_tours$HHVEH == 0] <- 0 +unique_joint_tours$AUTOSUFF[unique_joint_tours$HHVEH < unique_joint_tours$ADULTS & unique_joint_tours$HHVEH > 0] <- 1 +unique_joint_tours$AUTOSUFF[unique_joint_tours$HHVEH >= unique_joint_tours$ADULTS] <- 2 + +#Code tour purposes +tours$TOURPURP[tours$tour_purpose=="Work"] <- 1 +tours$TOURPURP[tours$tour_purpose=="University"] <- 2 +tours$TOURPURP[tours$tour_purpose=="School"] <- 3 +tours$TOURPURP[tours$tour_purpose=="Escort"] <- 4 +tours$TOURPURP[tours$tour_purpose=="Shop"] <- 5 +tours$TOURPURP[tours$tour_purpose=="Maintenance"] <- 6 +tours$TOURPURP[tours$tour_purpose=="Eating Out"] <- 7 +tours$TOURPURP[tours$tour_purpose=="Visiting"] <- 8 +tours$TOURPURP[tours$tour_purpose=="Discretionary"] <- 9 +tours$TOURPURP[tours$tour_purpose=="Work-Based"] <- 10 + +#[0:Mandatory, 1: Indi Non Mand, 2: At Work] +tours$TOURCAT[tours$tour_purpose=="Work"] <- 0 +tours$TOURCAT[tours$tour_purpose=="University"] <- 0 +tours$TOURCAT[tours$tour_purpose=="School"] <- 0 +tours$TOURCAT[tours$tour_purpose=="Escort"] <- 1 +tours$TOURCAT[tours$tour_purpose=="Shop"] <- 1 +tours$TOURCAT[tours$tour_purpose=="Maintenance"] <- 1 +tours$TOURCAT[tours$tour_purpose=="Eating Out"] <- 1 +tours$TOURCAT[tours$tour_purpose=="Visiting"] <- 1 +tours$TOURCAT[tours$tour_purpose=="Discretionary"] <- 1 +tours$TOURCAT[tours$tour_purpose=="Work-Based"] <- 2 + +#compute duration +tours$tourdur <- tours$end_period - tours$start_period + 1 #[to match survey] + +tours$TOURMODE <- tours$tour_mode +#tours$TOURMODE[tours$tour_mode==1] <- 1 +#tours$TOURMODE[tours$tour_mode==2] <- 2 +#tours$TOURMODE[tours$tour_mode==3] <- 3 +#tours$TOURMODE[tours$tour_mode>=7 & tours$tour_mode<=13] <- tours$tour_mode[tours$tour_mode>=7 & tours$tour_mode<=13]-3 +#tours$TOURMODE[tours$tour_mode>=14 & tours$tour_mode<=15] <- 11 +#tours$TOURMODE[tours$tour_mode==16] <- 12 + +# exclude school escorting stop from ride sharing mandatory tours + +unique_joint_tours$JOINT_PURP[unique_joint_tours$tour_purpose=='Shop'] <- 5 +unique_joint_tours$JOINT_PURP[unique_joint_tours$tour_purpose=='Maintenance'] <- 6 +unique_joint_tours$JOINT_PURP[unique_joint_tours$tour_purpose=='Eating Out'] <- 7 +unique_joint_tours$JOINT_PURP[unique_joint_tours$tour_purpose=='Visiting'] <- 8 +unique_joint_tours$JOINT_PURP[unique_joint_tours$tour_purpose=='Discretionary'] <- 9 + +unique_joint_tours$NUMBER_HH <- as.integer((nchar(as.character(unique_joint_tours$tour_participants))+1)/2) + +# get participant IDs +unique_joint_tours$PER1[unique_joint_tours$NUMBER_HH>=1] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=1]), 1, 1) +unique_joint_tours$PER2[unique_joint_tours$NUMBER_HH>=2] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=2]), 3, 3) +unique_joint_tours$PER3[unique_joint_tours$NUMBER_HH>=3] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=3]), 5, 5) +unique_joint_tours$PER4[unique_joint_tours$NUMBER_HH>=4] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=4]), 7, 7) +unique_joint_tours$PER5[unique_joint_tours$NUMBER_HH>=5] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=5]), 9, 9) +unique_joint_tours$PER6[unique_joint_tours$NUMBER_HH>=6] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=6]), 11, 11) +unique_joint_tours$PER7[unique_joint_tours$NUMBER_HH>=7] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=7]), 13, 13) +unique_joint_tours$PER8[unique_joint_tours$NUMBER_HH>=8] <- substr(as.character(unique_joint_tours$tour_participants[unique_joint_tours$NUMBER_HH>=8]), 15, 15) + +unique_joint_tours[is.na(unique_joint_tours)] <- 0 + +# get person type for each participant +unique_joint_tours$PTYPE1 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER1, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] +unique_joint_tours$PTYPE2 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER2, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] +unique_joint_tours$PTYPE3 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER3, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] +unique_joint_tours$PTYPE4 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER4, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] +unique_joint_tours$PTYPE5 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER5, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] +unique_joint_tours$PTYPE6 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER6, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] +unique_joint_tours$PTYPE7 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER7, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] +unique_joint_tours$PTYPE8 <- per$PERTYPE[match(paste(unique_joint_tours$hh_id,unique_joint_tours$PER8, sep = "-"), paste(per$hh_id,per$person_num, sep = "-"))] + +unique_joint_tours[is.na(unique_joint_tours)] <- 0 + +unique_joint_tours$num_tot_stops <- unique_joint_tours$num_ob_stops + unique_joint_tours$num_ib_stops + +unique_joint_tours$OTAZ <- mazCorrespondence$taz[match(unique_joint_tours$orig_mgra, mazCorrespondence$mgra)] +unique_joint_tours$DTAZ <- mazCorrespondence$taz[match(unique_joint_tours$dest_mgra, mazCorrespondence$mgra)] + +#compute duration +unique_joint_tours$tourdur <- unique_joint_tours$end_period - unique_joint_tours$start_period + 1 #[to match survye] + +unique_joint_tours$TOURMODE <- unique_joint_tours$tour_mode +#unique_joint_tours$TOURMODE[unique_joint_tours$tour_mode<=2] <- 1 +#unique_joint_tours$TOURMODE[unique_joint_tours$tour_mode>=3 & unique_joint_tours$tour_mode<=4] <- 2 +#unique_joint_tours$TOURMODE[unique_joint_tours$tour_mode>=5 & unique_joint_tours$tour_mode<=6] <- 3 +#unique_joint_tours$TOURMODE[unique_joint_tours$tour_mode>=7 & unique_joint_tours$tour_mode<=13] <- unique_joint_tours$tour_mode[unique_joint_tours$tour_mode>=7 & unique_joint_tours$tour_mode<=13]-3 +#unique_joint_tours$TOURMODE[unique_joint_tours$tour_mode>=14 & unique_joint_tours$tour_mode<=15] <- 11 +#unique_joint_tours$TOURMODE[unique_joint_tours$tour_mode==16] <- 12 + +# ---- +# this part is added by nagendra.dhakar@rsginc.com from binny.paul@rsginc.com soabm summaries + +# create a combined temp tour file for creating stop freq model summary +temp_tour1 <- tours[,c("TOURPURP","num_ob_stops","num_ib_stops")] +temp_tour2 <- unique_joint_tours[,c("JOINT_PURP","num_ob_stops","num_ib_stops")] +colnames(temp_tour2) <- colnames(temp_tour1) +temp_tour <- rbind(temp_tour1,temp_tour2) + +# code stop frequency model alternatives +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==0 & temp_tour$num_ib_stops==0] <- 1 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==0 & temp_tour$num_ib_stops==1] <- 2 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==0 & temp_tour$num_ib_stops==2] <- 3 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==0 & temp_tour$num_ib_stops>=3] <- 4 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==1 & temp_tour$num_ib_stops==0] <- 5 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==1 & temp_tour$num_ib_stops==1] <- 6 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==1 & temp_tour$num_ib_stops==2] <- 7 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==1 & temp_tour$num_ib_stops>=3] <- 8 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==2 & temp_tour$num_ib_stops==0] <- 9 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==2 & temp_tour$num_ib_stops==1] <- 10 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==2 & temp_tour$num_ib_stops==2] <- 11 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops==2 & temp_tour$num_ib_stops>=3] <- 12 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops>=3 & temp_tour$num_ib_stops==0] <- 13 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops>=3 & temp_tour$num_ib_stops==1] <- 14 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops>=3 & temp_tour$num_ib_stops==2] <- 15 +temp_tour$STOP_FREQ_ALT[temp_tour$num_ob_stops>=3 & temp_tour$num_ib_stops>=3] <- 16 +temp_tour$STOP_FREQ_ALT[is.na(temp_tour$STOP_FREQ_ALT)] <- 0 + +stopFreqModel_summary <- xtabs(~STOP_FREQ_ALT+TOURPURP, data = temp_tour[temp_tour$TOURPURP<=10,]) +write.csv(stopFreqModel_summary, "stopFreqModel_summary.csv", row.names = T) + +# ------ + +# Process Trip file +#------------------ +trips$TOURMODE <- trips$tour_mode +trips$TRIPMODE <- trips$trip_mode + +#trips$TOURMODE[trips$tour_mode<=2] <- 1 +#trips$TOURMODE[trips$tour_mode>=3 & trips$tour_mode<=4] <- 2 +#trips$TOURMODE[trips$tour_mode>=5 & trips$tour_mode<=6] <- 3 +#trips$TOURMODE[trips$tour_mode>=7 & trips$tour_mode<=13] <- trips$tour_mode[trips$tour_mode>=7 & trips$tour_mode<=13]-3 +#trips$TOURMODE[trips$tour_mode>=14 & trips$tour_mode<=15] <- 11 +#trips$TOURMODE[trips$tour_mode==16] <- 12 +# +#trips$TRIPMODE[trips$trip_mode<=2] <- 1 +#trips$TRIPMODE[trips$trip_mode>=3 & trips$trip_mode<=4] <- 2 +#trips$TRIPMODE[trips$trip_mode>=5 & trips$trip_mode<=6] <- 3 +#trips$TRIPMODE[trips$trip_mode>=7 & trips$trip_mode<=13] <- trips$trip_mode[trips$trip_mode>=7 & trips$trip_mode<=13]-3 +#trips$TRIPMODE[trips$trip_mode>=14 & trips$trip_mode<=15] <- 11 +#trips$TRIPMODE[trips$trip_mode==16] <- 12 + +#Code tour purposes +trips$TOURPURP[trips$tour_purpose=="Home"] <- 0 +trips$TOURPURP[trips$tour_purpose=="Work"] <- 1 +trips$TOURPURP[trips$tour_purpose=="University"] <- 2 +trips$TOURPURP[trips$tour_purpose=="School"] <- 3 +trips$TOURPURP[trips$tour_purpose=="Escort"] <- 4 +trips$TOURPURP[trips$tour_purpose=="Shop"] <- 5 +trips$TOURPURP[trips$tour_purpose=="Maintenance"] <- 6 +trips$TOURPURP[trips$tour_purpose=="Eating Out"] <- 7 +trips$TOURPURP[trips$tour_purpose=="Visiting"] <- 8 +trips$TOURPURP[trips$tour_purpose=="Discretionary"] <- 9 +trips$TOURPURP[trips$tour_purpose=="Work-Based" | trips$tour_purpose=="work related"] <- 10 + +trips$OPURP[trips$orig_purpose=="Home"] <- 0 +trips$OPURP[trips$orig_purpose=="Work"] <- 1 +trips$OPURP[trips$orig_purpose=="University"] <- 2 +trips$OPURP[trips$orig_purpose=="School"] <- 3 +trips$OPURP[trips$orig_purpose=="Escort"] <- 4 +trips$OPURP[trips$orig_purpose=="Shop"] <- 5 +trips$OPURP[trips$orig_purpose=="Maintenance"] <- 6 +trips$OPURP[trips$orig_purpose=="Eating Out"] <- 7 +trips$OPURP[trips$orig_purpose=="Visiting"] <- 8 +trips$OPURP[trips$orig_purpose=="Discretionary"] <- 9 +trips$OPURP[trips$orig_purpose=="Work-Based" | trips$orig_purpose=="work related"] <- 10 + +trips$DPURP[trips$dest_purpose=="Home"] <- 0 +trips$DPURP[trips$dest_purpose=="Work"] <- 1 +trips$DPURP[trips$dest_purpose=="University"] <- 2 +trips$DPURP[trips$dest_purpose=="School"] <- 3 +trips$DPURP[trips$dest_purpose=="Escort"] <- 4 +trips$DPURP[trips$dest_purpose=="Shop"] <- 5 +trips$DPURP[trips$dest_purpose=="Maintenance"] <- 6 +trips$DPURP[trips$dest_purpose=="Eating Out"] <- 7 +trips$DPURP[trips$dest_purpose=="Visiting"] <- 8 +trips$DPURP[trips$dest_purpose=="Discretionary"] <- 9 +trips$DPURP[trips$dest_purpose=="Work-Based" | trips$dest_purpose=="work related"] <- 10 + +#[0:Mandatory, 1: Indi Non Mand, 3: At Work] +trips$TOURCAT[trips$tour_purpose=="Work"] <- 0 +trips$TOURCAT[trips$tour_purpose=="University"] <- 0 +trips$TOURCAT[trips$tour_purpose=="School"] <- 0 +trips$TOURCAT[trips$tour_purpose=="Escort"] <- 1 +trips$TOURCAT[trips$tour_purpose=="Shop"] <- 1 +trips$TOURCAT[trips$tour_purpose=="Maintenance"] <- 1 +trips$TOURCAT[trips$tour_purpose=="Eating Out"] <- 1 +trips$TOURCAT[trips$tour_purpose=="Visiting"] <- 1 +trips$TOURCAT[trips$tour_purpose=="Discretionary"] <- 1 +trips$TOURCAT[trips$tour_purpose=="Work-Based"] <- 2 + +#Mark stops and get other attributes +nr <- nrow(trips) +trips$inb_next <- 0 +trips$inb_next[1:nr-1] <- trips$inbound[2:nr] +trips$stops[trips$DPURP>0 & ((trips$inbound==0 & trips$inb_next==0) | (trips$inbound==1 & trips$inb_next==1))] <- 1 +trips$stops[is.na(trips$stops)] <- 0 + +trips$OTAZ <- mazCorrespondence$taz[match(trips$orig_mgra, mazCorrespondence$mgra)] +trips$DTAZ <- mazCorrespondence$taz[match(trips$dest_mgra, mazCorrespondence$mgra)] + +trips$TOUROTAZ <- tours$OTAZ[match(trips$hh_id*1000+trips$person_num*100+trips$TOURCAT*10+trips$tour_id, + tours$hh_id*1000+tours$person_num*100+tours$TOURCAT*10+tours$tour_id)] +trips$TOURDTAZ <- tours$DTAZ[match(trips$hh_id*1000+trips$person_num*100+trips$TOURCAT*10+trips$tour_id, + tours$hh_id*1000+tours$person_num*100+tours$TOURCAT*10+tours$tour_id)] + +# trips$od_dist <- DST_SKM$dist[match(paste(trips$OTAZ, trips$DTAZ, sep = "-"), paste(DST_SKM$o, DST_SKM$d, sep = "-"))] +trips$oindex<-match(trips$OTAZ, skimLookUp$Lookup) +trips$dindex<-match(trips$DTAZ, skimLookUp$Lookup) +trips$od_dist<-DST_SKM[cbind(trips$oindex, trips$dindex)] + +#create stops table +stops <- trips[trips$stops==1,] + +stops$finaldestTAZ[stops$inbound==0] <- stops$TOURDTAZ[stops$inbound==0] +stops$finaldestTAZ[stops$inbound==1] <- stops$TOUROTAZ[stops$inbound==1] + +stops$oindex<-match(stops$OTAZ, skimLookUp$Lookup) +stops$dindex<-match(stops$finaldestTAZ, skimLookUp$Lookup) +stops$od_dist <- DST_SKM[cbind(stops$oindex, stops$dindex)] + +stops$oindex2<-match(stops$OTAZ, skimLookUp$Lookup) +stops$dindex2<-match(stops$DTAZ, skimLookUp$Lookup) +stops$os_dist <- DST_SKM[cbind(stops$oindex2, stops$dindex2)] + +stops$oindex3<-match(stops$DTAZ, skimLookUp$Lookup) +stops$dindex3<-match(stops$finaldestTAZ, skimLookUp$Lookup) +stops$sd_dist <- DST_SKM[cbind(stops$oindex3, stops$dindex3)] + +stops$out_dir_dist <- stops$os_dist + stops$sd_dist - stops$od_dist + +#joint trip + +jtrips$TOURMODE <- jtrips$tour_mode +#jtrips$TOURMODE[jtrips$tour_mode<=2] <- 1 +#jtrips$TOURMODE[jtrips$tour_mode>=3 & jtrips$tour_mode<=4] <- 2 +#jtrips$TOURMODE[jtrips$tour_mode>=5 & jtrips$tour_mode<=6] <- 3 +#jtrips$TOURMODE[jtrips$tour_mode>=7 & jtrips$tour_mode<=13] <- jtrips$tour_mode[jtrips$tour_mode>=7 & jtrips$tour_mode<=13]-3 +#jtrips$TOURMODE[jtrips$tour_mode>=14 & jtrips$tour_mode<=15] <- 11 +#jtrips$TOURMODE[jtrips$tour_mode==16] <- 12 + +jtrips$TRIPMODE <- jtrips$trip_mode +#jtrips$TRIPMODE[jtrips$trip_mode<=2] <- 1 +#jtrips$TRIPMODE[jtrips$trip_mode>=3 & jtrips$trip_mode<=4] <- 2 +#jtrips$TRIPMODE[jtrips$trip_mode>=5 & jtrips$trip_mode<=6] <- 3 +#jtrips$TRIPMODE[jtrips$trip_mode>=7 & jtrips$trip_mode<=13] <- jtrips$trip_mode[jtrips$trip_mode>=7 & jtrips$trip_mode<=13]-3 +#jtrips$TRIPMODE[jtrips$trip_mode>=14 & jtrips$trip_mode<=15] <- 11 +#jtrips$TRIPMODE[jtrips$trip_mode==16] <- 12 + +#Code joint tour purposes +jtrips$TOURPURP[jtrips$tour_purpose=="Work"] <- 1 +jtrips$TOURPURP[jtrips$tour_purpose=="University"] <- 2 +jtrips$TOURPURP[jtrips$tour_purpose=="School"] <- 3 +jtrips$TOURPURP[jtrips$tour_purpose=="Escort"] <- 4 +jtrips$TOURPURP[jtrips$tour_purpose=="Shop"] <- 5 +jtrips$TOURPURP[jtrips$tour_purpose=="Maintenance"] <- 6 +jtrips$TOURPURP[jtrips$tour_purpose=="Eating Out"] <- 7 +jtrips$TOURPURP[jtrips$tour_purpose=="Visiting"] <- 8 +jtrips$TOURPURP[jtrips$tour_purpose=="Discretionary"] <- 9 +jtrips$TOURPURP[jtrips$tour_purpose=="Work-Based" | jtrips$tour_purpose=="work related"] <- 10 + +jtrips$OPURP[jtrips$orig_purpose=="Home"] <- 0 +jtrips$OPURP[jtrips$orig_purpose=="Work"] <- 1 +jtrips$OPURP[jtrips$orig_purpose=="University"] <- 2 +jtrips$OPURP[jtrips$orig_purpose=="School"] <- 3 +jtrips$OPURP[jtrips$orig_purpose=="Escort"] <- 4 +jtrips$OPURP[jtrips$orig_purpose=="Shop"] <- 5 +jtrips$OPURP[jtrips$orig_purpose=="Maintenance"] <- 6 +jtrips$OPURP[jtrips$orig_purpose=="Eating Out"] <- 7 +jtrips$OPURP[jtrips$orig_purpose=="Visiting"] <- 8 +jtrips$OPURP[jtrips$orig_purpose=="Discretionary"] <- 9 +jtrips$OPURP[jtrips$orig_purpose=="Work-Based" | jtrips$orig_purpose=="work related"] <- 10 + +jtrips$DPURP[jtrips$dest_purpose=="Home"] <- 0 +jtrips$DPURP[jtrips$dest_purpose=="Work"] <- 1 +jtrips$DPURP[jtrips$dest_purpose=="University"] <- 2 +jtrips$DPURP[jtrips$dest_purpose=="School"] <- 3 +jtrips$DPURP[jtrips$dest_purpose=="Escort"] <- 4 +jtrips$DPURP[jtrips$dest_purpose=="Shop"] <- 5 +jtrips$DPURP[jtrips$dest_purpose=="Maintenance"] <- 6 +jtrips$DPURP[jtrips$dest_purpose=="Eating Out"] <- 7 +jtrips$DPURP[jtrips$dest_purpose=="Visiting"] <- 8 +jtrips$DPURP[jtrips$dest_purpose=="Discretionary"] <- 9 +jtrips$DPURP[jtrips$dest_purpose=="Work-Based" | jtrips$dest_purpose=="work related"] <- 10 + +#[0:Mandatory, 1: Indi Non Mand, 3: At Work] +jtrips$TOURCAT[jtrips$tour_purpose=="Work"] <- 0 +jtrips$TOURCAT[jtrips$tour_purpose=="University"] <- 0 +jtrips$TOURCAT[jtrips$tour_purpose=="School"] <- 0 +jtrips$TOURCAT[jtrips$tour_purpose=="Escort"] <- 1 +jtrips$TOURCAT[jtrips$tour_purpose=="Shop"] <- 1 +jtrips$TOURCAT[jtrips$tour_purpose=="Maintenance"] <- 1 +jtrips$TOURCAT[jtrips$tour_purpose=="Eating Out"] <- 1 +jtrips$TOURCAT[jtrips$tour_purpose=="Visiting"] <- 1 +jtrips$TOURCAT[jtrips$tour_purpose=="Discretionary"] <- 1 +jtrips$TOURCAT[jtrips$tour_purpose=="Work-Based"] <- 2 + +#Mark stops and get other attributes +nr <- nrow(jtrips) +jtrips$inb_next <- 0 +jtrips$inb_next[1:nr-1] <- jtrips$inbound[2:nr] +jtrips$stops[jtrips$DPURP>0 & ((jtrips$inbound==0 & jtrips$inb_next==0) | (jtrips$inbound==1 & jtrips$inb_next==1))] <- 1 +jtrips$stops[is.na(jtrips$stops)] <- 0 + +jtrips$OTAZ <- mazCorrespondence$taz[match(jtrips$orig_mgra, mazCorrespondence$mgra)] +jtrips$DTAZ <- mazCorrespondence$taz[match(jtrips$dest_mgra, mazCorrespondence$mgra)] + +jtrips$TOUROTAZ <- unique_joint_tours$OTAZ[match(jtrips$hh_id*1000+jtrips$tour_id, + unique_joint_tours$hh_id*1000+unique_joint_tours$tour_id)] +jtrips$TOURDTAZ <- unique_joint_tours$DTAZ[match(jtrips$hh_id*1000+jtrips$tour_id, + unique_joint_tours$hh_id*1000+unique_joint_tours$tour_id)] + +#create stops table +jstops <- jtrips[jtrips$stops==1,] + +jstops$finaldestTAZ[jstops$inbound==0] <- jstops$TOURDTAZ[jstops$inbound==0] +jstops$finaldestTAZ[jstops$inbound==1] <- jstops$TOUROTAZ[jstops$inbound==1] + +jstops$oindex<-match(jstops$OTAZ, skimLookUp$Lookup) +jstops$dindex<-match(jstops$finaldestTAZ, skimLookUp$Lookup) +jstops$od_dist <- DST_SKM[cbind(jstops$oindex, jstops$dindex)] + +jstops$oindex2<-match(jstops$OTAZ, skimLookUp$Lookup) +jstops$dindex2<-match(jstops$DTAZ, skimLookUp$Lookup) +jstops$os_dist <- DST_SKM[cbind(jstops$oindex2, jstops$dindex2)] + +jstops$oindex3<-match(jstops$DTAZ, skimLookUp$Lookup) +jstops$dindex3<-match(jstops$finaldestTAZ, skimLookUp$Lookup) +jstops$sd_dist <- DST_SKM[cbind(jstops$oindex3, jstops$dindex3)] + +jstops$out_dir_dist <- jstops$os_dist + jstops$sd_dist - jstops$od_dist + +#--------------------------------------------------------------------------- + +# Recode workrelated tours which are not at work subtour as work tour +#tours$TOURPURP[tours$TOURPURP == 10 & tours$IS_SUBTOUR == 0] <- 1 + +workCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 1") #[excluding at work subtours] +schlCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 2 | TOURPURP == 3") +inmCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP>=4 & TOURPURP<=9") + +# ----------------------- +# added for calibration by nagendra.dhakar@rsginc.com +# for indivudal NM tour generation +workCounts_temp <- workCounts +schlCounts_temp <- schlCounts +inmCounts_temp <- count(tours, c("hh_id", "person_num"), "TOURPURP>4 & TOURPURP<=9") #excluding school escort tours +atWorkCounts_temp <- count(tours, c("hh_id", "person_num"), "TOURPURP == 10") +escortCounts_temp <- count(tours, c("hh_id", "person_num"), "TOURPURP==4") + + +colnames(workCounts_temp)[3] <- "freq_work" +colnames(schlCounts_temp)[3] <- "freq_schl" +colnames(inmCounts_temp)[3] <- "freq_inm" +colnames(atWorkCounts_temp)[3] <- "freq_atwork" +colnames(escortCounts_temp)[3] <- "freq_escort" + +temp <- merge(workCounts_temp, schlCounts_temp, by = c("hh_id", "person_num")) +temp1 <- merge(temp, inmCounts_temp, by = c("hh_id", "person_num")) +temp1$freq_m <- temp1$freq_work + temp1$freq_schl +temp1$freq_itours <- temp1$freq_m+temp1$freq_inm + +#joint tours +#identify persons that made joint tour +#temp_joint <- melt(unique_joint_tours[,c("hh_id","tour_id" ,"PER1", "PER2", "PER3", "PER4", "PER5", "PER6", "PER7", "PER8")], id = c("hh_id","tour_id")) +temp_joint <- melt(unique_joint_tours[,c("hh_id","tour_id" ,"PER1", "PER2", "PER3", "PER4", "PER5", "PER6", "PER7")], id = c("hh_id","tour_id")) +colnames(temp_joint) <- c("hh_id", "tour_id", "var", "person_num") +temp_joint <- as.data.frame(temp_joint) +temp_joint$person_num <- as.integer(temp_joint$person_num) +temp_joint$joint<- 0 +temp_joint$joint[temp_joint$person_num>0] <- 1 + +temp_joint <- temp_joint[temp_joint$joint==1,] +person_unique_joint <- aggregate(joint~hh_id+person_num, temp_joint, sum) + +temp2 <- merge(temp1, person_unique_joint, by = c("hh_id", "person_num"), all = T) +temp2 <- merge(temp2, atWorkCounts_temp, by = c("hh_id", "person_num"), all = T) +temp2 <- merge(temp2, escortCounts_temp, by = c("hh_id", "person_num"), all = T) +temp2[is.na(temp2)] <- 0 + +#add number of joint tours to non-mandatory +temp2$freq_nm <- temp2$freq_inm + temp2$joint + +#get person type +temp2$PERTYPE <- per$PERTYPE[match(temp2$hh_id*10+temp2$person_num,per$hh_id*10+per$person_num)] + +#total tours +temp2$total_tours <- temp2$freq_nm+temp2$freq_m+temp2$freq_atwork+temp2$freq_escort + +persons_mand <- temp2[temp2$freq_m>0,] #persons with atleast 1 mandatory tours +persons_nomand <- temp2[temp2$freq_m==0,] #active persons with 0 mandatory tours + +freq_nmtours_mand <- count(persons_mand, c("PERTYPE","freq_nm")) +freq_nmtours_nomand <- count(persons_nomand, c("PERTYPE","freq_nm")) +test <- count(temp2, c("PERTYPE","freq_inm","freq_m","freq_nm","freq_atwork","freq_escort")) +write.csv(test, "tour_rate_debug.csv", row.names = F) +write.csv(temp2,"temp2.csv", row.names = F) + +write.table("Non-Mandatory Tours for Persons with at-least 1 Mandatory Tour", "indivNMTourFreq.csv", sep = ",", row.names = F, append = F) +write.table(freq_nmtours_mand, "indivNMTourFreq.csv", sep = ",", row.names = F, append = T) +write.table("Non-Mandatory Tours for Active Persons with 0 Mandatory Tour", "indivNMTourFreq.csv", sep = ",", row.names = F, append = T) +write.table(freq_nmtours_nomand, "indivNMTourFreq.csv", sep = ",", row.names = F, append = TRUE) + +# end of addition for calibration +# ----------------------- + + +# ---------------------- +# added for calibration by nagendra.dhakar@rsginc.com + +i4tourCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 4") +i5tourCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 5") +i6tourCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 6") +i7tourCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 7") +i8tourCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 8") +i9tourCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP == 9") + +# end of addition for calibration +# ----------------------- + +tourCounts <- count(tours, c("hh_id", "person_num"), "TOURPURP <= 9") #number of tours per person [excluding at work subtours] +joint5 <- count(unique_joint_tours, c("hh_id"), "JOINT_PURP==5") +joint6 <- count(unique_joint_tours, c("hh_id"), "JOINT_PURP==6") +joint7 <- count(unique_joint_tours, c("hh_id"), "JOINT_PURP==7") +joint8 <- count(unique_joint_tours, c("hh_id"), "JOINT_PURP==8") +joint9 <- count(unique_joint_tours, c("hh_id"), "JOINT_PURP==9") + +hh$joint5 <- joint5$freq[match(hh$hh_id, joint5$hh_id)] +hh$joint6 <- joint6$freq[match(hh$hh_id, joint6$hh_id)] +hh$joint7 <- joint7$freq[match(hh$hh_id, joint7$hh_id)] +hh$joint8 <- joint8$freq[match(hh$hh_id, joint8$hh_id)] +hh$joint9 <- joint9$freq[match(hh$hh_id, joint9$hh_id)] +hh$jtours <- hh$joint5+hh$joint6+hh$joint7+hh$joint8+hh$joint9 + +hh$joint5[is.na(hh$joint5)] <- 0 +hh$joint6[is.na(hh$joint6)] <- 0 +hh$joint7[is.na(hh$joint7)] <- 0 +hh$joint8[is.na(hh$joint8)] <- 0 +hh$joint9[is.na(hh$joint9)] <- 0 +hh$jtours[is.na(hh$jtours)] <- 0 + +#joint tour indicator +hh$JOINT <- 0 +hh$JOINT[substr(hh$cdap_pattern, nchar(as.character(hh$cdap_pattern)), nchar(as.character(hh$cdap_pattern)))=="j"] <- 1 + +# code JTF category +hh$jtf[hh$jtours==0] <- 1 +hh$jtf[hh$joint5==1] <- 2 +hh$jtf[hh$joint6==1] <- 3 +hh$jtf[hh$joint7==1] <- 4 +hh$jtf[hh$joint8==1] <- 5 +hh$jtf[hh$joint9==1] <- 6 + +hh$jtf[hh$joint5>=2] <- 7 +hh$jtf[hh$joint6>=2] <- 8 +hh$jtf[hh$joint7>=2] <- 9 +hh$jtf[hh$joint8>=2] <- 10 +hh$jtf[hh$joint9>=2] <- 11 + +hh$jtf[hh$joint5>=1 & hh$joint6>=1] <- 12 +hh$jtf[hh$joint5>=1 & hh$joint7>=1] <- 13 +hh$jtf[hh$joint5>=1 & hh$joint8>=1] <- 14 +hh$jtf[hh$joint5>=1 & hh$joint9>=1] <- 15 + +hh$jtf[hh$joint6>=1 & hh$joint7>=1] <- 16 +hh$jtf[hh$joint6>=1 & hh$joint8>=1] <- 17 +hh$jtf[hh$joint6>=1 & hh$joint9>=1] <- 18 + +hh$jtf[hh$joint7>=1 & hh$joint8>=1] <- 19 +hh$jtf[hh$joint7>=1 & hh$joint9>=1] <- 20 + +hh$jtf[hh$joint8>=1 & hh$joint9>=1] <- 21 + +per$workTours <- workCounts$freq[match(per$hh_id*10+per$person_num, workCounts$hh_id*10+workCounts$person_num)] +per$schlTours <- schlCounts$freq[match(per$hh_id*10+per$person_num, schlCounts$hh_id*10+schlCounts$person_num)] +per$inmTours <- inmCounts$freq[match(per$hh_id*10+per$person_num, inmCounts$hh_id*10+inmCounts$person_num)] +per$inmTours[is.na(per$inmTours)] <- 0 +per$numTours <- tourCounts$freq[match(per$hh_id*10+per$person_num, tourCounts$hh_id*10+tourCounts$person_num)] +per$numTours[is.na(per$numTours)] <- 0 + +# --------------------------------------------------- +# added for calibration by nagendra.dhakar@rsginc.com + +per$i4numTours <- i4tourCounts$freq[match(per$hh_id*10+per$person_num, i4tourCounts$hh_id*10+i4tourCounts$person_num)] +per$i4numTours[is.na(per$i4numTours)] <- 0 +per$i5numTours <- i5tourCounts$freq[match(per$hh_id*10+per$person_num, i5tourCounts$hh_id*10+i5tourCounts$person_num)] +per$i5numTours[is.na(per$i5numTours)] <- 0 +per$i6numTours <- i6tourCounts$freq[match(per$hh_id*10+per$person_num, i6tourCounts$hh_id*10+i6tourCounts$person_num)] +per$i6numTours[is.na(per$i6numTours)] <- 0 +per$i7numTours <- i7tourCounts$freq[match(per$hh_id*10+per$person_num, i7tourCounts$hh_id*10+i7tourCounts$person_num)] +per$i7numTours[is.na(per$i7numTours)] <- 0 +per$i8numTours <- i8tourCounts$freq[match(per$hh_id*10+per$person_num, i8tourCounts$hh_id*10+i8tourCounts$person_num)] +per$i8numTours[is.na(per$i8numTours)] <- 0 +per$i9numTours <- i9tourCounts$freq[match(per$hh_id*10+per$person_num, i9tourCounts$hh_id*10+i9tourCounts$person_num)] +per$i9numTours[is.na(per$i9numTours)] <- 0 + +# end of addition for calibration +# --------------------------------------------------- + +# Total tours by person type +per$numTours[is.na(per$numTours)] <- 0 +toursPertypeDistbn <- count(tours[tours$PERTYPE>0 & tours$TOURPURP!=10,], c("PERTYPE")) +write.csv(toursPertypeDistbn, "toursPertypeDistbn.csv", row.names = TRUE) + +# count joint tour fr each person type +temp_joint <- melt(unique_joint_tours[, c("hh_id","tour_id","PTYPE1","PTYPE2","PTYPE3","PTYPE4","PTYPE5","PTYPE6","PTYPE7","PTYPE8")], id = c("hh_id", "tour_id")) +names(temp_joint)[names(temp_joint)=="value"] <- "PERTYPE" +jtoursPertypeDistbn <- count(temp_joint[temp_joint$PERTYPE>0,], c("PERTYPE")) + +# Total tours by person type for visualizer +totaltoursPertypeDistbn <- toursPertypeDistbn +totaltoursPertypeDistbn$freq <- totaltoursPertypeDistbn$freq + jtoursPertypeDistbn$freq +write.csv(totaltoursPertypeDistbn, "total_tours_by_pertype_vis.csv", row.names = F) + +# Total indi NM tours by person type and purpose +tours_pertype_purpose <- count(tours[tours$TOURPURP>=4 & tours$TOURPURP<=9,], c("PERTYPE", "TOURPURP")) +write.csv(tours_pertype_purpose, "tours_pertype_purpose.csv", row.names = TRUE) + +# --------------------------------------------------- +# added for calibration by nagendra.dhakar@rsginc.com + +# code indi NM tour category +per$i4numTours[per$i4numTours>=2] <- 2 +per$i5numTours[per$i5numTours>=2] <- 2 +per$i6numTours[per$i6numTours>=2] <- 2 +per$i7numTours[per$i7numTours>=1] <- 1 +per$i8numTours[per$i8numTours>=1] <- 1 +per$i9numTours[per$i9numTours>=2] <- 2 + +tours_pertype_esco <- count(per, c("PERTYPE", "i4numTours")) +tours_pertype_shop <- count(per, c("PERTYPE", "i5numTours")) +tours_pertype_main <- count(per, c("PERTYPE", "i6numTours")) +tours_pertype_eati <- count(per, c("PERTYPE", "i7numTours")) +tours_pertype_visi <- count(per, c("PERTYPE", "i8numTours")) +tours_pertype_disc <- count(per, c("PERTYPE", "i9numTours")) + + +colnames(tours_pertype_esco) <- c("PERTYPE","inumTours","freq") +colnames(tours_pertype_shop) <- c("PERTYPE","inumTours","freq") +colnames(tours_pertype_main) <- c("PERTYPE","inumTours","freq") +colnames(tours_pertype_eati) <- c("PERTYPE","inumTours","freq") +colnames(tours_pertype_visi) <- c("PERTYPE","inumTours","freq") +colnames(tours_pertype_disc) <- c("PERTYPE","inumTours","freq") + +tours_pertype_esco$purpose <- 4 +tours_pertype_shop$purpose <- 5 +tours_pertype_main$purpose <- 6 +tours_pertype_eati$purpose <- 7 +tours_pertype_visi$purpose <- 8 +tours_pertype_disc$purpose <- 9 + +indi_nm_tours_pertype <- rbind(tours_pertype_esco,tours_pertype_shop,tours_pertype_main,tours_pertype_eati,tours_pertype_visi,tours_pertype_disc) +write.csv(indi_nm_tours_pertype, "inmtours_pertype_purpose.csv", row.names = F) + +# end of addition for calibration +# --------------------------------------------------- + +tours_pertype_purpose <- xtabs(freq~PERTYPE+TOURPURP, tours_pertype_purpose) +tours_pertype_purpose[is.na(tours_pertype_purpose)] <- 0 +tours_pertype_purpose <- addmargins(as.table(tours_pertype_purpose)) +tours_pertype_purpose <- as.data.frame.matrix(tours_pertype_purpose) + +totalPersons <- sum(pertypeDistbn$freq) +totalPersons_DF <- data.frame("Total", totalPersons) +colnames(totalPersons_DF) <- colnames(pertypeDistbn) +pertypeDF <- rbind(pertypeDistbn, totalPersons_DF) +nm_tour_rates <- tours_pertype_purpose/pertypeDF$freq +nm_tour_rates$pertype <- row.names(nm_tour_rates) +nm_tour_rates <- melt(nm_tour_rates, id = c("pertype")) +colnames(nm_tour_rates) <- c("pertype", "tour_purp", "tour_rate") +nm_tour_rates$pertype <- as.character(nm_tour_rates$pertype) +nm_tour_rates$tour_purp <- as.character(nm_tour_rates$tour_purp) +nm_tour_rates$pertype[nm_tour_rates$pertype=="Sum"] <- "All" +nm_tour_rates$tour_purp[nm_tour_rates$tour_purp=="Sum"] <- "All" +nm_tour_rates$pertype <- pertypeCodes$name[match(nm_tour_rates$pertype, pertypeCodes$code)] + +nm_tour_rates$tour_purp[nm_tour_rates$tour_purp==4] <- "Escorting" +nm_tour_rates$tour_purp[nm_tour_rates$tour_purp==5] <- "Shopping" +nm_tour_rates$tour_purp[nm_tour_rates$tour_purp==6] <- "Maintenance" +nm_tour_rates$tour_purp[nm_tour_rates$tour_purp==7] <- "EatingOut" +nm_tour_rates$tour_purp[nm_tour_rates$tour_purp==8] <- "Visiting" +nm_tour_rates$tour_purp[nm_tour_rates$tour_purp==9] <- "Discretionary" + +write.csv(nm_tour_rates, "nm_tour_rates.csv", row.names = F) + +# Total tours by purpose X tourtype +t1 <- hist(tours$TOURPURP[tours$TOURPURP<10], breaks = seq(1,10, by=1), freq = NULL, right=FALSE) +t3 <- hist(unique_joint_tours$JOINT_PURP, breaks = seq(1,10, by=1), freq = NULL, right=FALSE) +tours_purpose_type <- data.frame(t1$counts, t3$counts) +colnames(tours_purpose_type) <- c("indi", "joint") +write.csv(tours_purpose_type, "tours_purpose_type.csv", row.names = TRUE) + +# DAP by pertype +# recode pattern type for at-work and home schooling persons. +# these person have DAP as M. They should be recoded to N or H. +per[per$activity_pattern == 'M' & per$imf_choice==0 & per$inmf_choice>0]$activity_pattern = 'N' +per[per$activity_pattern == 'M' & per$imf_choice==0 & per$inmf_choice==0]$activity_pattern = 'H' + +dapSummary <- count(per, c("PERTYPE", "activity_pattern")) +write.csv(dapSummary, "dapSummary.csv", row.names = TRUE) + +# Prepare DAP summary for visualizer +dapSummary_vis <- xtabs(freq~PERTYPE+activity_pattern, dapSummary) +dapSummary_vis <- addmargins(as.table(dapSummary_vis)) +dapSummary_vis <- as.data.frame.matrix(dapSummary_vis) + +dapSummary_vis$id <- row.names(dapSummary_vis) +dapSummary_vis <- melt(dapSummary_vis, id = c("id")) +colnames(dapSummary_vis) <- c("PERTYPE", "DAP", "freq") +dapSummary_vis$PERTYPE <- as.character(dapSummary_vis$PERTYPE) +dapSummary_vis$DAP <- as.character(dapSummary_vis$DAP) +dapSummary_vis <- dapSummary_vis[dapSummary_vis$DAP!="Sum",] +dapSummary_vis$PERTYPE[dapSummary_vis$PERTYPE=="Sum"] <- "Total" +write.csv(dapSummary_vis, "dapSummary_vis.csv", row.names = TRUE) + +# HHSize X Joint +hhsizeJoint <- count(hh[hh$HHSIZE>=2,], c("HHSIZE", "JOINT")) +write.csv(hhsizeJoint, "hhsizeJoint.csv", row.names = TRUE) + +#mandatory tour frequency +mtfSummary <- count(per[per$imf_choice > 0,], c("PERTYPE", "imf_choice")) +write.csv(mtfSummary, "mtfSummary.csv") +#write.csv(tours, "tours_test.csv") + +# Prepare MTF summary for visualizer +mtfSummary_vis <- xtabs(freq~PERTYPE+imf_choice, mtfSummary) +mtfSummary_vis <- addmargins(as.table(mtfSummary_vis)) +mtfSummary_vis <- as.data.frame.matrix(mtfSummary_vis) + +mtfSummary_vis$id <- row.names(mtfSummary_vis) +mtfSummary_vis <- melt(mtfSummary_vis, id = c("id")) +colnames(mtfSummary_vis) <- c("PERTYPE", "MTF", "freq") +mtfSummary_vis$PERTYPE <- as.character(mtfSummary_vis$PERTYPE) +mtfSummary_vis$MTF <- as.character(mtfSummary_vis$MTF) +mtfSummary_vis <- mtfSummary_vis[mtfSummary_vis$MTF!="Sum",] +mtfSummary_vis$PERTYPE[mtfSummary_vis$PERTYPE=="Sum"] <- "Total" +write.csv(mtfSummary_vis, "mtfSummary_vis.csv") + +# indi NM summary +inm0Summary <- count(per[per$inmTours==0,], c("PERTYPE")) +inm1Summary <- count(per[per$inmTours==1,], c("PERTYPE")) +inm2Summary <- count(per[per$inmTours==2,], c("PERTYPE")) +inm3Summary <- count(per[per$inmTours>=3,], c("PERTYPE")) + +inmSummary <- data.frame(PERTYPE = c(1,2,3,4,5,6,7,8)) +inmSummary$tour0 <- inm0Summary$freq[match(inmSummary$PERTYPE, inm0Summary$PERTYPE)] +inmSummary$tour1 <- inm1Summary$freq[match(inmSummary$PERTYPE, inm1Summary$PERTYPE)] +inmSummary$tour2 <- inm2Summary$freq[match(inmSummary$PERTYPE, inm2Summary$PERTYPE)] +inmSummary$tour3pl <- inm3Summary$freq[match(inmSummary$PERTYPE, inm3Summary$PERTYPE)] + +write.table(inmSummary, "innmSummary.csv", col.names=TRUE, sep=",") + +# prepare INM summary for visualizer +inmSummary_vis <- melt(inmSummary, id=c("PERTYPE")) +inmSummary_vis$variable <- as.character(inmSummary_vis$variable) +inmSummary_vis$variable[inmSummary_vis$variable=="tour0"] <- "0" +inmSummary_vis$variable[inmSummary_vis$variable=="tour1"] <- "1" +inmSummary_vis$variable[inmSummary_vis$variable=="tour2"] <- "2" +inmSummary_vis$variable[inmSummary_vis$variable=="tour3pl"] <- "3pl" +inmSummary_vis <- xtabs(value~PERTYPE+variable, inmSummary_vis) +inmSummary_vis <- addmargins(as.table(inmSummary_vis)) +inmSummary_vis <- as.data.frame.matrix(inmSummary_vis) + +inmSummary_vis$id <- row.names(inmSummary_vis) +inmSummary_vis <- melt(inmSummary_vis, id = c("id")) +colnames(inmSummary_vis) <- c("PERTYPE", "nmtours", "freq") +inmSummary_vis$PERTYPE <- as.character(inmSummary_vis$PERTYPE) +inmSummary_vis$nmtours <- as.character(inmSummary_vis$nmtours) +inmSummary_vis <- inmSummary_vis[inmSummary_vis$nmtours!="Sum",] +inmSummary_vis$PERTYPE[inmSummary_vis$PERTYPE=="Sum"] <- "Total" +write.csv(inmSummary_vis, "inmSummary_vis.csv") + +# Joint Tour Frequency and composition +jtfSummary <- count(hh[!is.na(hh$jtf),], c("jtf")) +jointComp <- count(unique_joint_tours, c("tour_composition")) +jointPartySize <- count(unique_joint_tours, c("NUMBER_HH")) +jointCompPartySize <- count(unique_joint_tours, c("tour_composition","NUMBER_HH")) + +hh$jointCat[hh$jtours==0] <- 0 +hh$jointCat[hh$jtours==1] <- 1 +hh$jointCat[hh$jtours>=2] <- 2 + +jointToursHHSize <- count(hh[!is.na(hh$HHSIZE) & !is.na(hh$jointCat),], c("HHSIZE", "jointCat")) + +write.table(jtfSummary, "jtfSummary.csv", col.names=TRUE, sep=",") +write.table(jointComp, "jtfSummary.csv", col.names=TRUE, sep=",", append=TRUE) +write.table(jointPartySize, "jtfSummary.csv", col.names=TRUE, sep=",", append=TRUE) +write.table(jointCompPartySize, "jtfSummary.csv", col.names=TRUE, sep=",", append=TRUE) +write.table(jointToursHHSize, "jtfSummary.csv", col.names=TRUE, sep=",", append=TRUE) + +#cap joint party size to 5+ +jointPartySize$freq[jointPartySize$NUMBER_HH==5] <- sum(jointPartySize$freq[jointPartySize$NUMBER_HH>=5]) +jointPartySize <- jointPartySize[jointPartySize$NUMBER_HH<=5, ] + +jtf <- data.frame(jtf_code = seq(from = 1, to = 21), + alt_name = c("No Joint Tours", "1 Shopping", "1 Maintenance", "1 Eating Out", "1 Visiting", "1 Other Discretionary", + "2 Shopping", "1 Shopping / 1 Maintenance", "1 Shopping / 1 Eating Out", "1 Shopping / 1 Visiting", + "1 Shopping / 1 Other Discretionary", "2 Maintenance", "1 Maintenance / 1 Eating Out", + "1 Maintenance / 1 Visiting", "1 Maintenance / 1 Other Discretionary", "2 Eating Out", "1 Eating Out / 1 Visiting", + "1 Eating Out / 1 Other Discretionary", "2 Visiting", "1 Visiting / 1 Other Discretionary", "2 Other Discretionary")) +jtf$freq <- jtfSummary$freq[match(jtf$jtf_code, jtfSummary$jtf)] +jtf[is.na(jtf)] <- 0 + +jointComp$tour_composition[jointComp$tour_composition==1] <- "All Adult" +jointComp$tour_composition[jointComp$tour_composition==2] <- "All Children" +jointComp$tour_composition[jointComp$tour_composition==3] <- "Mixed" + +jointToursHHSizeProp <- xtabs(freq~jointCat+HHSIZE, jointToursHHSize[jointToursHHSize$HHSIZE>1,]) +jointToursHHSizeProp <- addmargins(as.table(jointToursHHSizeProp)) +jointToursHHSizeProp <- jointToursHHSizeProp[-4,] #remove last row +jointToursHHSizeProp <- prop.table(jointToursHHSizeProp, margin = 2) +jointToursHHSizeProp <- as.data.frame.matrix(jointToursHHSizeProp) +jointToursHHSizeProp <- jointToursHHSizeProp*100 +jointToursHHSizeProp$jointTours <- row.names(jointToursHHSizeProp) +jointToursHHSizeProp <- melt(jointToursHHSizeProp, id = c("jointTours")) +colnames(jointToursHHSizeProp) <- c("jointTours", "hhsize", "freq") +jointToursHHSizeProp$hhsize <- as.character(jointToursHHSizeProp$hhsize) +jointToursHHSizeProp$hhsize[jointToursHHSizeProp$hhsize=="Sum"] <- "Total" + +jointCompPartySize$tour_composition[jointCompPartySize$tour_composition==1] <- "All Adult" +jointCompPartySize$tour_composition[jointCompPartySize$tour_composition==2] <- "All Children" +jointCompPartySize$tour_composition[jointCompPartySize$tour_composition==3] <- "Mixed" + +jointCompPartySizeProp <- xtabs(freq~tour_composition+NUMBER_HH, jointCompPartySize) +jointCompPartySizeProp <- addmargins(as.table(jointCompPartySizeProp)) +jointCompPartySizeProp <- jointCompPartySizeProp[,-6] #remove last row +jointCompPartySizeProp <- prop.table(jointCompPartySizeProp, margin = 1) +jointCompPartySizeProp <- as.data.frame.matrix(jointCompPartySizeProp) +jointCompPartySizeProp <- jointCompPartySizeProp*100 +jointCompPartySizeProp$comp <- row.names(jointCompPartySizeProp) +jointCompPartySizeProp <- melt(jointCompPartySizeProp, id = c("comp")) +colnames(jointCompPartySizeProp) <- c("comp", "partysize", "freq") +jointCompPartySizeProp$comp <- as.character(jointCompPartySizeProp$comp) +jointCompPartySizeProp$comp[jointCompPartySizeProp$comp=="Sum"] <- "Total" + +# Cap joint comp party size at 5 +jointCompPartySizeProp <- jointCompPartySizeProp[jointCompPartySizeProp$partysize!="Sum",] +jointCompPartySizeProp$partysize <- as.numeric(as.character(jointCompPartySizeProp$partysize)) +jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="All Adult" & jointCompPartySizeProp$partysize==5] <- + sum(jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="All Adult" & jointCompPartySizeProp$partysize>=5]) +jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="All Children" & jointCompPartySizeProp$partysize==5] <- + sum(jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="All Children" & jointCompPartySizeProp$partysize>=5]) +jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="Mixed" & jointCompPartySizeProp$partysize==5] <- + sum(jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="Mixed" & jointCompPartySizeProp$partysize>=5]) +jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="Total" & jointCompPartySizeProp$partysize==5] <- + sum(jointCompPartySizeProp$freq[jointCompPartySizeProp$comp=="Total" & jointCompPartySizeProp$partysize>=5]) + +jointCompPartySizeProp <- jointCompPartySizeProp[jointCompPartySizeProp$partysize<=5,] + + +write.csv(jtf, "jtf.csv", row.names = F) +write.csv(jointComp, "jointComp.csv", row.names = F) +write.csv(jointPartySize, "jointPartySize.csv", row.names = F) +write.csv(jointCompPartySizeProp, "jointCompPartySize.csv", row.names = F) +write.csv(jointToursHHSizeProp, "jointToursHHSize.csv", row.names = F) + +# TOD Profile +#work.dep <- table(cut(tours$ANCHOR_DEPART_BIN[!is.na(tours$ANCHOR_DEPART_BIN)], seq(1,48, by=1), right=FALSE)) + +tod1 <- hist(tours$start_period[tours$TOURPURP==1], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod1_2 <- hist(tours$start_period[tours$TOURPURP==1 & tours$PERTYPE==2], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod2 <- hist(tours$start_period[tours$TOURPURP==2], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod3 <- hist(tours$start_period[tours$TOURPURP==3], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod4 <- hist(tours$start_period[tours$TOURPURP==4], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todi56 <- hist(tours$start_period[tours$TOURPURP>=5 & tours$TOURPURP<=6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todi789 <- hist(tours$start_period[tours$TOURPURP>=7 & tours$TOURPURP<=9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod6 <- hist(tours$start_period[tours$TOURPURP==6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod7 <- hist(tours$start_period[tours$TOURPURP==7], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod8 <- hist(tours$start_period[tours$TOURPURP==8], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod9 <- hist(tours$start_period[tours$TOURPURP==9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todj56 <- hist(unique_joint_tours$start_period[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todj789 <- hist(unique_joint_tours$start_period[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod11 <- hist(unique_joint_tours$start_period[unique_joint_tours$JOINT_PURP==6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod12 <- hist(unique_joint_tours$start_period[unique_joint_tours$JOINT_PURP==7], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod13 <- hist(unique_joint_tours$start_period[unique_joint_tours$JOINT_PURP==8], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod14 <- hist(unique_joint_tours$start_period[unique_joint_tours$JOINT_PURP==9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod15 <- hist(tours$start_period[tours$TOURPURP==10], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) + +todDepProfile <- data.frame(tod1$counts, tod2$counts, tod3$counts, tod4$counts, todi56$counts, todi789$counts + , todj56$counts, todj789$counts, tod15$counts) +colnames(todDepProfile) <- c("work", "univ", "sch", "esc", "imain", "idisc", + "jmain", "jdisc", "atwork") +write.csv(todDepProfile, "todDepProfile.csv") + +# prepare input for visualizer +todDepProfile_vis <- todDepProfile +todDepProfile_vis$id <- row.names(todDepProfile_vis) +todDepProfile_vis <- melt(todDepProfile_vis, id = c("id")) +colnames(todDepProfile_vis) <- c("id", "purpose", "freq_dep") + +todDepProfile_vis$purpose <- as.character(todDepProfile_vis$purpose) +todDepProfile_vis <- xtabs(freq_dep~id+purpose, todDepProfile_vis) +todDepProfile_vis <- addmargins(as.table(todDepProfile_vis)) +todDepProfile_vis <- as.data.frame.matrix(todDepProfile_vis) +todDepProfile_vis$id <- row.names(todDepProfile_vis) +todDepProfile_vis <- melt(todDepProfile_vis, id = c("id")) +colnames(todDepProfile_vis) <- c("timebin", "PURPOSE", "freq") +todDepProfile_vis$PURPOSE <- as.character(todDepProfile_vis$PURPOSE) +todDepProfile_vis$timebin <- as.character(todDepProfile_vis$timebin) +todDepProfile_vis <- todDepProfile_vis[todDepProfile_vis$timebin!="Sum",] +todDepProfile_vis$PURPOSE[todDepProfile_vis$PURPOSE=="Sum"] <- "Total" +todDepProfile_vis$timebin <- as.numeric(todDepProfile_vis$timebin) + +tod1 <- hist(tours$end_period[tours$TOURPURP==1], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod1_2 <- hist(tours$end_period[tours$TOURPURP==1 & tours$PERTYPE==2], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod2 <- hist(tours$end_period[tours$TOURPURP==2], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod3 <- hist(tours$end_period[tours$TOURPURP==3], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod4 <- hist(tours$end_period[tours$TOURPURP==4], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todi56 <- hist(tours$end_period[tours$TOURPURP>=5 & tours$TOURPURP<=6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todi789 <- hist(tours$end_period[tours$TOURPURP>=7 & tours$TOURPURP<=9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod8 <- hist(tours$end_period[tours$TOURPURP==8], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod9 <- hist(tours$end_period[tours$TOURPURP==9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todj56 <- hist(unique_joint_tours$end_period[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todj789 <- hist(unique_joint_tours$end_period[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod11 <- hist(unique_joint_tours$end_period[unique_joint_tours$JOINT_PURP==6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod12 <- hist(unique_joint_tours$end_period[unique_joint_tours$JOINT_PURP==7], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod13 <- hist(unique_joint_tours$end_period[unique_joint_tours$JOINT_PURP==8], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod14 <- hist(unique_joint_tours$end_period[unique_joint_tours$JOINT_PURP==9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod15 <- hist(tours$end_period[tours$TOURPURP==10], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) + +todArrProfile <- data.frame(tod1$counts, tod2$counts, tod3$counts, tod4$counts, todi56$counts, todi789$counts + , todj56$counts, todj789$counts, tod15$counts) +colnames(todArrProfile) <- c("work", "univ", "sch", "esc", "imain", "idisc", + "jmain", "jdisc", "atwork") +write.csv(todArrProfile, "todArrProfile.csv") + + +##stops by direction, purpose and model tod + +tours$start_tod <- 5 # EA: 3 am - 6 am +tours$start_tod <- ifelse(tours$start_period>=4 & tours$start_period<=9, 1, tours$start_tod) # AM: 6 am - 9 am +tours$start_tod <- ifelse(tours$start_period>=10 & tours$start_period<=22, 2, tours$start_tod) # MD: 9 am - 3:30 pm +tours$start_tod <- ifelse(tours$start_period>=23 & tours$start_period<=29, 3, tours$start_tod) # PM: 3:30 pm - 7 pm +tours$start_tod <- ifelse(tours$start_period>=30 & tours$start_period<=40, 4, tours$start_tod) # EV: 7 pm - 3 am + +tours$end_tod <- 5 # EA: 3 am - 6 am +tours$end_tod <- ifelse(tours$end_period>=4 & tours$end_period<=9, 1, tours$end_tod) # AM: 6 am - 9 am +tours$end_tod <- ifelse(tours$end_period>=10 & tours$end_period<=22, 2, tours$end_tod) # MD: 9 am - 3:30 pm +tours$end_tod <- ifelse(tours$end_period>=23 & tours$end_period<=29, 3, tours$end_tod) # PM: 3:30 pm - 7 pm +tours$end_tod <- ifelse(tours$end_period>=30 & tours$end_period<=40, 4, tours$end_tod) # EV: 7 pm - 3 am + +stops_ib_tod <- aggregate(num_ib_stops~tour_purpose+start_tod+end_tod, data=tours, FUN = sum) +stops_ob_tod <- aggregate(num_ob_stops~tour_purpose+start_tod+end_tod, data=tours, FUN = sum) +write.csv(stops_ib_tod, "todStopsIB.csv", row.names = F) +write.csv(stops_ob_tod, "todStopsOB.csv", row.names = F) + +#joint tours +unique_joint_tours$start_tod <- 5 # EA: 3 am - 6 am +unique_joint_tours$start_tod <- ifelse(unique_joint_tours$start_period>=4 & unique_joint_tours$start_period<=9, 1, unique_joint_tours$start_tod) # AM: 6 am - 9 am +unique_joint_tours$start_tod <- ifelse(unique_joint_tours$start_period>=10 & unique_joint_tours$start_period<=22, 2, unique_joint_tours$start_tod) # MD: 9 am - 3:30 pm +unique_joint_tours$start_tod <- ifelse(unique_joint_tours$start_period>=23 & unique_joint_tours$start_period<=29, 3, unique_joint_tours$start_tod) # PM: 3:30 pm - 7 pm +unique_joint_tours$start_tod <- ifelse(unique_joint_tours$start_period>=30 & unique_joint_tours$start_period<=40, 4, unique_joint_tours$start_tod) # EV: 7 pm - 3 am + +unique_joint_tours$end_tod <- 5 # EA: 3 am - 6 am +unique_joint_tours$end_tod <- ifelse(unique_joint_tours$end_period>=4 & unique_joint_tours$end_period<=9, 1, unique_joint_tours$end_tod) # AM: 6 am - 9 am +unique_joint_tours$end_tod <- ifelse(unique_joint_tours$end_period>=10 & unique_joint_tours$end_period<=22, 2, unique_joint_tours$end_tod) # MD: 9 am - 3:30 pm +unique_joint_tours$end_tod <- ifelse(unique_joint_tours$end_period>=23 & unique_joint_tours$end_period<=29, 3, unique_joint_tours$end_tod) # PM: 3:30 pm - 7 pm +unique_joint_tours$end_tod <- ifelse(unique_joint_tours$end_period>=30 & unique_joint_tours$end_period<=40, 4, unique_joint_tours$end_tod) # EV: 7 pm - 3 am + +jstops_ib_tod <- aggregate(num_ib_stops~tour_purpose+start_tod+end_tod, data=unique_joint_tours, FUN = sum) +jstops_ob_tod <- aggregate(num_ob_stops~tour_purpose+start_tod+end_tod, data=unique_joint_tours, FUN = sum) +write.csv(jstops_ib_tod, "todStopsIB_joint.csv", row.names = F) +write.csv(jstops_ob_tod, "todStopsOB_joint.csv", row.names = F) + +# prepare input for visualizer +todArrProfile_vis <- todArrProfile +todArrProfile_vis$id <- row.names(todArrProfile_vis) +todArrProfile_vis <- melt(todArrProfile_vis, id = c("id")) +colnames(todArrProfile_vis) <- c("id", "purpose", "freq_arr") + +todArrProfile_vis$purpose <- as.character(todArrProfile_vis$purpose) +todArrProfile_vis <- xtabs(freq_arr~id+purpose, todArrProfile_vis) +todArrProfile_vis <- addmargins(as.table(todArrProfile_vis)) +todArrProfile_vis <- as.data.frame.matrix(todArrProfile_vis) +todArrProfile_vis$id <- row.names(todArrProfile_vis) +todArrProfile_vis <- melt(todArrProfile_vis, id = c("id")) +colnames(todArrProfile_vis) <- c("timebin", "PURPOSE", "freq") +todArrProfile_vis$PURPOSE <- as.character(todArrProfile_vis$PURPOSE) +todArrProfile_vis$timebin <- as.character(todArrProfile_vis$timebin) +todArrProfile_vis <- todArrProfile_vis[todArrProfile_vis$timebin!="Sum",] +todArrProfile_vis$PURPOSE[todArrProfile_vis$PURPOSE=="Sum"] <- "Total" +todArrProfile_vis$timebin <- as.numeric(todArrProfile_vis$timebin) + + +tod1 <- hist(tours$tourdur[tours$TOURPURP==1], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod1_2 <- hist(tours$tourdur[tours$TOURPURP==1 & tours$PERTYPE==2], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +tod2 <- hist(tours$tourdur[tours$TOURPURP==2], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod3 <- hist(tours$tourdur[tours$TOURPURP==3], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +tod4 <- hist(tours$tourdur[tours$TOURPURP==4], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todi56 <- hist(tours$tourdur[tours$TOURPURP>=5 & tours$TOURPURP<=6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todi789 <- hist(tours$tourdur[tours$TOURPURP>=7 & tours$TOURPURP<=9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod6 <- hist(tours$tourdur[tours$TOURPURP==6], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +#tod7 <- hist(tours$tourdur[tours$TOURPURP==7], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +#tod8 <- hist(tours$tourdur[tours$TOURPURP==8], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +#tod9 <- hist(tours$tourdur[tours$TOURPURP==9], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +todj56 <- hist(unique_joint_tours$tourdur[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +todj789 <- hist(unique_joint_tours$tourdur[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) +#tod11 <- hist(unique_joint_tours$tourdur[unique_joint_tours$JOINT_PURP==6], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +#tod12 <- hist(unique_joint_tours$tourdur[unique_joint_tours$JOINT_PURP==7], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +#tod13 <- hist(unique_joint_tours$tourdur[unique_joint_tours$JOINT_PURP==8], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +#tod14 <- hist(unique_joint_tours$tourdur[unique_joint_tours$JOINT_PURP==9], breaks = seq(0,41, by=1), freq = NULL, right=FALSE) +tod15 <- hist(tours$tourdur[tours$TOURPURP==10], breaks = seq(1,41, by=1), freq = NULL, right=FALSE) + +todDurProfile <- data.frame(tod1$counts, tod2$counts, tod3$counts, tod4$counts, todi56$counts, todi789$counts + , todj56$counts, todj789$counts, tod15$counts) +colnames(todDurProfile) <- c("work", "univ", "sch", "esc", "imain", "idisc", + "jmain", "jdisc", "atwork") +write.csv(todDurProfile, "todDurProfile.csv") + +# prepare input for visualizer +todDurProfile_vis <- todDurProfile +todDurProfile_vis$id <- row.names(todDurProfile_vis) +todDurProfile_vis <- melt(todDurProfile_vis, id = c("id")) +colnames(todDurProfile_vis) <- c("id", "purpose", "freq_dur") + +todDurProfile_vis$purpose <- as.character(todDurProfile_vis$purpose) +todDurProfile_vis <- xtabs(freq_dur~id+purpose, todDurProfile_vis) +todDurProfile_vis <- addmargins(as.table(todDurProfile_vis)) +todDurProfile_vis <- as.data.frame.matrix(todDurProfile_vis) +todDurProfile_vis$id <- row.names(todDurProfile_vis) +todDurProfile_vis <- melt(todDurProfile_vis, id = c("id")) +colnames(todDurProfile_vis) <- c("timebin", "PURPOSE", "freq") +todDurProfile_vis$PURPOSE <- as.character(todDurProfile_vis$PURPOSE) +todDurProfile_vis$timebin <- as.character(todDurProfile_vis$timebin) +todDurProfile_vis <- todDurProfile_vis[todDurProfile_vis$timebin!="Sum",] +todDurProfile_vis$PURPOSE[todDurProfile_vis$PURPOSE=="Sum"] <- "Total" +todDurProfile_vis$timebin <- as.numeric(todDurProfile_vis$timebin) + +todDepProfile_vis <- todDepProfile_vis[order(todDepProfile_vis$timebin, todDepProfile_vis$PURPOSE), ] +todArrProfile_vis <- todArrProfile_vis[order(todArrProfile_vis$timebin, todArrProfile_vis$PURPOSE), ] +todDurProfile_vis <- todDurProfile_vis[order(todDurProfile_vis$timebin, todDurProfile_vis$PURPOSE), ] +todProfile_vis <- data.frame(todDepProfile_vis, todArrProfile_vis$freq, todDurProfile_vis$freq) +colnames(todProfile_vis) <- c("id", "purpose", "freq_dep", "freq_arr", "freq_dur") +write.csv(todProfile_vis, "todProfile_vis.csv", row.names = F) + +# Tour Mode X Auto Suff (seq changed from 10 to 13 due to increase in number of modes, changed by Khademul.haque@rsginc.com) +tmode1_as0 <- hist(tours$TOURMODE[tours$TOURPURP==1 & tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode2_as0 <- hist(tours$TOURMODE[tours$TOURPURP==2 & tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode3_as0 <- hist(tours$TOURMODE[tours$TOURPURP==3 & tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode4_as0 <- hist(tours$TOURMODE[tours$TOURPURP>=4 & tours$TOURPURP<=6 & tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode5_as0 <- hist(tours$TOURMODE[tours$TOURPURP>=7 & tours$TOURPURP<=9 & tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode6_as0 <- hist(unique_joint_tours$TOURMODE[unique_joint_tours$JOINT_PURP>=4 & unique_joint_tours$JOINT_PURP<=6 & unique_joint_tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode7_as0 <- hist(unique_joint_tours$TOURMODE[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9 & unique_joint_tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode8_as0 <- hist(tours$TOURMODE[tours$TOURPURP==10 & tours$AUTOSUFF==0], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tmodeAS0Profile <- data.frame(tmode1_as0$counts, tmode2_as0$counts, tmode3_as0$counts, tmode4_as0$counts, + tmode5_as0$counts, tmode6_as0$counts, tmode7_as0$counts, tmode8_as0$counts) +colnames(tmodeAS0Profile) <- c("work", "univ", "sch", "imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(tmodeAS0Profile, "tmodeAS0Profile.csv") + +# Prepeare data for visualizer (changed from 9 to 12) +tmodeAS0Profile_vis <- tmodeAS0Profile[1:13,] +tmodeAS0Profile_vis$id <- row.names(tmodeAS0Profile_vis) +tmodeAS0Profile_vis <- melt(tmodeAS0Profile_vis, id = c("id")) +colnames(tmodeAS0Profile_vis) <- c("id", "purpose", "freq_as0") + +tmodeAS0Profile_vis <- xtabs(freq_as0~id+purpose, tmodeAS0Profile_vis) +tmodeAS0Profile_vis[is.na(tmodeAS0Profile_vis)] <- 0 +tmodeAS0Profile_vis <- addmargins(as.table(tmodeAS0Profile_vis)) +tmodeAS0Profile_vis <- as.data.frame.matrix(tmodeAS0Profile_vis) + +tmodeAS0Profile_vis$id <- row.names(tmodeAS0Profile_vis) +tmodeAS0Profile_vis <- melt(tmodeAS0Profile_vis, id = c("id")) +colnames(tmodeAS0Profile_vis) <- c("id", "purpose", "freq_as0") +tmodeAS0Profile_vis$id <- as.character(tmodeAS0Profile_vis$id) +tmodeAS0Profile_vis$purpose <- as.character(tmodeAS0Profile_vis$purpose) +tmodeAS0Profile_vis <- tmodeAS0Profile_vis[tmodeAS0Profile_vis$id!="Sum",] +tmodeAS0Profile_vis$purpose[tmodeAS0Profile_vis$purpose=="Sum"] <- "Total" + +# (seq changed from 10 to 13 due to increase in number of modes, changed by Khademul.haque@rsginc.com) +tmode1_as1 <- hist(tours$TOURMODE[tours$TOURPURP==1 & tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode2_as1 <- hist(tours$TOURMODE[tours$TOURPURP==2 & tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode3_as1 <- hist(tours$TOURMODE[tours$TOURPURP==3 & tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode4_as1 <- hist(tours$TOURMODE[tours$TOURPURP>=4 & tours$TOURPURP<=6 & tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode5_as1 <- hist(tours$TOURMODE[tours$TOURPURP>=7 & tours$TOURPURP<=9 & tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode6_as1 <- hist(unique_joint_tours$TOURMODE[unique_joint_tours$JOINT_PURP>=4 & unique_joint_tours$JOINT_PURP<=6 & unique_joint_tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode7_as1 <- hist(unique_joint_tours$TOURMODE[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9 & unique_joint_tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode8_as1 <- hist(tours$TOURMODE[tours$TOURPURP==10 & tours$AUTOSUFF==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tmodeAS1Profile <- data.frame(tmode1_as1$counts, tmode2_as1$counts, tmode3_as1$counts, tmode4_as1$counts, + tmode5_as1$counts, tmode6_as1$counts, tmode7_as1$counts, tmode8_as1$counts) +colnames(tmodeAS1Profile) <- c("work", "univ", "sch", "imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(tmodeAS1Profile, "tmodeAS1Profile.csv") + +# Prepeare data for visualizer (changed from 9 to 12) +tmodeAS1Profile_vis <- tmodeAS1Profile[1:13,] +tmodeAS1Profile_vis$id <- row.names(tmodeAS1Profile_vis) +tmodeAS1Profile_vis <- melt(tmodeAS1Profile_vis, id = c("id")) +colnames(tmodeAS1Profile_vis) <- c("id", "purpose", "freq_as1") + +tmodeAS1Profile_vis <- xtabs(freq_as1~id+purpose, tmodeAS1Profile_vis) +tmodeAS1Profile_vis[is.na(tmodeAS1Profile_vis)] <- 0 +tmodeAS1Profile_vis <- addmargins(as.table(tmodeAS1Profile_vis)) +tmodeAS1Profile_vis <- as.data.frame.matrix(tmodeAS1Profile_vis) + +tmodeAS1Profile_vis$id <- row.names(tmodeAS1Profile_vis) +tmodeAS1Profile_vis <- melt(tmodeAS1Profile_vis, id = c("id")) +colnames(tmodeAS1Profile_vis) <- c("id", "purpose", "freq_as1") +tmodeAS1Profile_vis$id <- as.character(tmodeAS1Profile_vis$id) +tmodeAS1Profile_vis$purpose <- as.character(tmodeAS1Profile_vis$purpose) +tmodeAS1Profile_vis <- tmodeAS1Profile_vis[tmodeAS1Profile_vis$id!="Sum",] +tmodeAS1Profile_vis$purpose[tmodeAS1Profile_vis$purpose=="Sum"] <- "Total" + +# (seq changed from 10 to 13 due to increase in number of modes, changed by Khademul.haque@rsginc.com) +tmode1_as2 <- hist(tours$TOURMODE[tours$TOURPURP==1 & tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode2_as2 <- hist(tours$TOURMODE[tours$TOURPURP==2 & tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode3_as2 <- hist(tours$TOURMODE[tours$TOURPURP==3 & tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode4_as2 <- hist(tours$TOURMODE[tours$TOURPURP>=4 & tours$TOURPURP<=6 & tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode5_as2 <- hist(tours$TOURMODE[tours$TOURPURP>=7 & tours$TOURPURP<=9 & tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode6_as2 <- hist(unique_joint_tours$TOURMODE[unique_joint_tours$JOINT_PURP>=4 & unique_joint_tours$JOINT_PURP<=6 & unique_joint_tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode7_as2 <- hist(unique_joint_tours$TOURMODE[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9 & unique_joint_tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tmode8_as2 <- hist(tours$TOURMODE[tours$TOURPURP==10 & tours$AUTOSUFF==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tmodeAS2Profile <- data.frame(tmode1_as2$counts, tmode2_as2$counts, tmode3_as2$counts, tmode4_as2$counts, + tmode5_as2$counts, tmode6_as2$counts, tmode7_as2$counts, tmode8_as2$counts) +colnames(tmodeAS2Profile) <- c("work", "univ", "sch", "imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(tmodeAS2Profile, "tmodeAS2Profile.csv") + +# Prepeare data for visualizer (changed from 9 to 12) +tmodeAS2Profile_vis <- tmodeAS2Profile[1:13,] +tmodeAS2Profile_vis$id <- row.names(tmodeAS2Profile_vis) +tmodeAS2Profile_vis <- melt(tmodeAS2Profile_vis, id = c("id")) +colnames(tmodeAS2Profile_vis) <- c("id", "purpose", "freq_as2") + +tmodeAS2Profile_vis <- xtabs(freq_as2~id+purpose, tmodeAS2Profile_vis) +tmodeAS2Profile_vis[is.na(tmodeAS2Profile_vis)] <- 0 +tmodeAS2Profile_vis <- addmargins(as.table(tmodeAS2Profile_vis)) +tmodeAS2Profile_vis <- as.data.frame.matrix(tmodeAS2Profile_vis) + +tmodeAS2Profile_vis$id <- row.names(tmodeAS2Profile_vis) +tmodeAS2Profile_vis <- melt(tmodeAS2Profile_vis, id = c("id")) +colnames(tmodeAS2Profile_vis) <- c("id", "purpose", "freq_as2") +tmodeAS2Profile_vis$id <- as.character(tmodeAS2Profile_vis$id) +tmodeAS2Profile_vis$purpose <- as.character(tmodeAS2Profile_vis$purpose) +tmodeAS2Profile_vis <- tmodeAS2Profile_vis[tmodeAS2Profile_vis$id!="Sum",] +tmodeAS2Profile_vis$purpose[tmodeAS2Profile_vis$purpose=="Sum"] <- "Total" + + +# Combine three AS groups +tmodeProfile_vis <- data.frame(tmodeAS0Profile_vis, tmodeAS1Profile_vis$freq_as1, tmodeAS2Profile_vis$freq_as2) +colnames(tmodeProfile_vis) <- c("id", "purpose", "freq_as0", "freq_as1", "freq_as2") +tmodeProfile_vis$freq_all <- tmodeProfile_vis$freq_as0 + tmodeProfile_vis$freq_as1 + tmodeProfile_vis$freq_as2 +write.csv(tmodeProfile_vis, "tmodeProfile_vis.csv", row.names = F) + + +# Non Mand Tour lengths +tourdist4 <- hist(tours$tour_distance[tours$TOURPURP==4], breaks = c(seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +tourdisti56 <- hist(tours$tour_distance[tours$TOURPURP>=5 & tours$TOURPURP<=6], breaks = c(seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +tourdisti789 <- hist(tours$tour_distance[tours$TOURPURP>=7 & tours$TOURPURP<=9], breaks = c(seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +tourdistj56 <- hist(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], breaks = c(seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +tourdistj789 <- hist(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], breaks = c(seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +tourdist10 <- hist(tours$tour_distance[tours$TOURPURP==10], breaks = c(seq(0,40, by=1), 9999), freq = NULL, right=FALSE) + +tourDistProfile <- data.frame(tourdist4$counts, tourdisti56$counts, tourdisti789$counts, tourdistj56$counts, tourdistj789$counts, tourdist10$counts) + +colnames(tourDistProfile) <- c("esco", "imain", "idisc", "jmain", "jdisc", "atwork") + +write.csv(tourDistProfile, "nonMandTourDistProfile.csv") + +#prepare input for visualizer +tourDistProfile_vis <- tourDistProfile +tourDistProfile_vis$id <- row.names(tourDistProfile_vis) +tourDistProfile_vis <- melt(tourDistProfile_vis, id = c("id")) +colnames(tourDistProfile_vis) <- c("id", "purpose", "freq") + +tourDistProfile_vis <- xtabs(freq~id+purpose, tourDistProfile_vis) +tourDistProfile_vis <- addmargins(as.table(tourDistProfile_vis)) +tourDistProfile_vis <- as.data.frame.matrix(tourDistProfile_vis) +tourDistProfile_vis$id <- row.names(tourDistProfile_vis) +tourDistProfile_vis <- melt(tourDistProfile_vis, id = c("id")) +colnames(tourDistProfile_vis) <- c("distbin", "PURPOSE", "freq") +tourDistProfile_vis$PURPOSE <- as.character(tourDistProfile_vis$PURPOSE) +tourDistProfile_vis$distbin <- as.character(tourDistProfile_vis$distbin) +tourDistProfile_vis <- tourDistProfile_vis[tourDistProfile_vis$distbin!="Sum",] +tourDistProfile_vis$PURPOSE[tourDistProfile_vis$PURPOSE=="Sum"] <- "Total" +tourDistProfile_vis$distbin <- as.numeric(tourDistProfile_vis$distbin) + +write.csv(tourDistProfile_vis, "tourDistProfile_vis.csv", row.names = F) + +cat("\n Average Tour Distance [esco]: ", mean(tours$tour_distance[tours$TOURPURP==4], na.rm = TRUE)) +cat("\n Average Tour Distance [imain]: ", mean(tours$tour_distance[tours$TOURPURP>=5 & tours$TOURPURP<=6], na.rm = TRUE)) +cat("\n Average Tour Distance [idisc]: ", mean(tours$tour_distance[tours$TOURPURP>=7 & tours$TOURPURP<=9], na.rm = TRUE)) +cat("\n Average Tour Distance [jmain]: ", mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], na.rm = TRUE)) +cat("\n Average Tour Distance [jdisc]: ", mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], na.rm = TRUE)) +cat("\n Average Tour Distance [atwork]: ", mean(tours$tour_distance[tours$TOURPURP==10], na.rm = TRUE)) + +## Retirees +#cat("\n Average Tour Distance [esco]: ", mean(tours$tour_distance[tours$TOURPURP==4 & tours$PERTYPE==5], na.rm = TRUE)) +#cat("\n Average Tour Distance [imain]: ", mean(tours$tour_distance[tours$TOURPURP>=5 & tours$TOURPURP<=6 & tours$PERTYPE==5], na.rm = TRUE)) +#cat("\n Average Tour Distance [idisc]: ", mean(tours$tour_distance[tours$TOURPURP>=7 & tours$TOURPURP<=9 & tours$PERTYPE==5], na.rm = TRUE)) +#cat("\n Average Tour Distance [jmain]: ", mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6 & unique_joint_tours$PERTYPE==5], na.rm = TRUE)) +#cat("\n Average Tour Distance [jdisc]: ", mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9 & unique_joint_tours$PERTYPE==5], na.rm = TRUE)) +#cat("\n Average Tour Distance [atwork]: ", mean(tours$tour_distance[tours$TOURPURP==10 & tours$PERTYPE==5], na.rm = TRUE)) +# +## Non-reitrees +#cat("\n Average Tour Distance [esco]: ", mean(tours$tour_distance[tours$TOURPURP==4 & tours$PERTYPE!=5], na.rm = TRUE)) +#cat("\n Average Tour Distance [imain]: ", mean(tours$tour_distance[tours$TOURPURP>=5 & tours$TOURPURP<=6 & tours$PERTYPE!=5], na.rm = TRUE)) +#cat("\n Average Tour Distance [idisc]: ", mean(tours$tour_distance[tours$TOURPURP>=7 & tours$TOURPURP<=9 & tours$PERTYPE!=5], na.rm = TRUE)) +#cat("\n Average Tour Distance [jmain]: ", mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6 & unique_joint_tours$PERTYPE!=5], na.rm = TRUE)) +#cat("\n Average Tour Distance [jdisc]: ", mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9 & unique_joint_tours$PERTYPE!=5], na.rm = TRUE)) +#cat("\n Average Tour Distance [atwork]: ", mean(tours$tour_distance[tours$TOURPURP==10 & tours$PERTYPE!=5], na.rm = TRUE)) +# + +## Output average trips lengths for visualizer + +avgTripLengths <- c(mean(tours$tour_distance[tours$TOURPURP==4], na.rm = TRUE), + mean(tours$tour_distance[tours$TOURPURP>=5 & tours$TOURPURP<=6], na.rm = TRUE), + mean(tours$tour_distance[tours$TOURPURP>=7 & tours$TOURPURP<=9], na.rm = TRUE), + mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], na.rm = TRUE), + mean(unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], na.rm = TRUE), + mean(tours$tour_distance[tours$TOURPURP==10], na.rm = TRUE)) + +totAvgNonMand <- mean(c(tours$tour_distance[tours$TOURPURP %in% c(4,5,6,7,8,9,10)], + unique_joint_tours$tour_distance[unique_joint_tours$JOINT_PURP %in% c(5,6,7,8,9)]), + na.rm = T) +avgTripLengths <- c(avgTripLengths, totAvgNonMand) + +nonMandTourPurpose <- c("esco", "imain", "idisc", "jmain", "jdisc", "atwork", "Total") + +nonMandTripLengths <- data.frame(purpose = nonMandTourPurpose, avgTripLength = avgTripLengths) + +write.csv(nonMandTripLengths, "nonMandTripLengths.csv", row.names = F) + +# STop Frequency +#Outbound +stopfreq1 <- hist(tours$num_ob_stops[tours$TOURPURP==1], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq2 <- hist(tours$num_ob_stops[tours$TOURPURP==2], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq3 <- hist(tours$num_ob_stops[tours$TOURPURP==3], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq4 <- hist(tours$num_ob_stops[tours$TOURPURP==4], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi56 <- hist(tours$num_ob_stops[tours$TOURPURP>=5 & tours$TOURPURP<=6], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi789 <- hist(tours$num_ob_stops[tours$TOURPURP>=7 & tours$TOURPURP<=9], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj56 <- hist(unique_joint_tours$num_ob_stops[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj789 <- hist(unique_joint_tours$num_ob_stops[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq10 <- hist(tours$num_ob_stops[tours$TOURPURP==10], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) + +stopFreq <- data.frame(stopfreq1$counts, stopfreq2$counts, stopfreq3$counts, stopfreq4$counts, stopfreqi56$counts + , stopfreqi789$counts, stopfreqj56$counts, stopfreqj789$counts, stopfreq10$counts) +colnames(stopFreq) <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(stopFreq, "stopFreqOutProfile.csv") + +# prepare stop frequency input for visualizer +stopFreqout_vis <- stopFreq +stopFreqout_vis$id <- row.names(stopFreqout_vis) +stopFreqout_vis <- melt(stopFreqout_vis, id = c("id")) +colnames(stopFreqout_vis) <- c("id", "purpose", "freq") + +stopFreqout_vis <- xtabs(freq~purpose+id, stopFreqout_vis) +stopFreqout_vis <- addmargins(as.table(stopFreqout_vis)) +stopFreqout_vis <- as.data.frame.matrix(stopFreqout_vis) +stopFreqout_vis$id <- row.names(stopFreqout_vis) +stopFreqout_vis <- melt(stopFreqout_vis, id = c("id")) +colnames(stopFreqout_vis) <- c("purpose", "nstops", "freq") +stopFreqout_vis$purpose <- as.character(stopFreqout_vis$purpose) +stopFreqout_vis$nstops <- as.character(stopFreqout_vis$nstops) +stopFreqout_vis <- stopFreqout_vis[stopFreqout_vis$nstops!="Sum",] +stopFreqout_vis$purpose[stopFreqout_vis$purpose=="Sum"] <- "Total" + +#Inbound +stopfreq1 <- hist(tours$num_ib_stops[tours$TOURPURP==1], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq2 <- hist(tours$num_ib_stops[tours$TOURPURP==2], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq3 <- hist(tours$num_ib_stops[tours$TOURPURP==3], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq4 <- hist(tours$num_ib_stops[tours$TOURPURP==4], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi56 <- hist(tours$num_ib_stops[tours$TOURPURP>=5 & tours$TOURPURP<=6], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi789 <- hist(tours$num_ib_stops[tours$TOURPURP>=7 & tours$TOURPURP<=9], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj56 <- hist(unique_joint_tours$num_ib_stops[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj789 <- hist(unique_joint_tours$num_ib_stops[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) +stopfreq10 <- hist(tours$num_ib_stops[tours$TOURPURP==10], breaks = c(seq(0,3, by=1), 9999), freq = NULL, right=FALSE) + +stopFreq <- data.frame(stopfreq1$counts, stopfreq2$counts, stopfreq3$counts, stopfreq4$counts, stopfreqi56$counts + , stopfreqi789$counts, stopfreqj56$counts, stopfreqj789$counts, stopfreq10$counts) +colnames(stopFreq) <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(stopFreq, "stopFreqInbProfile.csv") + +# prepare stop frequency input for visualizer +stopFreqinb_vis <- stopFreq +stopFreqinb_vis$id <- row.names(stopFreqinb_vis) +stopFreqinb_vis <- melt(stopFreqinb_vis, id = c("id")) +colnames(stopFreqinb_vis) <- c("id", "purpose", "freq") + +stopFreqinb_vis <- xtabs(freq~purpose+id, stopFreqinb_vis) +stopFreqinb_vis <- addmargins(as.table(stopFreqinb_vis)) +stopFreqinb_vis <- as.data.frame.matrix(stopFreqinb_vis) +stopFreqinb_vis$id <- row.names(stopFreqinb_vis) +stopFreqinb_vis <- melt(stopFreqinb_vis, id = c("id")) +colnames(stopFreqinb_vis) <- c("purpose", "nstops", "freq") +stopFreqinb_vis$purpose <- as.character(stopFreqinb_vis$purpose) +stopFreqinb_vis$nstops <- as.character(stopFreqinb_vis$nstops) +stopFreqinb_vis <- stopFreqinb_vis[stopFreqinb_vis$nstops!="Sum",] +stopFreqinb_vis$purpose[stopFreqinb_vis$purpose=="Sum"] <- "Total" + + +stopfreqDir_vis <- data.frame(stopFreqout_vis, stopFreqinb_vis$freq) +colnames(stopfreqDir_vis) <- c("purpose", "nstops", "freq_out", "freq_inb") +write.csv(stopfreqDir_vis, "stopfreqDir_vis.csv", row.names = F) + + +#Total +stopfreq1 <- hist(tours$num_tot_stops[tours$TOURPURP==1], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreq2 <- hist(tours$num_tot_stops[tours$TOURPURP==2], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreq3 <- hist(tours$num_tot_stops[tours$TOURPURP==3], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreq4 <- hist(tours$num_tot_stops[tours$TOURPURP==4], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi56 <- hist(tours$num_tot_stops[tours$TOURPURP>=5 & tours$TOURPURP<=6], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi789 <- hist(tours$num_tot_stops[tours$TOURPURP>=7 & tours$TOURPURP<=9], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj56 <- hist(unique_joint_tours$num_tot_stops[unique_joint_tours$JOINT_PURP>=5 & unique_joint_tours$JOINT_PURP<=6], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj789 <- hist(unique_joint_tours$num_tot_stops[unique_joint_tours$JOINT_PURP>=7 & unique_joint_tours$JOINT_PURP<=9], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) +stopfreq10 <- hist(tours$num_tot_stops[tours$TOURPURP==10], breaks = c(seq(0,6, by=1), 9999), freq = NULL, right=FALSE) + +stopFreq <- data.frame(stopfreq1$counts, stopfreq2$counts, stopfreq3$counts, stopfreq4$counts, stopfreqi56$counts + , stopfreqi789$counts, stopfreqj56$counts, stopfreqj789$counts, stopfreq10$counts) +colnames(stopFreq) <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(stopFreq, "stopFreqTotProfile.csv") + +# prepare stop frequency input for visualizer +stopFreq_vis <- stopFreq +stopFreq_vis$id <- row.names(stopFreq_vis) +stopFreq_vis <- melt(stopFreq_vis, id = c("id")) +colnames(stopFreq_vis) <- c("id", "purpose", "freq") + +stopFreq_vis <- xtabs(freq~purpose+id, stopFreq_vis) +stopFreq_vis <- addmargins(as.table(stopFreq_vis)) +stopFreq_vis <- as.data.frame.matrix(stopFreq_vis) +stopFreq_vis$id <- row.names(stopFreq_vis) +stopFreq_vis <- melt(stopFreq_vis, id = c("id")) +colnames(stopFreq_vis) <- c("purpose", "nstops", "freq") +stopFreq_vis$purpose <- as.character(stopFreq_vis$purpose) +stopFreq_vis$nstops <- as.character(stopFreq_vis$nstops) +stopFreq_vis <- stopFreq_vis[stopFreq_vis$nstops!="Sum",] +stopFreq_vis$purpose[stopFreq_vis$purpose=="Sum"] <- "Total" + +write.csv(stopFreq_vis, "stopfreq_total_vis.csv", row.names = F) + +#STop purpose X TourPurpose +stopfreq1 <- hist(stops$DPURP[stops$TOURPURP==1], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreq2 <- hist(stops$DPURP[stops$TOURPURP==2], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreq3 <- hist(stops$DPURP[stops$TOURPURP==3], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreq4 <- hist(stops$DPURP[stops$TOURPURP==4], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi56 <- hist(stops$DPURP[stops$TOURPURP>=5 & stops$TOURPURP<=6], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi789 <- hist(stops$DPURP[stops$TOURPURP>=7 & stops$TOURPURP<=9], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj56 <- hist(jstops$DPURP[jstops$TOURPURP>=5 & jstops$TOURPURP<=6], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj789 <- hist(jstops$DPURP[jstops$TOURPURP>=7 & jstops$TOURPURP<=9], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) +stopfreq10 <- hist(stops$DPURP[stops$TOURPURP==10], breaks = c(seq(1,10, by=1), 9999), freq = NULL, right=FALSE) + +stopFreq <- data.frame(stopfreq1$counts, stopfreq2$counts, stopfreq3$counts, stopfreq4$counts, stopfreqi56$counts + , stopfreqi789$counts, stopfreqj56$counts, stopfreqj789$counts, stopfreq10$counts) +colnames(stopFreq) <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(stopFreq, "stopPurposeByTourPurpose.csv") + +# prepare stop frequency input for visualizer +stopFreq_vis <- stopFreq +stopFreq_vis$id <- row.names(stopFreq_vis) +stopFreq_vis <- melt(stopFreq_vis, id = c("id")) +colnames(stopFreq_vis) <- c("stop_purp", "purpose", "freq") + +stopFreq_vis <- xtabs(freq~purpose+stop_purp, stopFreq_vis) +stopFreq_vis <- addmargins(as.table(stopFreq_vis)) +stopFreq_vis <- as.data.frame.matrix(stopFreq_vis) +stopFreq_vis$purpose <- row.names(stopFreq_vis) +stopFreq_vis <- melt(stopFreq_vis, id = c("purpose")) +colnames(stopFreq_vis) <- c("purpose", "stop_purp", "freq") +stopFreq_vis$purpose <- as.character(stopFreq_vis$purpose) +stopFreq_vis$stop_purp <- as.character(stopFreq_vis$stop_purp) +stopFreq_vis <- stopFreq_vis[stopFreq_vis$stop_purp!="Sum",] +stopFreq_vis$purpose[stopFreq_vis$purpose=="Sum"] <- "Total" + +write.csv(stopFreq_vis, "stoppurpose_tourpurpose_vis.csv", row.names = F) + +#Out of direction - Stop Location +stopfreq1 <- hist(stops$out_dir_dist[stops$TOURPURP==1], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq2 <- hist(stops$out_dir_dist[stops$TOURPURP==2], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq3 <- hist(stops$out_dir_dist[stops$TOURPURP==3], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq4 <- hist(stops$out_dir_dist[stops$TOURPURP==4], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi56 <- hist(stops$out_dir_dist[stops$TOURPURP>=5 & stops$TOURPURP<=6], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi789 <- hist(stops$out_dir_dist[stops$TOURPURP>=7 & stops$TOURPURP<=9], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj56 <- hist(jstops$out_dir_dist[jstops$TOURPURP>=5 & jstops$TOURPURP<=6], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj789 <- hist(jstops$out_dir_dist[jstops$TOURPURP>=7 & jstops$TOURPURP<=9], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq10 <- hist(stops$out_dir_dist[stops$TOURPURP==10], breaks = c(-9999,seq(0,40, by=1), 9999), freq = NULL, right=FALSE) + +stopFreq <- data.frame(stopfreq1$counts, stopfreq2$counts, stopfreq3$counts, stopfreq4$counts, stopfreqi56$counts + , stopfreqi789$counts, stopfreqj56$counts, stopfreqj789$counts, stopfreq10$counts) +colnames(stopFreq) <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(stopFreq, "stopOutOfDirectionDC.csv") + +# prepare stop location input for visualizer +stopDC_vis <- stopFreq +stopDC_vis$id <- row.names(stopDC_vis) +stopDC_vis <- melt(stopDC_vis, id = c("id")) +colnames(stopDC_vis) <- c("id", "purpose", "freq") + +stopDC_vis <- xtabs(freq~id+purpose, stopDC_vis) +stopDC_vis <- addmargins(as.table(stopDC_vis)) +stopDC_vis <- as.data.frame.matrix(stopDC_vis) +stopDC_vis$id <- row.names(stopDC_vis) +stopDC_vis <- melt(stopDC_vis, id = c("id")) +colnames(stopDC_vis) <- c("distbin", "PURPOSE", "freq") +stopDC_vis$PURPOSE <- as.character(stopDC_vis$PURPOSE) +stopDC_vis$distbin <- as.character(stopDC_vis$distbin) +stopDC_vis <- stopDC_vis[stopDC_vis$distbin!="Sum",] +stopDC_vis$PURPOSE[stopDC_vis$PURPOSE=="Sum"] <- "Total" +stopDC_vis$distbin <- as.numeric(stopDC_vis$distbin) + +write.csv(stopDC_vis, "stopDC_vis.csv", row.names = F) + +# compute average out of dir distance for visualizer +avgDistances <- c(mean(stops$out_dir_dist[stops$TOURPURP==1], na.rm = TRUE), + mean(stops$out_dir_dist[stops$TOURPURP==2], na.rm = TRUE), + mean(stops$out_dir_dist[stops$TOURPURP==3], na.rm = TRUE), + mean(stops$out_dir_dist[stops$TOURPURP==4], na.rm = TRUE), + mean(stops$out_dir_dist[stops$TOURPURP>=5 & stops$TOURPURP<=6], na.rm = TRUE), + mean(stops$out_dir_dist[stops$TOURPURP>=7 & stops$TOURPURP<=9], na.rm = TRUE), + mean(jstops$out_dir_dist[jstops$TOURPURP>=5 & jstops$TOURPURP<=6], na.rm = TRUE), + mean(jstops$out_dir_dist[jstops$TOURPURP>=7 & jstops$TOURPURP<=9], na.rm = TRUE), + mean(stops$out_dir_dist[stops$TOURPURP==10], na.rm = TRUE), + mean(stops$out_dir_dist, na.rm = TRUE)) + +purp <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork", "total") + +avgStopOutofDirectionDist <- data.frame(purpose = purp, avgDist = avgDistances) + +write.csv(avgStopOutofDirectionDist, "avgStopOutofDirectionDist_vis.csv", row.names = F) + +#Stop Departure Time +stopfreq1 <- hist(stops$stop_period[stops$TOURPURP==1], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq2 <- hist(stops$stop_period[stops$TOURPURP==2], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq3 <- hist(stops$stop_period[stops$TOURPURP==3], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq4 <- hist(stops$stop_period[stops$TOURPURP==4], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi56 <- hist(stops$stop_period[stops$TOURPURP>=5 & stops$TOURPURP<=6], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi789 <- hist(stops$stop_period[stops$TOURPURP>=7 & stops$TOURPURP<=9], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj56 <- hist(jstops$stop_period[jstops$TOURPURP>=5 & jstops$TOURPURP<=6], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj789 <- hist(jstops$stop_period[jstops$TOURPURP>=7 & jstops$TOURPURP<=9], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq10 <- hist(stops$stop_period[stops$TOURPURP==10], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) + +stopFreq <- data.frame(stopfreq1$counts, stopfreq2$counts, stopfreq3$counts, stopfreq4$counts, stopfreqi56$counts + , stopfreqi789$counts, stopfreqj56$counts, stopfreqj789$counts, stopfreq10$counts) +colnames(stopFreq) <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(stopFreq, "stopDeparture.csv") + +# prepare stop departure input for visualizer +stopDep_vis <- stopFreq +stopDep_vis$id <- row.names(stopDep_vis) +stopDep_vis <- melt(stopDep_vis, id = c("id")) +colnames(stopDep_vis) <- c("id", "purpose", "freq_stop") + +stopDep_vis$purpose <- as.character(stopDep_vis$purpose) +stopDep_vis <- xtabs(freq_stop~id+purpose, stopDep_vis) +stopDep_vis <- addmargins(as.table(stopDep_vis)) +stopDep_vis <- as.data.frame.matrix(stopDep_vis) +stopDep_vis$id <- row.names(stopDep_vis) +stopDep_vis <- melt(stopDep_vis, id = c("id")) +colnames(stopDep_vis) <- c("timebin", "PURPOSE", "freq") +stopDep_vis$PURPOSE <- as.character(stopDep_vis$PURPOSE) +stopDep_vis$timebin <- as.character(stopDep_vis$timebin) +stopDep_vis <- stopDep_vis[stopDep_vis$timebin!="Sum",] +stopDep_vis$PURPOSE[stopDep_vis$PURPOSE=="Sum"] <- "Total" +stopDep_vis$timebin <- as.numeric(stopDep_vis$timebin) + +#Trip Departure Time +stopfreq1 <- hist(trips$stop_period[trips$TOURPURP==1], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq2 <- hist(trips$stop_period[trips$TOURPURP==2], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq3 <- hist(trips$stop_period[trips$TOURPURP==3], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq4 <- hist(trips$stop_period[trips$TOURPURP==4], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi56 <- hist(trips$stop_period[trips$TOURPURP>=5 & trips$TOURPURP<=6], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqi789 <- hist(trips$stop_period[trips$TOURPURP>=7 & trips$TOURPURP<=9], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj56 <- hist(jtrips$stop_period[jtrips$TOURPURP>=5 & jtrips$TOURPURP<=6], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreqj789 <- hist(jtrips$stop_period[jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) +stopfreq10 <- hist(trips$stop_period[trips$TOURPURP==10], breaks = c(seq(1,40, by=1), 9999), freq = NULL, right=FALSE) + +stopFreq <- data.frame(stopfreq1$counts, stopfreq2$counts, stopfreq3$counts, stopfreq4$counts, stopfreqi56$counts + , stopfreqi789$counts, stopfreqj56$counts, stopfreqj789$counts, stopfreq10$counts) +colnames(stopFreq) <- c("work", "univ", "sch", "esco","imain", "idisc", "jmain", "jdisc", "atwork") +write.csv(stopFreq, "tripDeparture.csv") + +# prepare stop departure input for visualizer +tripDep_vis <- stopFreq +tripDep_vis$id <- row.names(tripDep_vis) +tripDep_vis <- melt(tripDep_vis, id = c("id")) +colnames(tripDep_vis) <- c("id", "purpose", "freq_trip") + +tripDep_vis$purpose <- as.character(tripDep_vis$purpose) +tripDep_vis <- xtabs(freq_trip~id+purpose, tripDep_vis) +tripDep_vis <- addmargins(as.table(tripDep_vis)) +tripDep_vis <- as.data.frame.matrix(tripDep_vis) +tripDep_vis$id <- row.names(tripDep_vis) +tripDep_vis <- melt(tripDep_vis, id = c("id")) +colnames(tripDep_vis) <- c("timebin", "PURPOSE", "freq") +tripDep_vis$PURPOSE <- as.character(tripDep_vis$PURPOSE) +tripDep_vis$timebin <- as.character(tripDep_vis$timebin) +tripDep_vis <- tripDep_vis[tripDep_vis$timebin!="Sum",] +tripDep_vis$PURPOSE[tripDep_vis$PURPOSE=="Sum"] <- "Total" +tripDep_vis$timebin <- as.numeric(tripDep_vis$timebin) + +stopTripDep_vis <- data.frame(stopDep_vis, tripDep_vis$freq) +colnames(stopTripDep_vis) <- c("id", "purpose", "freq_stop", "freq_trip") +write.csv(stopTripDep_vis, "stopTripDep_vis.csv", row.names = F) + +#Trip Mode Summary (added 3 lines due to change in mode codes, changed seq 9 to 13, Khademul Haque) +#Work +tripmode1 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==1 & trips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_Work.csv") + +# Prepare data for visualizer (changed from 9 to 12) +tripModeProfile1_vis <- tripModeProfile[1:13,] +tripModeProfile1_vis$id <- row.names(tripModeProfile1_vis) +tripModeProfile1_vis <- melt(tripModeProfile1_vis, id = c("id")) +colnames(tripModeProfile1_vis) <- c("id", "purpose", "freq1") + +tripModeProfile1_vis <- xtabs(freq1~id+purpose, tripModeProfile1_vis) +tripModeProfile1_vis[is.na(tripModeProfile1_vis)] <- 0 +tripModeProfile1_vis <- addmargins(as.table(tripModeProfile1_vis)) +tripModeProfile1_vis <- as.data.frame.matrix(tripModeProfile1_vis) + +tripModeProfile1_vis$id <- row.names(tripModeProfile1_vis) +tripModeProfile1_vis <- melt(tripModeProfile1_vis, id = c("id")) +colnames(tripModeProfile1_vis) <- c("id", "purpose", "freq1") +tripModeProfile1_vis$id <- as.character(tripModeProfile1_vis$id) +tripModeProfile1_vis$purpose <- as.character(tripModeProfile1_vis$purpose) +tripModeProfile1_vis <- tripModeProfile1_vis[tripModeProfile1_vis$id!="Sum",] +tripModeProfile1_vis$purpose[tripModeProfile1_vis$purpose=="Sum"] <- "Total" + + +#University (added 3 lines due to change in mode codes, changed seq 9 to 13, Khademul Haque) +tripmode1 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==2 & trips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_Univ.csv") + +tripModeProfile2_vis <- tripModeProfile[1:13,] +tripModeProfile2_vis$id <- row.names(tripModeProfile2_vis) +tripModeProfile2_vis <- melt(tripModeProfile2_vis, id = c("id")) +colnames(tripModeProfile2_vis) <- c("id", "purpose", "freq2") + +tripModeProfile2_vis <- xtabs(freq2~id+purpose, tripModeProfile2_vis) +tripModeProfile2_vis[is.na(tripModeProfile2_vis)] <- 0 +tripModeProfile2_vis <- addmargins(as.table(tripModeProfile2_vis)) +tripModeProfile2_vis <- as.data.frame.matrix(tripModeProfile2_vis) + +tripModeProfile2_vis$id <- row.names(tripModeProfile2_vis) +tripModeProfile2_vis <- melt(tripModeProfile2_vis, id = c("id")) +colnames(tripModeProfile2_vis) <- c("id", "purpose", "freq2") +tripModeProfile2_vis$id <- as.character(tripModeProfile2_vis$id) +tripModeProfile2_vis$purpose <- as.character(tripModeProfile2_vis$purpose) +tripModeProfile2_vis <- tripModeProfile2_vis[tripModeProfile2_vis$id!="Sum",] +tripModeProfile2_vis$purpose[tripModeProfile2_vis$purpose=="Sum"] <- "Total" + +#School +tripmode1 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==3 & trips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_Schl.csv") + +tripModeProfile3_vis <- tripModeProfile[1:13,] +tripModeProfile3_vis$id <- row.names(tripModeProfile3_vis) +tripModeProfile3_vis <- melt(tripModeProfile3_vis, id = c("id")) +colnames(tripModeProfile3_vis) <- c("id", "purpose", "freq3") + +tripModeProfile3_vis <- xtabs(freq3~id+purpose, tripModeProfile3_vis) +tripModeProfile3_vis[is.na(tripModeProfile3_vis)] <- 0 +tripModeProfile3_vis <- addmargins(as.table(tripModeProfile3_vis)) +tripModeProfile3_vis <- as.data.frame.matrix(tripModeProfile3_vis) + +tripModeProfile3_vis$id <- row.names(tripModeProfile3_vis) +tripModeProfile3_vis <- melt(tripModeProfile3_vis, id = c("id")) +colnames(tripModeProfile3_vis) <- c("id", "purpose", "freq3") +tripModeProfile3_vis$id <- as.character(tripModeProfile3_vis$id) +tripModeProfile3_vis$purpose <- as.character(tripModeProfile3_vis$purpose) +tripModeProfile3_vis <- tripModeProfile3_vis[tripModeProfile3_vis$id!="Sum",] +tripModeProfile3_vis$purpose[tripModeProfile3_vis$purpose=="Sum"] <- "Total" + +#iMain +tripmode1 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=4 & trips$TOURPURP<=6 & trips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_iMain.csv") + +tripModeProfile4_vis <- tripModeProfile[1:13,] +tripModeProfile4_vis$id <- row.names(tripModeProfile4_vis) +tripModeProfile4_vis <- melt(tripModeProfile4_vis, id = c("id")) +colnames(tripModeProfile4_vis) <- c("id", "purpose", "freq4") + +tripModeProfile4_vis <- xtabs(freq4~id+purpose, tripModeProfile4_vis) +tripModeProfile4_vis[is.na(tripModeProfile4_vis)] <- 0 +tripModeProfile4_vis <- addmargins(as.table(tripModeProfile4_vis)) +tripModeProfile4_vis <- as.data.frame.matrix(tripModeProfile4_vis) + +tripModeProfile4_vis$id <- row.names(tripModeProfile4_vis) +tripModeProfile4_vis <- melt(tripModeProfile4_vis, id = c("id")) +colnames(tripModeProfile4_vis) <- c("id", "purpose", "freq4") +tripModeProfile4_vis$id <- as.character(tripModeProfile4_vis$id) +tripModeProfile4_vis$purpose <- as.character(tripModeProfile4_vis$purpose) +tripModeProfile4_vis <- tripModeProfile4_vis[tripModeProfile4_vis$id!="Sum",] +tripModeProfile4_vis$purpose[tripModeProfile4_vis$purpose=="Sum"] <- "Total" + +#iDisc +tripmode1 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP>=7 & trips$TOURPURP<=9 & trips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_iDisc.csv") + +tripModeProfile5_vis <- tripModeProfile[1:13,] +tripModeProfile5_vis$id <- row.names(tripModeProfile5_vis) +tripModeProfile5_vis <- melt(tripModeProfile5_vis, id = c("id")) +colnames(tripModeProfile5_vis) <- c("id", "purpose", "freq5") + +tripModeProfile5_vis <- xtabs(freq5~id+purpose, tripModeProfile5_vis) +tripModeProfile5_vis[is.na(tripModeProfile5_vis)] <- 0 +tripModeProfile5_vis <- addmargins(as.table(tripModeProfile5_vis)) +tripModeProfile5_vis <- as.data.frame.matrix(tripModeProfile5_vis) + +tripModeProfile5_vis$id <- row.names(tripModeProfile5_vis) +tripModeProfile5_vis <- melt(tripModeProfile5_vis, id = c("id")) +colnames(tripModeProfile5_vis) <- c("id", "purpose", "freq5") +tripModeProfile5_vis$id <- as.character(tripModeProfile5_vis$id) +tripModeProfile5_vis$purpose <- as.character(tripModeProfile5_vis$purpose) +tripModeProfile5_vis <- tripModeProfile5_vis[tripModeProfile5_vis$id!="Sum",] +tripModeProfile5_vis$purpose[tripModeProfile5_vis$purpose=="Sum"] <- "Total" + +#jMain +tripmode1 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=4 & jtrips$TOURPURP<=6 & jtrips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_jMain.csv") + +tripModeProfile6_vis <- tripModeProfile[1:13,] +tripModeProfile6_vis$id <- row.names(tripModeProfile6_vis) +tripModeProfile6_vis <- melt(tripModeProfile6_vis, id = c("id")) +colnames(tripModeProfile6_vis) <- c("id", "purpose", "freq6") + +tripModeProfile6_vis <- xtabs(freq6~id+purpose, tripModeProfile6_vis) +tripModeProfile6_vis[is.na(tripModeProfile6_vis)] <- 0 +tripModeProfile6_vis <- addmargins(as.table(tripModeProfile6_vis)) +tripModeProfile6_vis <- as.data.frame.matrix(tripModeProfile6_vis) + +tripModeProfile6_vis$id <- row.names(tripModeProfile6_vis) +tripModeProfile6_vis <- melt(tripModeProfile6_vis, id = c("id")) +colnames(tripModeProfile6_vis) <- c("id", "purpose", "freq6") +tripModeProfile6_vis$id <- as.character(tripModeProfile6_vis$id) +tripModeProfile6_vis$purpose <- as.character(tripModeProfile6_vis$purpose) +tripModeProfile6_vis <- tripModeProfile6_vis[tripModeProfile6_vis$id!="Sum",] +tripModeProfile6_vis$purpose[tripModeProfile6_vis$purpose=="Sum"] <- "Total" + +#jDisc +tripmode1 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURPURP>=7 & jtrips$TOURPURP<=9 & jtrips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_jDisc.csv") + +tripModeProfile7_vis <- tripModeProfile[1:13,] +tripModeProfile7_vis$id <- row.names(tripModeProfile7_vis) +tripModeProfile7_vis <- melt(tripModeProfile7_vis, id = c("id")) +colnames(tripModeProfile7_vis) <- c("id", "purpose", "freq7") + +tripModeProfile7_vis <- xtabs(freq7~id+purpose, tripModeProfile7_vis) +tripModeProfile7_vis[is.na(tripModeProfile7_vis)] <- 0 +tripModeProfile7_vis <- addmargins(as.table(tripModeProfile7_vis)) +tripModeProfile7_vis <- as.data.frame.matrix(tripModeProfile7_vis) + +tripModeProfile7_vis$id <- row.names(tripModeProfile7_vis) +tripModeProfile7_vis <- melt(tripModeProfile7_vis, id = c("id")) +colnames(tripModeProfile7_vis) <- c("id", "purpose", "freq7") +tripModeProfile7_vis$id <- as.character(tripModeProfile7_vis$id) +tripModeProfile7_vis$purpose <- as.character(tripModeProfile7_vis$purpose) +tripModeProfile7_vis <- tripModeProfile7_vis[tripModeProfile7_vis$id!="Sum",] +tripModeProfile7_vis$purpose[tripModeProfile7_vis$purpose=="Sum"] <- "Total" + +#At work +tripmode1 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode2 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode3 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode4 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode5 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode6 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode7 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode8 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode9 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode10 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode11 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode12 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +tripmode13 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURPURP==10 & trips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tripModeProfile <- data.frame(tripmode1$counts, tripmode2$counts, tripmode3$counts, tripmode4$counts, + tripmode5$counts, tripmode6$counts, tripmode7$counts, tripmode8$counts, tripmode9$counts, + tripmode10$counts, tripmode11$counts, tripmode12$counts, tripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_AtWork.csv") + +tripModeProfile8_vis <- tripModeProfile[1:13,] +tripModeProfile8_vis$id <- row.names(tripModeProfile8_vis) +tripModeProfile8_vis <- melt(tripModeProfile8_vis, id = c("id")) +colnames(tripModeProfile8_vis) <- c("id", "purpose", "freq8") + +tripModeProfile8_vis <- xtabs(freq8~id+purpose, tripModeProfile8_vis) +tripModeProfile8_vis[is.na(tripModeProfile8_vis)] <- 0 +tripModeProfile8_vis <- addmargins(as.table(tripModeProfile8_vis)) +tripModeProfile8_vis <- as.data.frame.matrix(tripModeProfile8_vis) + +tripModeProfile8_vis$id <- row.names(tripModeProfile8_vis) +tripModeProfile8_vis <- melt(tripModeProfile8_vis, id = c("id")) +colnames(tripModeProfile8_vis) <- c("id", "purpose", "freq8") +tripModeProfile8_vis$id <- as.character(tripModeProfile8_vis$id) +tripModeProfile8_vis$purpose <- as.character(tripModeProfile8_vis$purpose) +tripModeProfile8_vis <- tripModeProfile8_vis[tripModeProfile8_vis$id!="Sum",] +tripModeProfile8_vis$purpose[tripModeProfile8_vis$purpose=="Sum"] <- "Total" + +#iTotal +itripmode1 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode2 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode3 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode4 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode5 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode6 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode7 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode8 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode9 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode10 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode11 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode12 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +itripmode13 <- hist(trips$TRIPMODE[trips$TRIPMODE>0 & trips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +#jTotal +jtripmode1 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==1], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode2 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==2], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode3 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==3], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode4 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==4], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode5 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==5], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode6 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==6], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode7 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==7], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode8 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==8], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode9 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==9], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode10 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==10], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode11 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==11], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode12 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==12], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) +jtripmode13 <- hist(jtrips$TRIPMODE[jtrips$TRIPMODE>0 & jtrips$TOURMODE==13], breaks = seq(1,14, by=1), freq = NULL, right=FALSE) + +tripModeProfile <- data.frame(itripmode1$counts+jtripmode1$counts, itripmode2$counts+jtripmode2$counts, itripmode3$counts+jtripmode3$counts, itripmode4$counts+jtripmode4$counts, + itripmode5$counts+jtripmode5$counts, itripmode6$counts+jtripmode6$counts, itripmode7$counts+jtripmode7$counts, itripmode8$counts+jtripmode8$counts, + itripmode9$counts+jtripmode9$counts, itripmode10$counts+jtripmode10$counts, itripmode11$counts+jtripmode11$counts, itripmode12$counts+jtripmode12$counts, itripmode13$counts+jtripmode13$counts) +colnames(tripModeProfile) <- c("tourmode1", "tourmode2", "tourmode3", "tourmode4", "tourmode5", "tourmode6", "tourmode7", "tourmode8", "tourmode9", "tourmode10", "tourmode11", "tourmode12", "tourmode13") +write.csv(tripModeProfile, "tripModeProfile_Total.csv") + +tripModeProfile9_vis <- tripModeProfile[1:13,] +tripModeProfile9_vis$id <- row.names(tripModeProfile9_vis) +tripModeProfile9_vis <- melt(tripModeProfile9_vis, id = c("id")) +colnames(tripModeProfile9_vis) <- c("id", "purpose", "freq9") + +tripModeProfile9_vis <- xtabs(freq9~id+purpose, tripModeProfile9_vis) +tripModeProfile9_vis[is.na(tripModeProfile9_vis)] <- 0 +tripModeProfile9_vis <- addmargins(as.table(tripModeProfile9_vis)) +tripModeProfile9_vis <- as.data.frame.matrix(tripModeProfile9_vis) + +tripModeProfile9_vis$id <- row.names(tripModeProfile9_vis) +tripModeProfile9_vis <- melt(tripModeProfile9_vis, id = c("id")) +colnames(tripModeProfile9_vis) <- c("id", "purpose", "freq9") +tripModeProfile9_vis$id <- as.character(tripModeProfile9_vis$id) +tripModeProfile9_vis$purpose <- as.character(tripModeProfile9_vis$purpose) +tripModeProfile9_vis <- tripModeProfile9_vis[tripModeProfile9_vis$id!="Sum",] +tripModeProfile9_vis$purpose[tripModeProfile9_vis$purpose=="Sum"] <- "Total" + + +# combine all tripmode profile for visualizer +tripModeProfile_vis <- data.frame(tripModeProfile1_vis, tripModeProfile2_vis$freq2, tripModeProfile3_vis$freq3 + , tripModeProfile4_vis$freq4, tripModeProfile5_vis$freq5, tripModeProfile6_vis$freq6 + , tripModeProfile7_vis$freq7, tripModeProfile8_vis$freq8, tripModeProfile9_vis$freq9) +colnames(tripModeProfile_vis) <- c("tripmode", "tourmode", "work", "univ", "schl", "imain", "idisc", "jmain", "jdisc", "atwork", "total") + +temp <- melt(tripModeProfile_vis, id = c("tripmode", "tourmode")) +#tripModeProfile_vis <- cast(temp, tripmode+variable~tourmode) +#write.csv(tripModeProfile_vis, "tripModeProfile_vis.csv", row.names = F) +temp$grp_var <- paste(temp$variable, temp$tourmode, sep = "") + +# rename tour mode to standard names +temp$tourmode[temp$tourmode=="tourmode1"] <- 'Auto SOV' +temp$tourmode[temp$tourmode=="tourmode2"] <- 'Auto 2 Person' +temp$tourmode[temp$tourmode=="tourmode3"] <- 'Auto 3+ Person' +temp$tourmode[temp$tourmode=="tourmode4"] <- 'Walk' +temp$tourmode[temp$tourmode=="tourmode5"] <- 'Bike/Moped' +temp$tourmode[temp$tourmode=="tourmode6"] <- 'Walk-Transit' +temp$tourmode[temp$tourmode=="tourmode7"] <- 'PNR-Transit' +temp$tourmode[temp$tourmode=="tourmode8"] <- 'KNR-Transit' +temp$tourmode[temp$tourmode=="tourmode9"] <- 'TNC-Transit' +temp$tourmode[temp$tourmode=="tourmode10"] <- 'Taxi' +temp$tourmode[temp$tourmode=="tourmode11"] <- 'TNC-Single' +temp$tourmode[temp$tourmode=="tourmode12"] <- 'TNC-Shared' +temp$tourmode[temp$tourmode=="tourmode13"] <- 'School Bus' + +colnames(temp) <- c("tripmode","tourmode","purpose","value","grp_var") + +write.csv(temp, "tripModeProfile_vis.csv", row.names = F) + + +### +#trip mode by time period +#calculate time of day +trips$tod <- 5 # EA: 3 am - 6 am +trips$tod <- ifelse(trips$stop_period>=4 & trips$stop_period<=9, 1, trips$tod) # AM: 6 am - 9 am +trips$tod <- ifelse(trips$stop_period>=10 & trips$stop_period<=22, 2, trips$tod) # MD: 9 am - 3:30 pm +trips$tod <- ifelse(trips$stop_period>=23 & trips$stop_period<=29, 3, trips$tod) # PM: 3:30 pm - 7 pm +trips$tod <- ifelse(trips$stop_period>=30 & trips$stop_period<=40, 4, trips$tod) # EV: 7 pm - 3 am +trips$num_trips <- 1 + +jtrips$tod <- 5 # EA: 3 am - 6 am +jtrips$tod <- ifelse(jtrips$stop_period>=4 & jtrips$stop_period<=9, 1, jtrips$tod) # AM: 6 am - 9 am +jtrips$tod <- ifelse(jtrips$stop_period>=10 & jtrips$stop_period<=22, 2, jtrips$tod) # MD: 9 am - 3:30 pm +jtrips$tod <- ifelse(jtrips$stop_period>=23 & jtrips$stop_period<=29, 3, jtrips$tod) # PM: 3:30 pm - 7 pm +jtrips$tod <- ifelse(jtrips$stop_period>=30 & jtrips$stop_period<=40, 4, jtrips$tod) # EV: 7 pm - 3 am +jtrips$num_trips <- 1 +#jtrips$num_trips <- jtrips$num_participants + +itrips_summary <- aggregate(num_trips~tod+TOURPURP+TOURMODE+TRIPMODE, data=trips, FUN=sum) +jtrips_summary <- aggregate(num_trips~tod+TOURPURP+TOURMODE+TRIPMODE, data=jtrips, FUN=sum) + +write.csv(itrips_summary, "itrips_tripmode_summary.csv", row.names = F) +write.csv(jtrips_summary, "jtrips_tripmode_summary.csv", row.names = F) + +### + + + + +# Total number of stops, trips & tours +cat("Total number of stops : ", nrow(stops) + nrow(jstops)) +cat("Total number of trips : ", nrow(trips) + nrow(jtrips)) +cat("Total number of tours : ", nrow(tours) + sum(unique_joint_tours$NUMBER_HH)) + + +# output total numbers in a file +total_population <- sum(pertypeDistbn$freq) +total_households <- nrow(hh) +total_tours <- nrow(tours) + sum(unique_joint_tours$NUMBER_HH) +total_trips <- nrow(trips) + nrow(jtrips) +total_stops <- nrow(stops) + nrow(jstops) + +trips$num_travel[trips$TRIPMODE==1] <- 1 #sov +trips$num_travel[trips$TRIPMODE==2] <- 2 #hov2 +trips$num_travel[trips$TRIPMODE==3] <- 3.5 #hov3 +trips$num_travel[trips$TRIPMODE==10] <- 1.1 #taxi +trips$num_travel[trips$TRIPMODE==11] <- 1.2 #tnc single +trips$num_travel[trips$TRIPMODE==12] <- 2.0 #tnc shared +trips$num_travel[is.na(trips$num_travel)] <- 0 + +total_vmt <- sum((trips$od_dist[trips$TRIPMODE<=3])/trips$num_travel[trips$TRIPMODE<=3]) + sum((trips$od_dist[trips$TRIPMODE>=10 & trips$TRIPMODE<=12])/trips$num_travel[trips$TRIPMODE>=10 & trips$TRIPMODE<=12]) + +totals_var <- c("total_population", "total_households", "total_tours", "total_trips", "total_stops", "total_vmt") +totals_val <- c(total_population,total_households, total_tours, total_trips, total_stops, total_vmt) + +totals_df <- data.frame(name = totals_var, value = totals_val) + +write.csv(totals_df, "totals.csv", row.names = F) + +# HH Size distribution +hhSizeDist <- count(hh, c("HHSIZE")) +write.csv(hhSizeDist, "hhSizeDist.csv", row.names = F) + +# Persons by person type +actpertypeDistbn <- count(per[per$activity_pattern!="H"], c("PERTYPE")) +write.csv(actpertypeDistbn, "activePertypeDistbn.csv", row.names = TRUE) + + +### Generate school escorting summaries + +# detach plyr and load dplyr +#detach("package:plyr", unload=TRUE) +if (!"dplyr" %in% installed.packages()) install.packages("dplyr", repos='http://cran.us.r-project.org') +library(dplyr) + +# get driver person type +tours$out_chauffuer_ptype <- per$PERTYPE[match(tours$hh_id*100+tours$driver_num_out, + per$hh_id*100+per$person_num)] +tours$inb_chauffuer_ptype <- per$PERTYPE[match(tours$hh_id*100+tours$driver_num_in, + per$hh_id*100+per$person_num)] + +#tours$out_chauffuer_dap <- per$activity_pattern[match(tours$hh_id*100+tours$driver_num_out, per$hh_id*100+per$person_num)] +#tours$inb_chauffuer_dap <- per$activity_pattern[match(tours$hh_id*100+tours$driver_num_in, per$hh_id*100+per$person_num)] + + +tours[is.na(tours)] <- 0 + +tours_sample <- select(tours, hh_id, person_id, person_num, tour_id, tour_purpose, escort_type_out, escort_type_in, + driver_num_out, driver_num_in, person_type) + +tours_sample <- tours[tours$tour_purpose=="School" & tours$person_type>=6, ] + +# Code no escort as "3" to be same as OHAS data +tours_sample$escort_type_out[tours_sample$escort_type_out==0] <- 3 +tours_sample$escort_type_in[tours_sample$escort_type_in==0] <- 3 + + +# School tours by Escort Type X Child Type +out_table1 <- table(tours_sample$escort_type_out, tours_sample$person_type) +inb_table1 <- table(tours_sample$escort_type_in, tours_sample$person_type) + +# School tours by Escort Type X Chauffuer Type +out_sample2 <- filter(tours_sample, out_chauffuer_ptype>0) +inb_sample2 <- filter(tours_sample, inb_chauffuer_ptype>0) +out_table2 <- table(out_sample2$escort_type_out, out_sample2$out_chauffuer_ptype) +inb_table2 <- table(inb_sample2$escort_type_in, inb_sample2$inb_chauffuer_ptype) + +## Workers summary +# summary of worker with a child which went to school +# by escort type, can be separated by outbound and inbound direction + +#get list of active workers with at least one work tour +active_workers <- tours %>% + filter(tour_purpose %in% c("Work","Work-Based")) %>% #work and work-related + filter(person_type %in% c(1,2)) %>% #full and part-time worker + group_by(hh_id, person_num) %>% + summarise(person_type=max(person_type)) %>% + ungroup() + +workers <- per[per$PERTYPE %in% c(1,2), ] + +#get list of students with at least one school tour +active_students <- tours %>% + filter(tour_purpose %in% c("School")) %>% #school tour + filter(person_type %in% c(6,7,8)) %>% #all school students + group_by(hh_id, person_num) %>% + summarise(person_type=max(person_type)) %>% + ungroup() + +students <- per[per$PERTYPE %in% c(6,7,8), ] + +hh_active_student <- active_students %>% + group_by(hh_id) %>% + mutate(active_student=1) %>% + summarise(active_student = max(active_student)) %>% + ungroup() + +#tag active workers with active students in household +active_workers <- active_workers %>% + left_join(hh_active_student, by = c("hh_id")) %>% + mutate(active_student=ifelse(is.na(active_student), 0, active_student)) + + +#list of workers who did ride share or pure escort for school student +out_rs_workers <- tours %>% + select(hh_id, person_num, tour_id, tour_purpose, + escort_type_out, driver_num_out, out_chauffuer_ptype) %>% + filter(tour_purpose=="School" & escort_type_out==1) %>% + group_by(hh_id, driver_num_out) %>% + mutate(num_escort = 1) %>% + summarise(out_rs_escort = sum(num_escort)) + +out_pe_workers <- tours %>% + select(hh_id, person_num, tour_id, tour_purpose, + escort_type_out, driver_num_out, out_chauffuer_ptype) %>% + filter(tour_purpose=="School" & escort_type_out==2) %>% + group_by(hh_id, driver_num_out) %>% + mutate(num_escort = 1) %>% + summarise(out_pe_escort = sum(num_escort)) + +inb_rs_workers <- tours %>% + select(hh_id, person_num, tour_id, tour_purpose, + escort_type_in, driver_num_in, inb_chauffuer_ptype) %>% + filter(tour_purpose=="School" & escort_type_in==1) %>% + group_by(hh_id, driver_num_in) %>% + mutate(num_escort = 1) %>% + summarise(inb_rs_escort = sum(num_escort)) + +inb_pe_workers <- tours %>% + select(hh_id, person_num, tour_id, tour_purpose, + escort_type_in, driver_num_in, inb_chauffuer_ptype) %>% + filter(tour_purpose=="School" & escort_type_in==2) %>% + group_by(hh_id, driver_num_in) %>% + mutate(num_escort = 1) %>% + summarise(inb_pe_escort = sum(num_escort)) + +active_workers <- active_workers %>% + left_join(out_rs_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_out")) %>% + left_join(out_pe_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_out")) %>% + left_join(inb_rs_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_in")) %>% + left_join(inb_pe_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_in")) + +active_workers[is.na(active_workers)] <- 0 + +#workers <- workers %>% +# left_join(out_rs_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_out")) %>% +# left_join(out_pe_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_out")) %>% +# left_join(inb_rs_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_in")) %>% +# left_join(inb_pe_workers, by = c("hh_id"="hh_id", "person_num"="driver_num_in")) +# +#workers[is.na(workers)] <- 0 + +active_workers <- active_workers %>% + mutate(out_escort_type = 3) %>% + mutate(out_escort_type = ifelse(out_rs_escort>0, 1, out_escort_type)) %>% + mutate(out_escort_type = ifelse(out_pe_escort>0, 2, out_escort_type)) %>% + mutate(inb_escort_type = 3) %>% + mutate(inb_escort_type = ifelse(inb_rs_escort>0, 1, inb_escort_type)) %>% + mutate(inb_escort_type = ifelse(inb_pe_escort>0, 2, inb_escort_type)) + +temp <- filter(active_workers, active_student==1) +worker_table <- table(temp$out_escort_type, temp$inb_escort_type) + +## add marginal totals to all final tables +out_table1 <- addmargins(as.table(out_table1)) +inb_table1 <- addmargins(as.table(inb_table1)) +out_table2 <- addmargins(as.table(out_table2)) +inb_table2 <- addmargins(as.table(inb_table2)) +worker_table <- addmargins(as.table(worker_table)) + +## reshape data in required form for visualizer +out_table1 <- as.data.frame.matrix(out_table1) +out_table1$id <- row.names(out_table1) +out_table1 <- melt(out_table1, id = c("id")) +colnames(out_table1) <- c("esc_type", "child_type", "freq_out") +out_table1$esc_type <- as.character(out_table1$esc_type) +out_table1$child_type <- as.character(out_table1$child_type) +out_table1 <- out_table1[out_table1$esc_type!="Sum",] +out_table1$child_type[out_table1$child_type=="Sum"] <- "Total" + +inb_table1 <- as.data.frame.matrix(inb_table1) +inb_table1$id <- row.names(inb_table1) +inb_table1 <- melt(inb_table1, id = c("id")) +colnames(inb_table1) <- c("esc_type", "child_type", "freq_inb") +inb_table1$esc_type <- as.character(inb_table1$esc_type) +inb_table1$child_type <- as.character(inb_table1$child_type) +inb_table1 <- inb_table1[inb_table1$esc_type!="Sum",] +inb_table1$child_type[inb_table1$child_type=="Sum"] <- "Total" + +table1 <- out_table1 +table1$freq_inb <- inb_table1$freq_inb +table1$esc_type[table1$esc_type=='1'] <- "Ride Share" +table1$esc_type[table1$esc_type=='2'] <- "Pure Escort" +table1$esc_type[table1$esc_type=='3'] <- "No Escort" +table1$child_type[table1$child_type=='6'] <- 'Driv Student' +table1$child_type[table1$child_type=='7'] <- 'Non-DrivStudent' +table1$child_type[table1$child_type=='8'] <- 'Pre-Schooler' + + +out_table2 <- as.data.frame.matrix(out_table2) +out_table2$id <- row.names(out_table2) +out_table2 <- melt(out_table2, id = c("id")) +colnames(out_table2) <- c("esc_type", "chauffeur", "freq_out") +out_table2$esc_type <- as.character(out_table2$esc_type) +out_table2$chauffeur <- as.character(out_table2$chauffeur) +out_table2 <- out_table2[out_table2$esc_type!="Sum",] +out_table2$chauffeur[out_table2$chauffeur=="Sum"] <- "Total" + +inb_table2 <- as.data.frame.matrix(inb_table2) +inb_table2$id <- row.names(inb_table2) +inb_table2 <- melt(inb_table2, id = c("id")) +colnames(inb_table2) <- c("esc_type", "chauffeur", "freq_inb") +inb_table2$esc_type <- as.character(inb_table2$esc_type) +inb_table2$chauffeur <- as.character(inb_table2$chauffeur) +inb_table2 <- inb_table2[inb_table2$esc_type!="Sum",] +inb_table2$chauffeur[inb_table2$chauffeur=="Sum"] <- "Total" + +table2 <- out_table2 +table2$freq_inb <- inb_table2$freq_inb +table2$esc_type[table2$esc_type=="1"] <- "Ride Share" +table2$esc_type[table2$esc_type=="2"] <- "Pure Escort" +table2$esc_type[table2$esc_type=="3"] <- "No Escort" +table2$chauffeur[table2$chauffeur=='1'] <- "FT Worker" +table2$chauffeur[table2$chauffeur=='2'] <- "PT Worker" +table2$chauffeur[table2$chauffeur=='3'] <- "Univ Stud" +table2$chauffeur[table2$chauffeur=='4'] <- "Non-Worker" +table2$chauffeur[table2$chauffeur=='5'] <- "Retiree" +table2$chauffeur[table2$chauffeur=='6'] <- "Driv Student" + +worker_table <- as.data.frame.matrix(worker_table) +colnames(worker_table) <- c("Ride Share", "Pure Escort", "No Escort", "Total") +worker_table$DropOff <- row.names(worker_table) +worker_table$DropOff[worker_table$DropOff=="1"] <- "Ride Share" +worker_table$DropOff[worker_table$DropOff=="2"] <- "Pure Escort" +worker_table$DropOff[worker_table$DropOff=="3"] <- "No Escort" +worker_table$DropOff[worker_table$DropOff=="Sum"] <- "Total" + +worker_table <- worker_table[, c("DropOff", "Ride Share","Pure Escort","No Escort","Total")] + +## write outputs +write.csv(table1, "esctype_by_childtype.csv", row.names = F) +write.csv(table2, "esctype_by_chauffeurtype.csv", row.names = F) +write.csv(worker_table, "worker_school_escorting.csv", row.names = F) + +detach("package:dplyr", unload=TRUE) + + +#District level summary of transit tours and trips +#segment by Walk, PNR, and KNR +# tour mode/trip mode +# 9-Walk to Transit +# 10-PNR +# 11-KNR + +#tours +tours$ODISTRICT <- mazCorrespondence$pmsa[match(tours$orig_mgra, mazCorrespondence$mgra)] +tours$DDISTRICT <- mazCorrespondence$pmsa[match(tours$dest_mgra, mazCorrespondence$mgra)] +tours_transit <- tours[tours$tour_mode>=9 & tours$tour_mode<=12,] +tours_transit <- tours_transit[,c("ODISTRICT","DDISTRICT","tour_mode")] +tours_transit$NUMBER_HH <- 1 + +unique_joint_tours$ODISTRICT <- mazCorrespondence$pmsa[match(unique_joint_tours$orig_mgra, mazCorrespondence$mgra)] +unique_joint_tours$DDISTRICT <- mazCorrespondence$pmsa[match(unique_joint_tours$dest_mgra, mazCorrespondence$mgra)] +unique_joint_tours_transit <- unique_joint_tours[unique_joint_tours$tour_mode>=9 & unique_joint_tours$tour_mode<=12,] +unique_joint_tours_transit <- unique_joint_tours_transit[,c("ODISTRICT","DDISTRICT","tour_mode", "NUMBER_HH")] + +tours_transit_all <- rbind(tours_transit, unique_joint_tours_transit) + +district_flow_tours <- xtabs(NUMBER_HH~tour_mode+ODISTRICT+DDISTRICT, data=tours_transit_all) +write.csv(district_flow_tours, "district_flow_transit_tours.csv") + +#trips +trips$ODISTRICT <- mazCorrespondence$pmsa[match(trips$orig_mgra, mazCorrespondence$mgra)] +trips$DDISTRICT <- mazCorrespondence$pmsa[match(trips$dest_mgra, mazCorrespondence$mgra)] +trips_transit <- trips[trips$trip_mode>=9 & trips$trip_mode<=12,] +trips_transit <- trips_transit[,c("ODISTRICT","DDISTRICT","trip_mode")] +trips_transit$num_participants <- 1 + +jtrips$ODISTRICT <- mazCorrespondence$pmsa[match(jtrips$orig_mgra, mazCorrespondence$mgra)] +jtrips$DDISTRICT <- mazCorrespondence$pmsa[match(jtrips$dest_mgra, mazCorrespondence$mgra)] +jtrips_transit <- jtrips[jtrips$trip_mode>=9 & jtrips$trip_mode<=12,] +jtrips_transit <- jtrips_transit[,c("ODISTRICT","DDISTRICT","trip_mode","num_participants")] + +trips_transit_all <- rbind(trips_transit, jtrips_transit) + +district_flow_trips <- xtabs(num_participants~trip_mode+ODISTRICT+DDISTRICT, data=trips_transit_all) +write.csv(district_flow_trips, "district_flow_transit_trips.csv") + +# finish + +end_time <- Sys.time() +end_time - start_time diff --git a/sandag_abm/src/main/r/visualizer/_SYSTEM_VARIABLES.R b/sandag_abm/src/main/r/visualizer/_SYSTEM_VARIABLES.R new file mode 100644 index 0000000..bcbbaad --- /dev/null +++ b/sandag_abm/src/main/r/visualizer/_SYSTEM_VARIABLES.R @@ -0,0 +1,100 @@ +### Paths +SYSTEM_APP_PATH <- WORKING_DIR +SYSTEM_DATA_PATH <- file.path(SYSTEM_APP_PATH, "data") +SYSTEM_SHP_PATH <- file.path(SYSTEM_DATA_PATH, "SHP") +SYSTEM_TEMPLATES_PATH <- file.path(SYSTEM_APP_PATH, "templates") +SYSTEM_SCRIPTS_PATH <- file.path(SYSTEM_APP_PATH, "scripts") +OUTPUT_PATH <- file.path(SYSTEM_APP_PATH, "outputs") +RUNTIME_PATH <- file.path(SYSTEM_APP_PATH, "runtime") +BASE_DATA_PATH <- file.path(SYSTEM_DATA_PATH, "base") +BUILD_DATA_PATH <- file.path(SYSTEM_DATA_PATH, "build") + +### Names +if(IS_BASE_SURVEY=="Yes"){ + # Surey Base + BASE_SCENARIO_ALT <- "HTS" + DISTRICT_FLOW_CENSUS <- "HTS" + AO_CENSUS_SHORT <- "HTS" + AO_CENSUS_LONG <- "HTS" +}else{ + # Non-Survey Base + BASE_SCENARIO_ALT <- BASE_SCENARIO_NAME + DISTRICT_FLOW_CENSUS <- BASE_SCENARIO_NAME + AO_CENSUS_SHORT <- BASE_SCENARIO_NAME + AO_CENSUS_LONG <- BASE_SCENARIO_NAME +} + +### Other Codes +person_type_codes <- c(1, 2, 3, 4, 5, 6, 7, 8, "Total") +person_type_names <- c("1.FT Worker", "2.PT Worker", "3.Univ Stud", "4.Non-Worker", "5.Retiree", "6.Driv Student", "7.Non-DrivStudent", "8.Pre-Schooler", "Total") +person_type_char <- c("FT Worker", "PT Worker", "Univ Stud", "Non-Worker", "Retiree", "Driv Student", "Non-DrivStudent", "Pre-Schooler", "Total") +person_type_df <- data.frame(code = person_type_codes, name = person_type_names, name_char = person_type_char) + +purpose_type_codes <- c("atwork", "esc", "esco", "idisc", "imain", "jdisc", "jmain", "sch", "schl", "univ", "work", "total", "Total") +purpose_type_names <- c("At-Work", "Escorting", "Escorting", "Indi-Discretionary", "Indi-Maintenance", "Joint-Discretionary", "Joint-Maintenance", "School", "School", "University", "Work", "Total", "Total") +purpose_type_df <- data.frame(code = purpose_type_codes, name = purpose_type_names) + +mtf_codes <- c(1, 2, 3, 4, 5) +mtf_names <- c("1 Work", "2 Work", "1 School", "2 School", "1 Work & 1 School") +mtf_df <- data.frame(code = mtf_codes, name = mtf_names) +dap_types <- c("M", "N", "H") +jtf_alternatives <- c("No Joint Tours", "1 Shopping", "1 Maintenance", "1 Eating Out", "1 Visiting", "1 Other Discretionary", + "2 Shopping", "1 Shopping / 1 Maintenance", "1 Shopping / 1 Eating Out", "1 Shopping / 1 Visiting", + "1 Shopping / 1 Other Discretionary", "2 Maintenance", "1 Maintenance / 1 Eating Out", + "1 Maintenance / 1 Visiting", "1 Maintenance / 1 Other Discretionary", "2 Eating Out", "1 Eating Out / 1 Visiting", + "1 Eating Out / 1 Other Discretionary", "2 Visiting", "1 Visiting / 1 Other Discretionary", "2 Other Discretionary") +todBins <- c("03:00 AM to 05:00 AM","05:00 AM to 05:30 AM","05:30 AM to 06:00 AM","06:00 AM to 06:30 AM","06:30 AM to 07:00 AM", + "07:00 AM to 07:30 AM","07:30 AM to 08:00 AM","08:00 AM to 08:30 AM", "08:30 AM to 09:00 AM","09:00 AM to 09:30 AM", + "09:30 AM to 10:00 AM","10:00 AM to 10:30 AM", "10:30 AM to 11:00 AM","11:00 AM to 11:30 AM", "11:30 AM to 12:00 PM", + "12:00 PM to 12:30 PM", "12:30 PM to 01:00 PM","01:00 PM to 01:30 PM", "01:30 PM to 02:00 PM","02:00 PM to 02:30 PM", + "02:30 PM to 03:00 PM","03:00 PM to 03:30 PM", "03:30 PM to 04:00 PM","04:00 PM to 04:30 PM", "04:30 PM to 05:00 PM", + "05:00 PM to 05:30 PM", "05:30 PM to 06:00 PM","06:00 PM to 06:30 PM", "06:30 PM to 07:00 PM","07:00 PM to 07:30 PM", + "07:30 PM to 08:00 PM","08:00 PM to 08:30 PM", "08:30 PM to 09:00 PM","09:00 PM to 09:30 PM", "09:30 PM to 10:00 PM", + "10:00 PM to 10:30 PM", "10:30 PM to 11:00 PM","11:00 PM to 11:30 PM", "11:30 PM to 12:00 AM","12:00 PM to 03:00 AM") +tod_df <- data.frame(id = seq(from=1, to=40), bin = todBins) +durBins <- c("(0.5 hours)","(1 hours)","(1.5 hours)","(2 hours)","(2.5 hours)","(3 hours)","(3.5 hours)","(4 hours)","(4.5 hours)", + "(5 hours)","(5.5 hours)","(6 hours)","(6.5 hours)","(7 hours)","(7.5 hours)","(8 hours)","(8.5 hours)","(9 hours)", + "(9.5 hours)","(10 hours)","(10.5 hours)","(11 hours)","(11.5 hours)","(12 hours)","(12.5 hours)","(13 hours)", + "(13.5 hours)","(14 hours)","(14.5 hours)","(15 hours)","(15.5 hours)","(16 hours)","(16.5 hours)","(17 hours)", + "(17.5 hours)","(18 hours)","(18.5 hours)","(19 hours)","(19.5 hours)","(20 hours)") +dur_df <- data.frame(id = seq(from=1, to=40), bin = durBins) +stopPurposes <- c("Work","Univ","Schl","Esco","Shop","Main","Eati","Visi","Disc","Work-related") +outDirDist <- c("< 0", "0-1", "1-2", "2-3", "3-4", "4-5", "5-6", "6-7", "7-8", "8-9", "9-10", "10-11", "11-12", "12-13", "13-14", "14-15", "15-16", "16-17", "17-18", "18-19", "19-20", "20-21", + "21-22", "22-23", "23-24", "24-25", "25-26", "26-27", "27-28", "28-29", "29-30", "30-31", "31-32", "32-33", "33-34", "34-35", "35-36", "36-37", "37-38", "38-39", "39-40", "40p") +tourMode <- c('Auto SOV','Auto 2 Person','Auto 3+ Person','Walk','Bike/Moped','Walk-Transit','PNR-Transit','KNR-Transit','TNC-Transit','Taxi','TNC-Single','TNC-Shared','School Bus') +tripMode <- c('Auto SOV','Auto 2 Person','Auto 3+ Person','Walk','Bike/Moped','Walk-Transit','PNR-Transit','KNR-Transit','TNC-Transit','Taxi','TNC-Single','TNC-Shared','School Bus') +sch_esc_types <- c('Ride Share', 'Pure Escort', 'No Escort') +sch_esc_codes <- c(1, 2, 3) +sch_esc_df <- data.frame(code = sch_esc_codes, type = sch_esc_types) +facility_types <- c('Interstate', 'Principal Arterial', 'Minor Arterial', 'Major Collector', 'Minor Collector', 'Local Road', 'Ramp') +facility_codes <- c(1, 3, 4, 5, 6, 7, 30) +facility_df <- data.frame(code = facility_codes, type = facility_types) +timePeriods <- c("EV1","EA","AM","MD","PM","EV") +timePeriodBreaks <- c(0,1,4,10,23,30, 41) +occp_type_codes <- c("occ1", "occ2", "occ3", "occ4", "occ5", "occ6", "Total") +occp_type_names <- c("Management", "Service", "Sales & Office", "Natural Resources", "Production", "Military", "Total") +occp_type_df <- data.frame(code = occp_type_codes, name = occp_type_names) + +### Functions +copyFile <- function(fileList, sourceDir, targetDir){ + error <- F + setwd(sourceDir) + for(file in fileList){ + full_file <- paste(sourceDir, file, sep = "/") + ## check if file exists - copy if exists else error out + if(file.exists(file)){ + file.copy(full_file, targetDir, overwrite = T, copy.date = T) + }else{ + #winDialog("ok", paste(file, "does not exist in", sourceDir)) + write.table(paste(file, "does not exist in", sourceDir), paste(OUTPUT_PATH, "error.txt", sep = "/")) + error <- T + } + if(error) break + } + return(error) +} + + + + + diff --git a/sandag_abm/src/main/r/visualizer/workersByMAZ.R b/sandag_abm/src/main/r/visualizer/workersByMAZ.R new file mode 100644 index 0000000..29f9615 --- /dev/null +++ b/sandag_abm/src/main/r/visualizer/workersByMAZ.R @@ -0,0 +1,114 @@ +########################################################## +### Script to summarize workers by MAZ and Occupation Type + +##### LIST OF ALL INPUT FILES ##### +## 0. Path input data : parameters.csv +## 1. person data : personData_3.csv +## 2. Work school location data : wsLocResults_3.csv +## 3. MAZ data : mgra13_based_input2016.csv +## 4. Occupation factors data : occFactors.csv +## 5. Geographic crosswalk data : geographicXwalk_PMSA.csv + +### Read Command Line Arguments +args <- commandArgs(trailingOnly = TRUE) +Parameters_File <- args[1] +REF <- args[2] + +SYSTEM_REPORT_PKGS <- c("reshape", "dplyr", "data.table") +lib_sink <- suppressWarnings(suppressMessages(lapply(SYSTEM_REPORT_PKGS, library, character.only = TRUE))) + +### Read parameters file +parameters <- read.csv(Parameters_File, header = TRUE) + +### Read parameters from Parameters_File (REF) +PROJECT_DIR <- trimws(paste(parameters$Value[parameters$Key=="PROJECT_DIR"])) +if(REF){ + WD <- trimws(paste(parameters$Value[parameters$Key=="BASE_SUMMARY_DIR"])) + ABMOutputDir <- trimws(paste(parameters$Value[parameters$Key=="REF_DIR"])) + ABMInputDir <- trimws(paste(parameters$Value[parameters$Key=="REF_DIR_INP"])) + BUILD_SAMPLE_RATE <- as.numeric(trimws(paste(parameters$Value[parameters$Key=="BASE_SAMPLE_RATE"]))) +} else { + WD <- trimws(paste(parameters$Value[parameters$Key=="BUILD_SUMMARY_DIR"])) + + ABMOutputDir <- file.path(PROJECT_DIR, "output") + ABMInputDir <- file.path(PROJECT_DIR, "input") + BUILD_SAMPLE_RATE <- as.numeric(trimws(paste(parameters$Value[parameters$Key=="BUILD_SAMPLE_RATE"]))) +} + +MAX_ITER <- trimws(paste(parameters$Value[parameters$Key=="MAX_ITER"])) +WORKING_DIR <- trimws(paste(parameters$Value[parameters$Key=="WORKING_DIR"])) +geogXWalkDir <- trimws(paste(parameters$Value[parameters$Key=="geogXWalkDir"])) +mazFile <- trimws(paste(parameters$Value[parameters$Key=="mgraInputFile"])) +factorDir <- file.path(WORKING_DIR, "data") + +# read data +per <- read.csv(paste(ABMOutputDir, paste("personData_",MAX_ITER, ".csv", sep = ""), sep = "/"), as.is = T) +wsLoc <- read.csv(paste(ABMOutputDir, paste("wsLocResults_",MAX_ITER, ".csv", sep = ""), sep = "/"), as.is = T) +mazData <- read.csv(paste(ABMInputDir, basename(mazFile), sep = "/"), as.is = T) +occFac <- read.csv(paste(factorDir, "occFactors.csv", sep = "/"), as.is = T) +mazCorrespondence <- fread(paste(geogXWalkDir, "geographicXwalk_PMSA.csv", sep = "/"), stringsAsFactors = F) + +# workers by occupation type +workersbyMAZ <- wsLoc[wsLoc$PersonType<=3 & wsLoc$WorkLocation>0 & wsLoc$WorkSegment %in% c(0,1,2,3,4,5),] %>% + mutate(weight = 1/BUILD_SAMPLE_RATE) %>% + group_by(WorkLocation, WorkSegment) %>% + mutate(num_workers = sum(weight)) %>% + select(WorkLocation, WorkSegment, num_workers) + +ABM_Summary <- cast(workersbyMAZ, WorkLocation~WorkSegment, value = "num_workers", fun.aggregate = max) +ABM_Summary$`0`[is.infinite(ABM_Summary$`0`)] <- 0 +ABM_Summary$`1`[is.infinite(ABM_Summary$`1`)] <- 0 +ABM_Summary$`2`[is.infinite(ABM_Summary$`2`)] <- 0 +ABM_Summary$`3`[is.infinite(ABM_Summary$`3`)] <- 0 +ABM_Summary$`4`[is.infinite(ABM_Summary$`4`)] <- 0 +ABM_Summary$`5`[is.infinite(ABM_Summary$`5`)] <- 0 + +colnames(ABM_Summary) <- c("mgra", "occ1", "occ2", "occ3", "occ4", "occ5", "occ6") + + +# compute jobs by occupation type +empCat <- colnames(occFac)[colnames(occFac)!="emp_code"] + +mazData$occ1 <- 0 +mazData$occ2 <- 0 +mazData$occ3 <- 0 +mazData$occ4 <- 0 +mazData$occ5 <- 0 +mazData$occ6 <- 0 + +for(cat in empCat){ + mazData$occ1 <- mazData$occ1 + mazData[,c(cat)]*occFac[1,c(cat)] + mazData$occ2 <- mazData$occ2 + mazData[,c(cat)]*occFac[2,c(cat)] + mazData$occ3 <- mazData$occ3 + mazData[,c(cat)]*occFac[3,c(cat)] + mazData$occ4 <- mazData$occ4 + mazData[,c(cat)]*occFac[4,c(cat)] + mazData$occ5 <- mazData$occ5 + mazData[,c(cat)]*occFac[5,c(cat)] + mazData$occ6 <- mazData$occ6 + mazData[,c(cat)]*occFac[6,c(cat)] +} + +### get df in right format before outputting +df1 <- mazData[,c("mgra", "hhs")] %>% + left_join(ABM_Summary, by = c("mgra"="mgra")) %>% + select(-hhs) + +df1[is.na(df1)] <- 0 +df1$Total <- rowSums(df1[,!colnames(df1) %in% c("mgra")]) +df1[is.na(df1)] <- 0 +df1 <- melt(df1, id = c("mgra")) +colnames(df1) <- c("mgra", "occp", "value") + +df2 <- mazData[,c("mgra","occ1", "occ2", "occ3", "occ4", "occ5", "occ6")] +df2[is.na(df2)] <- 0 +df2$Total <- rowSums(df2[,!colnames(df2) %in% c("mgra")]) +df2[is.na(df2)] <- 0 +df2 <- melt(df2, id = c("mgra")) +colnames(df2) <- c("mgra", "occp", "value") + +df <- cbind(df1, df2$value) +colnames(df) <- c("mgra", "occp", "workers", "jobs") + +df$DISTRICT <- mazCorrespondence$pmsa[match(df$mgra, mazCorrespondence$mgra)] + +### Write outputs +write.csv(df, paste(WD, "job_worker_summary.csv", sep = "/"), row.names = F) + +# finish \ No newline at end of file diff --git a/sandag_abm/src/main/resources/BatchSubstitute.bat b/sandag_abm/src/main/resources/BatchSubstitute.bat new file mode 100644 index 0000000..99bffdc --- /dev/null +++ b/sandag_abm/src/main/resources/BatchSubstitute.bat @@ -0,0 +1,20 @@ +@echo off +REM -- Prepare the Command Processor -- +SETLOCAL ENABLEEXTENSIONS +SETLOCAL DISABLEDELAYEDEXPANSION + +::BatchSubstitude - parses a File line by line and replaces a substring" +::syntax: BatchSubstitude.bat OldStr NewStr File +:: OldStr [in] - string to be replaced +:: NewStr [in] - string to replace with +:: File [in] - file to be parsed +:$changed 20100115 +:$source http://www.dostips.com +if "%~1"=="" findstr "^::" "%~f0"&GOTO:EOF +for /f "tokens=1,* delims=]" %%A in ('"type %3|find /n /v """') do ( + set "line=%%B" + if defined line ( + call set "line=echo.%%line:%~1=%~2%%" + for /f "delims=" %%X in ('"echo."%%line%%""') do %%~X + ) ELSE echo. +) diff --git a/sandag_abm/src/main/resources/CTRampEnv.bat b/sandag_abm/src/main/resources/CTRampEnv.bat new file mode 100644 index 0000000..5f3e826 --- /dev/null +++ b/sandag_abm/src/main/resources/CTRampEnv.bat @@ -0,0 +1,61 @@ +rem this file has environment variables for CT-RAMP batch files + +rem set ports +set MATRIX_MANAGER_PORT=${matrix.server.port} +set HH_MANAGER_PORT=${household.server.port} + +rem set single node index +set SNODE=${snode} + +rem set machine names +set MAIN=${master.node.name} +set NODE1=${node.1.name} +set NODE2=${node.2.name} +set NODE3=${node.3.name} + + +rem set IP addresses +set MAIN_IP=${master.node.ip} +set HHMGR_IP=${household.server.host} + +rem JVM memory allocations +set MEMORY_MTXMGR_MIN=${mtxmgr.memory.min} +set MEMORY_MTXMGR_MAX=${mtxmgr.memory.max} +set MEMORY_HHMGR_MIN=${hhmgr.memory.min} +set MEMORY_HHMGR_MAX=${hhmgr.memory.max} +set MEMORY_CLIENT_MIN=${client.memory.min} +set MEMORY_CLIENT_MAX=${client.memory.max} +set MEMORY_SPMARKET_MIN=${spmarket.memory.min} +set MEMORY_SPMARKET_MAX=${spmarket.memory.max} +set MEMORY_BIKELOGSUM_MIN=${bikelogsum.memory.min} +set MEMORY_BIKELOGSUM_MAX=${bikelogsum.memory.max} +set MEMORY_WALKLOGSUM_MIN=${walklogsum.memory.min} +set MEMORY_WALKLOGSUM_MAX=${walklogsum.memory.max} +set MEMORY_BIKEROUTE_MIN=${bikeroute.memory.min} +set MEMORY_BIKEROUTE_MAX=${bikeroute.memory.max} +rem set MEMORY_DATAEXPORT_MIN=${dataexport.memory.min} +rem set MEMORY_DATAEXPORT_MAX=${dataexport.memory.max} +set MEMORY_EMFAC_MIN=${emfac.memory.min} +set MEMORY_EMFAC_MAX=${emfac.memory.max} +set MEMORY_VALIDATE_MIN=${validate.memory.min} +set MEMORY_VALIDATE_MAX=${validate.memory.max} + +rem set main property file name +set PROPERTIES_NAME=sandag_abm + +rem all nodes need to map the scenario drive, currently mapped as x: +set MAPDRIVE=${MAPDRIVE} +rem set MAPDRIVEFOLDER=\\${master.node.name}\${map.folder} +rem uncomment next line if use T drive as data folder. +rem !!!Note: much slower than a local data folder!!! +set MAPDRIVEFOLDER=${MAPDRIVEFOLDER} + +rem account settings for remote access using psexec +set USERNAME=${USERNAME} +set PASSWORD=${PASSWORD} + +rem location of mapAndRun.bat on remote machines +set MAPANDRUN=${MAPANDRUN} + +rem set location of java +set JAVA_64_PATH=${JAVA_64_PATH} \ No newline at end of file diff --git a/sandag_abm/src/main/resources/CheckOutput.bat b/sandag_abm/src/main/resources/CheckOutput.bat new file mode 100644 index 0000000..18b2c00 --- /dev/null +++ b/sandag_abm/src/main/resources/CheckOutput.bat @@ -0,0 +1,8 @@ +rem ### Declaring required environment variables +set PROJECT_DIRECTORY=%1 +set CHECK=%2 +set ITERATION=%3 + +rem ### Checking that files were generated +python %PROJECT_DIRECTORY%\python\check_output.py %PROJECT_DIRECTORY% %CHECK% %ITERATION% +if ERRORLEVEL 1 exit 2 diff --git a/sandag_abm/src/main/resources/CreateD2TAccessFile.bat b/sandag_abm/src/main/resources/CreateD2TAccessFile.bat new file mode 100644 index 0000000..fffc318 --- /dev/null +++ b/sandag_abm/src/main/resources/CreateD2TAccessFile.bat @@ -0,0 +1,9 @@ +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call bin\CTRampEnv.bat +set JAR_LOCATION=%PROJECT_DIRECTORY%/application + +%JAVA_64_PATH%\bin\java -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -Djxl.nowarnings=true -Dlog4j.configuration=log4j_d2t.xml -cp application/*;conf/ -Dproject.folder=%PROJECT_DIRECTORY% -Djava.library.path=%JAR_LOCATION% org.sandag.abm.application.SandagMGRAtoPNR %PROPERTIES_NAME% \ No newline at end of file diff --git a/sandag_abm/src/main/resources/DataExporter.bat b/sandag_abm/src/main/resources/DataExporter.bat new file mode 100644 index 0000000..7bf4bc1 --- /dev/null +++ b/sandag_abm/src/main/resources/DataExporter.bat @@ -0,0 +1,33 @@ +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call bin\CTRampEnv.bat +set JAR_LOCATION=%PROJECT_DIRECTORY%/application + +rem ### Connecting to Anaconda3 Environment +set ENV=C:\ProgramData\Anaconda3 +call %ENV%\Scripts\activate.bat %ENV% + +rem ### Checking if Data Exporter environment exists +rem ### Otherwise creates environment +set EXPORT_ENV=%PROJECT_DRIVE%%PROJECT_DIRECTORY%\python\dataExporter\environment.yml +call conda env list | find /i "abmDataExporter" +if not errorlevel 1 ( + call conda env update --name abmDataExporter --file %EXPORT_ENV% + call activate abmDataExporter +) else ( + call conda env create -f %EXPORT_ENV% + call activate abmDataExporter +) + +rem ### Running Data Exporter on scenario +python %PROJECT_DRIVE%%PROJECT_DIRECTORY%\python\dataExporter\serialRun.py %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem ### Check for the Data Exporter output files +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% Exporter %ITERATION% + +rem ### Exiting all Anaconda3 environments +call conda deactivate +call conda deactivate \ No newline at end of file diff --git a/sandag_abm/src/main/resources/DataLoadRequest.bat b/sandag_abm/src/main/resources/DataLoadRequest.bat new file mode 100644 index 0000000..74be0d6 --- /dev/null +++ b/sandag_abm/src/main/resources/DataLoadRequest.bat @@ -0,0 +1,7 @@ +set PROJECT_DIRECTORY="%1" +set ITERATION=%2 +set YEAR=%3 +set SAMPLE_RATE=%4 +set ABM_VERSION=${version} + +sqlcmd -d ${database_name} -E -S ${database_server} -Q "EXEC [data_load].[SP_REQUEST] $(year),'$(path)',$(iteration),$(sample_rate),'$(abm_version)'" -v year=%YEAR% path=%PROJECT_DIRECTORY% iteration=%ITERATION% sample_rate=%SAMPLE_RATE% abm_version=%ABM_VERSION% \ No newline at end of file diff --git a/sandag_abm/src/main/resources/DataSummary.bat b/sandag_abm/src/main/resources/DataSummary.bat new file mode 100644 index 0000000..46f0427 --- /dev/null +++ b/sandag_abm/src/main/resources/DataSummary.bat @@ -0,0 +1,14 @@ +rem forced to update excel links for auto reporting, YMA, 1/23/2019 + +@echo on + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SCENARIOYEAR=%3 +set SCENARIOID=%4 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +python %PROJECT_DRIVE%%PROJECT_DIRECTORY%\python\database_summary.py %PROJECT_DRIVE%%PROJECT_DIRECTORY% %SCENARIOYEAR% %SCENARIOID% + + diff --git a/sandag_abm/src/main/resources/ExcelUpdate.bat b/sandag_abm/src/main/resources/ExcelUpdate.bat new file mode 100644 index 0000000..4c893e9 --- /dev/null +++ b/sandag_abm/src/main/resources/ExcelUpdate.bat @@ -0,0 +1,16 @@ +rem forced to update excel links for auto reporting, YMA, 1/23/2019 + +@echo on + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SCENARIOYEAR=%3 +set SCENARIOID=%4 + +@echo path + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +python %PROJECT_DRIVE%%PROJECT_DIRECTORY%\python\excel_update.py %PROJECT_DRIVE%%PROJECT_DIRECTORY% %SCENARIOYEAR% %SCENARIOID% + + diff --git a/sandag_abm/src/main/resources/FHWADataExporter.bat b/sandag_abm/src/main/resources/FHWADataExporter.bat new file mode 100644 index 0000000..7b38dc0 --- /dev/null +++ b/sandag_abm/src/main/resources/FHWADataExporter.bat @@ -0,0 +1,142 @@ +set PROJECT_DRIVE_BASE=%1 +set PROJECT_DIRECTORY_BASE=%2 +set PROJECT_DRIVE_BUILD=%3 +set PROJECT_DIRECTORY_BUILD=%4 + +# ********************************************************************************************************************************** +# STEP 1: +# Create base trips with base skims +# ********************************************************************************************************************************** + +%PROJECT_DRIVE_BASE% +cd %PROJECT_DIRECTORY_BASE% +call bin\CTRampEnv.bat + +set PATH=%TRANSCAD_PATH%;C:\Windows\System32;application + +%JAVA_64_PATH%\bin\java -Xms%MEMORY_DATAEXPORT_MIN% -Xmx%MEMORY_DATAEXPORT_MAX% -Djava.library.path=%TRANSCAD_PATH%;application -cp %TRANSCAD_PATH%/GISDK/Matrices/*;application/*;conf/ org.sandag.abm.reporting.DataExporter + +# +# copy reports directory +# +echo d|xcopy report report_basetripbaseskim /S /Y + +# ********************************************************************************************************************************** +# STEP 2: +# Create build trips with build skims +# ********************************************************************************************************************************** + +%PROJECT_DRIVE_BUILD% +cd %PROJECT_DIRECTORY_BUILD% + +%JAVA_64_PATH%\bin\java -Xms%MEMORY_DATAEXPORT_MIN% -Xmx%MEMORY_DATAEXPORT_MAX% -Djava.library.path=%TRANSCAD_PATH%;application -cp %TRANSCAD_PATH%/GISDK/Matrices/*;application/*;conf/ org.sandag.abm.reporting.DataExporter + +# +# copy reports directory +# +echo d|xcopy report report_buildtripbuildskim /S /Y + +# ********************************************************************************************************************************** +# STEP 3: +# Create base trips with build skims +# ********************************************************************************************************************************** + +# currently in build directory: rename the disaggregate data +# +rename output\airport_out.csv airport_out.csv.build +rename output\crossBorderTours.csv crossBorderTours.csv.build +rename output\crossBorderTrips.csv crossBorderTrips.csv.build +rename output\householdData_3.csv householdData_3.csv.build +rename output\indivTourData_3.csv indivTourData_3.csv.build +rename output\indivTripData_3.csv indivTripData_3.csv.build +rename output\internalExternalTrips.csv internalExternalTrips.csv.build +rename output\jointTourData_3.csv jointTourData_3.csv.build +rename output\jointTripData_3.csv jointTripData_3.csv.build +rename output\luLogsums_logit.csv luLogsums_logit.csv.build +rename output\luLogsums_simple.csv luLogsums_simple.csv.build +rename output\personData_3.csv personData_3.csv.build +rename output\visitorTours.csv visitorTours.csv.build +rename output\visitorTrips.csv visitorTrips.csv.build +# +# copy base data to build directory +# +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\airport_out.csv output\airport_out.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\crossBorderTours.csv output\crossBorderTours.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\crossBorderTrips.csv output\crossBorderTrips.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\householdData_3.csv output\householdData_3.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\indivTourData_3.csv output\indivTourData_3.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\indivTripData_3.csv output\indivTripData_3.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\internalExternalTrips.csv output\internalExternalTrips.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\jointTourData_3.csv output\jointTourData_3.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\jointTripData_3.csv output\jointTripData_3.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\luLogsums_logit.csv output\luLogsums_logit.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\luLogsums_simple.csv output\luLogsums_simple.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\personData_3.csv output\personData_3.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\visitorTours.csv output\visitorTours.csv +copy %PROJECT_DRIVE_BASE%\%PROJECT_DIRECTORY_BASE%\output\visitorTrips.csv output\visitorTrips.csv +# +# run +# + +cd %PROJECT_DIRECTORY_BUILD% + +%JAVA_64_PATH%\bin\java -Xms%MEMORY_DATAEXPORT_MIN% -Xmx%MEMORY_DATAEXPORT_MAX% -Djava.library.path=%TRANSCAD_PATH%;application -cp %TRANSCAD_PATH%/GISDK/Matrices/*;application/*;conf/ org.sandag.abm.reporting.DataExporter +# +# rename report directory +# +echo d|xcopy report report_basetripbuildskim /S /Y +# +# ********************************************************************************************************************************** +# STEP 4: +# Create build trips with base skims +# ********************************************************************************************************************************** + +%PROJECT_DRIVE_BASE% +cd %PROJECT_DIRECTORY_BASE% + +# currently in base directory: rename the disaggregate data +# +rename output\airport_out.csv airport_out.csv.base +rename output\crossBorderTours.csv crossBorderTours.csv.base +rename output\crossBorderTrips.csv crossBorderTrips.csv.base +rename output\householdData_3.csv householdData_3.csv.base +rename output\indivTourData_3.csv indivTourData_3.csv.base +rename output\indivTripData_3.csv indivTripData_3.csv.base +rename output\internalExternalTrips.csv internalExternalTrips.csv.base +rename output\jointTourData_3.csv jointTourData_3.csv.base +rename output\jointTripData_3.csv jointTripData_3.csv.base +rename output\luLogsums_logit.csv luLogsums_logit.csv.base +rename output\luLogsums_simple.csv luLogsums_simple.csv.base +rename output\personData_3.csv personData_3.csv.base +rename output\visitorTours.csv visitorTours.csv.base +rename output\visitorTrips.csv visitorTrips.csv.base + +# +# copy build data to base directory +# + +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\airport_out.csv.build output\airport_out.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\crossBorderTours.csv.build output\crossBorderTours.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\crossBorderTrips.csv.build output\crossBorderTrips.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\householdData_3.csv.build output\householdData_3.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\indivTourData_3.csv.build output\indivTourData_3.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\indivTripData_3.csv.build output\indivTripData_3.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\internalExternalTrips.csv.build output\internalExternalTrips.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\jointTourData_3.csv.build output\jointTourData_3.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\jointTripData_3.csv.build output\jointTripData_3.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\luLogsums_logit.csv.build output\luLogsums_logit.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\luLogsums_simple.csv.build output\luLogsums_simple.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\personData_3.csv.build output\personData_3.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\visitorTours.csv.build output\visitorTours.csv +copy %PROJECT_DRIVE_BUILD%\%PROJECT_DIRECTORY_BUILD%\output\visitorTrips.csv.build output\visitorTrips.csv + +# +# run +# + +%JAVA_64_PATH%\bin\java -Xms%MEMORY_DATAEXPORT_MIN% -Xmx%MEMORY_DATAEXPORT_MAX% -Djava.library.path=%TRANSCAD_PATH%;application -cp %TRANSCAD_PATH%/GISDK/Matrices/*;application/*;conf/ org.sandag.abm.reporting.DataExporter + +# +# copy report directory +# +echo d|xcopy report report_buildtripbaseskim /S /Y diff --git a/sandag_abm/src/main/resources/GnuWin32/bin/libiconv2.dll b/sandag_abm/src/main/resources/GnuWin32/bin/libiconv2.dll new file mode 100644 index 0000000..747073f Binary files /dev/null and b/sandag_abm/src/main/resources/GnuWin32/bin/libiconv2.dll differ diff --git a/sandag_abm/src/main/resources/GnuWin32/bin/libintl3.dll b/sandag_abm/src/main/resources/GnuWin32/bin/libintl3.dll new file mode 100644 index 0000000..4f309be Binary files /dev/null and b/sandag_abm/src/main/resources/GnuWin32/bin/libintl3.dll differ diff --git a/sandag_abm/src/main/resources/GnuWin32/bin/tee.exe b/sandag_abm/src/main/resources/GnuWin32/bin/tee.exe new file mode 100644 index 0000000..aacad37 Binary files /dev/null and b/sandag_abm/src/main/resources/GnuWin32/bin/tee.exe differ diff --git a/sandag_abm/src/main/resources/HPPowerOff.bat b/sandag_abm/src/main/resources/HPPowerOff.bat new file mode 100644 index 0000000..94bbe66 --- /dev/null +++ b/sandag_abm/src/main/resources/HPPowerOff.bat @@ -0,0 +1 @@ +powercfg -SETACTIVE SCHEME_BALANCED \ No newline at end of file diff --git a/sandag_abm/src/main/resources/HPPowerOn.bat b/sandag_abm/src/main/resources/HPPowerOn.bat new file mode 100644 index 0000000..fd86012 --- /dev/null +++ b/sandag_abm/src/main/resources/HPPowerOn.bat @@ -0,0 +1 @@ +powercfg -SETACTIVE SCHEME_MIN \ No newline at end of file diff --git a/sandag_abm/src/main/resources/RunEMFAC2011.cmd b/sandag_abm/src/main/resources/RunEMFAC2011.cmd new file mode 100644 index 0000000..37cec7d --- /dev/null +++ b/sandag_abm/src/main/resources/RunEMFAC2011.cmd @@ -0,0 +1,12 @@ +rem Run EMFAC2011 after scenario is loaded into database +rem Takes 3 arguments: 1-prject drive 2-porject directory 3-scenario_id +rem EMFAC2011 results are written to a default location-%PROJECT_DRIVE%\%PROJECT_DIRECTORY%\output + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SCENARIO=%3 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat +python.exe %PROJECT_DIRECTORY%\bin\emfac2011_abm.py %SCENARO% %PROJECT_DRIVE%%PROJECT_DIRECTORY%\output \ No newline at end of file diff --git a/sandag_abm/src/main/resources/RunEMFAC2014.cmd b/sandag_abm/src/main/resources/RunEMFAC2014.cmd new file mode 100644 index 0000000..7f242d4 --- /dev/null +++ b/sandag_abm/src/main/resources/RunEMFAC2014.cmd @@ -0,0 +1,16 @@ +rem Run EMFAC2014 after scenario is loaded into database +rem Takes 3 arguments: 1-prject drive 2-porject directory 3-scenario_id 4-SB375 switch +rem EMFAC2014 results are written to a default location-%PROJECT_DRIVE%\%PROJECT_DIRECTORY%\output + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SCENARIO=%3 +set SB375=%4 + +call %PROJECT_DRIVE%%PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY%\python + +python.exe emfac2014_abm.py %SCENARIO% Annual %SB375% %PROJECT_DRIVE%%PROJECT_DIRECTORY%\output +python.exe emfac2014_abm.py %SCENARIO% Summer %SB375% %PROJECT_DRIVE%%PROJECT_DIRECTORY%\output +python.exe emfac2014_abm.py %SCENARIO% Winter %SB375% %PROJECT_DRIVE%%PROJECT_DIRECTORY%\output diff --git a/sandag_abm/src/main/resources/RunViz.bat b/sandag_abm/src/main/resources/RunViz.bat new file mode 100644 index 0000000..b13f18f --- /dev/null +++ b/sandag_abm/src/main/resources/RunViz.bat @@ -0,0 +1,126 @@ +:: ############################################################################ +:: # Batch file to summarize CT-RAMP outputs and generate HTML Visualizer +:: # khademul.haque@rsginc.com, March 2019 +:: # +:: # This script summarizes the CTRAMP outputs of both ABM and Reference scenarios and generates a visualizer comparing the ABM to the reference scenario +:: # ------------------------------------------------------------------------------ +:: # To-Do +:: # 1. create log files from scripts (for later) +:: # 2. identify the input files names used by the summary R scripts and visualizer. maybe we can put them in the batch file +:: # script arguments (for testing): +:: SET PROJECT_DRIVE=C: +:: SET PROJECT_DIRECTORY=\ABM_runs\maint_2019_RSG\Model\ABM2_14_2_0 +:: SET REFER_DIR=T:\projects\sr14\abm2_test\abm_runs\14_1_0\2016_local_mask_2\ +:: SET OUTPUT_HTML_NAME=SANDAG_Dashboard_2016_calib_3_19_19_final_test +:: SET IS_BASE_SURVEY=No +:: SET BASE_SCENARIO_NAME=REFERENCE +:: SET BUILD_SCENARIO_NAME=SDABM16 +:: SET MGRA_INPUT_FILE=input/mgra13_based_input2016.csv + +:: ############################################################################ + +@ECHO off +:: Inputs from arguments +SET PROJECT_DRIVE=%1 +SET PROJECT_DIRECTORY=%2 +SET REFER_DIR=%3 +SET OUTPUT_HTML_NAME=%4 +SET IS_BASE_SURVEY=%5 +SET BASE_SCENARIO_NAME=%6 +SET BUILD_SCENARIO_NAME=%7 +SET MGRA_INPUT_FILE=%8 + +:: Default inputs +SET MAX_ITER=3 +SET BASE_SAMPLE_RATE=1.0 +SET BUILD_SAMPLE_RATE=1.0 +SET SHP_FILE_NAME=pseudomsa.shp + +:: Set Directories + +SET PROJECT_DIR=%PROJECT_DRIVE%%PROJECT_DIRECTORY%\ +SET REFER_DIR=%REFER_DIR%\ +SET CURRENT_DIR=%PROJECT_DIR%visualizer\ +SET WORKING_DIR=%CURRENT_DIR% +SET SUMM_DIR=%WORKING_DIR%outputs\summaries\ +SET REF_DIR=%REFER_DIR%output +SET REF_DIR_INP=%REFER_DIR%input +SET BASE_SUMMARY_DIR=%SUMM_DIR%REF +SET BUILD_SUMMARY_DIR=%SUMM_DIR%BUILD +SET R_SCRIPT=%WORKING_DIR%dependencies\R-3.4.1\bin\Rscript +SET R_LIBRARY=%WORKING_DIR%dependencies\R-3.4.1\library +SET RSTUDIO_PANDOC=%WORKING_DIR%dependencies\Pandoc + +:: Extract Dependencies.zip +IF NOT EXIST %WORKING_DIR%dependencies unzip %WORKING_DIR%dependencies.zip -d %WORKING_DIR% + +:: Summarize BUILD +SET WD=%BUILD_SUMMARY_DIR% +SET ABMOutputDir=%PROJECT_DIR%output +SET INPUT_FILE_ABM=%SUMM_DIR%summ_inputs_abm.csv + +ECHO Key,Value > %INPUT_FILE_ABM% +ECHO WD,%WD% >> %INPUT_FILE_ABM% +ECHO ABMOutputDir,%ABMOutputDir% >> %INPUT_FILE_ABM% +ECHO geogXWalkDir,%WORKING_DIR%data >> %INPUT_FILE_ABM% +ECHO SkimDir,%ABMOutputDir% >> %INPUT_FILE_ABM% +ECHO MAX_ITER,%MAX_ITER% >> %INPUT_FILE_ABM% +:: Call R script to summarize BUILD outputs +ECHO %startTime%%Time%: Running R script to summarize BUILD outputs... +%R_SCRIPT% %WORKING_DIR%scripts\SummarizeABM2016.R %INPUT_FILE_ABM% + +:: Summarize REF +SET WD=%BASE_SUMMARY_DIR% +SET INPUT_FILE_REF=%SUMM_DIR%summ_inputs_ref.csv + +ECHO Key,Value > %INPUT_FILE_REF% +ECHO WD,%WD% >> %INPUT_FILE_REF% +ECHO ABMOutputDir,%REF_DIR% >> %INPUT_FILE_REF% +ECHO geogXWalkDir,%WORKING_DIR%data >> %INPUT_FILE_REF% +ECHO SkimDir,%REF_DIR% >> %INPUT_FILE_REF% +ECHO MAX_ITER,%MAX_ITER% >> %INPUT_FILE_REF% + +:: Call R script to summarize REF outputs +ECHO %startTime%%Time%: Running R script to summarize REF outputs... +%R_SCRIPT% %WORKING_DIR%scripts\SummarizeABM2016.R %INPUT_FILE_REF% + +:: Create Visualizer +:: Parameters file +SET PARAMETERS_FILE=%WORKING_DIR%runtime\parameters.csv + +ECHO Key,Value > %PARAMETERS_FILE% +ECHO PROJECT_DIR,%PROJECT_DIR% >> %PARAMETERS_FILE% +ECHO WORKING_DIR,%WORKING_DIR% >> %PARAMETERS_FILE% +ECHO REF_DIR,%REF_DIR% >> %PARAMETERS_FILE% +ECHO REF_DIR_INP,%REF_DIR_INP% >> %PARAMETERS_FILE% +ECHO BASE_SUMMARY_DIR,%BASE_SUMMARY_DIR% >> %PARAMETERS_FILE% +ECHO BUILD_SUMMARY_DIR,%BUILD_SUMMARY_DIR% >> %PARAMETERS_FILE% +ECHO BASE_SCENARIO_NAME,%BASE_SCENARIO_NAME% >> %PARAMETERS_FILE% +ECHO BUILD_SCENARIO_NAME,%BUILD_SCENARIO_NAME% >> %PARAMETERS_FILE% +ECHO BASE_SAMPLE_RATE,%BASE_SAMPLE_RATE% >> %PARAMETERS_FILE% +ECHO BUILD_SAMPLE_RATE,%BUILD_SAMPLE_RATE% >> %PARAMETERS_FILE% +ECHO R_LIBRARY,%R_LIBRARY% >> %PARAMETERS_FILE% +ECHO OUTPUT_HTML_NAME,%OUTPUT_HTML_NAME% >> %PARAMETERS_FILE% +ECHO SHP_FILE_NAME,%SHP_FILE_NAME% >> %PARAMETERS_FILE% +ECHO IS_BASE_SURVEY,%IS_BASE_SURVEY% >> %PARAMETERS_FILE% +ECHO MAX_ITER,%MAX_ITER% >> %PARAMETERS_FILE% +ECHO geogXWalkDir,%WORKING_DIR%data >> %PARAMETERS_FILE% +ECHO mgraInputFile,%MGRA_INPUT_FILE% >> %PARAMETERS_FILE% + +:: Call the R Script to process REF and BUILD output +:: ####################################### +ECHO %startTime%%Time%: Running R script to process REF output... +%R_SCRIPT% %WORKING_DIR%scripts\workersByMAZ.R %PARAMETERS_FILE% TRUE + +ECHO %startTime%%Time%: Running R script to process BUILD output... +%R_SCRIPT% %WORKING_DIR%scripts\workersByMAZ.R %PARAMETERS_FILE% FALSE + +:: Call the master R script +:: ######################## +ECHO %startTime%%Time%: Running R script to generate visualizer... +%R_SCRIPT% %WORKING_DIR%scripts\Master.R %PARAMETERS_FILE% +IF %ERRORLEVEL% EQU 11 ( + ECHO File missing error. Check error file in outputs. + EXIT /b %errorlevel% +) +ECHO %startTime%%Time%: Dashboard creation complete... \ No newline at end of file diff --git a/sandag_abm/src/main/resources/StartHHAndNodes.cmd b/sandag_abm/src/main/resources/StartHHAndNodes.cmd new file mode 100644 index 0000000..ba4ffc8 --- /dev/null +++ b/sandag_abm/src/main/resources/StartHHAndNodes.cmd @@ -0,0 +1,44 @@ +set PROJECT_DRIVE=%1 +set PATH_NO_DRIVE=%2 + +%PROJECT_DRIVE% +cd %PATH_NO_DRIVE% + +rem remove active connections so that limit is not exceeded +net session /delete /Y + +call %PATH_NO_DRIVE%\bin\CTRampEnv.bat + +If %SNODE%==yes goto :snode + +%PATH_NO_DRIVE%\bin\pskill \\%NODE1% java +%PATH_NO_DRIVE%\bin\pskill \\%NODE2% java +%PATH_NO_DRIVE%\bin\pskill \\%NODE3% java + +rem Start HH Manager on master node +call %PATH_NO_DRIVE%\bin\runHhMgr.cmd %PROJECT_DRIVE% %PATH_NO_DRIVE% + +rem Start remote worker nodes: SANDAG02 +set PROGRAMSTRING=%PATH_NO_DRIVE%\bin\runSandag02.cmd %MAPDRIVE% %PATH_NO_DRIVE% +start %PATH_NO_DRIVE%\bin\psExec \\%NODE1% -s -c -f %PATH_NO_DRIVE%\bin\%MAPANDRUN% %MAPDRIVE% %MAPDRIVEFOLDER% %PASSWORD% %USERNAME% %PATH_NO_DRIVE% %PROGRAMSTRING% + +rem start remote worker nodes: SANDAG03 +set PROGRAMSTRING=%PATH_NO_DRIVE%\bin\runSandag03.cmd %MAPDRIVE% %PATH_NO_DRIVE% +start %PATH_NO_DRIVE%\bin\psExec \\%NODE2% -s -c -f %PATH_NO_DRIVE%\bin\%MAPANDRUN% %MAPDRIVE% %MAPDRIVEFOLDER% %PASSWORD% %USERNAME% %PATH_NO_DRIVE% %PROGRAMSTRING% + +rem start remote worker nodes: SANDAG04 +set PROGRAMSTRING=%PATH_NO_DRIVE%\bin\runSandag04.cmd %MAPDRIVE% %PATH_NO_DRIVE% +start %PATH_NO_DRIVE%\bin\psExec \\%NODE3% -s -c -f %PATH_NO_DRIVE%\bin\%MAPANDRUN% %MAPDRIVE% %MAPDRIVEFOLDER% %PASSWORD% %USERNAME% %PATH_NO_DRIVE% %PROGRAMSTRING% +goto :end + +:snode +rem Start HH Manager on master node +call %PATH_NO_DRIVE%\bin\runHhMgr.cmd %PROJECT_DRIVE% %PATH_NO_DRIVE% +call %PATH_NO_DRIVE%\bin\runSandag01.cmd %PROJECT_DRIVE% %PATH_NO_DRIVE% + +:end + + + + + diff --git a/sandag_abm/src/main/resources/assignScenarioID.cmd b/sandag_abm/src/main/resources/assignScenarioID.cmd new file mode 100644 index 0000000..9c8e0f7 --- /dev/null +++ b/sandag_abm/src/main/resources/assignScenarioID.cmd @@ -0,0 +1,6 @@ +set root=C:\ProgramData\Anaconda3 +call %root%\Scripts\activate.bat %root% +cd.. +cd python +python assignScenarioID.py +pause \ No newline at end of file diff --git a/sandag_abm/src/main/resources/checkAtTransitNetworkConsistency.cmd b/sandag_abm/src/main/resources/checkAtTransitNetworkConsistency.cmd new file mode 100644 index 0000000..c4707c8 --- /dev/null +++ b/sandag_abm/src/main/resources/checkAtTransitNetworkConsistency.cmd @@ -0,0 +1,44 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +rem ### Note that a jdk is required; a jre is not sufficient, as the UEC class generates +rem ### and compiles code during the model run, and uses javac in the jdk to do this. +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%OLDPATH% + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem AT and Transit Networks Consistency Checking Java +%JAVA_64_PATH%\bin\java -showversion -server -Xms12000m -Xmx15000m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j_AtTransitCheck.xml -Dproject.folder=%PROJECT_DIRECTORY% -Djppf.config=jppf-client.properties org.sandag.abm.utilities.TapAtConsistencyCheck %PROPERTIES_NAME% %PROJECT_DRIVE%%PROJECT_DIRECTORY%\input + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% +set CLASSPATH=%OLDCLASSPATH% diff --git a/sandag_abm/src/main/resources/checkFreeSpaceOnC.bat b/sandag_abm/src/main/resources/checkFreeSpaceOnC.bat new file mode 100644 index 0000000..487231c --- /dev/null +++ b/sandag_abm/src/main/resources/checkFreeSpaceOnC.bat @@ -0,0 +1,2 @@ +set minSpace=%1 +python.exe ..\python\checkFreeSpace.py "c:\\" %minSpace% \ No newline at end of file diff --git a/sandag_abm/src/main/resources/copy_networkfiles_to_study.cmd b/sandag_abm/src/main/resources/copy_networkfiles_to_study.cmd new file mode 100644 index 0000000..909a941 --- /dev/null +++ b/sandag_abm/src/main/resources/copy_networkfiles_to_study.cmd @@ -0,0 +1,18 @@ +@echo off + +if "%1"=="" goto usage +if "%2"=="" goto usage + +set STUDY_FOLDER=%1 +set NETWORKDIR=%2 + +@echo creating study folder +md %STUDY_FOLDER%\network_build +cacls %STUDY_FOLDER% /t /e /g Everyone:f + +@echo /Y/E %NETWORKDIR%\"*.*" %STUDY_FOLDER%\network_build +xcopy /Y/E %NETWORKDIR%\"*.*" %STUDY_FOLDER%\network_build + +:usage + +@echo Usage: %0 ^ ^ diff --git a/sandag_abm/src/main/resources/copy_networks.cmd b/sandag_abm/src/main/resources/copy_networks.cmd new file mode 100644 index 0000000..6219ef8 --- /dev/null +++ b/sandag_abm/src/main/resources/copy_networks.cmd @@ -0,0 +1,17 @@ +@echo off + +if "%1"=="" goto usage +if "%2"=="" goto usage + +set FILE_LIST=hwycov.e00 trcov.e00 turns.csv trlink.csv trrt.csv trstop.csv tap.elev tap.ptype timexfer_EA.csv timexfer_AM.csv timexfer_MD.csv timexfer_PM.csv timexfer_EV.csv special_fares.txt linktypeturns.dbf tapcov.dbf tapcov.shp tapcov.shx tapcov.shp.xml mobilityhubtaps.csv mobilityHubMGRAs.csv SANDAG_Bike_Net.sbn SANDAG_Bike_Net.sbx SANDAG_Bike_Net.dbf SANDAG_Bike_Net.shp SANDAG_Bike_Net.shx SANDAG_Bike_Net.prj SANDAG_Bike_Node.sbn SANDAG_Bike_Node.sbx SANDAG_Bike_Node.dbf SANDAG_Bike_Node.shp SANDAG_Bike_Node.shx SANDAG_Bike_Node.prj rtcov.shp rtcov.shx rtcov.dbf rtcov.shp.xml + +@echo %FILE_LIST% + +for %%i in (%FILE_LIST%) do ( +@echo Copying and overwriting %1\%%i +xcopy /Y %1\%%i %2) + +goto :eof + +:usage +@echo Usage: %0 ^ ^ \ No newline at end of file diff --git a/sandag_abm/src/main/resources/create_scenario.cmd b/sandag_abm/src/main/resources/create_scenario.cmd new file mode 100644 index 0000000..843d69b --- /dev/null +++ b/sandag_abm/src/main/resources/create_scenario.cmd @@ -0,0 +1,107 @@ +rem create_scenario.cmd T:\projects\sr14\version_14_1_x\abm_runs\2016 2016 T:\projects\sr14\version_14_1_x\network_build\2016 4.4.0 + +@echo off + +if "%1"=="" goto usage +if "%2"=="" goto usage +if "%3"=="" goto usage +if "%4"=="" goto usage + +set SCENARIO_FOLDER=%1 +set YEAR=%2 +set NETWORKDIR=%3 +set EMME_VERSION=%4 + +@echo creating scenario folders +set FOLDERS=input application bin conf input_truck logFiles output python report sql uec analysis visualizer visualizer\outputs\summaries input_checker +for %%i in (%FOLDERS%) do ( +md %SCENARIO_FOLDER%\%%i) + +rem grant full permissions to scenario folder +cacls %SCENARIO_FOLDER% /t /e /g Everyone:f + +rem copy master server-config.csv to a scenario folder +rem to make local copy of server configuration file effective, user needs to rename it to server-config-local.csv +xcopy /Y T:\ABM\release\ABM\config\server-config.csv %SCENARIO_FOLDER%\conf + +rem setup model folders +xcopy /Y .\common\application\"*.*" %SCENARIO_FOLDER%\application +xcopy /E/Y/i .\common\application\GnuWin32\"*.*" %SCENARIO_FOLDER%\application\GnuWin32 +xcopy /Y/E .\common\python\"*.*" %SCENARIO_FOLDER%\python +xcopy /Y/E .\common\sql\"*.*" %SCENARIO_FOLDER%\sql +xcopy /Y .\common\uec\"*.*" %SCENARIO_FOLDER%\uec +xcopy /Y .\common\bin\"*.*" %SCENARIO_FOLDER%\bin +rem xcopy /Y .\conf\%YEAR%\"*.*" %SCENARIO_FOLDER%\conf +xcopy /Y .\common\conf\"*.*" %SCENARIO_FOLDER%\conf +xcopy /Y .\common\output\"*.*" %SCENARIO_FOLDER%\output +xcopy /s/Y .\common\visualizer %SCENARIO_FOLDER%\visualizer +xcopy /s/Y .\dependencies.* %SCENARIO_FOLDER%\visualizer +xcopy /Y/s/E .\common\input\input_checker\"*.*" %SCENARIO_FOLDER%\input_checker + +@echo assemble inputs +del %SCENARIO_FOLDER%\input /q +rem copy pop, hh, landuse, and other input files +xcopy /Y .\input\%YEAR%\"*.*" %SCENARIO_FOLDER%\input +rem copy common geography files to input folder +xcopy /Y .\common\input\geography\"*.*" %SCENARIO_FOLDER%\input +rem copy ctm paramter tables to input folder +xcopy /Y .\common\input\ctm\"*.*" %SCENARIO_FOLDER%\input +rem copy common model files to input folder +xcopy /Y .\common\input\model\"*.*" %SCENARIO_FOLDER%\input +rem copy common truck files to input_truck folder +xcopy /Y .\common\input\truck\"*.*" %SCENARIO_FOLDER%\input_truck +rem copy airport input files +xcopy /Y .\common\input\airports\"*.*" %SCENARIO_FOLDER%\input +rem copy ei input files +xcopy /Y .\common\input\ei\"*.*" %SCENARIO_FOLDER%\input +rem copy ie input files +xcopy /Y .\common\input\ie\"*.*" %SCENARIO_FOLDER%\input +rem copy ee input files +xcopy /Y .\common\input\ee\"*.*" %SCENARIO_FOLDER%\input +rem copy emfact input files +xcopy /Y .\common\input\emfact\"*.*" %SCENARIO_FOLDER%\input +rem copy special event input files +xcopy /Y .\common\input\specialevent\"*.*" %SCENARIO_FOLDER%\input +rem copy xborder input files +xcopy /Y .\common\input\xborder\"*.*" %SCENARIO_FOLDER%\input +rem copy visitor input files +xcopy /Y .\common\input\visitor\"*.*" %SCENARIO_FOLDER%\input +rem copy input checker config files +xcopy /Y .\common\input\input_checker\"*.*" %SCENARIO_FOLDER% +rem copy network inputs +call copy_networks.cmd %NETWORKDIR% %SCENARIO_FOLDER%\input + + +rem copy analysis templates +@echo copy analysis templates +if %YEAR%==2016 (xcopy /Y/S .\common\input\template\validation\2016\"*.*" %SCENARIO_FOLDER%\analysis\validation\) +if %YEAR%==2018 (xcopy /Y/S .\common\input\template\validation\2018\"*.*" %SCENARIO_FOLDER%\\analysis\validation\) +xcopy /Y/S .\common\input\template\summary\"*.*" %SCENARIO_FOLDER%\analysis\summary\ + +rem populate scenario year into sandag_abm.properties +set PROP_FILE=%SCENARIO_FOLDER%\conf\sandag_abm.properties +set TEMP_FILE=%SCENARIO_FOLDER%\conf\temp.properties +set RAW_YEAR=%YEAR:nb=% +type nul>%TEMP_FILE% +for /f "USEBACKQ delims=" %%A in (`type "%PROP_FILE%" ^| find /V /N ""`) do ( + set ln=%%A + setlocal enableDelayedExpansion + set ln=!ln:${year}=%RAW_YEAR%! + set ln=!ln:${year_build}=%YEAR%! + set ln=!ln:*]=! + echo(!ln!>>%TEMP_FILE% + endlocal +) +del %PROP_FILE% +move %TEMP_FILE% %PROP_FILE% + +@echo init emme folder +call init_emme.cmd %SCENARIO_FOLDER% %EMME_VERSION% + +:usage + +@echo Usage: %0 ^ ^ ^ ^ +@echo If 3rd parameter is empty, default network inputs in standard release are used + + + diff --git a/sandag_abm/src/main/resources/cvm.bat b/sandag_abm/src/main/resources/cvm.bat new file mode 100644 index 0000000..7ded2f6 --- /dev/null +++ b/sandag_abm/src/main/resources/cvm.bat @@ -0,0 +1,30 @@ +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set PROJECT_DIRECTORY_FWD=%3 +set CVM_ScaleFactor=%4 +set MGRA_DATA=%5 +set TAZ_CENTROIDS=%6 + +set "SCEN_DIR=%PROJECT_DRIVE%%PROJECT_DIRECTORY%" +set "SCEN_DIR_FWD=%PROJECT_DRIVE%%PROJECT_DIRECTORY_FWD%" +%PROJECT_DRIVE% +cd %SCEN_DIR% + +call %SCEN_DIR%\bin\CTRampEnv.bat + +set CLASSPATH=%SCEN_DIR%/application/* + +REM create the land-use data +python %SCEN_DIR%\python\cvm_input_create.py %SCEN_DIR% %MGRA_DATA% %TAZ_CENTROIDS% "Zonal Properties CVM.csv" + +REM create the commercial vehicle tours +python %SCEN_DIR%\python\sdcvm.py -s %CVM_ScaleFactor% -p %SCEN_DIR% + +REM run the java code +%JAVA_64_PATH%\bin\java.exe -Xmx24000m -Xmn16000M -Dlog4j.configuration=file:./conf/log4j.xml -Djava.library.path=%SCEN_DIR%/application -DSCENDIR=%SCEN_DIR_FWD% -cp %CLASSPATH% org.sandag.cvm.activityTravel.cvm.GenerateCommercialTours "conf/cvm.properties" + +REM summarize model outputs +python %SCEN_DIR%\python\sdcvm_summarize.py -p %SCEN_DIR% + +REM checking for CVM outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% CVM diff --git a/sandag_abm/src/main/resources/cvm.properties b/sandag_abm/src/main/resources/cvm.properties new file mode 100644 index 0000000..6eade7a --- /dev/null +++ b/sandag_abm/src/main/resources/cvm.properties @@ -0,0 +1,39 @@ +# location of input files +CSVFileLocation=%SCENDIR%/input/ +# input files names +ZonalPropertiesFileName=Zonal Properties CVM +ZonalPropertiesFileName2=CVMToursAccess + +UseTripModes = true + +# output file location +TripLogPath=%SCENDIR%/output/ + +# Note with TRANSCAD SKIMS you need +# you need to put the Transcad path's into your system path (see the end of the line below) +#C:\Program Files\Microsoft Visual Studio\Common\Tools;C:\Program Files\Microsoft Visual Studio\Common\Msdev98\BIN;C:\Program Files\Microsoft Visual Studio\DF98\BIN;C:\Program Files\Microsoft Visual Studio\VC98\BIN;C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;C:\Program Files (x86)\Dell\SysMgt\RAC5;C:\Program Files (x86)\Dell\SysMgt\oma\bin;C:\WINDOWS\system32\WindowsPowerShell\v1.0;C:\Program Files (x86)\Common Files\Acronis\SnapAPI\;C:\WINDOWS\system32\WindowsPowerShell\v1.0;C:\mpj-v0_38\bin;C:\Program Files\Java\jre6\bin;C:\arcgis\arcexe10x\bin;C:\Program Files\SlikSvn\bin;C:\Program Files\TortoiseSVN\bin;C:\Program Files (x86)\TransCAD;;C:\Program Files\TransCAD\GISDK\Matrices + + +OMXSkimLocation=%SCENDIR%/output/ +#These next two are to write new Transcad Matrix files +#CSVOutputFileLocation=%SCENDIR%/output/ +#ReadOutputMatrices=FALSE + +# To write CSV files instead of TRANSCAD matrices +# First need to tell program not to read the output matrices, to instead create them +ReadOutputMatrices=False +# Then need to explain where to write them when they are populated with trips. +CSVOutputFileLocation=%SCENDIR%/output/TripMatrices.csv + +StartZone=13 +EndZone=4996 +#RunZones=101, 102, 103 + +nThreads=22 + +# Tour counts are FirstPart_SecondPart in zonal properties files +# Coefficient files are FirstPart.csv and SecondPart.csv +FirstPart=FA,GO,IN,SV,TH,RE,WH +SecondPart=MD,AM,PM,OE,OL +#FirstPart=GO +#SecondPart=OE,OL diff --git a/sandag_abm/src/main/resources/emme_python.bat b/sandag_abm/src/main/resources/emme_python.bat new file mode 100644 index 0000000..4059839 --- /dev/null +++ b/sandag_abm/src/main/resources/emme_python.bat @@ -0,0 +1,31 @@ +rem ////////////////////////////////////////////////////////////////////////////// +rem //// +rem //// emme_python.bat +rem //// +rem //// Configure environment and start Python script to run Emme-related task. +rem //// Passes the input script name and one argument for the python script. +rem //// 1 : drive, e.g. "T:" +rem //// 2 : full path for working directory, including drive +rem //// 3 : full path to Emme python script +rem //// 4 : single argument for python script +rem //// +rem //// +rem ////////////////////////////////////////////////////////////////////////////// +rem +rem if necessary can set the EMMEPATH to point to a specific version of Emme +rem set EMMEPATH=C:\Program Files\INRO\Emme\Emme 4\Emme-4.3.5 +rem +rem +set MODELLER_PYTHON=%EMMEPATH%\Python27\ +set path=%EMMEPATH%\programs;%MODELLER_PYTHON%;%PATH% +rem map T drive for file access +net use t: \\sandag.org\transdata /persistent:yes +%1 rem set the drive +cd %2 rem change to the correct directory +rem restart the ISM as script user, must be configured to already be connected to mustang +taskkill /F /IM INROSoftwareManager.exe /T +PING localhost -n 5 >NUL +start /d "C:\Program Files (x86)\INRO\INRO Software Manager\INRO Software Manager 1.1.0" INROSoftwareManager.exe +PING localhost -n 5 >NUL +rem start the python script with one input +python %3 %4 \ No newline at end of file diff --git a/sandag_abm/src/main/resources/init_emme.cmd b/sandag_abm/src/main/resources/init_emme.cmd new file mode 100644 index 0000000..97ecddc --- /dev/null +++ b/sandag_abm/src/main/resources/init_emme.cmd @@ -0,0 +1,37 @@ +rem @echo off + +if "%1"=="" goto usage +if "%2"=="" goto usage +set SCENARIO_FOLDER=%1 +set EMME_VERSION=%2 + +rem add EMME to PATH +set E_PATH=C:\\Program Files\\INRO\\Emme\\Emme 4\\Emme-%EMME_VERSION% +set PATH=%E_PATH%\\programs;%E_PATH%\\python27;%PATH% +set EMMEPATH=%E_PATH% + +rem delete existing emme_project folder +:removedir +if exist %SCENARIO_FOLDER%\emme_project ( + rd /s /q %SCENARIO_FOLDER%\\emme_project + goto removedir +) + +rem create EMME project folder +python .\\common\\python\\emme\\init_emme_project.py -r %SCENARIO_FOLDER% -t emmebank -v %EMME_VERSION% + +rem create toolbox +python .\\common\\python\\emme\\toolbox\\build_toolbox.py -s .\\common\\python\\emme\\toolbox -p %SCENARIO_FOLDER%\emme_project\Scripts\sandag_toolbox.mtbx +copy .\\common\\python\\emme\\solutions.mtbx %SCENARIO_FOLDER%\emme_project\Scripts\solutions.mtbx + +rem create a batch script at startup +( +echo set python_virtualenv=C:\python_virtualenv\abm14_2_0 +echo start "TITLE" "%E_PATH%\\programs\\EmmeDesktop.exe" ./emme_project.emp +)>%SCENARIO_FOLDER%\emme_project\start_emme_with_virtualenv.bat + +rem mkdir %SCENARIO_FOLDER%\emme_project\Scripts\yaml +rem copy .\\common\\python\\emme\\yaml\\*.* %SCENARIO_FOLDER%\emme_project\Scripts\yaml + +:usage +@echo Usage: %0 ^ ^ \ No newline at end of file diff --git a/sandag_abm/src/main/resources/jhdf.dll b/sandag_abm/src/main/resources/jhdf.dll new file mode 100644 index 0000000..fd03758 Binary files /dev/null and b/sandag_abm/src/main/resources/jhdf.dll differ diff --git a/sandag_abm/src/main/resources/jhdf5.dll b/sandag_abm/src/main/resources/jhdf5.dll new file mode 100644 index 0000000..3d47abf Binary files /dev/null and b/sandag_abm/src/main/resources/jhdf5.dll differ diff --git a/sandag_abm/src/main/resources/jppf-client.properties b/sandag_abm/src/main/resources/jppf-client.properties new file mode 100644 index 0000000..20639a8 --- /dev/null +++ b/sandag_abm/src/main/resources/jppf-client.properties @@ -0,0 +1,141 @@ +#------------------------------------------------------------------------------# +# Java Parallel Processing Framework. # +# Copyright (C) 2005-2008 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + + +#------------------------------------------------------------------------------# +# List of drivers this client may connect to # +#------------------------------------------------------------------------------# + +# jppf.drivers = driver1 + +#------------------------------------------------------------------------------# +# Host name, or ip address, of the host the JPPF driver is running on # +#------------------------------------------------------------------------------# + +driver1.jppf.server.host = ${master.node.name} + +#------------------------------------------------------------------------------# +# port number for the class server that performs remote class loading # +# default value is 11111; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +driver1.class.server.port = 11111 + +#------------------------------------------------------------------------------# +# port number the clients / applications connect to # +# default value is 11112; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +driver1.app.server.port = 11112 + +#------------------------------------------------------------------------------# +# Priority given to the driver # +# The client is always connected to the available driver(s) with the highest # +# priority. If multiple drivers have the same priority, they will be used as a # +# pool and tasks will be evenly distributed among them. # +# default value is 0; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +driver1.priority = 10 + +#------------------------------------------------------------------------------# +# Enable/Disable automatic discovery of JPPF drivers. # +# default value is true; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +jppf.discovery.enabled = false + +#------------------------------------------------------------------------------# +# UDP multicast group to which drivers broadcast their connection parameters # +# and to which clients and nodes listen. Default value is 230.0.0.1 # +#------------------------------------------------------------------------------# + +#jppf.discovery.group = 230.0.0.1 + +#------------------------------------------------------------------------------# +# UDP multicast port to which drivers broadcast their connection parameters # +# and to which clients and nodes listen. Default value is 11111 # +#------------------------------------------------------------------------------# + +#jppf.discovery.port = 11111 + +#------------------------------------------------------------------------------# +# Automatic recovery: number of seconds before the first reconnection attempt. # +# default value is 1; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +#reconnect.initial.delay = 1 + +#------------------------------------------------------------------------------# +# Automatic recovery: time after which the system stops trying to reconnect, # +# in seconds. Default value is 60; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +reconnect.max.time = 5 + +#------------------------------------------------------------------------------# +# Automatic recovery: time between two connection attempts, in seconds. # +# default value is 1; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +#reconnect.interval = 1 + +#------------------------------------------------------------------------------# +# Monitoring UI: interval between 2 refresh from the server, in milliseconds. # +# default value is 1,000 (1 second); uncomment to specify a different value # +#------------------------------------------------------------------------------# + +default.refresh.interval = 1000 + +#------------------------------------------------------------------------------# +# IPV4 address patterns included in the server dscovery mechanism # +#------------------------------------------------------------------------------# + +#jppf.discovery.ipv4.include = 192.168.1. + +#------------------------------------------------------------------------------# +# IPV4 address patterns excluded from the server dscovery mechanism # +#------------------------------------------------------------------------------# + +#jppf.discovery.ipv4.exclude = 192.168.1.-9; 192.168.1.100- + +#------------------------------------------------------------------------------# +# IPV6 address patterns included in the server dscovery mechanism # +#------------------------------------------------------------------------------# + +#jppf.discovery.ipv6.include = 1080:0:0:0:8:800:200C-20FF:- + +#------------------------------------------------------------------------------# +# IPV6 address patterns excluded from the server dscovery mechanism # +#------------------------------------------------------------------------------# + +#jppf.discovery.ipv6.exclude = 1080:0:0:0:8:800:200C-20FF:0C00-0EFF + +#------------------------------------------------------------------------------# +# Enable local execution of tasks? Default value is false # +#------------------------------------------------------------------------------# + +jppf.local.execution.enabled = true + +#------------------------------------------------------------------------------# +# Number of threads to use for loacal execution # +# The default value is the number of CPUs available to the JVM # +#------------------------------------------------------------------------------# + +#jppf.local.execution.threads = 24 +jppf.processing.threads = ${jppf.processing.threads} diff --git a/sandag_abm/src/main/resources/jppf-clientDistributed.properties b/sandag_abm/src/main/resources/jppf-clientDistributed.properties new file mode 100644 index 0000000..69e0d88 --- /dev/null +++ b/sandag_abm/src/main/resources/jppf-clientDistributed.properties @@ -0,0 +1,37 @@ +#------------------------------------------------------------------------------# +# Java Parallel Processing Framework. # +# Copyright (C) 2005-2008 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + + +#------------------------------------------------------------------------------# +# List of drivers this client may connect to # +#------------------------------------------------------------------------------# + +jppf.drivers = driver1 + +#------------------------------------------------------------------------------# +# Host name, or ip address, of the host the JPPF driver is running on # +#------------------------------------------------------------------------------# + +driver1.jppf.server.host = ${master.node.name} + +#------------------------------------------------------------------------------# +# Enable/Disable automatic discovery of JPPF drivers. # +# default value is true; uncomment to specify a different value # +#------------------------------------------------------------------------------# + +jppf.discovery.enabled = false diff --git a/sandag_abm/src/main/resources/jppf-driver.properties b/sandag_abm/src/main/resources/jppf-driver.properties new file mode 100644 index 0000000..a5d59ed --- /dev/null +++ b/sandag_abm/src/main/resources/jppf-driver.properties @@ -0,0 +1,297 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2015 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +#------------------------------------------------------------------------------# +# port number to which the server listens for plain connections # +# default value is 11111; uncomment to specify a different value # +# to disable, specify a negative port number # +#------------------------------------------------------------------------------# + +#jppf.server.port = 11111 + +#------------------------------------------------------------------------------# +# port number to which the server listens for secure connections # +# default value is 11443; uncomment to specify a different value # +# to disable, specify a negative port number # +#------------------------------------------------------------------------------# + +#jppf.ssl.server.port = 11443 +#jppf.ssl.server.port = -1 + +#------------------------------------------------------------------------------# +# SSL Settings # +#------------------------------------------------------------------------------# + +# location of the SSL configuration on the file system +#jppf.ssl.configuration.file = config/ssl/ssl-server.properties + +# SSL configuration as an arbitrary source. Value is the fully qualified name +# of an implementation of java.util.concurrent.Callable +# with optional space-separated arguments +#jppf.ssl.configuration.source = org.jppf.ssl.FileStoreSource config/ssl/ssl-server.properties + +# enable secure communications with other servers; defaults to false (disabled)# +#jppf.peer.ssl.enabled = true + +#------------------------------------------------------------------------------# +# Enabling and configuring JMX features # +#------------------------------------------------------------------------------# + +# non-secure JMX connections; default is true (enabled) +#jppf.management.enabled = true + +# secure JMX connections via SSL/TLS; default is false (disabled) +#jppf.management.ssl.enabled = true + +# JMX management host IP address. If not specified (recommended), the first non-local +# IP address (i.e. neither 127.0.0.1 nor localhost) on this machine will be used. +# If no non-local IP is found, localhost will be used +#jppf.management.host = localhost + +# JMX management port. Defaults to 11198. If the port is already bound, the driver +# will scan for the first available port instead. +#jppf.management.port = 11198 + +#------------------------------------------------------------------------------# +# Configuration of the driver discovery broadcast service # +#------------------------------------------------------------------------------# + +# Enable/Disable automatic discovery of this JPPF drivers; default to true +#jppf.discovery.enabled = false + +# UDP multicast group to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Default value is 230.0.0.1 +#jppf.discovery.group = 230.0.0.1 + +# UDP multicast port to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Default value is 11111 +#jppf.discovery.port = 11111 + +# Time between 2 broadcasts, in milliseconds. Default value is 1000 +#jppf.discovery.broadcast.interval = 1000 + +# IPv4 inclusion patterns: broadcast these ipv4 addresses +#jppf.discovery.broadcast.include.ipv4 = 192.168.1.; 192.168.1.0/24 + +# IPv4 exclusion patterns: do not broadcast these ipv4 addresses +#jppf.discovery.exclude.ipv4 = 192.168.1.128-; 192.168.1.0/25 + +# IPv6 inclusion patterns: broadcast these ipv6 addresses +#jppf.discovery.include.ipv6 = 1080:0:0:0:8:800:200C-20FF:-; ::1/80 + +# IPv6 exclusion patterns: do not broadcast these ipv6 addresses +#jppf.discovery.exclude.ipv6 = 1080:0:0:0:8:800:200C-20FF:0C00-0EFF; ::1/64 + +#------------------------------------------------------------------------------# +# Connection with other servers, enabling P2P communication # +#------------------------------------------------------------------------------# + +# Enable/disable auto-discovery of remote peer drivers. Default value is false +#jppf.peer.discovery.enabled = true + +# manual configuration of peer servers, as a space-separated list of peers names to connect to +#jppf.peers = server_1 server_2 + +# enable both automatic and manual discovery +#jppf.peers = jppf_discovery server_1 server_2 + +# connection to server_1 +#jppf.peer.server_1.server.host = host_1 +#jppf.peer.server_1.server.port = 11111 +# connection to server_2 +#jppf.peer.server_2.server.host = host_2 +#jppf.peer.server_2.server.port = 11112 + +#------------------------------------------------------------------------------# +# Load-balancing configuration # +#------------------------------------------------------------------------------# + +# name of the load-balancing algorithm to use; pre-defined possible values are: +# manual | autotuned | proportional | rl | nodethreads +# it can also be the name of a user-defined algorithm. Default value is "manual" +jppf.load.balancing.algorithm = proportional + +# name of the set of parameter values (aka profile) to use for the algorithm +jppf.load.balancing.profile = proportional_profile + +# "manual" profile +jppf.load.balancing.profile.manual_profile.size = 1 + +# "autotuned" profile +jppf.load.balancing.profile.autotuned_profile.size = 5 +jppf.load.balancing.profile.autotuned_profile.minSamplesToAnalyse = 100 +jppf.load.balancing.profile.autotuned_profile.minSamplesToCheckConvergence = 50 +jppf.load.balancing.profile.autotuned_profile.maxDeviation = 0.2 +jppf.load.balancing.profile.autotuned_profile.maxGuessToStable = 50 +jppf.load.balancing.profile.autotuned_profile.sizeRatioDeviation = 1.5 +jppf.load.balancing.profile.autotuned_profile.decreaseRatio = 0.2 + +# "proportional" profile +jppf.load.balancing.profile.proportional_profile.size = 5 +jppf.load.balancing.profile.proportional_profile.initialMeanTime = 1e10 +jppf.load.balancing.profile.proportional_profile.performanceCacheSize = 300 +jppf.load.balancing.profile.proportional_profile.proportionalityFactor = 1 + +# "rl" profile +jppf.load.balancing.profile.rl_profile.performanceCacheSize = 1000 +jppf.load.balancing.profile.rl_profile.performanceVariationThreshold = 0.0001 +jppf.load.balancing.profile.rl_profile.maxActionRange = 10 + +# "nodethreads" profile +jppf.load.balancing.profile.nodethreads_profile.multiplicator = 1 + +#------------------------------------------------------------------------------# +# Other JVM options added to the java command line when the driver is started # +# as a subprocess. Multiple options are separated by spaces. # +#------------------------------------------------------------------------------# + +jppf.jvm.options = -server -XX:+HeapDumpOnOutOfMemoryError -Xms1000m -Xmx9000m + +# example with remote debugging options +#jppf.jvm.options = -server -Xmx256m -Xrunjdwp:transport=dt_socket,address=localhost:8000,server=y,suspend=n + +#------------------------------------------------------------------------------# +# Specify alternate serialization schemes. # +# Defaults to org.jppf.serialization.DefaultJavaSerialization. # +#------------------------------------------------------------------------------# + +# default +#jppf.object.serialization.class = org.jppf.serialization.DefaultJavaSerialization + +# built-in object serialization schemes +#jppf.object.serialization.class = org.jppf.serialization.DefaultJPPFSerialization +#jppf.object.serialization.class = org.jppf.serialization.XstreamSerialization + +# defined in the "Kryo Serialization" sample +#jppf.object.serialization.class = org.jppf.serialization.kryo.KryoSerialization + +#------------------------------------------------------------------------------# +# Specify a data transformation class. If unspecified, no transformation occurs# +#------------------------------------------------------------------------------# + +# Defined in the "Network Data Encryption" sample +#jppf.data.transform.class = org.jppf.example.dataencryption.SecureKeyCipherTransform + + +#------------------------------------------------------------------------------# +# whether to resolve the nodes' ip addresses into host names # +# defaults to true (resolve the addresses) # +#------------------------------------------------------------------------------# + +org.jppf.resolve.addresses = true + +#------------------------------------------------------------------------------# +# Local (in-JVM) node. When enabled, any node-specific properties will apply # +#------------------------------------------------------------------------------# + +# Enable/disable the local node. Default is false (disabled) +#jppf.local.node.enabled = false + +#------------------------------------------------------------------------------# +# In idle mode configuration. In this mode the server or node starts when no # +# mouse or keyboard activity has occurred since the specified timeout, and is # +# stopped when any new activity occurs. # +#------------------------------------------------------------------------------# + +# Idle mode enabled/disabled. Default is false (disabled) +#jppf.idle.mode.enabled = false + +# Fully qualified class name of the factory object that instantiates a platform-specific idle state detector +#jppf.idle.detector.factory = org.jppf.example.idlesystem.IdleTimeDetectorFactoryImpl + +# Time of keyboard and mouse inactivity to consider the system idle, in milliseconds +# Default value is 300000 (5 minutes) +#jppf.idle.timeout = 6000 + +# Interval between 2 successive calls to the native APIs to determine idle state changes +# Default value is 1000 +#jppf.idle.poll.interval = 1000 + +#------------------------------------------------------------------------------# +# Automatic recovery from hard failure of the nodes connections. These # +# parameters configure how the driver reacts when a node fails to respond to # +# its heartbeat messages. # +#------------------------------------------------------------------------------# + +# Enable recovery from failures on the nodes. Default to false (disabled) +#jppf.recovery.enabled = false + +# Max number of attempts to get a response from the node before the connection +# is considered broken. Default value is 3 +#jppf.recovery.max.retries = 3 + +# Max time in milliseconds allowed for each attempt to get a response from the node. +# Default value is 6000 (6 seconds) +#jppf.recovery.read.timeout = 6000 + +# Dedicated port number for the detection of node failure. Defaults to 22222. +# If server discovery is enabled on the nodes, this value will override the port number specified in the nodes +#jppf.recovery.server.port = 22222 + +# Interval in milliseconds between two runs of the connection reaper +# Default value is 60000 (1 minute) +#jppf.recovery.reaper.run.interval = 60000 + +# Number of threads allocated to the reaper. Default to the number of available CPUs +#jppf.recovery.reaper.pool.size = 8 + +#------------------------------------------------------------------------------# +# Redirecting System.out and System.err to files. # +#------------------------------------------------------------------------------# + +# file path on the file system where System.out is redirected. +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.out = System.out.log +# whether to append to an existing file or to create a new one +jppf.redirect.out.append = false + +# file path on the file system where System.err is redirected +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.err = System.err.log +# whether to append to an existing file or to create a new one +jppf.redirect.err.append = false + +#------------------------------------------------------------------------------# +# Global performance tuning parameters. These affect the performance and # +# throughput of I/O operations in JPPF. The values provided in the vanilla # +# JPPF distribution are known to offer a good performance in most situations # +# and environments. # +#------------------------------------------------------------------------------# + +# Size of send and receive buffer for socket connections. +# Defaults to 32768 and must be in range [1024, 1024*1024] +# 128 * 1024 = 131072 +jppf.socket.buffer.size = 131072 +# Size of temporary buffers (including direct buffers) used in I/O transfers. +# Defaults to 32768 and must be in range [1024, 1024*1024] +jppf.temp.buffer.size = 12288 +# Maximum size of temporary buffers pool (excluding direct buffers). When this size +# is reached, new buffers are still created, but not released into the pool, so they +# can be quickly garbage-collected. The size of each buffer is defined with ${jppf.temp.buffer.size} +# Defaults to 10 and must be in range [1, 2048] +jppf.temp.buffer.pool.size = 200 +# Size of temporary buffer pool for reading lengths as ints (size of each buffer is 4). +# Defaults to 100 and must be in range [1, 2048] +jppf.length.buffer.pool.size = 100 + +#------------------------------------------------------------------------------# +# Enabling or disabling the lookup of classpath resources in the file system # +# Defaults to true (enabled) # +#------------------------------------------------------------------------------# + +#jppf.classloader.file.lookup = true diff --git a/sandag_abm/src/main/resources/jppf-sandag01.properties b/sandag_abm/src/main/resources/jppf-sandag01.properties new file mode 100644 index 0000000..1d5dce8 --- /dev/null +++ b/sandag_abm/src/main/resources/jppf-sandag01.properties @@ -0,0 +1,298 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2015 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +#------------------------------------------------------------------------------# +# Manual configuration of the server connection # +#------------------------------------------------------------------------------# + +# Host name, or ip address, of the host the JPPF driver is running on +# defaults to 'localhost' +jppf.server.host = ${master.node.name} + +# port number the server is listening to for connections, defaults to 11111 +#jppf.server.port = 11111 + +#------------------------------------------------------------------------------# +# Configuration of JMX management server # +#------------------------------------------------------------------------------# + +# enable/disable management, defaults to true +#jppf.management.enabled = true + +# JMX management host IP address. If unspecified (recommended), the first +# non-local IP address (i.e. neither 127.0.0.1 nor localhost) on this machine +# will be used. If no non-local IP is found, 'localhost' will be used. +#jppf.management.host = localhost + +# JMX management port, defaults to 11198 (no SSL) or 11193 with SSL. If the port +# is already bound, the node will automatically scan for the next available port. +#jppf.node.management.port = 12001 + +#------------------------------------------------------------------------------# +# SSL Settings # +#------------------------------------------------------------------------------# + +# Enable SSL, defaults to false (disabled). If enabled, only SSL connections are established +#jppf.ssl.enabled = true + +# location of the SSL configuration on the file system +#jppf.ssl.configuration.file = config/ssl/ssl.properties + +# SSL configuration as an arbitrary source. Value is the fully qualified name of +# an implementation of java.util.concurrent.Callable with optional space-separated arguments +#jppf.ssl.configuration.source = org.jppf.ssl.FileStoreSource config/ssl/ssl.properties + +#------------------------------------------------------------------------------# +# path to the JPPF security policy file # +# comment out this entry to disable security on the node # +#------------------------------------------------------------------------------# + +#jppf.policy.file = config/jppf.policy + +#------------------------------------------------------------------------------# +# Server discovery. # +#------------------------------------------------------------------------------# + +# Enable/disable automatic discovery of JPPF drivers, defaults to true. +jppf.discovery.enabled = false + +# UDP multicast group to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Default to 230.0.0.1 +#jppf.discovery.group = 230.0.0.1 + +# UDP multicast port to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Defaults to 11111 +#jppf.discovery.port = 11111 + +# How long the node will attempt to automatically discover a driver before falling +# back to the parameters specified in this configuration file. Defaults to 5000 ms +#jppf.discovery.timeout = 5000 + +# IPv4 address patterns included in the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be included +# in the list of discovered drivers. +#jppf.discovery.include.ipv4 = 192.168.1.; 192.168.1.0/24 + +# IPv4 address patterns excluded from the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be excluded +# from the list of discovered drivers. +#jppf.discovery.exclude.ipv4 = 192.168.1.128-; 192.168.1.0/25 + +# IPv6 address patterns included in the server dscovery mechanism +#jppf.discovery.include.ipv6 = 1080:0:0:0:8:800:200C-20FF:-; ::1/80 + +# IPv6 address patterns excluded from the server dscovery mechanism +#jppf.discovery.exclude.ipv6 = 1080:0:0:0:8:800:200C-20FF:0C00-0EFF; ::1/96 + +#------------------------------------------------------------------------------# +# Automatic recovery from disconnection from the server # +#------------------------------------------------------------------------------# + +# number of seconds before the first reconnection attempt, default to 1 +#jppf.reconnect.initial.delay = 1 + +# time after which the node stops trying to reconnect, in seconds. Defaults to 60 +jppf.reconnect.max.time = 5 + +# time between two connection attempts, in seconds. Defaults to 1 +#jppf.reconnect.interval = 1 + +#------------------------------------------------------------------------------# +# Processing Threads: number of threads running tasks in this node. # +# default value is the number of available CPUs; uncomment to specify a # +# different value. Blocking tasks might benefit from a number larger than CPUs # +#------------------------------------------------------------------------------# + +jppf.processing.threads = ${node.1.execution.threads} + +#------------------------------------------------------------------------------# +# Thread Manager: manager that wraps the executor service for running tasks. # +# default value is ThreadManagerThreadPool - that wraps ThreadPoolExecutor # +#------------------------------------------------------------------------------# + +# built-in thread manager +#jppf.thread.manager.class = default + +# fork/join thread manager +#jppf.thread.manager.class = org.jppf.server.node.fj.ThreadManagerForkJoin + +#------------------------------------------------------------------------------# +# Specify alternate serialization schemes. # +# Defaults to org.jppf.serialization.DefaultJavaSerialization. # +#------------------------------------------------------------------------------# + +# default +#jppf.object.serialization.class = org.jppf.serialization.DefaultJavaSerialization + +# built-in object serialization schemes +#jppf.object.serialization.class = org.jppf.serialization.DefaultJPPFSerialization +#jppf.object.serialization.class = org.jppf.serialization.XstreamSerialization + +# defined in the "Kryo Serialization" sample +#jppf.object.serialization.class = org.jppf.serialization.kryo.KryoSerialization + +#------------------------------------------------------------------------------# +# Specify a data transformation class. If unspecified, none is used. # +#------------------------------------------------------------------------------# + +# Defined in the "Network Data Encryption" sample +#jppf.data.transform.class = org.jppf.example.dataencryption.SecureKeyCipherTransform + +#------------------------------------------------------------------------------# +# Other JVM options added to the java command line when the node is started as # +# a subprocess. Multiple options are separated by spaces. # +#------------------------------------------------------------------------------# + +jppf.jvm.options = -Xms45000m -Xmx120000m -Dlog4j.configuration=log4j-sandag01.xml -Dnode.name=sandag01 + +# example with remote debugging options +#jppf.jvm.options = -server -Xmx128m -Xrunjdwp:transport=dt_socket,address=localhost:8000,server=y,suspend=n + +#------------------------------------------------------------------------------# +# Idle mode configuration. In idle mode, the server ot node starts when no # +# mouse or keyboard activity has occurred since the specified tiemout, and is # +# stopped when any new activity occurs. See "jppf.idle.timeout" below. # +#------------------------------------------------------------------------------# + +# enable/disable idle mode, defaults to false (disabled) +#jppf.idle.mode.enabled = false + +# Time of keyboard and mouse inactivity after which the system is considered +# idle, in ms. Defaults to 300000 (5 minutes) +#jppf.idle.timeout = 6000 + +# Interval between 2 successive calls to the native APIs to determine whether +# the system idle state has changed. Defaults to 1000 ms. +#jppf.idle.poll.interval = 1000 + +# Whether to shutdown the node immediately when a mouse/keyboard activity is detected, +# or wait until the node is no longer executing tasks. Defaults to true (immediate shutdown). +#jppf.idle.interruptIfRunning = true + +#------------------------------------------------------------------------------# +# Automatic recovery from hard failure of the server connection. These # +# parameters configure how the node reacts to the heartbeats sent by the # +# server, or lack thereof. # +#------------------------------------------------------------------------------# + +# Enable recovery from hardware failures, defaults to false (disabled) +#jppf.recovery.enabled = true + +# Dedicated port number for the detection of connection failure, must be the +# same as the value specified in the server configuration. Defaults to 22222. +# If server discovery is enabled, this value will be overridden by the port +# number specified in the driver configuration. +#jppf.recovery.server.port = 22222 + +# Maximum number of attempts to get a message from the server before the +# connection is considered broken. Default value is 2 +#jppf.recovery.max.retries = 2 + +# Maximum time in milliseconds allowed for each attempt to get a response from +# the node. Default value is 60000 ms (1 minute). + +#jppf.recovery.read.timeout = 60000 + +#------------------------------------------------------------------------------# +# JPPF class loader-related properties # +#------------------------------------------------------------------------------# + +# JPPF class loader delegation model. values: parent | url, defaults to parent +#jppf.classloader.delegation = parent + +# size of the class loader cache in the node, defaults to 50 +#jppf.classloader.cache.size = 50 + +# class loader resource cache enabled? defaults to true. +#jppf.resource.cache.enabled = true +# resource cache's type of storage: either "file" (the default) or "memory" +#jppf.resource.cache.storage = file +# root location of the file-persisted caches +#jppf.resource.cache.dir = some_directory + +#------------------------------------------------------------------------------# +# Screen saver settings # +#------------------------------------------------------------------------------# + +# include the settings from a separate file to avoid cluttering this config file +#!include file config/screensaver.properties + +#------------------------------------------------------------------------------# +# Redirecting System.out and System.err to files. # +#------------------------------------------------------------------------------# + +# file path on the file system where System.out is redirected. +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.out = System.out.log +# whether to append to an existing file or to create a new one +#jppf.redirect.out.append = false + +# file path on the file system where System.err is redirected +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.err = System.err.log +# whether to append to an existing file or to create a new one +#jppf.redirect.err.append = false + +#------------------------------------------------------------------------------# +# Node provisioning configuration # +#------------------------------------------------------------------------------# + +# Define a node as master. Defaults to true +#jppf.node.provisioning.master = true +# Define a node as a slave. Defaults to false +#jppf.node.provisioning.slave = false +# Specify the path prefix used for the root directory of each slave node +# defaults to "slave_nodes/node_", relative to the master root directory +#jppf.node.provisioning.slave.path.prefix = slave_nodes/node_ +# Specify the directory where slave-specific configuration files are located +# Defaults to the "config" folder, relative to the master root directory +#jppf.node.provisioning.slave.config.path = config +# A set of space-separated JVM options always added to the slave startup command +#jppf.node.provisioning.slave.jvm.options = -Dlog4j.configuration=config/log4j-node.properties +# Specify the number of slaves to launch upon master node startup. Defaults to 0 +#jppf.node.provisioning.startup.slaves = 0 + +#------------------------------------------------------------------------------# +# Global performance tuning parameters. These affect the performance and # +# throughput of I/O operations in JPPF. The values provided in the vanilla # +# JPPF distribution are known to offer a good performance in most situations # +# and environments. # +#------------------------------------------------------------------------------# + +# Size of send and receive buffer for socket connections. +# Defaults to 32768 and must be in range [1024, 1024*1024] +# 128 * 1024 = 131072 +#jppf.socket.buffer.size = 131072 +# Size of temporary buffers (including direct buffers) used in I/O transfers. +# Defaults to 32768 and must be in range [1024, 1024*1024] +#jppf.temp.buffer.size = 12288 +# Maximum size of temporary buffers pool (excluding direct buffers). When this size +# is reached, new buffers are still created, but not released into the pool, so they +# can be quickly garbage-collected. The size of each buffer is defined with ${jppf.temp.buffer.size} +# Defaults to 10 and must be in range [1, 2048] +#jppf.temp.buffer.pool.size = 200 +# Size of temporary buffer pool for reading lengths as ints (size of each buffer is 4). +# Defaults to 100 and must be in range [1, 2048] +#jppf.length.buffer.pool.size = 100 + +#------------------------------------------------------------------------------# +# Enabling or disabling the lookup of classpath resources in the file system # +# Defaults to true (enabled) # +#------------------------------------------------------------------------------# + +#jppf.classloader.file.lookup = true diff --git a/sandag_abm/src/main/resources/jppf-sandag02.properties b/sandag_abm/src/main/resources/jppf-sandag02.properties new file mode 100644 index 0000000..290be6d --- /dev/null +++ b/sandag_abm/src/main/resources/jppf-sandag02.properties @@ -0,0 +1,298 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2015 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +#------------------------------------------------------------------------------# +# Manual configuration of the server connection # +#------------------------------------------------------------------------------# + +# Host name, or ip address, of the host the JPPF driver is running on +# defaults to 'localhost' +jppf.server.host = ${master.node.name} + +# port number the server is listening to for connections, defaults to 11111 +#jppf.server.port = 11111 + +#------------------------------------------------------------------------------# +# Configuration of JMX management server # +#------------------------------------------------------------------------------# + +# enable/disable management, defaults to true +#jppf.management.enabled = true + +# JMX management host IP address. If unspecified (recommended), the first +# non-local IP address (i.e. neither 127.0.0.1 nor localhost) on this machine +# will be used. If no non-local IP is found, 'localhost' will be used. +#jppf.management.host = localhost + +# JMX management port, defaults to 11198 (no SSL) or 11193 with SSL. If the port +# is already bound, the node will automatically scan for the next available port. +#jppf.node.management.port = 12001 + +#------------------------------------------------------------------------------# +# SSL Settings # +#------------------------------------------------------------------------------# + +# Enable SSL, defaults to false (disabled). If enabled, only SSL connections are established +#jppf.ssl.enabled = true + +# location of the SSL configuration on the file system +#jppf.ssl.configuration.file = config/ssl/ssl.properties + +# SSL configuration as an arbitrary source. Value is the fully qualified name of +# an implementation of java.util.concurrent.Callable with optional space-separated arguments +#jppf.ssl.configuration.source = org.jppf.ssl.FileStoreSource config/ssl/ssl.properties + +#------------------------------------------------------------------------------# +# path to the JPPF security policy file # +# comment out this entry to disable security on the node # +#------------------------------------------------------------------------------# + +#jppf.policy.file = config/jppf.policy + +#------------------------------------------------------------------------------# +# Server discovery. # +#------------------------------------------------------------------------------# + +# Enable/disable automatic discovery of JPPF drivers, defaults to true. +jppf.discovery.enabled = false + +# UDP multicast group to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Default to 230.0.0.1 +#jppf.discovery.group = 230.0.0.1 + +# UDP multicast port to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Defaults to 11111 +#jppf.discovery.port = 11111 + +# How long the node will attempt to automatically discover a driver before falling +# back to the parameters specified in this configuration file. Defaults to 5000 ms +#jppf.discovery.timeout = 5000 + +# IPv4 address patterns included in the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be included +# in the list of discovered drivers. +#jppf.discovery.include.ipv4 = 192.168.1.; 192.168.1.0/24 + +# IPv4 address patterns excluded from the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be excluded +# from the list of discovered drivers. +#jppf.discovery.exclude.ipv4 = 192.168.1.128-; 192.168.1.0/25 + +# IPv6 address patterns included in the server dscovery mechanism +#jppf.discovery.include.ipv6 = 1080:0:0:0:8:800:200C-20FF:-; ::1/80 + +# IPv6 address patterns excluded from the server dscovery mechanism +#jppf.discovery.exclude.ipv6 = 1080:0:0:0:8:800:200C-20FF:0C00-0EFF; ::1/96 + +#------------------------------------------------------------------------------# +# Automatic recovery from disconnection from the server # +#------------------------------------------------------------------------------# + +# number of seconds before the first reconnection attempt, default to 1 +#jppf.reconnect.initial.delay = 1 + +# time after which the node stops trying to reconnect, in seconds. Defaults to 60 +jppf.reconnect.max.time = 5 + +# time between two connection attempts, in seconds. Defaults to 1 +#jppf.reconnect.interval = 1 + +#------------------------------------------------------------------------------# +# Processing Threads: number of threads running tasks in this node. # +# default value is the number of available CPUs; uncomment to specify a # +# different value. Blocking tasks might benefit from a number larger than CPUs # +#------------------------------------------------------------------------------# + +jppf.processing.threads = ${node.1.execution.threads} + +#------------------------------------------------------------------------------# +# Thread Manager: manager that wraps the executor service for running tasks. # +# default value is ThreadManagerThreadPool - that wraps ThreadPoolExecutor # +#------------------------------------------------------------------------------# + +# built-in thread manager +#jppf.thread.manager.class = default + +# fork/join thread manager +#jppf.thread.manager.class = org.jppf.server.node.fj.ThreadManagerForkJoin + +#------------------------------------------------------------------------------# +# Specify alternate serialization schemes. # +# Defaults to org.jppf.serialization.DefaultJavaSerialization. # +#------------------------------------------------------------------------------# + +# default +#jppf.object.serialization.class = org.jppf.serialization.DefaultJavaSerialization + +# built-in object serialization schemes +#jppf.object.serialization.class = org.jppf.serialization.DefaultJPPFSerialization +#jppf.object.serialization.class = org.jppf.serialization.XstreamSerialization + +# defined in the "Kryo Serialization" sample +#jppf.object.serialization.class = org.jppf.serialization.kryo.KryoSerialization + +#------------------------------------------------------------------------------# +# Specify a data transformation class. If unspecified, none is used. # +#------------------------------------------------------------------------------# + +# Defined in the "Network Data Encryption" sample +#jppf.data.transform.class = org.jppf.example.dataencryption.SecureKeyCipherTransform + +#------------------------------------------------------------------------------# +# Other JVM options added to the java command line when the node is started as # +# a subprocess. Multiple options are separated by spaces. # +#------------------------------------------------------------------------------# + +jppf.jvm.options = -Xms45000m -Xmx120000m -Dlog4j.configuration=log4j-sandag02.xml -Dnode.name=sandag02 + +# example with remote debugging options +#jppf.jvm.options = -server -Xmx128m -Xrunjdwp:transport=dt_socket,address=localhost:8000,server=y,suspend=n + +#------------------------------------------------------------------------------# +# Idle mode configuration. In idle mode, the server ot node starts when no # +# mouse or keyboard activity has occurred since the specified tiemout, and is # +# stopped when any new activity occurs. See "jppf.idle.timeout" below. # +#------------------------------------------------------------------------------# + +# enable/disable idle mode, defaults to false (disabled) +#jppf.idle.mode.enabled = false + +# Time of keyboard and mouse inactivity after which the system is considered +# idle, in ms. Defaults to 300000 (5 minutes) +#jppf.idle.timeout = 6000 + +# Interval between 2 successive calls to the native APIs to determine whether +# the system idle state has changed. Defaults to 1000 ms. +#jppf.idle.poll.interval = 1000 + +# Whether to shutdown the node immediately when a mouse/keyboard activity is detected, +# or wait until the node is no longer executing tasks. Defaults to true (immediate shutdown). +#jppf.idle.interruptIfRunning = true + +#------------------------------------------------------------------------------# +# Automatic recovery from hard failure of the server connection. These # +# parameters configure how the node reacts to the heartbeats sent by the # +# server, or lack thereof. # +#------------------------------------------------------------------------------# + +# Enable recovery from hardware failures, defaults to false (disabled) +#jppf.recovery.enabled = true + +# Dedicated port number for the detection of connection failure, must be the +# same as the value specified in the server configuration. Defaults to 22222. +# If server discovery is enabled, this value will be overridden by the port +# number specified in the driver configuration. +#jppf.recovery.server.port = 22222 + +# Maximum number of attempts to get a message from the server before the +# connection is considered broken. Default value is 2 +#jppf.recovery.max.retries = 2 + +# Maximum time in milliseconds allowed for each attempt to get a response from +# the node. Default value is 60000 ms (1 minute). + +#jppf.recovery.read.timeout = 60000 + +#------------------------------------------------------------------------------# +# JPPF class loader-related properties # +#------------------------------------------------------------------------------# + +# JPPF class loader delegation model. values: parent | url, defaults to parent +#jppf.classloader.delegation = parent + +# size of the class loader cache in the node, defaults to 50 +#jppf.classloader.cache.size = 50 + +# class loader resource cache enabled? defaults to true. +#jppf.resource.cache.enabled = true +# resource cache's type of storage: either "file" (the default) or "memory" +#jppf.resource.cache.storage = file +# root location of the file-persisted caches +#jppf.resource.cache.dir = some_directory + +#------------------------------------------------------------------------------# +# Screen saver settings # +#------------------------------------------------------------------------------# + +# include the settings from a separate file to avoid cluttering this config file +#!include file config/screensaver.properties + +#------------------------------------------------------------------------------# +# Redirecting System.out and System.err to files. # +#------------------------------------------------------------------------------# + +# file path on the file system where System.out is redirected. +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.out = System.out.log +# whether to append to an existing file or to create a new one +#jppf.redirect.out.append = false + +# file path on the file system where System.err is redirected +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.err = System.err.log +# whether to append to an existing file or to create a new one +#jppf.redirect.err.append = false + +#------------------------------------------------------------------------------# +# Node provisioning configuration # +#------------------------------------------------------------------------------# + +# Define a node as master. Defaults to true +#jppf.node.provisioning.master = true +# Define a node as a slave. Defaults to false +#jppf.node.provisioning.slave = false +# Specify the path prefix used for the root directory of each slave node +# defaults to "slave_nodes/node_", relative to the master root directory +#jppf.node.provisioning.slave.path.prefix = slave_nodes/node_ +# Specify the directory where slave-specific configuration files are located +# Defaults to the "config" folder, relative to the master root directory +#jppf.node.provisioning.slave.config.path = config +# A set of space-separated JVM options always added to the slave startup command +#jppf.node.provisioning.slave.jvm.options = -Dlog4j.configuration=config/log4j-node.properties +# Specify the number of slaves to launch upon master node startup. Defaults to 0 +#jppf.node.provisioning.startup.slaves = 0 + +#------------------------------------------------------------------------------# +# Global performance tuning parameters. These affect the performance and # +# throughput of I/O operations in JPPF. The values provided in the vanilla # +# JPPF distribution are known to offer a good performance in most situations # +# and environments. # +#------------------------------------------------------------------------------# + +# Size of send and receive buffer for socket connections. +# Defaults to 32768 and must be in range [1024, 1024*1024] +# 128 * 1024 = 131072 +#jppf.socket.buffer.size = 131072 +# Size of temporary buffers (including direct buffers) used in I/O transfers. +# Defaults to 32768 and must be in range [1024, 1024*1024] +#jppf.temp.buffer.size = 12288 +# Maximum size of temporary buffers pool (excluding direct buffers). When this size +# is reached, new buffers are still created, but not released into the pool, so they +# can be quickly garbage-collected. The size of each buffer is defined with ${jppf.temp.buffer.size} +# Defaults to 10 and must be in range [1, 2048] +#jppf.temp.buffer.pool.size = 200 +# Size of temporary buffer pool for reading lengths as ints (size of each buffer is 4). +# Defaults to 100 and must be in range [1, 2048] +#jppf.length.buffer.pool.size = 100 + +#------------------------------------------------------------------------------# +# Enabling or disabling the lookup of classpath resources in the file system # +# Defaults to true (enabled) # +#------------------------------------------------------------------------------# + +#jppf.classloader.file.lookup = true diff --git a/sandag_abm/src/main/resources/jppf-sandag03.properties b/sandag_abm/src/main/resources/jppf-sandag03.properties new file mode 100644 index 0000000..ab3a6a2 --- /dev/null +++ b/sandag_abm/src/main/resources/jppf-sandag03.properties @@ -0,0 +1,298 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2015 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +#------------------------------------------------------------------------------# +# Manual configuration of the server connection # +#------------------------------------------------------------------------------# + +# Host name, or ip address, of the host the JPPF driver is running on +# defaults to 'localhost' +jppf.server.host = ${master.node.name} + +# port number the server is listening to for connections, defaults to 11111 +#jppf.server.port = 11111 + +#------------------------------------------------------------------------------# +# Configuration of JMX management server # +#------------------------------------------------------------------------------# + +# enable/disable management, defaults to true +#jppf.management.enabled = true + +# JMX management host IP address. If unspecified (recommended), the first +# non-local IP address (i.e. neither 127.0.0.1 nor localhost) on this machine +# will be used. If no non-local IP is found, 'localhost' will be used. +#jppf.management.host = localhost + +# JMX management port, defaults to 11198 (no SSL) or 11193 with SSL. If the port +# is already bound, the node will automatically scan for the next available port. +#jppf.node.management.port = 12001 + +#------------------------------------------------------------------------------# +# SSL Settings # +#------------------------------------------------------------------------------# + +# Enable SSL, defaults to false (disabled). If enabled, only SSL connections are established +#jppf.ssl.enabled = true + +# location of the SSL configuration on the file system +#jppf.ssl.configuration.file = config/ssl/ssl.properties + +# SSL configuration as an arbitrary source. Value is the fully qualified name of +# an implementation of java.util.concurrent.Callable with optional space-separated arguments +#jppf.ssl.configuration.source = org.jppf.ssl.FileStoreSource config/ssl/ssl.properties + +#------------------------------------------------------------------------------# +# path to the JPPF security policy file # +# comment out this entry to disable security on the node # +#------------------------------------------------------------------------------# + +#jppf.policy.file = config/jppf.policy + +#------------------------------------------------------------------------------# +# Server discovery. # +#------------------------------------------------------------------------------# + +# Enable/disable automatic discovery of JPPF drivers, defaults to true. +jppf.discovery.enabled = false + +# UDP multicast group to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Default to 230.0.0.1 +#jppf.discovery.group = 230.0.0.1 + +# UDP multicast port to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Defaults to 11111 +#jppf.discovery.port = 11111 + +# How long the node will attempt to automatically discover a driver before falling +# back to the parameters specified in this configuration file. Defaults to 5000 ms +#jppf.discovery.timeout = 5000 + +# IPv4 address patterns included in the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be included +# in the list of discovered drivers. +#jppf.discovery.include.ipv4 = 192.168.1.; 192.168.1.0/24 + +# IPv4 address patterns excluded from the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be excluded +# from the list of discovered drivers. +#jppf.discovery.exclude.ipv4 = 192.168.1.128-; 192.168.1.0/25 + +# IPv6 address patterns included in the server dscovery mechanism +#jppf.discovery.include.ipv6 = 1080:0:0:0:8:800:200C-20FF:-; ::1/80 + +# IPv6 address patterns excluded from the server dscovery mechanism +#jppf.discovery.exclude.ipv6 = 1080:0:0:0:8:800:200C-20FF:0C00-0EFF; ::1/96 + +#------------------------------------------------------------------------------# +# Automatic recovery from disconnection from the server # +#------------------------------------------------------------------------------# + +# number of seconds before the first reconnection attempt, default to 1 +#jppf.reconnect.initial.delay = 1 + +# time after which the node stops trying to reconnect, in seconds. Defaults to 60 +jppf.reconnect.max.time = 5 + +# time between two connection attempts, in seconds. Defaults to 1 +#jppf.reconnect.interval = 1 + +#------------------------------------------------------------------------------# +# Processing Threads: number of threads running tasks in this node. # +# default value is the number of available CPUs; uncomment to specify a # +# different value. Blocking tasks might benefit from a number larger than CPUs # +#------------------------------------------------------------------------------# + +jppf.processing.threads = ${node.2.execution.threads} + +#------------------------------------------------------------------------------# +# Thread Manager: manager that wraps the executor service for running tasks. # +# default value is ThreadManagerThreadPool - that wraps ThreadPoolExecutor # +#------------------------------------------------------------------------------# + +# built-in thread manager +#jppf.thread.manager.class = default + +# fork/join thread manager +#jppf.thread.manager.class = org.jppf.server.node.fj.ThreadManagerForkJoin + +#------------------------------------------------------------------------------# +# Specify alternate serialization schemes. # +# Defaults to org.jppf.serialization.DefaultJavaSerialization. # +#------------------------------------------------------------------------------# + +# default +#jppf.object.serialization.class = org.jppf.serialization.DefaultJavaSerialization + +# built-in object serialization schemes +#jppf.object.serialization.class = org.jppf.serialization.DefaultJPPFSerialization +#jppf.object.serialization.class = org.jppf.serialization.XstreamSerialization + +# defined in the "Kryo Serialization" sample +#jppf.object.serialization.class = org.jppf.serialization.kryo.KryoSerialization + +#------------------------------------------------------------------------------# +# Specify a data transformation class. If unspecified, none is used. # +#------------------------------------------------------------------------------# + +# Defined in the "Network Data Encryption" sample +#jppf.data.transform.class = org.jppf.example.dataencryption.SecureKeyCipherTransform + +#------------------------------------------------------------------------------# +# Other JVM options added to the java command line when the node is started as # +# a subprocess. Multiple options are separated by spaces. # +#------------------------------------------------------------------------------# + +jppf.jvm.options = -Xms45000m -Xmx120000m -Dlog4j.configuration=log4j-sandag03.xml -Dnode.name=sandag03 + +# example with remote debugging options +#jppf.jvm.options = -server -Xmx128m -Xrunjdwp:transport=dt_socket,address=localhost:8000,server=y,suspend=n + +#------------------------------------------------------------------------------# +# Idle mode configuration. In idle mode, the server ot node starts when no # +# mouse or keyboard activity has occurred since the specified tiemout, and is # +# stopped when any new activity occurs. See "jppf.idle.timeout" below. # +#------------------------------------------------------------------------------# + +# enable/disable idle mode, defaults to false (disabled) +#jppf.idle.mode.enabled = false + +# Time of keyboard and mouse inactivity after which the system is considered +# idle, in ms. Defaults to 300000 (5 minutes) +#jppf.idle.timeout = 6000 + +# Interval between 2 successive calls to the native APIs to determine whether +# the system idle state has changed. Defaults to 1000 ms. +#jppf.idle.poll.interval = 1000 + +# Whether to shutdown the node immediately when a mouse/keyboard activity is detected, +# or wait until the node is no longer executing tasks. Defaults to true (immediate shutdown). +#jppf.idle.interruptIfRunning = true + +#------------------------------------------------------------------------------# +# Automatic recovery from hard failure of the server connection. These # +# parameters configure how the node reacts to the heartbeats sent by the # +# server, or lack thereof. # +#------------------------------------------------------------------------------# + +# Enable recovery from hardware failures, defaults to false (disabled) +#jppf.recovery.enabled = true + +# Dedicated port number for the detection of connection failure, must be the +# same as the value specified in the server configuration. Defaults to 22222. +# If server discovery is enabled, this value will be overridden by the port +# number specified in the driver configuration. +#jppf.recovery.server.port = 22222 + +# Maximum number of attempts to get a message from the server before the +# connection is considered broken. Default value is 2 +#jppf.recovery.max.retries = 2 + +# Maximum time in milliseconds allowed for each attempt to get a response from +# the node. Default value is 60000 ms (1 minute). + +#jppf.recovery.read.timeout = 60000 + +#------------------------------------------------------------------------------# +# JPPF class loader-related properties # +#------------------------------------------------------------------------------# + +# JPPF class loader delegation model. values: parent | url, defaults to parent +#jppf.classloader.delegation = parent + +# size of the class loader cache in the node, defaults to 50 +#jppf.classloader.cache.size = 50 + +# class loader resource cache enabled? defaults to true. +#jppf.resource.cache.enabled = true +# resource cache's type of storage: either "file" (the default) or "memory" +#jppf.resource.cache.storage = file +# root location of the file-persisted caches +#jppf.resource.cache.dir = some_directory + +#------------------------------------------------------------------------------# +# Screen saver settings # +#------------------------------------------------------------------------------# + +# include the settings from a separate file to avoid cluttering this config file +#!include file config/screensaver.properties + +#------------------------------------------------------------------------------# +# Redirecting System.out and System.err to files. # +#------------------------------------------------------------------------------# + +# file path on the file system where System.out is redirected. +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.out = System.out.log +# whether to append to an existing file or to create a new one +#jppf.redirect.out.append = false + +# file path on the file system where System.err is redirected +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.err = System.err.log +# whether to append to an existing file or to create a new one +#jppf.redirect.err.append = false + +#------------------------------------------------------------------------------# +# Node provisioning configuration # +#------------------------------------------------------------------------------# + +# Define a node as master. Defaults to true +#jppf.node.provisioning.master = true +# Define a node as a slave. Defaults to false +#jppf.node.provisioning.slave = false +# Specify the path prefix used for the root directory of each slave node +# defaults to "slave_nodes/node_", relative to the master root directory +#jppf.node.provisioning.slave.path.prefix = slave_nodes/node_ +# Specify the directory where slave-specific configuration files are located +# Defaults to the "config" folder, relative to the master root directory +#jppf.node.provisioning.slave.config.path = config +# A set of space-separated JVM options always added to the slave startup command +#jppf.node.provisioning.slave.jvm.options = -Dlog4j.configuration=config/log4j-node.properties +# Specify the number of slaves to launch upon master node startup. Defaults to 0 +#jppf.node.provisioning.startup.slaves = 0 + +#------------------------------------------------------------------------------# +# Global performance tuning parameters. These affect the performance and # +# throughput of I/O operations in JPPF. The values provided in the vanilla # +# JPPF distribution are known to offer a good performance in most situations # +# and environments. # +#------------------------------------------------------------------------------# + +# Size of send and receive buffer for socket connections. +# Defaults to 32768 and must be in range [1024, 1024*1024] +# 128 * 1024 = 131072 +#jppf.socket.buffer.size = 131072 +# Size of temporary buffers (including direct buffers) used in I/O transfers. +# Defaults to 32768 and must be in range [1024, 1024*1024] +#jppf.temp.buffer.size = 12288 +# Maximum size of temporary buffers pool (excluding direct buffers). When this size +# is reached, new buffers are still created, but not released into the pool, so they +# can be quickly garbage-collected. The size of each buffer is defined with ${jppf.temp.buffer.size} +# Defaults to 10 and must be in range [1, 2048] +#jppf.temp.buffer.pool.size = 200 +# Size of temporary buffer pool for reading lengths as ints (size of each buffer is 4). +# Defaults to 100 and must be in range [1, 2048] +#jppf.length.buffer.pool.size = 100 + +#------------------------------------------------------------------------------# +# Enabling or disabling the lookup of classpath resources in the file system # +# Defaults to true (enabled) # +#------------------------------------------------------------------------------# + +#jppf.classloader.file.lookup = true diff --git a/sandag_abm/src/main/resources/jppf-sandag04.properties b/sandag_abm/src/main/resources/jppf-sandag04.properties new file mode 100644 index 0000000..61f887c --- /dev/null +++ b/sandag_abm/src/main/resources/jppf-sandag04.properties @@ -0,0 +1,298 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2015 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +#------------------------------------------------------------------------------# +# Manual configuration of the server connection # +#------------------------------------------------------------------------------# + +# Host name, or ip address, of the host the JPPF driver is running on +# defaults to 'localhost' +jppf.server.host = ${master.node.name} + +# port number the server is listening to for connections, defaults to 11111 +#jppf.server.port = 11111 + +#------------------------------------------------------------------------------# +# Configuration of JMX management server # +#------------------------------------------------------------------------------# + +# enable/disable management, defaults to true +#jppf.management.enabled = true + +# JMX management host IP address. If unspecified (recommended), the first +# non-local IP address (i.e. neither 127.0.0.1 nor localhost) on this machine +# will be used. If no non-local IP is found, 'localhost' will be used. +#jppf.management.host = localhost + +# JMX management port, defaults to 11198 (no SSL) or 11193 with SSL. If the port +# is already bound, the node will automatically scan for the next available port. +#jppf.node.management.port = 12001 + +#------------------------------------------------------------------------------# +# SSL Settings # +#------------------------------------------------------------------------------# + +# Enable SSL, defaults to false (disabled). If enabled, only SSL connections are established +#jppf.ssl.enabled = true + +# location of the SSL configuration on the file system +#jppf.ssl.configuration.file = config/ssl/ssl.properties + +# SSL configuration as an arbitrary source. Value is the fully qualified name of +# an implementation of java.util.concurrent.Callable with optional space-separated arguments +#jppf.ssl.configuration.source = org.jppf.ssl.FileStoreSource config/ssl/ssl.properties + +#------------------------------------------------------------------------------# +# path to the JPPF security policy file # +# comment out this entry to disable security on the node # +#------------------------------------------------------------------------------# + +#jppf.policy.file = config/jppf.policy + +#------------------------------------------------------------------------------# +# Server discovery. # +#------------------------------------------------------------------------------# + +# Enable/disable automatic discovery of JPPF drivers, defaults to true. +jppf.discovery.enabled = false + +# UDP multicast group to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Default to 230.0.0.1 +#jppf.discovery.group = 230.0.0.1 + +# UDP multicast port to which drivers broadcast their connection parameters +# and to which clients and nodes listen. Defaults to 11111 +#jppf.discovery.port = 11111 + +# How long the node will attempt to automatically discover a driver before falling +# back to the parameters specified in this configuration file. Defaults to 5000 ms +#jppf.discovery.timeout = 5000 + +# IPv4 address patterns included in the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be included +# in the list of discovered drivers. +#jppf.discovery.include.ipv4 = 192.168.1.; 192.168.1.0/24 + +# IPv4 address patterns excluded from the server dscovery mechanism +# Drivers whose IPv4 address matches the pattern will be excluded +# from the list of discovered drivers. +#jppf.discovery.exclude.ipv4 = 192.168.1.128-; 192.168.1.0/25 + +# IPv6 address patterns included in the server dscovery mechanism +#jppf.discovery.include.ipv6 = 1080:0:0:0:8:800:200C-20FF:-; ::1/80 + +# IPv6 address patterns excluded from the server dscovery mechanism +#jppf.discovery.exclude.ipv6 = 1080:0:0:0:8:800:200C-20FF:0C00-0EFF; ::1/96 + +#------------------------------------------------------------------------------# +# Automatic recovery from disconnection from the server # +#------------------------------------------------------------------------------# + +# number of seconds before the first reconnection attempt, default to 1 +#jppf.reconnect.initial.delay = 1 + +# time after which the node stops trying to reconnect, in seconds. Defaults to 60 +jppf.reconnect.max.time = 5 + +# time between two connection attempts, in seconds. Defaults to 1 +#jppf.reconnect.interval = 1 + +#------------------------------------------------------------------------------# +# Processing Threads: number of threads running tasks in this node. # +# default value is the number of available CPUs; uncomment to specify a # +# different value. Blocking tasks might benefit from a number larger than CPUs # +#------------------------------------------------------------------------------# + +jppf.processing.threads = ${node.3.execution.threads} + +#------------------------------------------------------------------------------# +# Thread Manager: manager that wraps the executor service for running tasks. # +# default value is ThreadManagerThreadPool - that wraps ThreadPoolExecutor # +#------------------------------------------------------------------------------# + +# built-in thread manager +#jppf.thread.manager.class = default + +# fork/join thread manager +#jppf.thread.manager.class = org.jppf.server.node.fj.ThreadManagerForkJoin + +#------------------------------------------------------------------------------# +# Specify alternate serialization schemes. # +# Defaults to org.jppf.serialization.DefaultJavaSerialization. # +#------------------------------------------------------------------------------# + +# default +#jppf.object.serialization.class = org.jppf.serialization.DefaultJavaSerialization + +# built-in object serialization schemes +#jppf.object.serialization.class = org.jppf.serialization.DefaultJPPFSerialization +#jppf.object.serialization.class = org.jppf.serialization.XstreamSerialization + +# defined in the "Kryo Serialization" sample +#jppf.object.serialization.class = org.jppf.serialization.kryo.KryoSerialization + +#------------------------------------------------------------------------------# +# Specify a data transformation class. If unspecified, none is used. # +#------------------------------------------------------------------------------# + +# Defined in the "Network Data Encryption" sample +#jppf.data.transform.class = org.jppf.example.dataencryption.SecureKeyCipherTransform + +#------------------------------------------------------------------------------# +# Other JVM options added to the java command line when the node is started as # +# a subprocess. Multiple options are separated by spaces. # +#------------------------------------------------------------------------------# + +jppf.jvm.options = -Xms45000m -Xmx120000m -Dlog4j.configuration=log4j-sandag04.xml -Dnode.name=sandag04 + +# example with remote debugging options +#jppf.jvm.options = -server -Xmx128m -Xrunjdwp:transport=dt_socket,address=localhost:8000,server=y,suspend=n + +#------------------------------------------------------------------------------# +# Idle mode configuration. In idle mode, the server ot node starts when no # +# mouse or keyboard activity has occurred since the specified tiemout, and is # +# stopped when any new activity occurs. See "jppf.idle.timeout" below. # +#------------------------------------------------------------------------------# + +# enable/disable idle mode, defaults to false (disabled) +#jppf.idle.mode.enabled = false + +# Time of keyboard and mouse inactivity after which the system is considered +# idle, in ms. Defaults to 300000 (5 minutes) +#jppf.idle.timeout = 6000 + +# Interval between 2 successive calls to the native APIs to determine whether +# the system idle state has changed. Defaults to 1000 ms. +#jppf.idle.poll.interval = 1000 + +# Whether to shutdown the node immediately when a mouse/keyboard activity is detected, +# or wait until the node is no longer executing tasks. Defaults to true (immediate shutdown). +#jppf.idle.interruptIfRunning = true + +#------------------------------------------------------------------------------# +# Automatic recovery from hard failure of the server connection. These # +# parameters configure how the node reacts to the heartbeats sent by the # +# server, or lack thereof. # +#------------------------------------------------------------------------------# + +# Enable recovery from hardware failures, defaults to false (disabled) +#jppf.recovery.enabled = true + +# Dedicated port number for the detection of connection failure, must be the +# same as the value specified in the server configuration. Defaults to 22222. +# If server discovery is enabled, this value will be overridden by the port +# number specified in the driver configuration. +#jppf.recovery.server.port = 22222 + +# Maximum number of attempts to get a message from the server before the +# connection is considered broken. Default value is 2 +#jppf.recovery.max.retries = 2 + +# Maximum time in milliseconds allowed for each attempt to get a response from +# the node. Default value is 60000 ms (1 minute). + +#jppf.recovery.read.timeout = 60000 + +#------------------------------------------------------------------------------# +# JPPF class loader-related properties # +#------------------------------------------------------------------------------# + +# JPPF class loader delegation model. values: parent | url, defaults to parent +#jppf.classloader.delegation = parent + +# size of the class loader cache in the node, defaults to 50 +#jppf.classloader.cache.size = 50 + +# class loader resource cache enabled? defaults to true. +#jppf.resource.cache.enabled = true +# resource cache's type of storage: either "file" (the default) or "memory" +#jppf.resource.cache.storage = file +# root location of the file-persisted caches +#jppf.resource.cache.dir = some_directory + +#------------------------------------------------------------------------------# +# Screen saver settings # +#------------------------------------------------------------------------------# + +# include the settings from a separate file to avoid cluttering this config file +#!include file config/screensaver.properties + +#------------------------------------------------------------------------------# +# Redirecting System.out and System.err to files. # +#------------------------------------------------------------------------------# + +# file path on the file system where System.out is redirected. +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.out = System.out.log +# whether to append to an existing file or to create a new one +#jppf.redirect.out.append = false + +# file path on the file system where System.err is redirected +# if unspecified or invalid, then no redirection occurs +#jppf.redirect.err = System.err.log +# whether to append to an existing file or to create a new one +#jppf.redirect.err.append = false + +#------------------------------------------------------------------------------# +# Node provisioning configuration # +#------------------------------------------------------------------------------# + +# Define a node as master. Defaults to true +#jppf.node.provisioning.master = true +# Define a node as a slave. Defaults to false +#jppf.node.provisioning.slave = false +# Specify the path prefix used for the root directory of each slave node +# defaults to "slave_nodes/node_", relative to the master root directory +#jppf.node.provisioning.slave.path.prefix = slave_nodes/node_ +# Specify the directory where slave-specific configuration files are located +# Defaults to the "config" folder, relative to the master root directory +#jppf.node.provisioning.slave.config.path = config +# A set of space-separated JVM options always added to the slave startup command +#jppf.node.provisioning.slave.jvm.options = -Dlog4j.configuration=config/log4j-node.properties +# Specify the number of slaves to launch upon master node startup. Defaults to 0 +#jppf.node.provisioning.startup.slaves = 0 + +#------------------------------------------------------------------------------# +# Global performance tuning parameters. These affect the performance and # +# throughput of I/O operations in JPPF. The values provided in the vanilla # +# JPPF distribution are known to offer a good performance in most situations # +# and environments. # +#------------------------------------------------------------------------------# + +# Size of send and receive buffer for socket connections. +# Defaults to 32768 and must be in range [1024, 1024*1024] +# 128 * 1024 = 131072 +#jppf.socket.buffer.size = 131072 +# Size of temporary buffers (including direct buffers) used in I/O transfers. +# Defaults to 32768 and must be in range [1024, 1024*1024] +#jppf.temp.buffer.size = 12288 +# Maximum size of temporary buffers pool (excluding direct buffers). When this size +# is reached, new buffers are still created, but not released into the pool, so they +# can be quickly garbage-collected. The size of each buffer is defined with ${jppf.temp.buffer.size} +# Defaults to 10 and must be in range [1, 2048] +#jppf.temp.buffer.pool.size = 200 +# Size of temporary buffer pool for reading lengths as ints (size of each buffer is 4). +# Defaults to 100 and must be in range [1, 2048] +#jppf.length.buffer.pool.size = 100 + +#------------------------------------------------------------------------------# +# Enabling or disabling the lookup of classpath resources in the file system # +# Defaults to true (enabled) # +#------------------------------------------------------------------------------# + +#jppf.classloader.file.lookup = true diff --git a/sandag_abm/src/main/resources/log4j-client.properties b/sandag_abm/src/main/resources/log4j-client.properties new file mode 100644 index 0000000..4f4307a --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-client.properties @@ -0,0 +1,39 @@ +#------------------------------------------------------------------------------# +# Java Parallel Processing Framework. # +# Copyright (C) 2005-2008 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +### direct log messages to stdout ### +#log4j.appender.stdout=org.apache.log4j.ConsoleAppender +#log4j.appender.stdout.Target=System.out +#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file jppf-client.log ### +log4j.appender.JPPF=org.apache.log4j.FileAppender +log4j.appender.JPPF.File=logfiles/jppf-client.log +log4j.appender.JPPF.Append=false +log4j.appender.JPPF.layout=org.apache.log4j.PatternLayout +#log4j.appender.JPPF.layout.ConversionPattern=%d{ABSOLUTE} [%-5p][%c.%M(%L)]: %m\n +log4j.appender.JPPF.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### set log levels - for more verbose logging change 'info' to 'debug' ### + +log4j.rootLogger=INFO, JPPF +#log4j.rootLogger=DEBUG, JPPF + +#log4j.logger.org.jppf.client=DEBUG +#log4j.logger.org.jppf.common.socket=DEBUG diff --git a/sandag_abm/src/main/resources/log4j-driver.properties b/sandag_abm/src/main/resources/log4j-driver.properties new file mode 100644 index 0000000..dbf6fa8 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-driver.properties @@ -0,0 +1,42 @@ +#------------------------------------------------------------------------------# +# Java Parallel Processing Framework. # +# Copyright (C) 2005-2008 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +### direct log messages to stdout ### +#log4j.appender.stdout=org.apache.log4j.ConsoleAppender +#log4j.appender.stdout.Target=System.out +#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file jppf-driver.log ### +log4j.appender.JPPF=org.apache.log4j.FileAppender +log4j.appender.JPPF.File=./logFiles/jppf-driver.log +log4j.appender.JPPF.Append=false +log4j.appender.JPPF.layout=org.apache.log4j.PatternLayout +#log4j.appender.JPPF.layout.ConversionPattern=%d{ABSOLUTE} [%-5p][%c.%M(%L)]: %m\n +log4j.appender.JPPF.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### set log levels - for more verbose logging change 'info' to 'debug' ### + +#log4j.logger.org.jppf.server.nio.StateTransitionTask=DEBUG + +# log information about interactions between the client and server +#log4j.logger.org.jppf.server.app=DEBUG +#log4j.logger.org.jppf.io.IOHelper=DEBUG + +log4j.rootLogger=INFO, JPPF +#log4j.rootLogger=DEBUG, JPPF diff --git a/sandag_abm/src/main/resources/log4j-sandag01.properties b/sandag_abm/src/main/resources/log4j-sandag01.properties new file mode 100644 index 0000000..01af856 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag01.properties @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2010 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +### direct log messages to stdout ### +#log4j.appender.stdout=org.apache.log4j.ConsoleAppender +#log4j.appender.stdout.Target=System.out +#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file jppf-node.log ### +log4j.appender.JPPF=org.apache.log4j.FileAppender +log4j.appender.JPPF.File=logFiles/event-sandag01.log +log4j.appender.JPPF.Append=false +log4j.appender.JPPF.layout=org.apache.log4j.PatternLayout +#log4j.appender.JPPF.layout.ConversionPattern=%d{ABSOLUTE} [%-5p][%c.%M(%L)]: %m\n +log4j.appender.JPPF.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### direct messages to the JMX Logger ### +log4j.appender.JMX=org.jppf.logging.log4j.JmxAppender +log4j.appender.JMX.layout=org.apache.log4j.PatternLayout +log4j.appender.JMX.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### set log levels - for more verbose logging change 'info' to 'debug' ### + +# will produce messages like "writing object size = " when sending to the server +log4j.logger.org.jppf.server.node.remote.RemoteNodeIO=TRACE +# will produce messages like "i = , read data size = " when receiving from the server +log4j.logger.org.jppf.server.node.remote.JPPFRemoteContainer=TRACE + +#log4j.rootLogger=TRACE, DEBUG, JPPF +log4j.rootLogger=INFO, JPPF, JMX diff --git a/sandag_abm/src/main/resources/log4j-sandag01.xml b/sandag_abm/src/main/resources/log4j-sandag01.xml new file mode 100644 index 0000000..4f5ed1d --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag01.xml @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j-sandag02.properties b/sandag_abm/src/main/resources/log4j-sandag02.properties new file mode 100644 index 0000000..9aae59a --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag02.properties @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2010 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +### direct log messages to stdout ### +#log4j.appender.stdout=org.apache.log4j.ConsoleAppender +#log4j.appender.stdout.Target=System.out +#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file jppf-node.log ### +log4j.appender.JPPF=org.apache.log4j.FileAppender +log4j.appender.JPPF.File=logFiles/event-sandag02.log +log4j.appender.JPPF.Append=false +log4j.appender.JPPF.layout=org.apache.log4j.PatternLayout +#log4j.appender.JPPF.layout.ConversionPattern=%d{ABSOLUTE} [%-5p][%c.%M(%L)]: %m\n +log4j.appender.JPPF.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### direct messages to the JMX Logger ### +log4j.appender.JMX=org.jppf.logging.log4j.JmxAppender +log4j.appender.JMX.layout=org.apache.log4j.PatternLayout +log4j.appender.JMX.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### set log levels - for more verbose logging change 'info' to 'debug' ### + +# will produce messages like "writing object size = " when sending to the server +log4j.logger.org.jppf.server.node.remote.RemoteNodeIO=TRACE +# will produce messages like "i = , read data size = " when receiving from the server +log4j.logger.org.jppf.server.node.remote.JPPFRemoteContainer=TRACE + +#log4j.rootLogger=TRACE, DEBUG, JPPF +log4j.rootLogger=INFO, JPPF, JMX diff --git a/sandag_abm/src/main/resources/log4j-sandag02.xml b/sandag_abm/src/main/resources/log4j-sandag02.xml new file mode 100644 index 0000000..5629089 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag02.xml @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j-sandag03.properties b/sandag_abm/src/main/resources/log4j-sandag03.properties new file mode 100644 index 0000000..771824a --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag03.properties @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2010 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +### direct log messages to stdout ### +#log4j.appender.stdout=org.apache.log4j.ConsoleAppender +#log4j.appender.stdout.Target=System.out +#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file jppf-node.log ### +log4j.appender.JPPF=org.apache.log4j.FileAppender +log4j.appender.JPPF.File=logFiles/event-sandag03.log +log4j.appender.JPPF.Append=false +log4j.appender.JPPF.layout=org.apache.log4j.PatternLayout +#log4j.appender.JPPF.layout.ConversionPattern=%d{ABSOLUTE} [%-5p][%c.%M(%L)]: %m\n +log4j.appender.JPPF.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### direct messages to the JMX Logger ### +log4j.appender.JMX=org.jppf.logging.log4j.JmxAppender +log4j.appender.JMX.layout=org.apache.log4j.PatternLayout +log4j.appender.JMX.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### set log levels - for more verbose logging change 'info' to 'debug' ### + +# will produce messages like "writing object size = " when sending to the server +log4j.logger.org.jppf.server.node.remote.RemoteNodeIO=TRACE +# will produce messages like "i = , read data size = " when receiving from the server +log4j.logger.org.jppf.server.node.remote.JPPFRemoteContainer=TRACE + +#log4j.rootLogger=TRACE, DEBUG, JPPF +log4j.rootLogger=INFO, JPPF, JMX diff --git a/sandag_abm/src/main/resources/log4j-sandag03.xml b/sandag_abm/src/main/resources/log4j-sandag03.xml new file mode 100644 index 0000000..2377353 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag03.xml @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j-sandag04.properties b/sandag_abm/src/main/resources/log4j-sandag04.properties new file mode 100644 index 0000000..fea28c2 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag04.properties @@ -0,0 +1,46 @@ +#------------------------------------------------------------------------------# +# JPPF # +# Copyright (C) 2005-2010 JPPF Team. # +# http://www.jppf.org # +# # +# Licensed under the Apache License, Version 2.0 (the "License"); # +# you may not use this file except in compliance with the License. # +# You may obtain a copy of the License at # +# # +# http://www.apache.org/licenses/LICENSE-2.0 # +# # +# Unless required by applicable law or agreed to in writing, software # +# distributed under the License is distributed on an "AS IS" BASIS, # +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # +# See the License for the specific language governing permissions and # +# limitations under the License. # +#------------------------------------------------------------------------------# + +### direct log messages to stdout ### +#log4j.appender.stdout=org.apache.log4j.ConsoleAppender +#log4j.appender.stdout.Target=System.out +#log4j.appender.stdout.layout=org.apache.log4j.PatternLayout +#log4j.appender.stdout.layout.ConversionPattern=%d{ABSOLUTE} %5p %c{1}:%L - %m%n + +### direct messages to file jppf-node.log ### +log4j.appender.JPPF=org.apache.log4j.FileAppender +log4j.appender.JPPF.File=logFiles/event-sandag04.log +log4j.appender.JPPF.Append=false +log4j.appender.JPPF.layout=org.apache.log4j.PatternLayout +#log4j.appender.JPPF.layout.ConversionPattern=%d{ABSOLUTE} [%-5p][%c.%M(%L)]: %m\n +log4j.appender.JPPF.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### direct messages to the JMX Logger ### +log4j.appender.JMX=org.jppf.logging.log4j.JmxAppender +log4j.appender.JMX.layout=org.apache.log4j.PatternLayout +log4j.appender.JMX.layout.ConversionPattern=%d [%-5p][%c.%M(%L)]: %m\n + +### set log levels - for more verbose logging change 'info' to 'debug' ### + +# will produce messages like "writing object size = " when sending to the server +log4j.logger.org.jppf.server.node.remote.RemoteNodeIO=TRACE +# will produce messages like "i = , read data size = " when receiving from the server +log4j.logger.org.jppf.server.node.remote.JPPFRemoteContainer=TRACE + +#log4j.rootLogger=TRACE, DEBUG, JPPF +log4j.rootLogger=INFO, JPPF, JMX diff --git a/sandag_abm/src/main/resources/log4j-sandag04.xml b/sandag_abm/src/main/resources/log4j-sandag04.xml new file mode 100644 index 0000000..e7937af --- /dev/null +++ b/sandag_abm/src/main/resources/log4j-sandag04.xml @@ -0,0 +1,439 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j.xml b/sandag_abm/src/main/resources/log4j.xml new file mode 100644 index 0000000..97a3996 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j.xml @@ -0,0 +1,443 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j_AtTransitCheck.xml b/sandag_abm/src/main/resources/log4j_AtTransitCheck.xml new file mode 100644 index 0000000..ad2ebf9 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j_AtTransitCheck.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j_d2t.xml b/sandag_abm/src/main/resources/log4j_d2t.xml new file mode 100644 index 0000000..ec13a3d --- /dev/null +++ b/sandag_abm/src/main/resources/log4j_d2t.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j_hh.xml b/sandag_abm/src/main/resources/log4j_hh.xml new file mode 100644 index 0000000..834f12e --- /dev/null +++ b/sandag_abm/src/main/resources/log4j_hh.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j_mtx.xml b/sandag_abm/src/main/resources/log4j_mtx.xml new file mode 100644 index 0000000..d8c6e40 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j_mtx.xml @@ -0,0 +1,36 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/log4j_test.xml b/sandag_abm/src/main/resources/log4j_test.xml new file mode 100644 index 0000000..7f52d65 --- /dev/null +++ b/sandag_abm/src/main/resources/log4j_test.xml @@ -0,0 +1,455 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sandag_abm/src/main/resources/mapAndRun.bat b/sandag_abm/src/main/resources/mapAndRun.bat new file mode 100644 index 0000000..b1318cf --- /dev/null +++ b/sandag_abm/src/main/resources/mapAndRun.bat @@ -0,0 +1,33 @@ +:: script to map a drive and then call a batch file remotely using psexec +:: 1 is the drive letter to map (e.g. “M:”) +:: 2 is the share to map (e.g. “\\w-ampdx-d-sag01\mtc”) +:: 3 is the password +:: 4 is the user +:: 5 is the working directory for calling the batch file (starting from the mapped drive letter) +:: 6 is the name of the batch file to call +:: 7-10 are extra arguments (note DOS only does 9 arguments unless you use SHIFT) + +SET ONE=%1 +SET TWO=%2 +SET THREE=%3 +SET FOUR=%4 +SET FIVE=%5 +SET SIX=%6 +SET SEVEN=%7 +SET EIGHT=%8 +SET NINE=%9 +SHIFT +SHIFT +SHIFT +SHIFT +SHIFT +SHIFT +SHIFT +SHIFT +SHIFT +SET TEN=%1 + +net use %ONE% %TWO% /persistent:yes +%ONE% +cd %FIVE% +call %SIX% %SEVEN% %EIGHT% %NINE% %TEN% diff --git a/sandag_abm/src/main/resources/pskill.exe b/sandag_abm/src/main/resources/pskill.exe new file mode 100644 index 0000000..2e9d0d4 Binary files /dev/null and b/sandag_abm/src/main/resources/pskill.exe differ diff --git a/sandag_abm/src/main/resources/runDriver.cmd b/sandag_abm/src/main/resources/runDriver.cmd new file mode 100644 index 0000000..7ace356 --- /dev/null +++ b/sandag_abm/src/main/resources/runDriver.cmd @@ -0,0 +1,17 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ############ PARAMETERS ############ + +rem ############ JPPF DRIVER ############ +set JPPF_LIB=%PROJECT_DIRECTORY%\application\* +set CLASSPATH=%PROJECT_DIRECTORY%\conf;%JPPF_LIB% + +start %JAVA_64_PATH%\bin\java -server -Xmx16m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j-driver.properties -Djppf.config=jppf-driver.properties org.jppf.server.DriverLauncher diff --git a/sandag_abm/src/main/resources/runHhMgr.cmd b/sandag_abm/src/main/resources/runHhMgr.cmd new file mode 100644 index 0000000..2fd44c6 --- /dev/null +++ b/sandag_abm/src/main/resources/runHhMgr.cmd @@ -0,0 +1,54 @@ +rem @echo off + +rem %1 is the project directory +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem JVM allocations +set MEMORY_HHMGR_MIN=%MEMORY_HHMGR_MIN% +set MEMORY_HHMGR_MAX=%MEMORY_HHMGR_MAX% + +rem Running on SAG02 +set HOST_IP_ADDRESS=%HHMGR_IP% + +rem 1129 used to calibrate the 20% sample +set HOST_PORT=%HH_MANAGER_PORT% + +rem (X:) is mapped to \\w-ampdx-d-sag01\C +rem set DRIVE=%MAPDRIVE% +set DRIVE=%PROJECT_DRIVE% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +rem set RUNTIME=%DRIVE%%PROJECT_DIRECTORY% +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + +set JAR_LOCATION=%RUNTIME%/application + +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%;%JAR_LOCATION%\* + + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_64_PATH%\bin;%OLDPATH% + +rem ### Change current directory to RUNTIME, and issue the java command to run the model. +rem Note: Running java script in separate window to properly redirect console output +start %PROJECT_DIRECTORY%\bin\runHhMgr_log.bat %JAVA_64_PATH% %MEMORY_HHMGR_MIN% %MEMORY_HHMGR_MAX% %CLASSPATH% %HOST_IP_ADDRESS% %HOST_PORT% %RUNTIME% +rem start %JAVA_64_PATH%/bin/java -server -Xms%MEMORY_HHMGR_MIN% -Xmx%MEMORY_HHMGR_MAX% -cp "%CLASSPATH%" -Dlog4j.configuration=log4j_hh.xml org.sandag.abm.application.SandagHouseholdDataManager2 -hostname %HOST_IP_ADDRESS% -port %HOST_PORT% +rem java -Xdebug -Xrunjdwp:transport=dt_socket,address=1044,server=y,suspend=y -server -Xmx12000m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j_hh.xml org.sandag.abm.application.SandagHouseholdDataManager2 -hostname %HOST_IP_ADDRESS% + +rem ### restore saved environment variable values, and change back to original current directory +set PATH=%OLDPATH% + diff --git a/sandag_abm/src/main/resources/runHhMgr_log.bat b/sandag_abm/src/main/resources/runHhMgr_log.bat new file mode 100644 index 0000000..ae594fa --- /dev/null +++ b/sandag_abm/src/main/resources/runHhMgr_log.bat @@ -0,0 +1,18 @@ +rem @echo off + +rem ### Declaring required environment variables +set JAVA_64_PATH = %1 +set MEMORY_HHMGR_MIN = %2 +set MEMORY_HHMGR_MAX = %3 +set CLASSPATH = %4;%5;%6;%7 +set HOST_IP_ADDRESS = %8 +set HOST_PORT = %9 +shift +set RUNTIME = %9 + + +rem ### Running household manager and redirecting output to {PROJECT_DIRECTORY}\logFiles\hhMgrConsole.log +2>&1 (%JAVA_64_PATH%/bin/java -server -Xms%MEMORY_HHMGR_MIN% -Xmx%MEMORY_HHMGR_MAX% -cp "%CLASSPATH%" -Dlog4j.configuration=log4j_hh.xml org.sandag.abm.application.SandagHouseholdDataManager2 -hostname %HOST_IP_ADDRESS% -port %HOST_PORT%) | %RUNTIME%\application\GnuWin32\bin\tee.exe %RUNTIME%\logFiles\hhMgrConsole.log + +rem ### Exit window +exit 0 \ No newline at end of file diff --git a/sandag_abm/src/main/resources/runMtxMgr.cmd b/sandag_abm/src/main/resources/runMtxMgr.cmd new file mode 100644 index 0000000..6503f3a --- /dev/null +++ b/sandag_abm/src/main/resources/runMtxMgr.cmd @@ -0,0 +1,43 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem call ctramp properties +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem JVM allocations +set MEMORY_MTXMGR_MIN=%MEMORY_MTXMGR_MIN% +set MEMORY_MTXMGR_MAX=%MEMORY_MTXMGR_MAX% + +rem Run the matrix manager on SAG1 +set HOST_IP_ADDRESS=%MAIN_IP% + +rem kill java tasks +taskkill /F /IM java.exe + +rem run ping to add a pause so that taskkill has time to fully kill java processes +ping -n 10 %MAIN% > nul + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set CONFIG=%PROJECT_DIRECTORY%/conf + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set OLDPATH=%PATH% +set CLASSPATH=%CONFIG%;%JAR_LOCATION%\* + +rem java -Dname=p%2 -Xdebug -Xrunjdwp:transport=dt_socket,address=1049,server=y,suspend=y -server -Xms8000m -Xmx8000m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j_mtx.xml org.sandag.abm.ctramp.MatrixDataServer -hostname %HOST_IP_ADDRESS% -port %HOST_MATRIX_PORT% -label "SANDAG Matrix Sever" +rem Note: Running Java script in separate window to properly redirect console output +start %PROJECT_DIRECTORY%\bin\runMtxMgr_log.bat %JAVA_64_PATH% %MEMORY_MTXMGR_MIN% %MEMORY_MTXMGR_MAX% %JAR_LOCATION% %HOST_IP_ADDRESS% %MATRIX_MANAGER_PORT% %PROJECT_DIRECTORY% +rem start %JAVA_64_PATH%\bin\java -server -Xms%MEMORY_MTXMGR_MIN% -Xmx%MEMORY_MTXMGR_MAX% -Dlog4j.configuration=log4j_mtx.xml -Djava.library.path=%JAR_LOCATION% org.sandag.abm.ctramp.MatrixDataServer -hostname %HOST_IP_ADDRESS% -port %MATRIX_MANAGER_PORT% -ram 1500 -label "SANDAG Matrix Server" + +set CLASSPATH=%OLDCLASSPATH% +set PATH=%OLDPATH% diff --git a/sandag_abm/src/main/resources/runMtxMgr_log.bat b/sandag_abm/src/main/resources/runMtxMgr_log.bat new file mode 100644 index 0000000..7b5f6b0 --- /dev/null +++ b/sandag_abm/src/main/resources/runMtxMgr_log.bat @@ -0,0 +1,17 @@ +rem @echo off + +rem ### Declaring required environment variables +set JAVA_64_PATH = %1 +set MEMORY_MTXMGR_MIN = %2 +set MEMORY_MTXMGR_MAX = %3 +set JAR_LOCATION = %4 +set HOST_IP_ADDRESS = %5 +set MATRIX_MANAGER_PORT = %6 +set PROJECT_DIRECTORY = %7 + + +rem ### Running matrix manager and redirecting output to {PROJECT_DIRECTORY}\logFiles\mtxMgrConsole.log +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_MTXMGR_MIN% -Xmx%MEMORY_MTXMGR_MAX% -Dlog4j.configuration=log4j_mtx.xml -Djava.library.path=%PROJECT_DIRECTORY%\application org.sandag.abm.ctramp.MatrixDataServer -hostname %HOST_IP_ADDRESS% -port %MATRIX_MANAGER_PORT% -ram 1500 -label "SANDAG Matrix Server" 2>&1 | %PROJECT_DIRECTORY%\application\GnuWin32\bin\tee.exe %PROJECT_DIRECTORY%\logFiles\mtxMgrConsole.log + +rem ### Exit window +exit 0 \ No newline at end of file diff --git a/sandag_abm/src/main/resources/runSandag01.cmd b/sandag_abm/src/main/resources/runSandag01.cmd new file mode 100644 index 0000000..9bcf0be --- /dev/null +++ b/sandag_abm/src/main/resources/runSandag01.cmd @@ -0,0 +1,16 @@ +@echo off + +rem ############ PARAMETERS ############ +set DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +rem ############ JPPF DRIVER ############ +set JPPF_LIB=%PROJECT_DIRECTORY%\application\* +set CLASSPATH=%PROJECT_DIRECTORY%\conf;%JPPF_LIB% + +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +%DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +start %PROJECT_DIRECTORY%\bin\runSandag01_log.bat %JAVA_64_PATH% %CLASSPATH% %PROJECT_DIRECTORY% +rem start %JAVA_64_PATH%\bin\java -server -Xms16m -Xmx16m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j-sandag01.properties -Djppf.config=jppf-sandag01.properties org.jppf.node.NodeLauncher diff --git a/sandag_abm/src/main/resources/runSandag01_log.bat b/sandag_abm/src/main/resources/runSandag01_log.bat new file mode 100644 index 0000000..93ae263 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandag01_log.bat @@ -0,0 +1,13 @@ +rem @echo off + +rem ### Declaring required environment variables +set JAVA_64_PATH = %1 +set CLASSPATH = %2;%3 +set PROJECT_DIRECTORY = %4 + + +rem ### Running master node and redirecting output to {PROJECT_DIRECTORY}\logFiles\sandag01Console.log +2>&1 (%JAVA_64_PATH%\bin\java -server -Xms16m -Xmx16m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j-sandag01.properties -Djppf.config=jppf-sandag01.properties org.jppf.node.NodeLauncher) | %PROJECT_DIRECTORY%\application\GnuWin32\bin\tee.exe %PROJECT_DIRECTORY%\logFiles\sandag01Console.log + +rem ### Exit window +exit 0 \ No newline at end of file diff --git a/sandag_abm/src/main/resources/runSandag02.cmd b/sandag_abm/src/main/resources/runSandag02.cmd new file mode 100644 index 0000000..4171880 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandag02.cmd @@ -0,0 +1,15 @@ +@echo off + +rem ############ PARAMETERS ############ +set DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +rem ############ JPPF DRIVER ############ +set JPPF_LIB=%PROJECT_DIRECTORY%\application\* +set CLASSPATH=%PROJECT_DIRECTORY%\conf;%JPPF_LIB% + +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +%DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +start %JAVA_64_PATH%\bin\java -server -Xms16m -Xmx16m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j-sandag02.properties -Djppf.config=jppf-sandag02.properties org.jppf.node.NodeLauncher diff --git a/sandag_abm/src/main/resources/runSandag03.cmd b/sandag_abm/src/main/resources/runSandag03.cmd new file mode 100644 index 0000000..97591ae --- /dev/null +++ b/sandag_abm/src/main/resources/runSandag03.cmd @@ -0,0 +1,15 @@ +@echo off + +rem ############ PARAMETERS ############ +set DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +rem ############ JPPF DRIVER ############ +set JPPF_LIB=%PROJECT_DIRECTORY%\application\* +set CLASSPATH=%PROJECT_DIRECTORY%\conf;%JPPF_LIB% + +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +%DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +start %JAVA_64_PATH%\bin\java -server -Xms16m -Xmx16m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j-sandag03.properties -Djppf.config=jppf-sandag03.properties org.jppf.node.NodeLauncher diff --git a/sandag_abm/src/main/resources/runSandag04.cmd b/sandag_abm/src/main/resources/runSandag04.cmd new file mode 100644 index 0000000..42aa4fb --- /dev/null +++ b/sandag_abm/src/main/resources/runSandag04.cmd @@ -0,0 +1,15 @@ +@echo off + +rem ############ PARAMETERS ############ +set DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +rem ############ JPPF DRIVER ############ +set JPPF_LIB=%PROJECT_DIRECTORY%\application\* +set CLASSPATH=%PROJECT_DIRECTORY%\conf;%JPPF_LIB% + +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +%DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +start %JAVA_64_PATH%\bin\java -server -Xms16m -Xmx16m -cp "%CLASSPATH%" -Dlog4j.configuration=log4j-sandag04.properties -Djppf.config=jppf-sandag04.properties org.jppf.node.NodeLauncher diff --git a/sandag_abm/src/main/resources/runSandagAbm_MAAS.cmd b/sandag_abm/src/main/resources/runSandagAbm_MAAS.cmd new file mode 100644 index 0000000..05e804b --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagAbm_MAAS.cmd @@ -0,0 +1,59 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SAMPLERATE=%3 +set ITERATION=%4 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +rem ### Note that a jdk is required; a jre is not sufficient, as the UEC class generates +rem ### and compiles code during the model run, and uses javac in the jdk to do this. +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%OLDPATH% + +rem ### Run ping to add a pause so that hhMgr and mtxMgr have time to fully start +ping -n 10 %MAIN% > nul + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem ### TNC Fleet Model +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.maas.TNCFleetModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem ### Checking for TNC outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% TNC %ITERATION% + +rem ### Household AV Allocation Model +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.maas.HouseholdAVAllocationModelRunner %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem ### Checking for AV outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% AV %ITERATION% + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% +set CLASSPATH=%OLDCLASSPATH% diff --git a/sandag_abm/src/main/resources/runSandagAbm_MCDiagnostic.cmd b/sandag_abm/src/main/resources/runSandagAbm_MCDiagnostic.cmd new file mode 100644 index 0000000..dd526a2 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagAbm_MCDiagnostic.cmd @@ -0,0 +1,55 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SAMPLERATE=%3 +set ITERATION=%4 +set SEED=2354345 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat +set PROPERTIES_NAME=sandag_abm_mcd + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +rem ### Note that a jdk is required; a jre is not sufficient, as the UEC class generates +rem ### and compiles code during the model run, and uses javac in the jdk to do this. +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%OLDPATH% + +rem run ping to add a pause so that hhMgr and mtxMgr have time to fully start +ping -n 10 %MAIN% > nul + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem ## works for both single node and distributed settings; modified jppf-clientDistrubuted.properties to handle both single and distributed settings## +%JAVA_64_PATH%\bin\java -showversion -server -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% -Djppf.config=jppf-client.properties org.sandag.abm.utilities.RunModeChoice %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% -sampleSeed %SEED% + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% +set CLASSPATH=%OLDCLASSPATH% + +rem kill java tasks +taskkill /F /IM java.exe \ No newline at end of file diff --git a/sandag_abm/src/main/resources/runSandagAbm_SDRM.cmd b/sandag_abm/src/main/resources/runSandagAbm_SDRM.cmd new file mode 100644 index 0000000..95810a6 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagAbm_SDRM.cmd @@ -0,0 +1,68 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SAMPLERATE=%3 +set ITERATION=%4 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +rem ### Note that a jdk is required; a jre is not sufficient, as the UEC class generates +rem ### and compiles code during the model run, and uses javac in the jdk to do this. +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%JAR_LOCATION%\GnuWin32\bin;%OLDPATH% + +rem ### Run ping to add a pause so that hhMgr and mtxMgr have time to fully start +ping -n 10 %MAIN% > nul + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem ## works for both single node and distributed settings; modified jppf-clientDistrubuted.properties to handle both single and distributed settings## +%JAVA_64_PATH%\bin\java -showversion -server -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% -Djppf.config=jppf-client.properties org.sandag.abm.application.SandagTourBasedModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% -sampleSeed %SEED% -luAcc false 2>&1 | tee.exe %PROJECT_DIRECTORY%\logFiles\sdrmConsole_%ITERATION%.log + +rem ### Build trip tables +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.application.SandagTripTables %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem ### Checking for Resident Model outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% SDRM %ITERATION% + +rem ### Internal-external model +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.internalexternal.InternalExternalModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem ### Build internal-external model trip tables +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.internalexternal.InternalExternalTripTables %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem ### Checking for IE outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% IE %ITERATION% + +rem kill java tasks +rem taskkill /F /IM java.exe + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% +set CLASSPATH=%OLDCLASSPATH% diff --git a/sandag_abm/src/main/resources/runSandagAbm_SEM.cmd b/sandag_abm/src/main/resources/runSandagAbm_SEM.cmd new file mode 100644 index 0000000..c3c1283 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagAbm_SEM.cmd @@ -0,0 +1,57 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SAMPLERATE=%3 +set ITERATION=%4 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +rem ### Note that a jdk is required; a jre is not sufficient, as the UEC class generates +rem ### and compiles code during the model run, and uses javac in the jdk to do this. +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%OLDPATH% + +rem run ping to add a pause so that hhMgr and mtxMgr have time to fully start +ping -n 10 %MAIN% > nul + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem Special Event model +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.specialevent.SpecialEventModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem Build Special Event model trip tables +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -Djava.library.path=%TRANSCAD_PATH% -cp "%CLASSPATH%" -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.specialevent.SpecialEventTripTables %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + + +rem kill java tasks +taskkill /F /IM java.exe + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% +set CLASSPATH=%OLDCLASSPATH% diff --git a/sandag_abm/src/main/resources/runSandagAbm_SMM.cmd b/sandag_abm/src/main/resources/runSandagAbm_SMM.cmd new file mode 100644 index 0000000..d243f44 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagAbm_SMM.cmd @@ -0,0 +1,86 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SAMPLERATE=%3 +set ITERATION=%4 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +rem ### Note that a jdk is required; a jre is not sufficient, as the UEC class generates +rem ### and compiles code during the model run, and uses javac in the jdk to do this. +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%JAR_LOCATION%\GnuWin32\bin;%OLDPATH% + +rem ### Run ping to add a pause so that hhMgr and mtxMgr have time to fully start +ping -n 10 %MAIN% > nul + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem ### Airport model - SAN +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.airport.AirportModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% -airport SAN 2>&1 | tee.exe %PROJECT_DIRECTORY%\logFiles\airportSANModelConsole_%ITERATION%.log + +rem ### Build airport model trip tables - SAN +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.airport.AirportTripTables %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% -airport SAN + +rem ### Checking for SAN outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% SAN %ITERATION% + +rem ### Airport model - CBX +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.airport.AirportModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% -airport CBX 2>&1 | tee.exe %PROJECT_DIRECTORY%\logFiles\airportCBXModelConsole_%ITERATION%.log + +rem ### Build airport model trip tables - CBX +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.airport.AirportTripTables %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% -airport CBX + +rem ### Checking for CBX outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% CBX %ITERATION% + +rem ### Cross-border model +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.crossborder.CrossBorderModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% 2>&1 | tee.exe %PROJECT_DIRECTORY%\logFiles\crossBorderModelConsole_%ITERATION%.log + +rem ### Build cross-border model trip tables +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.crossborder.CrossBorderTripTables %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem ### Checking for CBM outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% CBM %ITERATION% + +rem ### Visitor model +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_CLIENT_MIN% -Xmx%MEMORY_CLIENT_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.visitor.VisitorModel %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% 2>&1 | tee.exe %PROJECT_DIRECTORY%\logFiles\visitorModelConsole_%ITERATION%.log + +rem ### Build visitor model trip tables +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.visitor.VisitorTripTables %PROPERTIES_NAME% -iteration %ITERATION% -sampleRate %SAMPLERATE% + +rem ### Checking for Visitor outputs +call %PROJECT_DIRECTORY%\bin\CheckOutput.bat %PROJECT_DIRECTORY% Visitor %ITERATION% + +rem kill java tasks +rem taskkill /F /IM java.exe + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% +set CLASSPATH=%OLDCLASSPATH% diff --git a/sandag_abm/src/main/resources/runSandagBikeLogsums.cmd b/sandag_abm/src/main/resources/runSandagBikeLogsums.cmd new file mode 100644 index 0000000..79a20c9 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagBikeLogsums.cmd @@ -0,0 +1,45 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%OLDPATH% + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem rem build bike logsums +%JAVA_64_PATH%\bin\java -showversion -server -Xmx%MEMORY_BIKELOGSUM_MAX% -cp "%CLASSPATH%" -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.active.sandag.SandagBikePathChoiceLogsumMatrixApplication %PROPERTIES_NAME% +if ERRORLEVEL 1 goto DONE + +:done +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% + + diff --git a/sandag_abm/src/main/resources/runSandagBikeRouteChoice.cmd b/sandag_abm/src/main/resources/runSandagBikeRouteChoice.cmd new file mode 100644 index 0000000..aa243b7 --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagBikeRouteChoice.cmd @@ -0,0 +1,38 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set SAMPLERATE=%3 +set ITERATION=%4 +set PROPERTIES_NAME=sandag_abm + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + +rem ### Set the name of the properties file the application uses by giving just the base part of the name (with ".xxx" extension) +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem run bike assignment +%JAVA_64_PATH%\bin\java -showversion -server -Xmx%MEMORY_BIKEROUTE_MAX% -XX:-UseGCOverheadLimit -cp "%CLASSPATH%" -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.active.sandag.SandagBikePathChoiceEdgeAssignmentApplication %PROPERTIES_NAME% %SAMPLERATE% %ITERATION% +if ERRORLEVEL 1 goto DONE + +:done +rem kill java tasks +rem taskkill /F /IM java.exe + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% diff --git a/sandag_abm/src/main/resources/runSandagWalkLogsums.cmd b/sandag_abm/src/main/resources/runSandagWalkLogsums.cmd new file mode 100644 index 0000000..248541c --- /dev/null +++ b/sandag_abm/src/main/resources/runSandagWalkLogsums.cmd @@ -0,0 +1,45 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%OLDPATH% + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem rem build walk skims +%JAVA_64_PATH%\bin\java -showversion -server -Xmx%MEMORY_WALKLOGSUM_MAX% -cp "%CLASSPATH%" -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.active.sandag.SandagWalkPathChoiceLogsumMatrixApplication %PROPERTIES_NAME% +if ERRORLEVEL 1 goto DONE + +python %PROJECT_DRIVE%%PROJECT_DIRECTORY%\python\calculate_micromobility.py --properties_file %PROJECT_DRIVE%%PROJECT_DIRECTORY%\conf\sandag_abm.properties --outputs_directory %PROJECT_DRIVE%%PROJECT_DIRECTORY%\output --inputs_parent_directory %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +:done +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% diff --git a/sandag_abm/src/main/resources/runTransitReporter.cmd b/sandag_abm/src/main/resources/runTransitReporter.cmd new file mode 100644 index 0000000..3162c79 --- /dev/null +++ b/sandag_abm/src/main/resources/runTransitReporter.cmd @@ -0,0 +1,48 @@ +rem @echo off + +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set THRESHOLD=%3 +set TOD=%4 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% +call %PROJECT_DIRECTORY%\bin\CTRampEnv.bat + +rem ### First save the JAVA_PATH environment variable so it s value can be restored at the end. +set OLDJAVAPATH=%JAVA_PATH% + +rem ### Set the directory of the jdk version desired for this model run +rem ### Note that a jdk is required; a jre is not sufficient, as the UEC class generates +rem ### and compiles code during the model run, and uses javac in the jdk to do this. +set JAVA_PATH=%JAVA_64_PATH% + +rem ### Name the project directory. This directory will hava data and runtime subdirectories +set RUNTIME=%PROJECT_DIRECTORY% +set CONFIG=%RUNTIME%/conf + + +set JAR_LOCATION=%PROJECT_DIRECTORY%/application +set LIB_JAR_PATH=%JAR_LOCATION%\* + +rem ### Define the CLASSPATH environment variable for the classpath needed in this model run. +set OLDCLASSPATH=%CLASSPATH% +set CLASSPATH=%CONFIG%;%RUNTIME%;%LIB_JAR_PATH%; + +rem ### Save the name of the PATH environment variable, so it can be restored at the end of the model run. +set OLDPATH=%PATH% + +rem ### Change the PATH environment variable so that JAVA_HOME is listed first in the PATH. +rem ### Doing this ensures that the JAVA_HOME path we defined above is the on that gets used in case other java paths are in PATH. +set PATH=%JAVA_PATH%\bin;%OLDPATH% + +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY% + +rem TransitTimeReporter +rem %JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.reporting.TransitTimeReporter %PROPERTIES_NAME% -threshold %THRESHOLD% -period %TOD% -outWalkFileName walkMgrasWithin%THRESHOLD%Min.csv -outDriveFileName driveMgrasWithin%THRESHOLD%Min.csv +%JAVA_64_PATH%\bin\java -server -Xms%MEMORY_SPMARKET_MIN% -Xmx%MEMORY_SPMARKET_MAX% -cp "%CLASSPATH%" -Djxl.nowarnings=true -Dlog4j.configuration=log4j.xml -Dproject.folder=%PROJECT_DIRECTORY% org.sandag.abm.reporting.TransitTimeReporter %PROPERTIES_NAME% -threshold %THRESHOLD% -period %TOD% -outWalkFileName walkMgrasWithin%THRESHOLD%Min.csv + +rem ### restore saved environment variable values, and change back to original current directory +set JAVA_PATH=%OLDJAVAPATH% +set PATH=%OLDPATH% +set CLASSPATH=%OLDCLASSPATH% diff --git a/sandag_abm/src/main/resources/sandag_abm.properties b/sandag_abm/src/main/resources/sandag_abm.properties new file mode 100644 index 0000000..a93d575 --- /dev/null +++ b/sandag_abm/src/main/resources/sandag_abm.properties @@ -0,0 +1,1357 @@ +#SANDAG ABM Properties +#Software Version +version=${version} +############################################################################################################################################################################# +# +# CLUSTER PROPERTIES: MODIFY WHEN CHANGING CLUSTER CONFIGURATION OR MOVING TO NEW CLUSTER. +# +############################################################################################################################################################################# +RunModel.MatrixServerAddress=${matrix.server.host} +RunModel.MatrixServerPort=${matrix.server.port} +RunModel.HouseholdServerAddress=${household.server.host} +RunModel.HouseholdServerPort=${household.server.port} + +############################################################################################################################################################################# +# +# RUN PROPERTIES: MODEL COMPONENT SWITCHES +# +############################################################################################################################################################################# +#set sample rates +sample_rates=0.2,0.5,1.0 + +#highway assignment convergence criteria +convergence=0.0005 + +#set warm up inputs +RunModel.useLocalDrive = true +RunModel.skipInitialization = false +RunModel.deleteAllMatrices = true +RunModel.skip4Ds = false +RunModel.skipInputChecker = false +RunModel.skipCopyWarmupTripTables = false +RunModel.skipCopyBikeLogsum = false +RunModel.skipBikeLogsums = true +#always create walk logsum (walk to TAP file); modification from GUI disallowed +RunModel.skipCopyWalkImpedance = true +RunModel.skipWalkLogsums = false + +#build networks +RunModel.skipBuildNetwork = false + +# start looping +# set startFromIteration to 4 if only want +# to run final hwy and transit steps +RunModel.startFromIteration = 1 +RunModel.skipHighwayAssignment = false,false,false +RunModel.skipTransitSkimming = false,false,false +RunModel.skipTransponderExport = false,false,false +RunModel.skipCoreABM = false,false,false +RunModel.skipOtherSimulateModel = false,false,false +RunModel.skipMAASModel = false,false,false +RunModel.skipSpecialEventModel = true,true,true +RunModel.skipCTM = false,false,false +RunModel.skipEI = false,false,false +RunModel.skipTruck = false,false,false +RunModel.skipTripTableCreation = false,false,false +# end looping + +RunModel.skipFinalHighwayAssignment = false +RunModel.skipFinalHighwayAssignmentStochastic = true +RunModel.skipFinalTransitAssignment = false +RunModel.collapseOnOffByRoute=false +RunModel.skipLUZSkimCreation = true +RunModel.skipVisualizer = true +RunModel.skipDataExport = false +RunModel.skipDataLoadRequest = false +RunModel.skipDeleteIntermediateFiles = false +RunModel.MatrixPrecision = 0.0005 +# minimual space (MB) on C drive +RunModel.minSpaceOnC =250 + +TNC.totalThreads=10 + +############################################################################################################################################################################# +# +# LOGGING PROPERTIES: USE FOR TRACING HOUSEHOLDS OR AGENTS THROUGH SIMULATION. +# +# Note that the way that logging works right now, the trace zones also have to be valid transit stops or the code will crash. Check the skims to make sure they exist. +# Turn off trace debugging in routine model runs to speed things up (comment out Debug.Trace.HouseholdIdList) +# +############################################################################################################################################################################# +# Resident models +Trace = false +#Trace.otaz = 1638 +#Trace.dtaz = 2447 +Trace.otaz = +Trace.dtaz = +Seek = false +Process.Debug.HHs.Only = false +Debug.Trace.HouseholdIdList= + +# Internal-External models +internalExternal.seek = false +internalExternal.trace = 50 + +# Cross-Border models +crossBorder.seek = false +# trace by tourId +crossBorder.trace = 12 + +# Visitor models +visitor.seek = false +#trace by tourId +#visitor.trace = 742 +visitor.trace = 742 + +# Special event models +specialEvent.seek = false +specialEvent.trace = 5855 + +# Trace TransCAD trip table creation by TAZ (to/from); only applies to SD resident model +tripTable.trace=4384 + +RunModel.LogResults = true + +############################################################################################################################################################################# +# PATH PROPERTIES: MODIFY AS NEEDED WHEN COPY RELEASE TO A LOCAL RUN FOLDER +############################################################################################################################################################################# +Project.Directory = %project.folder%/ +generic.path = %project.folder%/input/ +scenario.path = %project.folder%/ +skims.path = %project.folder%/output/ +uec.path = %project.folder%/uec/ +report.path = %project.folder%/report/ + +# Visitor model is run using Java 7 Fork\Join Framework. Parallelism controls number of simultaneous threads. Can increase if more processors. +# 5 threads provided optimum runtimes on a 6 core, 24 thread machine with 128GB of RAM. +visitor.run.concurrent = true +visitor.concurrent.parallelism = 5 + +############################################################################################################################################################################# +# +# SCENARIO PROPERTIES: MODIFY WHEN RUNNING NEW SCENARIO, IF NECESSARY +# +############################################################################################################################################################################# +# MGRA data file: this token is referred to in many UECs +mgra.socec.file = input/mgra13_based_input${year}.csv + +# scenario year +scenarioYear=${year} + +# scenario build +scenarioBuild=${year_build} + +# Auto operating costs: these tokens are referred to in many UECs +aoc.fuel =${aoc.fuel} +aoc.maintenance =${aoc.maintenance} + +# Cross border model is run using Java 7 Fork\Join Framework. Parallelism controls number of simultaneous threads. Can increase if more processors. +crossBorder.run.concurrent = true +crossBorder.concurrent.parallelism = 8 + +# Cross border model settings: Number of tours, share of tours that are SENTRI. +crossBorder.tours =${crossBorder.tours} +crossBorder.sentriShare = ${crossBorder.sentriShare} + +# Visitor model settings: occupancy rates for hotels, households and share of each that are business visitors +visitor.hotel.occupancyRate = 0.7 +visitor.household.occupancyRate = 0.018 +visitor.hotel.businessPercent = 0.3 +visitor.household.businessPercent = 0.04 + +# Airport model settings: enplanements, connecting passengers, average party size, MGRA that the airport is in +airport.SAN.enplanements =${airport.SAN.enplanements} +airport.SAN.connecting =${airport.SAN.connecting} +airport.SAN.annualizationFactor = 365 +airport.SAN.averageSize = 1.7 +airport.SAN.airportMgra =${airport.SAN.airportMgra} + +airport.CBX.enplanements =${airport.CBX.enplanements} +airport.CBX.connecting =${airport.CBX.connecting} +airport.CBX.annualizationFactor = 365 +airport.CBX.averageSize = 2.2 +airport.CBX.airportMgra =${airport.CBX.airportMgra} + +# Truck model settings: +truck.FFyear =${year} + +# Destination zones for the transponder accessibility calculator +transponder.destinations = 4027,2563,2258 + +#taz crosswalk file +taz.to.cluster.crosswalk.file = input/taz_crosswalk.csv +cluster.zone.centroid.file = input/cluster_zones.csv + +############################################################################################ +# EMERGING MOBILITY SECTION: MODIFY WHEN CHANGE AV, TNC, and MICROMOBILITY ASSUMPTIONS +#------------------------------------------------------------------------------------------- +# AV Mobility Scenario Parameters +#------------------------------------------------------------------------------------------- +# AV.Share: the share of vehicles assumed to be AVs in the vehicle fleet; Auto ownership ASCs will be calibrated for different levels of AV penetration +# AV.ProbabilityBoost: the increased probability (multiplicative) for using AVs for tours, based on autos to drivers. The highest this should go is 1.2 +# AV.IVTFactor: the auto in-vehicle time factor to apply to AVs +# AV.ParkingCostFactor: The auto parking cost factor to apply to AVs, assuming some AVs are sent to remote locations or home +# AV.CostPerMileFactor: The auto cost per mile factor to apply to AVs, assuming AVs are more efficient in terms of fuel consumption than human-driven vehicles +# AV.TerminalTimeFactor: The factor to apply to terminal time for AVs, assuming AVs offer curbside passenger pickup/dropoff +# TNC.shared.IVTFactor: The factor to apply to in-vehicle time for shared TNC mode, reflecting out-direction travel for pickup/dropoff of other passengers + +Mobility.AV.Share = ${Mobility.AV.Share} +Mobility.AV.ProbabilityBoost.AutosLTDrivers = 1.2 +Mobility.AV.ProbabilityBoost.AutosGEDrivers = 1.1 +Mobility.AV.IVTFactor = 0.75 +Mobility.AV.ParkingCostFactor = 0.5 +Mobility.AV.CostPerMileFactor = 0.7 +Mobility.AV.TerminalTimeFactor = 0.65 +Mobility.AV.MinimumAgeDriveAlone = 13 +Mobility.TNC.shared.IVTFactor = 1.25 +crossBorder.avShare = 0.0 + +#------------------------------------------------------------------------------------------- +# Taxi and TNC cost and wait time parameters +#------------------------------------------------------------------------------------------- +# 3 modes: taxi, TNC - single, and TNC - shared +# baseFare: Initial fare +# costPerMile: The cost per mile +# costPerMinute: The cost per minute +# costMinimum: The minimum cost (for TNC modes only) +# +# Wait times are drawn from a distribution by area type (emp+hh)/sq. miles +# The mean and standard deviation is given for each area type range +# The ranges are configurable, set by WaitTimeDistribution.EndPopEmpPerSqMi + +taxi.baseFare = ${taxi.baseFare} +taxi.costPerMile = ${taxi.costPerMile} +taxi.costPerMinute = ${taxi.costPerMinute} + +TNC.single.baseFare = ${TNC.single.baseFare} +TNC.single.costPerMile = ${TNC.single.costPerMile} +TNC.single.costPerMinute = ${TNC.single.costPerMinute} +TNC.single.costMinimum = ${TNC.single.costMinimum} + +# use lower costs - these are synthesized, need real prices +TNC.shared.baseFare = ${TNC.shared.baseFare} +TNC.shared.costPerMile = ${TNC.shared.costPerMile} +TNC.shared.costPerMinute = ${TNC.shared.costPerMinute} +TNC.shared.costMinimum = ${TNC.shared.costMinimum} + +#Note: the following comma-separated value properties cannot have spaces between them, or else the RuntimeConfiguration.py code won't work +TNC.single.waitTime.mean = 10.3,8.5,8.4,6.3,4.7 +TNC.single.waitTime.sd = 4.1,4.1,4.1,4.1,4.1 + +TNC.shared.waitTime.mean = 15.0,15.0,11.0,8.0,7.0 +TNC.shared.waitTime.sd = 4.1,4.1,4.1,4.1,4.1 + +Taxi.waitTime.mean = 26.5,17.3,13.3,9.5,5.5 +Taxi.waitTime.sd = 6.4,6.4,6.4,6.4,6.4 + +WaitTimeDistribution.EndPopEmpPerSqMi = 500,2000,5000,15000,9999999999 + +#------------------------------------------------------------------------------------------- +# Taxi and TNC vehcicle trip conversion factors +#------------------------------------------------------------------------------------------- +# The following properties are used to split out the taxi, TNC-single, and TNC-shared trips into vehicle trips to be added to the rest of the vehicle trips by occupancy prior to assignment. + +Taxi.da.share = 0.0 +Taxi.s2.share = 0.9 +Taxi.s3.share = 0.1 +Taxi.passengersPerVehicle = 1.1 + +TNC.single.da.share = 0.0 +TNC.single.s2.share = 0.8 +TNC.single.s3.share = 0.2 +TNC.single.passengersPerVehicle = 1.2 + +TNC.shared.da.share = 0.0 +TNC.shared.s2.share = 0.3 +TNC.shared.s3.share = 0.7 +TNC.shared.passengersPerVehicle = 2.0 + +#------------------------------------------------------------------------------------------- +# Maas Routing Model Properties +#------------------------------------------------------------------------------------------- +Maas.RoutingModel.maxDistanceForPickup = 5 +Maas.RoutingModel.maxDiversionTimeForPickup = 5 +Maas.RoutingModel.minutesPerSimulationPeriod = 5 +Maas.RoutingModel.maxPassengers=6 +Maas.RoutingModel.maxWalkDistance = 0.15 +Maas.RoutingModel.vehicletrip.output.file=output/TNCTrips.csv +Maas.RoutingModel.vehicletrip.output.matrix=output/TNCVehicleTrips + +Maas.RoutingModel.routeIntrazonal=false +#NULL,DRIVEALONE,SHARED2,SHARED3,WALK,BIKE,WALK_SET,PNR_SET,KNR_SET,TNC_SET,TAXI,TNC_SINGLE,TNC_SHARED,SCHBUS +Maas.RoutingModel.Modes =0,0,0,0,0,0,0,0,0,0,1,1,1,0 +Maas.RoutingModel.SharedEligible=0,0,0,0,0,0,0,0,0,0,0,0,1,0 +Maas.RoutingModel.maxDistanceBeforeRefuel = 300 +Maas.RoutingModel.timeRequiredForRefuel = 15 + +Maas.AVAllocationModel.vehicletrip.output.file = output/householdAVTrips.csv +Maas.AVAllocationModel.vehicletrip.output.matrix = output/emptyAVTrips + +Maas.AVAllocation.uec.file = AutonomousVehicleAllocationChoice.xls +Maas.AVAllocation.data.page = 0 +Maas.AVAllocation.vehiclechoice.model.page = 1 +Maas.AVAllocation.parkingchoice.model.page = 2 +Maas.AVAllocation.triputility.model.page = 3 +Mobility.AV.RemoteParkingCostPerHour = ${Mobility.AV.RemoteParkingCostPerHour} + +# END--EMERGING MOBILITY SECTION +############################################################################################ + +############################################################################################################################################################################# +# +# CORE MODEL RUN PROPERTIES: CONTROL STEPS RUN IN CORE MODEL +# +############################################################################################################################################################################# +Model.Random.Seed = 1 + +RunModel.Clear.MatrixMgr.At.Start=false + +# Set to true if read the accessibilities from an input file instead of calculating them prior to running CTRAMP +acc.read.input.file = false + +# Setting shadow price files to null will reset prices to 0. If running new land-use scenario, set files to null and set maximum iterations to 20. +# Then copy shadow price output files to input directory, set maximum iterations to 1 for any subsequent runs with the same land-use file. +UsualWorkLocationChoice.ShadowPrice.Input.File = input/${workShadowPricing.iteration} +UsualSchoolLocationChoice.ShadowPrice.Input.File = input/${schoolShadowPricing.iteration} +uwsl.ShadowPricing.Work.MaximumIterations = 1 +uwsl.ShadowPricing.School.MaximumIterations = 1 +uwsl.ShadowPricing.OutputFile = output/ShadowPricingOutput.csv + +uwsl.run.workLocChoice = true +uwsl.run.schoolLocChoice = true +uwsl.write.results = true + +uwsl.use.new.soa = false +nmdc.use.new.soa = false +slc.use.new.soa = false + +# properties for distributed time coefficient +distributedTimeCoefficients = true + +timeDistribution.mean.work = 1.0 +timeDistribution.standardDeviation.work = 0.7 +timeDistribution.mean.nonWork = 1.0 +timeDistribution.standardDeviation.nonWork = 0.6 + +timeDistribution.randomSeed = 2301832 + +# value of time thresholds for skimming, assignment, mode choice UECs and trip tables ($/hr). +valueOfTime.threshold.low = 8.81 +valueOfTime.threshold.med = 18.00 + + +# save tour mode choice utilities and probabilities (for debugging purpose) +TourModeChoice.Save.UtilsAndProbs = true + +# packet size for distributing households, DO NOT change +distributed.task.packet.size = 200 + +#RunModel.RestartWithHhServer = uwsl +RunModel.RestartWithHhServer = none +#RunModel.RestartWithHhServer = ao +#RunModel.RestartWithHhServer = stf + +# Model Component run flags; Wu's note: not functional yet +RunModel.PreAutoOwnership = true +RunModel.UsualWorkAndSchoolLocationChoice = true +RunModel.AutoOwnership = true +RunModel.TransponderChoice = true +RunModel.FreeParking = true +RunModel.CoordinatedDailyActivityPattern = true +RunModel.IndividualMandatoryTourFrequency = true +RunModel.MandatoryTourModeChoice = true +RunModel.MandatoryTourDepartureTimeAndDuration = true +RunModel.SchoolEscortModel = true +RunModel.JointTourFrequency = true +RunModel.JointTourLocationChoice = true +RunModel.JointTourDepartureTimeAndDuration = true +RunModel.JointTourModeChoice = true +RunModel.IndividualNonMandatoryTourFrequency = true +RunModel.IndividualNonMandatoryTourLocationChoice = true +RunModel.IndividualNonMandatoryTourDepartureTimeAndDuration = true +RunModel.IndividualNonMandatoryTourModeChoice = true +RunModel.AtWorkSubTourFrequency = true +RunModel.AtWorkSubTourLocationChoice = true +RunModel.AtWorkSubTourDepartureTimeAndDuration = true +RunModel.AtWorkSubTourModeChoice = true +RunModel.StopFrequency =true +RunModel.StopLocation = true + +############################################################################################################################################################################# +# +# INPUT PROPERTIES +# +############################################################################################################################################################################# +#PopSyn Inputs +PopulationSynthesizer.InputToCTRAMP.HouseholdFile = input/households.csv +PopulationSynthesizer.InputToCTRAMP.PersonFile = input/persons.csv +PopulationSynthesizer.OccupCodes = input/pecas_occ_occsoc_acs.csv +PopulationSynthesizer.IndustryCodes = input/activity_code_indcen_acs.csv +# +# The military industry ranges are used to recode military occupation. This is +# necessary because military workers identify themselves as non-military occupations. +# The models need to be consistent with PECAS, where all military workers are in +# the military occupation category 56. +PopulationSynthesizer.MilitaryIndustryRange=9670,9870 + +# auxiliary inputs, these are scenario-specific +taz.driveaccess.taps.file = input/accessam.csv +tap.ptype.file = input/tap.ptype +taz.parkingtype.file = input/zone.park +taz.terminal.time.file = input/zone.term +maz.tap.tapLines = output/tapLines.csv + +# transit stop attribute file +transit.stop.file = input/trstop.csv + +############################################################################################################################################################################# +# +# OUTPUT PROPERTIES +# +############################################################################################################################################################################# +Results.WriteDataToFiles= true +Results.HouseholdDataFile = output/householdData.csv +Results.PersonDataFile = output/personData.csv +Results.IndivTourDataFile = output/indivTourData.csv +Results.JointTourDataFile = output/jointTourData.csv +Results.IndivTripDataFile = output/indivTripData.csv +Results.JointTripDataFile = output/jointTripData.csv +Results.WriteDataToDatabase = false +Results.HouseholdTable = household_data +Results.PersonTable = person_data +Results.IndivTourTable = indiv_tour_data +Results.JointTourTable = joint_tour_data +Results.IndivTripTable = indiv_trip_data +Results.JointTripTable = joint_trip_data +Results.AutoTripMatrix = output/autoTrips +Results.TranTripMatrix = output/tranTrips +Results.NMotTripMatrix = output/nmotTrips +Results.OthrTripMatrix = output/othrTrips +Results.PNRFile = output/PNRByTAP_Vehicles.csv +Results.CBDFile = output/CBDByMGRA_Vehicles.csv +Results.MatrixType = OMX +Results.segmentByTransponderOwnership = true + + +Results.AutoOwnership=output/aoResults.csv +read.pre.ao.results=false +read.pre.ao.filename=output/aoResults_pre.csv + +Results.UsualWorkAndSchoolLocationChoice=output/wsLocResults.csv +read.uwsl.results=false +read.uwsl.filename=output/wsLocResults_1.csv + +############################################################################################################################################################################# +# +# CORE MODEL UECS +# +############################################################################################################################################################################# +# UECs for calculating accessibilities +acc.uec.file = %project.folder%/uec/Accessibilities.xls +acc.data.page = 0 +acc.sov.offpeak.page = 1 +acc.sov.peak.page = 2 +acc.hov.offpeak.page = 3 +acc.hov.peak.page = 4 +acc.maas.offpeak.page = 5 +acc.maas.peak.page = 6 +acc.nonmotorized.page = 7 +acc.constants.page = 8 +acc.sizeTerm.page = 9 +acc.schoolSizeTerm.page = 10 +acc.workerSizeTerm.page = 11 +acc.dcUtility.uec.file = %project.folder%/uec/Accessibilities_DC.xls +acc.dcUtility.data.page = 0 +acc.dcUtility.page = 1 + +# accessibility file location +acc.output.file = input/accessibilities.csv + +#UECs for calculating destination choice based land use accessibilities +lu.acc.dcUtility.uec.file = %project.folder%/uec/Accessibilities_LU_DC.xls +lu.acc.dcUtility.data.page = 0 +lu.acc.dcUtility.page = 1 +lu.accessibility.alts.file = Acc_LU_alts.csv + +# land use accessibililty file locations +lu.acc.output.file = output/luAccessibilities.csv +lu.acc.mc.logsums.output.file = output/luLogsums.csv + +# set either or both averaging methods to be used to write LU accessibilities files +# also requires command line parameter "-luAcc true" and acc.read.input.file = false +lu.acc.simple.averaging.method = true +lu.acc.logit.averaging.method = true + +accessibility.alts.file = Acc_alts.csv + +#UEC for Mandatory accessibilities +acc.mandatory.uec.file = %project.folder%/uec/MandatoryAccess.xls +acc.mandatory.data.page = 0 +acc.mandatory.auto.page = 1 +acc.mandatory.autoLogsum.page = 2 +acc.mandatory.bestWalkTransit.page = 3 +acc.mandatory.bestDriveTransit.page = 4 +acc.mandatory.transitLogsum.page = 5 + +# UECs for auto ownership model +ao.uec.file = AutoOwnership.xls +ao.data.page = 0 +ao.model.page = 1 + +# UECs for Mandatory tour destination choice model +uwsl.dc.uec.file = ${uwsl.dc.uec.file} +uwsl.dc2.uec.file = TourDestinationChoice2.xls +uwsl.soa.uec.file = DestinationChoiceAlternativeSample.xls +uwsl.soa.alts.file = DestinationChoiceAlternatives.csv +uwsl.work.soa.SampleSize = 30 +uwsl.school.soa.SampleSize = 30 + +# The UEC file for work purposes includes TAZ Size in the expressions +work.soa.uec.file = TourDcSoaDistance.xls +work.soa.uec.data = 0 +work.soa.uec.model = 1 + +# The UEC file for school purposes does not include TAZ Size in the expressions +# so that the utilities can be stored as exponentiated distance utility matrices +# for univ, hs, gs, and ps, and then multiplied by the various school segment +# size terms for each of these 4 groups of school segments. +univ.soa.uec.file = TourDcSoaDistanceNoSchoolSize.xls +univ.soa.uec.data = 0 +univ.soa.uec.model = 1 + +hs.soa.uec.file = TourDcSoaDistanceNoSchoolSize.xls +hs.soa.uec.data = 0 +hs.soa.uec.model = 2 + +gs.soa.uec.file = TourDcSoaDistanceNoSchoolSize.xls +gs.soa.uec.data = 0 +gs.soa.uec.model = 3 + +ps.soa.uec.file = TourDcSoaDistanceNoSchoolSize.xls +ps.soa.uec.data = 0 +ps.soa.uec.model = 4 + +#UECs for transponder ownership model +tc.choice.avgtts.file = output/transponderModelAccessibilities.csv +tc.uec.file = TransponderOwnership.xls +tc.data.page = 0 +tc.model.page = 1 +tc.everyone.owns = ${tc.everyone.owns} + + +#UECs for parking provision model +fp.uec.file = ParkingProvision.xls +fp.data.page = 0 +fp.model.page = 1 + +#UEC for telecommute model +te.uec.file = Telecommute.xls +te.data.page = 0 +te.model.page = 1 + + +#UECs for CDAP model +cdap.uec.file = CoordinatedDailyActivityPattern.xls +cdap.data.page = 0 +cdap.one.person.page = 1 +cdap.two.person.page = 2 +cdap.three.person.page = 3 +cdap.all.person.page = 4 +cdap.joint.page = 5 + +#UECs for individual mandatory tour frequency model +imtf.uec.file = MandatoryTourFrequency.xls +imtf.data.page = 0 +imtf.model.page = 1 + +#UECs for Non-Mandatory tour destination sampling +nonSchool.soa.uec.file = TourDcSoaDistance.xls +escort.soa.uec.data = 0 +escort.soa.uec.model = 2 +other.nonman.soa.uec.data = 0 +other.nonman.soa.uec.model = 3 +atwork.soa.uec.data = 0 +atwork.soa.uec.model = 4 + +soa.taz.dist.alts.file = SoaTazDistAlts.csv + +nmdc.dist.alts.file = NonMandatoryTlcAlternatives.csv +nmdc.soa.alts.file = DestinationChoiceAlternatives.csv +nmdc.soa.SampleSize = 30 + +#UECs for Non-Mandatory tour destination choice model +nmdc.uec.file2 = TourDestinationChoice2.xls +nmdc.uec.file = ${nmdc.uec.file} +nmdc.data.page = 0 +nmdc.escort.model.page = 7 +nmdc.shop.model.page = 8 +nmdc.maint.model.page = 9 +nmdc.eat.model.page = 10 +nmdc.visit.model.page = 11 +nmdc.discr.model.page = 12 +nmdc.atwork.model.page = 13 + +# following properties use tod sampling instead of logsums +nmdc.SampleTODPeriod = true +nmdc.SampleTODPeriod.file = input/Non_Mand_Tours_ArrDep_Distbn.csv + +#UECs for Non-Mandatory tour destination sampling +nmdc.soa.uec.file = DestinationChoiceAlternativeSample.xls +nmdc.soa.data.page = 0 +nmdc.soa.escort.model.page = 6 +nmdc.soa.shop.model.page = 7 +nmdc.soa.maint.model.page = 7 +nmdc.soa.eat.model.page = 7 +nmdc.soa.visit.model.page = 7 +nmdc.soa.discr.model.page = 7 +nmdc.soa.atwork.model.page = 8 + +#UECs for School Escorting Model +school.escort.uec.filename = SchoolEscorting.xls +school.escort.alts.file = SchoolEscortingAlts.csv +school.escort.data.sheet = 0 +school.escort.outbound.model.sheet = 1 +school.escort.inbound.conditonal.model.sheet = 2 +school.escort.outbound.conditonal.model.sheet = 3 +school.escort.RNG.offset = 384571483 + +#UECs for tour mode choice model +tourModeChoice.uec.file =TourModeChoice.xls +tourModeChoice.maint.model.page = 4 +tourModeChoice.discr.model.page = 5 +tourModeChoice.atwork.model.page = 6 + +# utility coefficients by tour purpose (work, univ, school, maintenance, discretionary, work-based). These are at tour level. +tour.utility.ivt.coeffs = -0.016,-0.016,-0.01,-0.017,-0.015,-0.032 +tour.utility.income.coeffs = -0.625,-0.262,-0.262,-0.262,-0.262,-0.262 +tour.utility.income.exponents = 0.6,0.5,0.5,0.5,0.5,0.5 + +#UECs for tour TOD choice model +departTime.uec.file = TourDepartureAndDuration.xls +departTime.data.page = 0 +departTime.work.page = 1 +departTime.univ.page = 2 +departTime.school.page = 3 +departTime.escort.page = 4 +departTime.shop.page = 5 +departTime.maint.page = 6 +departTime.eat.page = 7 +departTime.visit.page = 8 +departTime.discr.page = 9 +departTime.atwork.page = 10 +departTime.alts.file = DepartureTimeAndDurationAlternatives.csv + +#UECs for joint tour frequency choice model +jtfcp.uec.file = JointTourFrequency.xls +jtfcp.alternatives.file = JointAlternatives.csv +jtfcp.data.page = 0 +jtfcp.freq.comp.page = 1 +jtfcp.participate.page = 2 + +#UECs for individual non-mandatory tour frequency model +inmtf.uec.file = NonMandatoryIndividualTourFrequency.xls +inmtf.FrequencyExtension.ProbabilityFile = IndividualNonMandatoryTourFrequencyExtensionProbabilities_p1.csv +IndividualNonMandatoryTourFrequency.AlternativesList.InputFile = IndividualNonMandatoryTourFrequencyAlternatives.csv +inmtf.data.page = 0 +inmtf.perstype1.page = 1 +inmtf.perstype2.page = 2 +inmtf.perstype3.page = 3 +inmtf.perstype4.page = 4 +inmtf.perstype5.page = 5 +inmtf.perstype6.page = 6 +inmtf.perstype7.page = 7 +inmtf.perstype8.page = 8 + +#UECs for at work subtour frequency model +awtf.uec.file = AtWorkSubtourFrequency.xls +awtf.data.page = 0 +awtf.model.page = 1 + +#UECs for stop frequency model +stf.uec.file = StopFrequency.xls +stf.purposeLookup.proportions = StopPurposeLookupProportions.csv +stf.data.page = 0 +stf.work.page = 1 +stf.univ.page = 2 +stf.school.page = 3 +stf.escort.page = 4 +stf.shop.page = 5 +stf.maint.page = 6 +stf.eat.page = 7 +stf.visit.page = 8 +stf.discr.page = 9 +stf.subtour.page = 10 + +#UECs for stop location choice model +slc.uec.file = StopLocationChoice.xls +slc.uec.data.page = 0 +slc.mandatory.uec.model.page = 1 +slc.maintenance.uec.model.page = 2 +slc.discretionary.uec.model.page = 3 +slc.alts.file = SlcAlternatives.csv + +slc.soa.uec.file = SlcSoaSize.xls +slc.soa.alts.file = DestinationChoiceAlternatives.csv + +auto.slc.soa.distance.uec.file = SlcSoaDistanceUtility.xls +auto.slc.soa.distance.data.page = 0 +auto.slc.soa.distance.model.page = 1 + +slc.soa.size.uec.file = SlcSoaSize.xls +slc.soa.size.uec.data.page = 0 +slc.soa.size.uec.model.page = 1 + +stop.depart.arrive.proportions = StopDepartArriveProportions.csv + +#UECs for trip mode choice model +tripModeChoice.uec.file =TripModeChoice.xls + +# utility coefficients by tour purpose (work, univ, school, maintenance, discretionary, work-based). These are at trip level. +trip.utility.ivt.coeffs = -0.032,-0.032,-0.02,-0.034,-0.03,-0.064 +trip.utility.income.coeffs = -1.25,-0.524,-0.524,-0.524,-0.524,-0.524 +trip.utility.income.exponents = 0.6,0.5,0.5,0.5,0.5,0.5 + + +#UECs for parking location choice model +plc.uec.file = ParkLocationChoice.xls +plc.uec.data.page = 0 +plc.uec.model.page = 1 + +plc.alts.corresp.file = ParkLocationAlts.csv +plc.alts.file = ParkLocationSampleAlts.csv + +mgra.avg.cost.output.file = output/mgraParkingCost.csv + +mgra.avg.cost.dist.coeff.work = -8.6 +mgra.avg.cost.dist.coeff.other = -4.9 + +park.cost.reimb.mean = -0.05 +park.cost.reimb.std.dev = 0.54 + +#UECs for best transit path finding +utility.bestTransitPath.uec.file =BestTransitPathUtility.xls +utility.bestTransitPath.data.page = 0 +utility.bestTransitPath.tapToTap.page = 1 +utility.bestTransitPath.walkAccess.page = 2 +utility.bestTransitPath.driveAccess.page = 3 +utility.bestTransitPath.walkEgress.page = 4 +utility.bestTransitPath.driveEgress.page = 5 +utility.bestTransitPath.driveAccDisutility.page = 6 +utility.bestTransitPath.driveEgrDisutility.page = 7 +utility.bestTransitPath.skim.sets = 3 +utility.bestTransitPath.alts = 4 +utility.bestTransitPath.maxPathsPerSkimSetForLogsum = 1,1,1 +utility.bestTransitPath.nesting.coeff = 0.24 + +#UECs for auto skimming +skims.auto.uec.file = AutoSkims.xls +skims.auto.data.page = 0 +skims.auto.ea.page = 1 +skims.auto.am.page = 2 +skims.auto.md.page = 3 +skims.auto.pm.page = 4 +skims.auto.ev.page = 5 + +#UECs for TAZ distances +taz.distance.uec.file = tazDistance.xls +taz.distance.data.page = 0 +taz.od.distance.ea.page = 1 +taz.od.distance.am.page = 2 +taz.od.distance.md.page = 3 +taz.od.distance.pm.page = 4 +taz.od.distance.ev.page = 5 + +#UECs for TAZ times +taz.od.time.ea.page = 6 +taz.od.time.am.page = 7 +taz.od.time.md.page = 8 +taz.od.time.pm.page = 9 +taz.od.time.ev.page = 10 + + +#UECs for walk-transit-walk skimming +skim.walk.transit.walk.uec.file = WalkTransitWalkSkims.xls +skim.walk.transit.walk.data.page = 0 +skim.walk.transit.walk.skim.page = 1 +skim.walk.transit.walk.skims = 13 + +#UECs for walk-transit-drive skimming +skim.walk.transit.drive.uec.file = WalkTransitDriveSkims.xls +skim.walk.transit.drive.data.page = 0 +skim.walk.transit.drive.skim.page = 1 +skim.walk.transit.drive.skims = 13 + +#UECs for drive-transit-walk skimming +skim.drive.transit.walk.uec.file = DriveTransitWalkSkims.xls +skim.drive.transit.walk.data.page = 0 +skim.drive.transit.walk.skim.page = 1 +skim.drive.transit.walk.skims = 13 + + +##################################################################################### +# IE Model Settings (run as part of CT-RAMP) +##################################################################################### + +RunModel.InternalExternal = true + +ie.uec.file = InternalExternalTripChoice.xls +ie.data.page = 0 +ie.model.page = 1 +ie.logsum.distance.coeff = -0.05 +external.tazs = 1,2,3,4,5,6,7,8,9,10,11,12 + + +internalExternal.dc.uec.file = InternalExternalDestinationChoice.xls +internalExternal.dc.uec.data.page = 0 +internalExternal.dc.uec.model.page = 1 +internalExternal.dc.uec.alts.file = InternalExternalDestinationChoiceAlternatives.csv + +internalExternal.tour.tod.file = input/internalExternal_tourTOD.csv + +internalExternal.trip.mc.uec.file =InternalExternalTripModeChoice.xls +internalExternal.trip.mc.data.page = 0 +internalExternal.trip.mc.model.page = 1 + +internalExternal.trip.output.file = output/internalExternalTrips.csv + +internalExternal.results.autoTripMatrix = output/autoInternalExternalTrips +internalExternal.results.nMotTripMatrix = output/nmotInternalExternalTrips +internalExternal.results.tranTripMatrix = output/tranInternalExternalTrips +internalExternal.results.othrTripMatrix = output/othrInternalExternalTrips + +##################################################################################### +# Cross-Border Model Settings +##################################################################################### +crossBorder.purpose.nonsentri.file = input/crossBorder_tourPurpose_nonSENTRI.csv +crossBorder.purpose.sentri.file = input/crossBorder_tourPurpose_SENTRI.csv + +crossBorder.tour.tod.file = input/crossBorder_tourEntryAndReturn.csv + +crossBorder.dc.soa.uec.file = CrossBorderDestinationChoiceSample.xls +crossBorder.dc.soa.data.page = 0 +crossBorder.dc.soa.model.page = 1 +crossBorder.dc.soa.size.page = 2 +crossborder.dc.soa.alts.file =${crossborder.dc.soa.alts.file} + +crossBorder.dc.uec.file =${crossBorder.dc.uec.file} +crossBorder.dc.data.page = 0 +crossBorder.dc.model.page = 1 +crossborder.dc.alts.file = CrossBorderDestinationChoiceAlternatives.csv + +crossBorder.dc.colonia.file = input/crossBorder_supercolonia.csv +crossBorder.dc.colonia.distance.parameter = -0.19 +crossBorder.dc.soa.sampleRate = 30 + +#crossBorder.tour.mc.uec.file = CrossBorderTourModeChoice.xls +crossBorder.tour.mc.uec.file =${crossBorder.tour.mc.uec.file} +crossBorder.tour.mc.data.page = 0 +crossBorder.tour.mc.mandatory.model.page = 1 +crossBorder.tour.mc.nonmandatory.model.page = 2 +crossBorder.poe.waittime.file = input/crossBorder_pointOfEntryWaitTime.csv + +crossBorder.trip.mc.uec.file =CrossBorderTripModeChoice.xls +crossBorder.trip.mc.data.page = 0 +crossBorder.trip.mc.model.page = 1 + +crossBorder.stop.frequency.file = input/crossBorder_stopFrequency.csv +crossBorder.stop.purpose.file = input/crossBorder_stopPurpose.csv + +crossBorder.slc.soa.uec.file = CrossBorderStopLocationChoiceSample.xls +crossBorder.slc.soa.data.page = 0 +crossBorder.slc.soa.model.page = 1 +crossBorder.slc.soa.alts.file = SoaTazDistAlts.csv + +crossBorder.slc.uec.file = CrossBorderStopLocationChoice.xls +crossBorder.slc.data.page = 0 +crossBorder.slc.model.page = 1 + +crossBorder.stop.outbound.duration.file = input/crossBorder_outboundStopDuration.csv +crossBorder.stop.inbound.duration.file = input/crossBorder_inboundStopDuration.csv + +crossBorder.tour.output.file = output/crossBorderTours.csv +crossBorder.trip.output.file = output/crossBorderTrips.csv + +crossBorder.results.autoTripMatrix = output/autoCrossBorderTrips +crossBorder.results.nMotTripMatrix = output/nmotCrossBorderTrips +crossBorder.results.tranTripMatrix = output/tranCrossBorderTrips +crossBorder.results.othrTripMatrix = output/othrCrossBorderTrips + +##################################################################################### +# Visitor Model Settings +##################################################################################### +visitor.business.tour.file = input/visitor_businessFrequency.csv +visitor.personal.tour.file = input/visitor_personalFrequency.csv + +visitor.partySize.file = input/visitor_partySize.csv +visitor.autoAvailable.file = input/visitor_autoAvailable.csv +visitor.income.file = input/visitor_income.csv + +visitor.dc.soa.uec.file = VisitorDestinationChoiceSample.xls +visitor.dc.soa.data.page = 0 +visitor.dc.soa.work.page = 1 +visitor.dc.soa.recreate.page = 2 +visitor.dc.soa.dining.page = 3 +visitor.dc.soa.size.page = 4 +visitor.dc.soa.alts.file = SoaTazDistAlts.csv + +visitor.dc.uec.file = VisitorDestinationChoice.xls +visitor.dc.data.page = 0 +visitor.dc.work.page = 1 +visitor.dc.recreate.page = 2 +visitor.dc.dining.page = 3 + +visitor.tour.tod.file = input/visitor_tourTOD.csv + +visitor.mc.uec.file =VisitorTourModeChoice.xls +visitor.mc.data.page = 0 +visitor.mc.model.page = 1 + +visitor.stop.frequency.file = input/visitor_stopFrequency.csv +visitor.stop.purpose.file = input/visitor_stopPurpose.csv +visitor.stop.outbound.duration.file = input/visitor_outboundStopDuration.csv +visitor.stop.inbound.duration.file = input/visitor_inboundStopDuration.csv + +visitor.slc.soa.uec.file = VisitorStopLocationChoiceSample.xls +visitor.slc.soa.data.page = 0 +visitor.slc.soa.model.page = 1 + +visitor.slc.uec.file = VisitorStopLocationChoice.xls +visitor.slc.data.page = 0 +visitor.slc.model.page = 1 + +visitor.trip.mc.uec.file =VisitorTripModeChoice.xls +visitor.trip.mc.data.page = 0 +visitor.trip.mc.model.page = 1 + +visitor.micromobility.uec.file = VisitorMicromobilityChoice.xls +visitor.micromobility.data.page = 0 +visitor.micromobility.model.page = 1 + + + + +visitor.tour.output.file = output/visitorTours.csv +visitor.trip.output.file = output/visitorTrips.csv + +visitor.results.autoTripMatrix = output/autoVisitorTrips +visitor.results.nMotTripMatrix = output/nmotVisitorTrips +visitor.results.tranTripMatrix = output/tranVisitorTrips +visitor.results.othrTripMatrix = output/othrVisitorTrips + + +# These settings are for building an estimation file, not used for main visitor model code +visitor.uec.file = VisitorSize.xls +visitor.uec.data.page = 0 +visitor.uec.sizeTerms.page = 1 + +##################################################################################### +# SAN Airport Model Settings +##################################################################################### +airport.SAN.purpose.file = input/airport_purpose.SAN.csv +airport.SAN.size.file = input/airport_party.SAN.csv +airport.SAN.duration.file = input/airport_nights.SAN.csv +airport.SAN.income.file = input/airport_income.SAN.csv +airport.SAN.departureTime.file = input/airport_departure.SAN.csv +airport.SAN.arrivalTime.file = input/airport_arrival.SAN.csv +airport.SAN.output.file = output/airport_out.SAN.csv + +airport.SAN.dc.uec.file = AirportDestinationChoice.SAN.xls +airport.SAN.dc.data.page = 0 +airport.SAN.dc.size.page = 5 +airport.SAN.dc.segment1.page = 1 +airport.SAN.dc.segment2.page = 2 +airport.SAN.dc.segment3.page = 3 +airport.SAN.dc.segment4.page = 4 + +airport.SAN.mc.uec.file =AirportModeChoice.SAN.xls +airport.SAN.mc.data.page = 0 +airport.SAN.mc.da.page = 1 +airport.SAN.mc.s2.page = 2 +airport.SAN.mc.s3.page = 3 +airport.SAN.mc.transit.page = 4 +airport.SAN.mc.accessMode.page = 5 + +airport.SAN.externalStationFile = uec/InternalExternalDestinationChoiceAlternatives.csv + +airport.SAN.results.autoTripMatrix = output/autoAirportTrips.SAN +airport.SAN.results.nMotTripMatrix = output/nmotAirportTrips.SAN +airport.SAN.results.tranTripMatrix = output/tranAirportTrips.SAN +airport.SAN.results.othrTripMatrix = output/othrAirportTrips.SAN + +##################################################################################### +# CBX Airport Model Settings +##################################################################################### +airport.CBX.purpose.file = input/airport_purpose.CBX.csv +airport.CBX.size.file = input/airport_party.CBX.csv +airport.CBX.duration.file = input/airport_nights.CBX.csv +airport.CBX.income.file = input/airport_income.CBX.csv +airport.CBX.departureTime.file = input/airport_departure.CBX.csv +airport.CBX.arrivalTime.file = input/airport_arrival.CBX.csv +airport.CBX.output.file = output/airport_out.CBX.csv + +airport.CBX.dc.uec.file = AirportDestinationChoice.CBX.xls +airport.CBX.dc.data.page = 0 +airport.CBX.dc.size.page = 5 +airport.CBX.dc.segment1.page = 1 +airport.CBX.dc.segment2.page = 2 +airport.CBX.dc.segment3.page = 3 +airport.CBX.dc.segment4.page = 4 + +airport.CBX.mc.uec.file =AirportModeChoice.CBX.xls +airport.CBX.mc.data.page = 0 +airport.CBX.mc.da.page = 1 +airport.CBX.mc.s2.page = 2 +airport.CBX.mc.s3.page = 3 +airport.CBX.mc.transit.page = 4 +airport.CBX.mc.accessMode.page = 5 + +airport.CBX.externalStationFile = uec/InternalExternalDestinationChoiceAlternatives.csv + +airport.CBX.results.autoTripMatrix = output/autoAirportTrips.CBX +airport.CBX.results.nMotTripMatrix = output/nmotAirportTrips.CBX +airport.CBX.results.tranTripMatrix = output/tranAirportTrips.CBX +airport.CBX.results.othrTripMatrix = output/othrAirportTrips.CBX + +##################################################################################### +# Truck Model Settings +##################################################################################### +truck.DFyear = ${model_years} +truck.luOverRide = "False" + +##################################################################################### +# Commercial Vehicle Model Settings +##################################################################################### +#scale factor to use in cvm trip generation. Also, used during demand import to factor-in demand accordingly +cvm.scale_factor = 1 +#scale factors by vehicle (light, medium, and heavy) and time of day (ea,am,md,pm,ev) - used to boost cvm demand +#light vehicles +cvm.scale_light = 1,2,3.5,2,1 +#medium vehicles +cvm.scale_medium = 1,1,1,1,1 +#heavy vehicles +cvm.scale_heavy = 1,1,1,1,1 +#cvm vehicle shares representing portions of the cvm vehicle trips that go to light-heavy trucks. +#share value should be between 0 and 1. 0 representing none will go to light-heavy truck and 1 means all will go. +cvm.share.light = 0.04 +cvm.share.medium = 0.64 +cvm.share.heavy = 0 + +################################################################# +# Report Section +################################################################# +Report.exportData=True +Report.iteration=3 +Report.tables = taztotap,indivtrips,jointtrips,airporttripsSAN,airporttripsCBX,cbtrips,visitortours,visitortrips,ietrip,commtrip +#aggregate trips eetrip, eitrip, and trucktrip are exported in Python, always +#Report.writeTransitIVT = True +##################################################################################### +# Trip Table Settings +##################################################################################### +# occupancies needed for trip table creation +occ3plus.purpose.Work = 3.34 +occ3plus.purpose.University = 3.34 +occ3plus.purpose.School = 3.34 +occ3plus.purpose.Escort = 3.34 +occ3plus.purpose.Shop = 3.34 +occ3plus.purpose.Maintenance = 3.34 +occ3plus.purpose.EatingOut = 3.34 +occ3plus.purpose.Visiting = 3.34 +occ3plus.purpose.Discretionary = 3.34 +occ3plus.purpose.WorkBased = 3.34 + +################################################################# +# Active Transportation Model Settings +# updated 4/2/2014 wsu +################################################################# +active.node.file = %project.folder%/input/SANDAG_Bike_NODE.dbf +active.node.id = NodeLev_ID +active.node.fieldnames = mgra,taz,x,y,tap,signalized +active.node.columns = MGRA,TAZ,XCOORD,YCOORD,TAP,Signal +active.edge.file = %project.folder%/input/SANDAG_Bike_NET.dbf +active.edge.anode = A +active.edge.bnode = B +active.edge.directional = false +active.edge.fieldnames = functionalClass,distance,gain,bikeClass,lanes,cycleTrack,bikeBlvd,roadsegid +active.edge.columns.ab = Func_Class,Distance,AB_Gain,ABBikeClas,AB_Lanes,Bike2Sep,Bike3Blvd,ROADSEGID +active.edge.columns.ba = Func_Class,Distance,BA_Gain,BABikeClas,BA_Lanes,Bike2Sep,Bike3Blvd,ROADSEGID +active.edge.centroid.field = functionalClass +active.edge.centroid.value = 10 +active.edge.autospermitted.field = functionalClass +active.edge.autospermitted.values = 1, 2, 3, 4, 5, 6, 7 +# distance bins for control of path sampling +active.sample.distance.breaks = 99 +# minimum path sizes of alternative lists for each distance bin +active.sample.pathsizes = 2 +# minimum count of samples for each distance bin +active.sample.count.min = 10 +# maximum count of samples for each distance bin +active.sample.count.max = 100 +# scale of random cost for each sampling iteration where random cost = cost + scale * unif(0,1) * distance +active.sample.random.scale.coef = 0.5 +active.sample.random.scale.link = 0.7 +active.sample.random.seeded = true +active.sample.maxcost = 998 +active.maxdist.walk.mgra = 3.0 +active.maxdist.walk.tap = 1.0 +active.maxdist.bike.taz = ${active.maxdist.bike.taz} +active.maxdist.bike.mgra = ${active.maxdist.bike.mgra} +active.maxdist.micromobility.mgra = 3.0 +active.maxdist.micromobility.tap = 1.0 +active.maxdist.microtransit.mgra = 3.0 +active.maxdist.microtransit.tap = 3.0 +active.output.bike = %project.folder%/output/ +active.output.walk = %project.folder%/output/ +active.coef.distcla0 = ${active.coef.distcla0} +active.coef.distcla1 = ${active.coef.distcla1} +active.coef.distcla2 = ${active.coef.distcla2} +active.coef.distcla3 = ${active.coef.distcla3} +active.coef.dartne2 = ${active.coef.dartne2} +active.coef.dwrongwy = ${active.coef.dwrongwy} +active.coef.dcyctrac = ${active.coef.dcyctrac} +active.coef.dbikblvd = ${active.coef.dbikblvd} +active.coef.nonscenic = 0.300 +active.coef.gain = 0.015 +active.coef.turn = 0.083 +active.coef.signals = 0.040 +active.coef.unlfrma = 0.360 +active.coef.unlfrmi = 0.150 +active.coef.untoma = 0.480 +active.coef.untomi = 0.100 +active.coef.gain.walk = 0.034 + +active.walk.minutes.per.mile = 20 +active.bike.minutes.per.mile = ${active.bike.minutes.per.mile} +active.ebike.ownership = ${active.ebike.ownership} +active.ebike.max.benefit = 10 +active.micromobility.speed = 15 +active.micromobility.variableCost = ${active.micromobility.variableCost} +active.micromobility.fixedCost = ${active.micromobility.fixedCost} +active.micromobility.rentalTime = 1 +active.micromobility.constant = 60 +# 2020 VOT $15 converted to 2010 $ at $12.17 +active.micromobility.vot = 12.17 + +micromobility.uec.file = MicromobilityChoice.xls +micromobility.data.page = 0 +micromobility.model.page = 1 + +active.microtransit.speed = 17 +active.microtransit.variableCost = 0.0 +active.microtransit.fixedCost = ${active.microtransit.fixedCost} +active.microtransit.waitTime = 4.0 +active.microtransit.accessTime = 0.0 +active.microtransit.constant = 120 +active.microtransit.notAvailable = 999 + +active.microtransit.tap.file = input/mobilityHubTaps.csv +active.microtransit.mgra.file = input/mobilityHubMGRAs.csv + +#active.trace.origins.taz = 500, 1000, 1500, 2000, 2500, 3000, 3500, 4000, 4500 +#active.trace.origins.mgra = 1000, 2000, 3000, 4000, 5000, 6000, 7000, 8000, 9000, 10000, 11000, 12000, 13000, 14000, 15000, 16000, 17000, 18000, 19000, 20000 +#active.trace.origins.tap = 1, 3, 5, 7, 8, 9, 15 +#active.trace.exclusive = false +#active.debug.origin = 200003500 +#active.debug.destination = 200003601 + +active.trace.outputassignmentpaths = false + +path.choice.uec.spreadsheet = %project.folder%/uec/BikeTripPathChoice.xls +path.choice.uec.model.sheet = 1 +path.choice.uec.data.sheet = 0 +path.choice.max.path.count = 200 +btpc.alts.file = bike_path_alts.csv +active.logsum.matrix.file.bike.taz = bikeTazLogsum.csv +active.logsum.matrix.file.bike.mgra = bikeMgraLogsum.csv +active.logsum.matrix.file.walk.mgra = walkMgraEquivMinutes.csv +active.logsum.matrix.file.walk.mgratap = walkMgraTapEquivMinutes.csv + +active.bike.write.derived.network = true +active.bike.derived.network.edges = derivedBikeEdges.csv +active.bike.derived.network.nodes = derivedBikeNodes.csv +active.bike.derived.network.traversals = derivedBikeTraversals.csv + +active.assignment.file.bike = bikeAssignmentResults.csv +active.micromobility.file.walk.mgra = microMgraEquivMinutes.csv +active.micromobility.file.walk.mgratap = microMgraTapEquivMinutes.csv + +AtTransitConsistency.xThreshold=1.0 +AtTransitConsistency.yThreshold=1.0 + +##################################################################################### +# SUMMIT Settings +##################################################################################### +summit.output.directory = output/ +# Purposes (which correspond to SUMMIT files) are as follows: +summit.purpose.Work = 1 +summit.purpose.University = 2 +summit.purpose.School = 3 +summit.purpose.Escort = 4 +summit.purpose.Shop = 4 +summit.purpose.Maintenance = 4 +summit.purpose.EatingOut = 5 +summit.purpose.Visiting = 5 +summit.purpose.Discretionary = 5 +summit.purpose.WorkBased = 6 + +summit.filename.1 = Work +summit.filename.2 = University +summit.filename.3 = School +summit.filename.4 = Maintenance +summit.filename.5 = Discretionary +summit.filename.6 = Workbased + +summit.ivt.file.1 = -0.016 +summit.ivt.file.2 = -0.016 +summit.ivt.file.3 = -0.010 +summit.ivt.file.4 = -0.017 +summit.ivt.file.5 = -0.015 +summit.ivt.file.6 = -0.032 + +summit.modes = 26 +# 1=wt,2=dt 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 +summit.mode.array = 0,0,0,0,0,0,0,0,0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 0 + +summit.upperEA = 3 +summit.upperAM = 9 +summit.upperMD = 22 +summit.upperPM = 29 + +################################################################# +# TAPS Creation Settings +# updated 4/28/2015 ymm +################################################################# +taps.formal.premium.maxDist = 10.0 +taps.formal.express.maxDist = 4.0 +taps.formal.local.maxDist = 4.0 +taps.informal.premium.maxDist = 4.0 +taps.informal.express.maxDist = 2.0 +taps.informal.local.maxDist = 2.0 + +taps.premium.modes = 4,5,6,7 +taps.express.modes = 8,9 +taps.local.modes = 10 + +taps.skim = traffic_skims_AM.omx +taps.skim.dist = AM_SOV_NT_M_DIST +taps.skim.time = AM_SOV_NT_M_TIME + +################################################################# +# Military Adjustment Section +# updated 4/26/2016 Wu Sun +################################################################# +RunModel.militaryCtmAdjustment=true + +##################################################################################### +# Special Event Model Settings +# Wu Sun 5/15/2017 +##################################################################################### +specialEvent.event.file = input/specialEvent_eventData.csv + +specialEvent.partySize.file = input/specialEvent_partySize.csv +specialEvent.income.file = input/specialEvent_income.csv + +specialEvent.dc.uec.file = SpecialEventOriginChoice.xls +specialEvent.dc.data.page = 0 +specialEvent.dc.model.page = 1 +specialEvent.dc.size.page = 2 + +specialEvent.saveUtilsAndProbs= false + +specialEvent.trip.mc.uec.file =SpecialEventTripModeChoice.xls +specialEvent.trip.mc.data.page = 0 +specialEvent.trip.mc.model.page = 1 + +specialEvent.tour.output.file = output/specialEventTours.csv +specialEvent.trip.output.file = output/specialEventTrips.csv + +specialEvent.results.autoTripMatrix = output/autoSpecialEventTrips +specialEvent.results.nMotTripMatrix = output/nmotSpecialEventTrips +specialEvent.results.tranTripMatrix = output/tranSpecialEventTrips +specialEvent.results.othrTripMatrix = output/othrSpecialEventTrips + +##################################################################################### +# Transit Shed Properties wsu 8/7/18 +##################################################################################### +RunModel.skipTransitShed= true +#transit access threshold (in minutes, must be integer) +transitShed.threshold=30 +#TOD to use in Transit Shed analysis-EA, AM, MD, PM, and EV +transitShed.TOD=AM +#Transit Shed time components (walk to transit). Options: walkAccTime,walkEgrTime,walkAuxTime,1stWaitTime,xferWaitTime,IVTime +transitShed.walkTransitTimeComponents=walkAccTime,walkEgrTime,walkAuxTime,1stWaitTime,xferWaitTime,IVTime +#Transit Shed time components (drive to transit). Options: driveAccTime,walkEgrTime,walkAuxTime,1stWaitTime,xferWaitTime,IVTime +transitShed.driveTransitTimeComponents=drvAccTime,walkEgrTime,walkAuxTime,1stWaitTime,xferWaitTime,IVTime + +##################################################################################### +# Smart Signal Properties wsu 8/22/18 +##################################################################################### +smartSignal.factor.LC=${smartSignal.factor.LC} +smartSignal.factor.MA=${smartSignal.factor.MA} +smartSignal.factor.PA=${smartSignal.factor.PA} + +##################################################################################### +##################################################################################### +# Transit Tier 1 EMME Link Name zou 5/7/20 +##################################################################################### +transit.newMode = TIER 1 RAIL +transit.newMode.route = 581,582,583 + +##################################################################################### +# ATDM Properties wsu 8/22/18 +##################################################################################### +atdm.factor = ${atdm.factor} +##################################################################################### +# Transit PCE VEH Conversion cliu 8/19/20 +##################################################################################### +transit.bus.pceveh = 3.0 +##################################################################################### +# Local Drive Run Settings wsu 1/19/19 +##################################################################################### +RunModel.FileMask.Download = output,report,sql,logFiles +RunModel.FileMask.Upload = application,bin,input_truck,uec,output\iter*,output\*_1.csv,output\*_2.csv +##################################################################################### +# Visualizer Settings (run once after feedback loops) +##################################################################################### +visualizer.reference.path = ${visualizer.reference.path} +visualizer.output = SANDAG_Dashboard +visualizer.reference.label = REFERENCE +visualizer.build.label = SDABM + +##################################################################################### +# add year specific vehicle class toll factor wsu 6/18/20 +##################################################################################### +vehicle.class.toll.factor=vehicle_class_toll_factors.csv +vehicle.class.toll.factor.path = input/vehicle_class_toll_factors.csv + +##################################################################################### +# Stochastic traffic assignment settings ag 10/07/20 +##################################################################################### +stochasticHighwayAssignment.distributionType = GUMBEL +stochasticHighwayAssignment.replications = 10 +stochasticHighwayAssignment.aParameter = 1.0 +stochasticHighwayAssignment.bParameter = 0.05 +stochasticHighwayAssignment.seed = 1 + +############################################################################### +# DTA post-processing properties +############################################################################### + +dta.postprocessing.RandomSeed = 1004831 + +dta.postprocessing.outputs.path = %project.folder%/output/ + +dta.postprocessing.disaggregateTOD.path = %project.folder%//input/ +dta.postprocessing.disaggregateZone.path = %project.folder%//input/ +dta.postprocessing.disaggregateNode.path = %project.folder%//input/ + +dta.postprocessing.DetailedTODFile = DetailedTODFactors.csv +dta.postprocessing.NodeFile = NodeFactors.csv +dta.postprocessing.ZoneFile = MGRAFactors.csv +dta.postprocessing.BroadTODFile = BroadTODFactors.csv + +skims.path = %project.folder%/output/ +skims.extension = .omx +da.no.toll.skims.prefix = traffic_skims_ +skims.mat.name.suffix = SOVGPM_TIME + +dta.postprocessing.outputs.TripFile = dtaTripsOut.csv \ No newline at end of file diff --git a/sandag_abm/src/main/resources/serverswap.bat b/sandag_abm/src/main/resources/serverswap.bat new file mode 100644 index 0000000..303c7da --- /dev/null +++ b/sandag_abm/src/main/resources/serverswap.bat @@ -0,0 +1,9 @@ +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 +set PROJECT_DIRECTORY_FWD=%3 + +%PROJECT_DRIVE% +set "SCEN_DIR=%PROJECT_DRIVE%%PROJECT_DIRECTORY%" +set "SCEN_DIR_FWD=%PROJECT_DRIVE%%PROJECT_DIRECTORY_FWD%" + +python.exe %SCEN_DIR%\python\serverswap.py -p %SCEN_DIR_FWD% \ No newline at end of file diff --git a/sandag_abm/src/main/resources/serverswap_files.csv b/sandag_abm/src/main/resources/serverswap_files.csv new file mode 100644 index 0000000..4f155bd --- /dev/null +++ b/sandag_abm/src/main/resources/serverswap_files.csv @@ -0,0 +1,25 @@ +fileName,property,separator,refValue +/bin/CTRampEnv.bat,MAIN,=,MAIN +/bin/CTRampEnv.bat,NODE1,=,NODE1 +/bin/CTRampEnv.bat,NODE2,=,NODE2 +/bin/CTRampEnv.bat,NODE3,=,NODE3 +/bin/CTRampEnv.bat,MAIN_IP,=,ModelIP +/bin/CTRampEnv.bat,HHMGR_IP,=,ModelIP +/bin/CTRampEnv.bat,SNODE,=,SNODE +/bin/CTRampEnv.bat,TRANSCAD_PATH,=,TRANSCAD_PATH +/bin/stopABM.cmd,pskill,\\,MAIN +/bin/stopABM.cmd,pskill,\\,NODE1 +/bin/stopABM.cmd,pskill,\\,NODE2 +/conf/jppf-client.properties,driver1.jppf.server.host, = ,MAIN +/conf/jppf-client.properties,jppf.processing.threads, = ,THREADN1 +/conf/jppf-clientDistributed.properties,driver1.jppf.server.host, = ,MAIN +/conf/jppf-sandag01.properties,jppf.server.host, = ,MAIN +/conf/jppf-sandag01.properties,jppf.processing.threads, = ,THREADM +/conf/jppf-sandag02.properties,jppf.server.host, = ,MAIN +/conf/jppf-sandag02.properties,jppf.processing.threads, = ,THREADN1 +/conf/jppf-sandag03.properties,jppf.server.host, = ,MAIN +/conf/jppf-sandag03.properties,jppf.processing.threads, = ,THREADN2 +/conf/jppf-sandag04.properties,jppf.server.host, = ,MAIN +/conf/jppf-sandag04.properties,jppf.processing.threads, = ,THREADN3 +/conf/sandag_abm.properties,RunModel.MatrixServerAddress,=,ModelIP +/conf/sandag_abm.properties,RunModel.HouseholdServerAddress,=,ModelIP diff --git a/sandag_abm/src/main/resources/setup.bat b/sandag_abm/src/main/resources/setup.bat new file mode 100644 index 0000000..88bf3fe --- /dev/null +++ b/sandag_abm/src/main/resources/setup.bat @@ -0,0 +1 @@ +python ./src/main/python/pythonGUI/setup.py py2exe \ No newline at end of file diff --git a/sandag_abm/src/main/resources/stopABM.cmd b/sandag_abm/src/main/resources/stopABM.cmd new file mode 100644 index 0000000..509cfd6 --- /dev/null +++ b/sandag_abm/src/main/resources/stopABM.cmd @@ -0,0 +1,5 @@ +rem stopping all java processes on cluster + +%CD%\pskill \\${master.node.name} java.exe +%CD%\pskill \\${node.1.name} java.exe +%CD%\pskill \\${node.2.name} java.exe diff --git a/sandag_abm/src/main/resources/taskkill.bat b/sandag_abm/src/main/resources/taskkill.bat new file mode 100644 index 0000000..29cd2a6 --- /dev/null +++ b/sandag_abm/src/main/resources/taskkill.bat @@ -0,0 +1,2 @@ +rem kill java tasks +taskkill /F /IM java.exe \ No newline at end of file diff --git a/sandag_abm/src/main/resources/updateYearSpecificProps.bat b/sandag_abm/src/main/resources/updateYearSpecificProps.bat new file mode 100644 index 0000000..fe51ecd --- /dev/null +++ b/sandag_abm/src/main/resources/updateYearSpecificProps.bat @@ -0,0 +1,6 @@ +set PROJECT_DRIVE=%1 +set PROJECT_DIRECTORY=%2 + +%PROJECT_DRIVE% +cd %PROJECT_DRIVE%%PROJECT_DIRECTORY%\python +python.exe parameterUpdate.py diff --git a/sandag_abm/src/main/resources/w9xpopen.exe b/sandag_abm/src/main/resources/w9xpopen.exe new file mode 100644 index 0000000..f6033fd Binary files /dev/null and b/sandag_abm/src/main/resources/w9xpopen.exe differ diff --git a/sandag_rsm/__init__.py b/sandag_rsm/__init__.py index e5a0d9b..96299dd 100644 --- a/sandag_rsm/__init__.py +++ b/sandag_rsm/__init__.py @@ -1 +1,3 @@ -#!/usr/bin/env python3 +from .logging import logging_start + +logging_start(20) diff --git a/sandag_rsm/data_load/__init__.py b/sandag_rsm/data_load/__init__.py new file mode 100644 index 0000000..96370c6 --- /dev/null +++ b/sandag_rsm/data_load/__init__.py @@ -0,0 +1,44 @@ +import logging +import os +from pathlib import Path + +import requests + +logger = logging.getLogger(__name__) + + +def get_test_file(download_file, destination_dir="."): + """ + Download one or more test files from GitHib resources. + + Parameters + ---------- + download_file : str or list[str] + One or more test file names to download from GitHib resources. + destination_dir : path-like, optional + Location to save downloaded files. + + """ + os.makedirs(destination_dir, exist_ok=True) + resource_urls = [ + "https://media.githubusercontent.com/media/wsp-sag/client_sandag_rsm_resources/main/", + "https://raw.githubusercontent.com/wsp-sag/client_sandag_rsm_resources/main/", + "https://media.githubusercontent.com/media/camsys/client_sandag_rsm_resources/main/", + "https://raw.githubusercontent.com/camsys/client_sandag_rsm_resources/main/", + ] + if isinstance(download_file, (str, Path)): + if os.path.exists(os.path.join(destination_dir, download_file)): + logger.warning(f"file {download_file!r} already exists") + return + for resource_url in resource_urls: + r = requests.get((resource_url + download_file), allow_redirects=True) + if r.ok: + open(os.path.join(destination_dir, download_file), "wb").write( + r.content + ) + break + else: + raise FileNotFoundError(download_file) + else: + for f in download_file: + get_test_file(f, destination_dir) diff --git a/sandag_rsm/data_load/skims.py b/sandag_rsm/data_load/skims.py new file mode 100644 index 0000000..51dea70 --- /dev/null +++ b/sandag_rsm/data_load/skims.py @@ -0,0 +1,28 @@ +import os + +import openmatrix + + +def open_skims( + skims_filename="FromSANDAG-Files/traffic_skims_AM.omx", + data_dir=None, +): + + if data_dir is not None: + data_dir = os.path.expanduser(data_dir) + cwd = os.getcwd() + os.chdir(data_dir) + else: + cwd = None + + try: + s = openmatrix.open_file( + skims_filename, + mode="r", + ) + return s + + finally: + # change back to original cwd + if cwd is not None: + os.chdir(cwd) diff --git a/sandag_rsm/data_load/triplist.py b/sandag_rsm/data_load/triplist.py new file mode 100644 index 0000000..a1963ef --- /dev/null +++ b/sandag_rsm/data_load/triplist.py @@ -0,0 +1,106 @@ +import os + +import pandas as pd + + +def load_trip_list( + trips_filename="indivTripData_3.parquet", + data_dir=None, +): + if data_dir is not None: + data_dir = os.path.expanduser(data_dir) + cwd = os.getcwd() + os.chdir(data_dir) + else: + cwd = None + + try: + if trips_filename.endswith(".pq") or trips_filename.endswith(".parquet"): + trips = pd.read_parquet(trips_filename) + else: + trips = pd.read_csv(trips_filename) + return trips + + finally: + # change back to original cwd + os.chdir(cwd) + + +def trip_mode_shares_by_mgra( + trips, + background_per_mgra=50, + mgras=None, +): + trip_modes = { + 1: "Au", # Drive Alone + 2: "Au", # Shared Ride 2 + 3: "Au", # Shared Ride 3 + 4: "NM", # Walk + 5: "NM", # Bike + 6: "WT", # Walk to Transit + 7: "DT", # Park and Ride to Transit + 8: "DT", # Kiss and Ride to Transit + 9: "Au", # TNC to Transit + 10: "Au", # Taxi + 11: "Au", # TNC Single + 12: "Au", # TNC Shared + 13: "Au", # School Bus + } + trip_mode_cat = trips["trip_mode"].apply(trip_modes.get) + tmo = trips.groupby([trips.orig_mgra, trip_mode_cat]).size().unstack().fillna(0) + tmd = trips.groupby([trips.dest_mgra, trip_mode_cat]).size().unstack().fillna(0) + tm = tmo + tmd + tm_total = tm.sum() + background = background_per_mgra * tm_total / tm_total.sum() + if mgras is not None: + tm = tm.reindex(mgras).fillna(0) + tm = tm + background + tripmodeshare = tm.div(tm.sum(axis=1), axis=0) + return tripmodeshare + + +def trip_mode_shares_by_taz( + trips, + mgra_to_taz=None, + background_per_taz=50, + tazs=None, + mgra_gdf=None, +): + if mgra_gdf is not None and mgra_to_taz is None: + mgra_to_taz = pd.Series(mgra_gdf.taz.values, index=mgra_gdf.MGRA) + trip_modes = { + 1: "Au", # Drive Alone + 2: "Au", # Shared Ride 2 + 3: "Au", # Shared Ride 3 + 4: "NM", # Walk + 5: "NM", # Bike + 6: "WT", # Walk to Transit + 7: "DT", # Park and Ride to Transit + 8: "DT", # Kiss and Ride to Transit + 9: "Au", # TNC to Transit + 10: "Au", # Taxi + 11: "Au", # TNC Single + 12: "Au", # TNC Shared + 13: "Au", # School Bus + } + trip_mode_cat = trips["trip_mode"].apply(trip_modes.get) + tmo = ( + trips.groupby([trips.orig_mgra.map(mgra_to_taz), trip_mode_cat]) + .size() + .unstack() + .fillna(0) + ) + tmd = ( + trips.groupby([trips.dest_mgra.map(mgra_to_taz), trip_mode_cat]) + .size() + .unstack() + .fillna(0) + ) + tm = tmo + tmd + tm_total = tm.sum() + background = background_per_taz * tm_total / tm_total.sum() + if tazs is not None: + tm = tm.reindex(tazs).fillna(0) + tm = tm + background + tripmodeshare = tm.div(tm.sum(axis=1), axis=0) + return tripmodeshare diff --git a/sandag_rsm/data_load/zones.py b/sandag_rsm/data_load/zones.py new file mode 100644 index 0000000..06e6fea --- /dev/null +++ b/sandag_rsm/data_load/zones.py @@ -0,0 +1,96 @@ +import logging +import os +import warnings + +import geopandas as gpd +import pandas as pd +import pyproj +from shapely.ops import orient # version >=1.7a2 + +logger = logging.getLogger(__name__) + + +def geometry_cleanup(gdf): + gdf.geometry = gdf.geometry.apply(orient, args=(-1,)) + gdf.geometry = gdf.geometry.buffer(0) + return gdf + + +def simplify_shapefile( + shapefilename="MGRASHAPE.zip", + simplify_tolerance=1, + prequantize=False, + layername="MGRA", + topo=True, + output_filename=None, +): + if output_filename is not None: + gpkg_filename = output_filename + else: + gpkg_filename = ( + os.path.splitext(shapefilename)[0] + + f"_simplified_{simplify_tolerance}.gpkg" + ) + if os.path.exists(gpkg_filename): + gdf = gpd.read_file(gpkg_filename) + return geometry_cleanup(gdf) + gdf = gpd.read_file(shapefilename) + if topo: + try: + import topojson as tp + except ImportError: + warnings.warn("topojson is not installed") + gdf.geometry = gdf.geometry.simplify(simplify_tolerance) + return geometry_cleanup(gdf) + else: + logger.info("converting to epsg:3857") + gdf = gdf.to_crs(pyproj.CRS.from_epsg(3857)) + logger.info("creating topology") + topo = tp.Topology(gdf, prequantize=prequantize) + logger.info("simplifying topology") + topo = topo.toposimplify(simplify_tolerance) + logger.info("converting to gdf") + gdf = topo.to_gdf() + gdf.crs = pyproj.CRS.from_epsg(3857) + logger.info("checking orientation") + gdf.geometry = gdf.geometry.apply(orient, args=(-1,)) + logger.info("completed") + gdf.to_file(gpkg_filename, layer=layername, driver="GPKG") + return geometry_cleanup(gdf) + else: + if simplify_tolerance is not None: + gdf.geometry = gdf.geometry.simplify(simplify_tolerance) + return geometry_cleanup(gdf) + + +def load_mgra_data( + shapefilename="MGRASHAPE.zip", + supplemental_features="mgra13_based_input2016.csv.gz", + data_dir=None, + simplify_tolerance=1, + prequantize=False, + topo=True, +): + if data_dir is not None: + data_dir = os.path.expanduser(data_dir) + cwd = os.getcwd() + os.chdir(data_dir) + else: + cwd = None + + try: + gdf = simplify_shapefile( + shapefilename=shapefilename, + simplify_tolerance=simplify_tolerance, + layername="MGRA", + prequantize=prequantize, + topo=topo, + ) + sdf = pd.read_csv(supplemental_features) + mgra = gdf.merge(sdf, left_on="MGRA", right_on="mgra") + return mgra + + finally: + # change back to original cwd + if cwd is not None: + os.chdir(cwd) diff --git a/sandag_rsm/logging.py b/sandag_rsm/logging.py new file mode 100644 index 0000000..5af270d --- /dev/null +++ b/sandag_rsm/logging.py @@ -0,0 +1,28 @@ +import logging +import sys + + +class ElapsedTimeFormatter(logging.Formatter): + def format(self, record): + duration_milliseconds = record.relativeCreated + hours, rem = divmod(duration_milliseconds / 1000, 3600) + minutes, seconds = divmod(rem, 60) + if hours: + record.elapsedTime = "{:0>2}:{:0>2}:{:05.2f}".format( + int(hours), int(minutes), seconds + ) + else: + record.elapsedTime = "{:0>2}:{:05.2f}".format(int(minutes), seconds) + return super(ElapsedTimeFormatter, self).format(record) + + +def logging_start(level=None): + formatter = ElapsedTimeFormatter( + fmt="[{elapsedTime}] {levelname:s}: {message:s}", + style="{", + ) + handler = logging.StreamHandler(sys.stdout) + handler.setFormatter(formatter) + logging.getLogger().addHandler(handler) + if level is not None: + logging.getLogger().setLevel(level) diff --git a/sandag_rsm/poi.py b/sandag_rsm/poi.py new file mode 100644 index 0000000..d5c0a03 --- /dev/null +++ b/sandag_rsm/poi.py @@ -0,0 +1,93 @@ +import itertools +from pathlib import Path + +import pandas as pd +import pyproj +import shapely.geometry.point + +from .data_load.skims import open_skims + +# lat-lon of certain points +points_of_interest = dict( + san_diego_city_hall=(32.71691, -117.16282), + outside_pendleton_gate=(33.20722, -117.38973), + escondido_city_hall=(33.122711, -117.08309), + viejas_casino=(32.842097, -116.705582), + san_ysidro_trolley=(32.544536, -117.02963), +) + + +def poi_taz_mgra(gdf): + zones = {} + mgra4326 = gdf.to_crs(pyproj.CRS.from_epsg(4326)) + for name, latlon in points_of_interest.items(): + pt = shapely.geometry.point.Point(*reversed(latlon)) + y = mgra4326.contains(pt) + if y.sum() == 1: + target = mgra4326[y].iloc[0] + zones[name] = {"taz": target.taz, "mgra": target.mgra} + return zones + + +def attach_poi_taz_skims( + gdf, skims_omx, names, poi=None, data_dir=None, taz_col="taz", cluster_factors=None +): + """ + Attach TAZ-based skim values to rows of a geodataframe. + + Parameters + ---------- + gdf : GeoDataFrame + The skimmed values will be added as columns to this [geo]dataframe. + If the POI's are given explicitly, this could be a regular pandas + DataFrame, otherwise the geometry is used to find the TAZ's of the + points of interest. + skims_omx : path-like or openmatrix.File + names : str or Mapping + Keys give the names of matrix tables to load out of the skims file. + Values give the relative weight for each table (used later in + clustering). + poi : Mapping + Maps named points of interest to the 'taz' id of each. If not given, + these will be computed based on the `gdf`. + data_dir : path-like, optional + Directory where the `skims_omx` file can be found, if not the current + working directory. + cluster_factors : Mapping, optional + Existing cluster_factors, to which the new factors are added. + + Returns + ------- + gdf : GeoDataFrame + cluster_factors : Mapping + """ + if poi is None: + poi = poi_taz_mgra(gdf) + if isinstance(names, str): + names = {names: 1.0} + if isinstance(skims_omx, (str, Path)): + skims_omx = open_skims(skims_omx, data_dir=data_dir) + zone_nums = skims_omx.root.lookup.zone_number + cols = {} + for k in poi: + ktaz = poi[k][taz_col] + for name in names: + cols[f"{k}_{name}"] = pd.Series( + skims_omx.root.data[name][ktaz - 1], + index=zone_nums[:], + ) + add_to_gdf = {} + if taz_col in gdf: + gdf_taz_col = gdf[taz_col] + elif gdf.index.name == taz_col: + gdf_taz_col = pd.Series(data=gdf.index, index=gdf.index) + else: + raise KeyError(taz_col) + for c in cols: + add_to_gdf[c] = gdf_taz_col.map(cols[c]) + if cluster_factors is None: + cluster_factors = {} + new_cluster_factors = { + f"{i}_{j}": names[j] for i, j in itertools.product(poi.keys(), names.keys()) + } + return gdf.assign(**add_to_gdf), cluster_factors | new_cluster_factors diff --git a/sandag_rsm/translate.py b/sandag_rsm/translate.py new file mode 100644 index 0000000..c1fde7a --- /dev/null +++ b/sandag_rsm/translate.py @@ -0,0 +1,101 @@ +import os +import logging +import pandas as pd +from pathlib import Path +import openmatrix as omx + +logger = logging.getLogger(__name__) + + +def _aggregate_matrix(input_mtx, aggregate_mapping_dict): + matrix_array = input_mtx.read() + matrix_df = pd.DataFrame(matrix_array, columns = list(aggregate_mapping_dict.keys())) + + matrix_agg_df = matrix_df.rename(columns=(aggregate_mapping_dict)) + matrix_agg_df.index = list(aggregate_mapping_dict.values()) + + matrix_agg_df = matrix_agg_df.stack().groupby(level=[0,1]).sum().unstack() + matrix_agg_df = matrix_agg_df[sorted(matrix_agg_df.columns)] + matrix_agg_df = matrix_agg_df.sort_index() + + output_mtx = matrix_agg_df.to_numpy() + + return output_mtx + + +def translate_demand( + matrix_names, + agg_zone_mapping, + input_dir=".", + output_dir="." +): + """ + aggregates the omx demand matrix to aggregated zone system + + Parameters + ---------- + matrix_names : list + omx matrix filenames to aggregate + agg_zone_mapping: Path-like or pandas.DataFrame + zone number mapping between original and aggregated zones. + columns: original zones as 'taz' and aggregated zones as 'cluster_id' + input_dir : Path-like, default "." + output_dir : Path-like, default "." + + Returns + ------- + + """ + + input_dir = Path(input_dir or ".") + output_dir = Path(output_dir or ".") + + def _resolve_df(x): + if isinstance(x, (str, Path)): + # read in the file to a pandas DataFrame + x = Path(x).expanduser() + if not x.is_absolute(): + x = x.absolute() + try: + result = pd.read_csv(x) + except FileNotFoundError: + raise + elif isinstance(x, pd.DataFrame): + result = x + else: + raise TypeError(x + " must be path-like or DataFrame") + + return result + + agg_zone_mapping_df = _resolve_df(agg_zone_mapping) + agg_zone_mapping_df = agg_zone_mapping_df.sort_values('taz') + + zone_mapping = dict(zip(agg_zone_mapping_df['taz'], agg_zone_mapping_df['cluster_id'])) + agg_zones = sorted(agg_zone_mapping_df['cluster_id'].unique()) + + for mat_name in matrix_names: + if '.omx' not in mat_name: + mat_name = mat_name + ".omx" + + logger.info("Aggregating Matrix: " + mat_name + " ...") + + input_skim_file = Path(input_dir).expanduser().joinpath(mat_name) + output_skim_file = Path(output_dir).expanduser().joinpath(mat_name) + + assert os.path.isfile(input_skim_file) + + input_matrix = omx.open_file(input_skim_file, mode="r") + input_mapping_name = input_matrix.list_mappings()[0] + input_cores = input_matrix.list_matrices() + + output_matrix = omx.open_file(output_skim_file, mode="w") + + for core in input_cores: + matrix = input_matrix[core] + matrix_agg = _aggregate_matrix(matrix, zone_mapping) + output_matrix[core] = matrix_agg + + output_matrix.create_mapping(title=input_mapping_name, entries=agg_zones) + + input_matrix.close() + output_matrix.close() \ No newline at end of file diff --git a/sandag_rsm/zone_agg.py b/sandag_rsm/zone_agg.py new file mode 100644 index 0000000..1e8b160 --- /dev/null +++ b/sandag_rsm/zone_agg.py @@ -0,0 +1,493 @@ +import logging +from functools import partial +from numbers import Number +from statistics import mode + +import geopandas as gpd +import networkx as nx +import numpy as np +import pandas as pd +import pyproj +from scipy.optimize import minimize_scalar +from sklearn.cluster import AgglomerativeClustering, KMeans +from sklearn.preprocessing import OneHotEncoder + +logger = logging.getLogger(__name__) + + +def merge_zone_data( + gdf, + agg_instruction=None, + cluster_id="cluster_id", +): + if agg_instruction is None: + # make a sliver of area series as a backstop for weighted avg on other things + # we add this small value to each weighting, so that if the desired weighting values + # are all zero for any weighted average, the geographic area becomes the backup + # weight ... and if any are non-zero, then these areas round off to effectively nil. + gdf_area_small = gdf.area / gdf.area.mean() / 1000 + + def wgt_avg_by(x, c): + try: + return np.average( + x, weights=gdf.loc[x.index, c] + gdf_area_small.loc[x.index] + ) + except ZeroDivisionError: + return np.average(x) + + wgt_avg_by_hh = lambda x: wgt_avg_by(x, "hh") + wgt_avg_hpc = lambda x: wgt_avg_by(x, "hstallssam") + wgt_avg_dpc = lambda x: wgt_avg_by(x, "dstallssam") + wgt_avg_mpc = lambda x: wgt_avg_by(x, "mstallssam") + wgt_avg_by_pop = lambda x: wgt_avg_by(x, "pop") + wgt_avg_empden = lambda x: wgt_avg_by(x, "emp_total") + wgt_avg_popden = lambda x: wgt_avg_by(x, "pop") + wgt_avg_rtempden = lambda x: wgt_avg_by(x, "emp_retail") + + def wgt_avg_peden(x): + try: + return np.average( + x, + weights=gdf.loc[x.index, "emp_total"] + + gdf.loc[x.index, "pop"] + + gdf_area_small.loc[x.index], + ) + except ZeroDivisionError: + return np.average(x) + + get_mode = lambda x: mode(x) + agg_instruction = { + "hs": "sum", + "hs_sf": "sum", + "hs_mf": "sum", + "hs_mh": "sum", + "hh": "sum", + "hh_sf": "sum", + "hh_mf": "sum", + "hh_mh": "sum", + "gq_civ": "sum", + "gq_mil": "sum", + "i1": "sum", + "i2": "sum", + "i3": "sum", + "i4": "sum", + "i5": "sum", + "i6": "sum", + "i7": "sum", + "i8": "sum", + "i9": "sum", + "i10": "sum", + "hhs": wgt_avg_by_hh, + "pop": "sum", + "hhp": "sum", + "emp_ag": "sum", + "emp_const_non_bldg_prod": "sum", + "emp_const_non_bldg_office": "sum", + "emp_utilities_prod": "sum", + "emp_utilities_office": "sum", + "emp_const_bldg_prod": "sum", + "emp_const_bldg_office": "sum", + "emp_mfg_prod": "sum", + "emp_mfg_office": "sum", + "emp_whsle_whs": "sum", + "emp_trans": "sum", + "emp_retail": "sum", + "emp_prof_bus_svcs": "sum", + "emp_prof_bus_svcs_bldg_maint": "sum", + "emp_pvt_ed_k12": "sum", + "emp_pvt_ed_post_k12_oth": "sum", + "emp_health": "sum", + "emp_personal_svcs_office": "sum", + "emp_amusement": "sum", + "emp_hotel": "sum", + "emp_restaurant_bar": "sum", + "emp_personal_svcs_retail": "sum", + "emp_religious": "sum", + "emp_pvt_hh": "sum", + "emp_state_local_gov_ent": "sum", + "emp_fed_non_mil": "sum", + "emp_fed_mil": "sum", + "emp_state_local_gov_blue": "sum", + "emp_state_local_gov_white": "sum", + "emp_public_ed": "sum", + "emp_own_occ_dwell_mgmt": "sum", + "emp_fed_gov_accts": "sum", + "emp_st_lcl_gov_accts": "sum", + "emp_cap_accts": "sum", + "emp_total": "sum", + "enrollgradekto8": "sum", + "enrollgrade9to12": "sum", + "collegeenroll": "sum", + "othercollegeenroll": "sum", + "adultschenrl": "sum", + "ech_dist": get_mode, + "hch_dist": get_mode, + "parkarea": "max", + "hstallsoth": "sum", + "hstallssam": "sum", + "hparkcost": wgt_avg_hpc, + "numfreehrs": wgt_avg_hpc, + "dstallsoth": "sum", + "dstallssam": "sum", + "dparkcost": wgt_avg_dpc, + "mstallsoth": "sum", + "mstallssam": "sum", + "mparkcost": wgt_avg_mpc, + "parkactive": "sum", + "openspaceparkpreserve": "sum", + "beachactive": "sum", + "budgetroom": "sum", + "economyroom": "sum", + "luxuryroom": "sum", + "midpriceroom": "sum", + "upscaleroom": "sum", + "hotelroomtotal": "sum", + # "luz_id": "sum", + "truckregiontype": "sum", + "district27": get_mode, + "milestocoast": wgt_avg_by_pop, + # "acres": "sum", + # "effective_acres": "sum", + # "land_acres": "sum", + "MicroAccessTime": wgt_avg_by_pop, + "remoteAVParking": "max", + "refueling_stations": "sum", + "totint": "sum", + "duden": wgt_avg_by_hh, + "empden": wgt_avg_empden, + "popden": wgt_avg_popden, + "retempden": wgt_avg_rtempden, + # "totintbin": "sum", #bins in original data 0, 80, 130 + # "empdenbin": "sum", #bins in original data 0, 10, 30 + # "dudenbin": "sum", #bins in original data 0, 5, 10 + "PopEmpDenPerMi": wgt_avg_peden, + } + + dissolved = gdf[[cluster_id, "geometry"]].dissolve(by=cluster_id) + other_data = gdf.groupby(cluster_id).agg(agg_instruction) + dissolved = dissolved.join(other_data) + + # adding bins + dissolved["totintbin"] = 1 + dissolved.loc[ + (dissolved["totintbin"] >= 80) & (dissolved["totintbin"] < 130), "totintbin" + ] = 2 + dissolved.loc[(dissolved["totintbin"] >= 130), "totintbin"] = 3 + + dissolved["empdenbin"] = 1 + dissolved.loc[ + (dissolved["empdenbin"] >= 10) & (dissolved["empdenbin"] < 30), "empdenbin" + ] = 2 + dissolved.loc[(dissolved["empdenbin"] >= 30), "empdenbin"] = 3 + + dissolved["dudenbin"] = 1 + dissolved.loc[ + (dissolved["dudenbin"] >= 5) & (dissolved["dudenbin"] < 10), "dudenbin" + ] = 2 + dissolved.loc[(dissolved["dudenbin"] >= 10), "dudenbin"] = 3 + + return dissolved + + +def aggregate_zones( + mgra_gdf, + method="kmeans", + n_zones=2000, + random_state=0, + cluster_factors=None, + cluster_factors_onehot=None, + use_xy=True, + explicit_agg=(), + explicit_col="mgra", + agg_instruction=None, + start_cluster_ids=13, +): + """ + Aggregate zones. + + Parameters + ---------- + mgra_gdf : GeoDataFrame + Geometry and attibutes of MGRAs + method : {'kmeans', 'agglom', 'agglom_adj'} + n_zones : int + random_state : RandomState or int + cluster_factors : dict + cluster_factors_onehot : dict + use_xy : bool + Use X and Y coordinates as a cluster factor + explicit_agg : list[int or list] + A list containing integers (individual MGRAs that should not be aggregated) + or lists of integers (groups of MGRAs that should be aggregated exactly as + given, with no less and no more) + explicit_col : str + The name of the column containing the ID's from `explicit_agg`, usually + 'mgra' or 'taz' + agg_instruction : dict + Dictionary passed to pandas `agg` that says how to aggregate data columns. + start_cluster_ids : int, default 13 + Cluster id's start at this value. Can be 1, but typically SANDAG has the + smallest id's reserved for external zones, so starting at a greater value + is typical. + + Returns + ------- + GeoDataFrame + """ + + if cluster_factors is None: + cluster_factors = {} + + n = start_cluster_ids + if explicit_agg: + explicit_agg_ids = {} + for i in explicit_agg: + if isinstance(i, Number): + explicit_agg_ids[i] = n + else: + for j in i: + explicit_agg_ids[j] = n + n += 1 + if explicit_col == mgra_gdf.index.name: + mgra_gdf = mgra_gdf.reset_index() + mgra_gdf.index = mgra_gdf[explicit_col] + in_explicit = mgra_gdf[explicit_col].isin(explicit_agg_ids) + mgra_gdf_algo = mgra_gdf.loc[~in_explicit].copy() + mgra_gdf_explicit = mgra_gdf.loc[in_explicit].copy() + mgra_gdf_explicit["cluster_id"] = mgra_gdf_explicit[explicit_col].map( + explicit_agg_ids + ) + n_zones_algorithm = n_zones - len( + mgra_gdf_explicit["cluster_id"].value_counts() + ) + else: + mgra_gdf_algo = mgra_gdf.copy() + mgra_gdf_explicit = None + n_zones_algorithm = n_zones + + if use_xy: + geometry = mgra_gdf_algo.centroid + X = list(geometry.apply(lambda p: p.x)) + Y = list(geometry.apply(lambda p: p.y)) + factors = [np.asarray(X) * use_xy, np.asarray(Y) * use_xy] + else: + factors = [] + for cf, cf_wgt in cluster_factors.items(): + factors.append(cf_wgt * mgra_gdf_algo[cf].values.astype(np.float32)) + if cluster_factors_onehot: + for cf, cf_wgt in cluster_factors_onehot.items(): + factors.append(cf_wgt * OneHotEncoder().fit_transform(mgra_gdf_algo[[cf]])) + from scipy.sparse import hstack + + factors2d = [] + for j in factors: + if j.ndim < 2: + factors2d.append(np.expand_dims(j, -1)) + else: + factors2d.append(j) + data = hstack(factors2d).toarray() + else: + data = np.array(factors).T + + if method == "kmeans": + kmeans = KMeans(n_clusters=n_zones_algorithm, random_state=random_state) + kmeans.fit(data) + cluster_id = kmeans.labels_ + elif method == "agglom": + agglom = AgglomerativeClustering( + n_clusters=n_zones_algorithm, affinity="euclidean", linkage="ward" + ) + agglom.fit_predict(data) + cluster_id = agglom.labels_ + elif method == "agglom_adj": + from libpysal.weights import Rook + + w_rook = Rook.from_dataframe(mgra_gdf_algo) + adj_mat = nx.adjacency_matrix(w_rook.to_networkx()) + agglom = AgglomerativeClustering( + n_clusters=n_zones_algorithm, + affinity="euclidean", + linkage="ward", + connectivity=adj_mat, + ) + agglom.fit_predict(data) + cluster_id = agglom.labels_ + else: + raise NotImplementedError(method) + mgra_gdf_algo["cluster_id"] = cluster_id + + if mgra_gdf_explicit is None or len(mgra_gdf_explicit) == 0: + combined = merge_zone_data( + mgra_gdf_algo, + agg_instruction, + cluster_id="cluster_id", + ) + combined["cluster_id"] = list(range(n, n + n_zones_algorithm)) + else: + pending = [] + for df in [mgra_gdf_algo, mgra_gdf_explicit]: + logger.info(f"... merging {len(df)}") + pending.append( + merge_zone_data( + df, + agg_instruction, + cluster_id="cluster_id", + ).reset_index() + ) + + pending[0]["cluster_id"] = list(range(n, n + n_zones_algorithm)) + + pending[0] = pending[0][ + [c for c in pending[1].columns if c in pending[0].columns] + ] + pending[1] = pending[1][ + [c for c in pending[0].columns if c in pending[1].columns] + ] + combined = pd.concat(pending, ignore_index=False) + combined = combined.reset_index(drop=True) + + return combined + + +def _scale_zones(x, zones_by_district, district_focus): + x = np.abs(x) + agg_by_district = pd.Series(zones_by_district) * x + for i, j in district_focus.items(): + agg_by_district[i] *= j + agg_by_district = np.minimum(agg_by_district, zones_by_district) + agg_by_district = np.maximum(agg_by_district, 1) + return agg_by_district + + +def _rescale_zones(x, n_z, zones_by_district, district_focus): + return (_scale_zones(x, zones_by_district, district_focus).sum() - n_z) ** 2 + + +def aggregate_zones_within_districts( + mgra_gdf, + method="kmeans", + n_zones=2000, + random_state=0, + cluster_factors=None, + cluster_factors_onehot=None, + use_xy=True, + explicit_agg=(), + explicit_col="mgra", + agg_instruction=None, + district_col="district27", + district_focus=None, +): + logger.info("aggregate_zones_within_districts...") + if district_focus is None: + district_focus = {} + zones_by_district = mgra_gdf[district_col].value_counts() + rescale_zones = partial( + _rescale_zones, + n_z=n_zones, + zones_by_district=zones_by_district, + district_focus=district_focus, + ) + zone_factor = minimize_scalar(rescale_zones).x + agg_by_district = ( + _scale_zones(zone_factor, zones_by_district, district_focus).round().astype(int) + ) + out = [] + for district_n, district_z in agg_by_district.items(): + district_gdf = mgra_gdf[mgra_gdf[district_col] == district_n] + logger.info( + f"combining district {district_n} from {len(district_gdf)} zones into {district_z} zones" + ) + out.append( + aggregate_zones( + district_gdf, + method=method, + n_zones=district_z, + random_state=random_state + district_n, + cluster_factors=cluster_factors, + cluster_factors_onehot=cluster_factors_onehot, + use_xy=use_xy, + explicit_agg=explicit_agg, + explicit_col=explicit_col, + agg_instruction=agg_instruction, + ) + ) + return pd.concat(out).reset_index(drop=True) + + +def make_crosswalk(new_zones, old_zones, new_index="cluster_id", old_index=None): + if new_index is not None and ( + new_index in new_zones.columns or not isinstance(new_index, str) + ): + new_zones = new_zones.set_index(new_index) + if old_index is not None and ( + old_index in old_zones.columns or not isinstance(old_index, str) + ): + old_zones = old_zones.set_index(old_index) + crosswalk = new_zones[["geometry"]].sjoin( + gpd.GeoDataFrame( + geometry=old_zones.representative_point(), + index=old_zones.index, + ).to_crs(new_zones.crs), + how="right", + predicate="contains", + ) + crosswalk = crosswalk["index_left"].astype(int).rename(new_index).to_frame() + if old_zones.index.name: + crosswalk = crosswalk.rename_axis(index=old_zones.index.name) + return crosswalk.reset_index() + + +def mark_centroids(gdf, crs="NAD 1983 StatePlane California VI FIPS 0406 Feet"): + c = gdf.to_crs(crs).centroid + gdf["centroid_x"] = c.x.astype(int) + gdf["centroid_y"] = c.y.astype(int) + return gdf + + +def viewer( + gdf, + *, + simplify_tolerance=None, + color=None, + transparent=False, + **kwargs, +): + import plotly.express as px + + gdf = gdf.copy() + if simplify_tolerance is not None: + gdf.geometry = gdf.geometry.simplify(tolerance=simplify_tolerance) + gdf = gdf.to_crs(pyproj.CRS.from_epsg(4326)) + kwargs1 = {} + if color is not None: + kwargs1["color"] = color + fig = px.choropleth( + gdf, + geojson=gdf.geometry, + locations=gdf.index, + **kwargs1, + ) + fig.update_shapes() + fig.update_geos( + visible=False, + fitbounds="locations", + ) + fig.update_layout(height=300, margin={"r": 0, "t": 0, "l": 0, "b": 0}) + if kwargs: + fig.update_traces(**kwargs) + if transparent: + fig.update_traces( + colorscale=((0.0, "rgba(0, 0, 0, 0.0)"), (1.0, "rgba(0, 0, 0, 0.0)")) + ) + return fig + + +def viewer2( + edges, + colors, + color_col, +): + coloring_map = viewer(colors, color=color_col, marker_line_width=0) + edge_map = viewer(edges, transparent=True, marker_line_color="white") + coloring_map.add_trace(edge_map.data[0]) + return coloring_map diff --git a/setup.cfg b/setup.cfg index dcad608..ef2a05f 100644 --- a/setup.cfg +++ b/setup.cfg @@ -9,14 +9,15 @@ include_package_data = True python_requires = >=3.7 install_requires = numpy >= 1.19 - pandas - scikit-learn geopandas libpysal - pyproj - plotly networkx - + openmatrix + pandas + plotly + pyarrow + pyproj + scikit-learn [flake8] exclude = diff --git a/test/data/prepare_test_data.py b/test/data/prepare_test_data.py new file mode 100644 index 0000000..8b27f01 --- /dev/null +++ b/test/data/prepare_test_data.py @@ -0,0 +1,61 @@ +# SANDAG Test Data Generator +# This script create the minimal test data for the SANDAG RSM, from +# an original full-scale data source. + +import gzip +import os +import shutil +from pathlib import Path + +import numpy as np +import openmatrix as omx +import pandas as pd + +from sandag_rsm.data_load.zones import simplify_shapefile + +this_dir = Path(os.path.dirname(__file__)) + + +def mgra_geopackage(shapefilename="MGRASHAPE.zip"): + simplify_shapefile( + shapefilename=shapefilename, + simplify_tolerance=10, + prequantize=False, + layername="MGRA", + topo=True, + output_filename=this_dir / "MGRASHAPE_simplified_10.gpkg", + ) + + +def mini_skim(full_skim="Data/traffic_skims_AM.omx", tablename="AM_SOV_TR_M_TIME"): + output_filename = this_dir / "traffic_skims_AM_mini.omx" + f = omx.open_file(full_skim, mode="r") + out = omx.open_file(str(output_filename), mode="w") + out[tablename] = f[tablename][:].astype(np.float32) + out.create_array( + "/lookup", + "zone_number", + f.root["lookup"]["zone_number"][:], + ) + out.flush() + out.close() + f.close() + + +def gz_copy(in_file, out_file="mgra13_based_input2016.csv.gz"): + with open(in_file, "rb") as f_in: + with gzip.open(out_file, "wb") as f_out: + shutil.copyfileobj(f_in, f_out) + + +def sample_trips(in_file="indivTripData_3.csv.gz", out_file="trips_sample.pq"): + trips = pd.read_csv(in_file) + trips = trips.iloc[::25] + trips.to_parquet(out_file) + + +if __name__ == "__main__": + mgra_geopackage(shapefilename="Data/MGRASHAPE.zip") + mini_skim("Data/traffic_skims_AM.omx", "AM_SOV_TR_M_TIME") + gz_copy("Data/mgra13_based_input2016.csv") + sample_trips("Data/indivTripData_3.csv.gz")