diff --git a/.github/workflows/CI.yml b/.github/workflows/CI.yml new file mode 100644 index 0000000..3b1d808 --- /dev/null +++ b/.github/workflows/CI.yml @@ -0,0 +1,59 @@ +name: CI +on: + push: + branches: + - main + tags: '*' + pull_request: +concurrency: + # Skip intermediate builds: always. + # Cancel intermediate builds: only if it is a pull request build. + group: ${{ github.workflow }}-${{ github.ref }} + cancel-in-progress: ${{ startsWith(github.ref, 'refs/pull/') }} +jobs: + test: + name: Julia ${{ matrix.version }} - ${{ matrix.os }} - ${{ matrix.arch }} - ${{ github.event_name }} + runs-on: ${{ matrix.os }} + strategy: + fail-fast: false + matrix: + version: + - '1.6' + - '1.7' + - 'nightly' + os: + - ubuntu-latest + - macOS-latest + - windows-latest + arch: + # - x86 + - x64 + # - aarch64 + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@v1 + with: + version: ${{ matrix.version }} + arch: ${{ matrix.arch }} + - uses: julia-actions/cache@v1 + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-runtest@v1 + docs: + name: Documentation + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: julia-actions/setup-julia@v1 + with: + version: '1' + - uses: julia-actions/julia-buildpkg@v1 + - uses: julia-actions/julia-docdeploy@v1 + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} + - run: | + julia --project=docs -e ' + using Documenter: DocMeta, doctest + using TrainRuns + DocMeta.setdocmeta!(TrainRuns, :DocTestSetup, :(using TrainRuns); recursive=true) + doctest(TrainRuns)' diff --git a/.github/workflows/CompatHelper.yml b/.github/workflows/CompatHelper.yml new file mode 100644 index 0000000..cba9134 --- /dev/null +++ b/.github/workflows/CompatHelper.yml @@ -0,0 +1,16 @@ +name: CompatHelper +on: + schedule: + - cron: 0 0 * * * + workflow_dispatch: +jobs: + CompatHelper: + runs-on: ubuntu-latest + steps: + - name: Pkg.add("CompatHelper") + run: julia -e 'using Pkg; Pkg.add("CompatHelper")' + - name: CompatHelper.main() + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + COMPATHELPER_PRIV: ${{ secrets.DOCUMENTER_KEY }} + run: julia -e 'using CompatHelper; CompatHelper.main()' diff --git a/.github/workflows/TagBot.yml b/.github/workflows/TagBot.yml new file mode 100644 index 0000000..f49313b --- /dev/null +++ b/.github/workflows/TagBot.yml @@ -0,0 +1,15 @@ +name: TagBot +on: + issue_comment: + types: + - created + workflow_dispatch: +jobs: + TagBot: + if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' + runs-on: ubuntu-latest + steps: + - uses: JuliaRegistries/TagBot@v1 + with: + token: ${{ secrets.GITHUB_TOKEN }} + ssh: ${{ secrets.DOCUMENTER_KEY }} diff --git a/.github/workflows/register.yml b/.github/workflows/register.yml new file mode 100644 index 0000000..6e71f2f --- /dev/null +++ b/.github/workflows/register.yml @@ -0,0 +1,14 @@ +name: Register Package +on: + workflow_dispatch: + inputs: + version: + description: Version to register or component to bump + required: true +jobs: + register: + runs-on: ubuntu-latest + steps: + - uses: julia-actions/RegisterAction@latest + with: + token: ${{ secrets.GITHUB_TOKEN }} diff --git a/CHANGELOG.md b/CHANGELOG.md index 9f17d0c..9ccca20 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -9,6 +9,36 @@ Categories: Added, Changed, Deprecated, Removed, Fixed, and Security. ## [Unreleased] +### Added +* dependency JSONSchema +* validation of YAML input via JSON schema + +### Changed +* renamed TrainRun into TrainRuns +* replaced settings::Dict with type Settings as struct +* replaced path::Dict with type Path as struct +* replaced train::Dict with type Train as struct +* restructured examples/ and data/ in docs/ and test/ +* modified test to work with Julia Testsets and with simplier naming of input files +* renamed Validate.jl into types.jl +* renamed TrainRunCalc.jl into calc.jl +* moved trainrun function from calc.jl to TrainRun.jl +* moved createDataPoint() from behavior.jl to types.jl +* moved createBehaviorSection() from behavior.jl to types.jl +* moved createMovingSection() from characteristics.jl to types.jl +* moved createCharacteristicSection() from characteristics.jl to types.jl +* changed title of include files from upper case to lower case +* changed seperation of submodules into a single module with file include +* updated test files to railtoolkit/schema (2022.05) + +### Removed +* dependency Plots and CSV +* AdditionalOutput.jl +* EnergySaving.jl +* test/testEnums.jl +* import.jl +* export.jl +* settings for CSV export ## Version [0.8] 2022-01-20 @@ -142,18 +172,18 @@ Modules and variables were renamed. Proof of concept and master thesis submission. -[Unreleased]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.8...master -[0.8]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.7...v0.8 -[0.7]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.6.2...v0.7 -[0.6.2]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.6.1...v0.6.2 -[0.6.1]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.6...v0.6.1 -[0.6]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.5.3...v0.6 -[0.5.3]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.5.2...v0.5.3 -[0.5.2]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.5.1...v0.5.2 -[0.5.1]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.5...v0.5.1 -[0.5]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.4.1...v0.5 -[0.4.1]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.4...v0.4.1 -[0.4]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.3...v0.4 -[0.3]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.2...v0.3 -[0.2]: https://github.com/railtoolkit/TrainRun.jl/compare/v0.1...v0.2 -[0.1]: https://github.com/railtoolkit/TrainRun.jl/releases/tag/v0.1 \ No newline at end of file +[Unreleased]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.8...main +[0.8]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.7...v0.8 +[0.7]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.6.2...v0.7 +[0.6.2]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.6.1...v0.6.2 +[0.6.1]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.6...v0.6.1 +[0.6]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.5.3...v0.6 +[0.5.3]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.5.2...v0.5.3 +[0.5.2]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.5.1...v0.5.2 +[0.5.1]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.5...v0.5.1 +[0.5]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.4.1...v0.5 +[0.4.1]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.4...v0.4.1 +[0.4]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.3...v0.4 +[0.3]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.2...v0.3 +[0.2]: https://github.com/railtoolkit/TrainRuns.jl/compare/v0.1...v0.2 +[0.1]: https://github.com/railtoolkit/TrainRuns.jl/releases/tag/v0.1 \ No newline at end of file diff --git a/CITATION.cff b/CITATION.cff index f2822e0..7b696cd 100644 --- a/CITATION.cff +++ b/CITATION.cff @@ -3,7 +3,7 @@ # Visit https://bit.ly/cffinit to generate yours today! --- cff-version: 1.2.0 -title: TrainRun.jl +title: TrainRuns.jl message: 'If you use this software, please cite it using these metadata.' type: software authors: @@ -22,12 +22,12 @@ identifiers: - type: doi value: 10.5281/zenodo.6448564 description: Current version -url: 'https://www.railtoolkit.org/projects/TrainRun.jl/' -repository: 'https://github.com/railtoolkit/TrainRun.jl' +url: 'https://www.railtoolkit.org/projects/TrainRuns.jl/' +repository: 'https://github.com/railtoolkit/TrainRuns.jl' abstract: >- - TrainRun.jl is a step towards open science and open data in railway engineering. + TrainRuns.jl is a step towards open science and open data in railway engineering. Its modular design offers the possibility to serve as a basis for future - optimization and development. TrainRun.jl is suitable for qualitative + optimization and development. TrainRuns.jl is suitable for qualitative calculations to compare different trains, and it is publicly available, and we invite others to collaborate. keywords: diff --git a/CODE_OF_CONDUCT.md b/CODE_OF_CONDUCT.md index 561c180..d14ad9e 100644 --- a/CODE_OF_CONDUCT.md +++ b/CODE_OF_CONDUCT.md @@ -55,7 +55,7 @@ further defined and clarified by project maintainers. ## Enforcement Instances of abusive, harassing, or otherwise unacceptable behavior may be -reported by contacting the project team at [INSERT EMAIL ADDRESS]. All +reported by contacting the project team at railtoolkit@ownx.net. All complaints will be reviewed and investigated and will result in a response that is deemed necessary and appropriate to the circumstances. The project team is obligated to maintain confidentiality with regard to the reporter of an incident. diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 4743fbf..df36fce 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -5,7 +5,83 @@ email, or any other method with the owners of this repository before making a ch Please note we have a code of conduct, please follow it in all your interactions with the project. -# Pull Request Process +## Julia Development Environment - * add your changes to the CHANGELOG.md under [Unreleased] - * TODO! \ No newline at end of file +Link your local git repository to Julia: +```console +$ ln -s ~/path/to/TrainRuns.jl ~/.julia/dev/TrainRuns +``` + +Have a look how to develop Julia packages: https://github.com/ShozenD/julia-pkg-dev +You might want to use `Revise.jl` as well: +```julia +Pkg.add("Revise") +``` +and then just load with `using Revise` (preferably by putting it in the `~/.julia/config/startup.jl` file). + +You can overide the standard TrainRuns package with the local development branch (see linking above) with: +```julia +julia> # use the ] key +(@v1.x) pkg> develop TrainRuns +(@v1.x) pkg> # use backspace +julia> using TrainRuns # local development branch will be loaded +``` + +If you want to add a dependency use: +```julia +julia> # use the ] key +(@v1.x) pkg> activate TrainRuns +(TrainRuns) pkg> +``` + +## Files in TrainRuns + +| file | concern | +| --------------- | ------------------------------ | +| TrainRuns.jl | main file and function | +| types.jl | special TrainRuns types | +| constructors.jl | type constructors | +| formulary.jl | formulars from literature | +| output.jl | transformation into DataFrames | + +## Reporting Issues + +* It's always good to start with a quick search for an existing issue to post on, + or related issues for context, before opening a new issue +* Including minimal examples is greatly appreciated +* If it's a bug, or unexpected behaviour, reproducing on the latest development version + (`Pkg.add(name="TrainRuns", rev="main")`) is a good gut check and can streamline the process, + along with including the first two lines of output from `versioninfo()` + +## Style Guidelines + +TODO + +## Git Recommendations For Pull Requests + +* Avoid working from the `main` branch of your fork, creating a new branch will make it + easier if TrainRuns.jl `main` branch changes and you need to update your pull request; +* All PRs and issues should be opened against the `main` branch not against the current release; +* Run tests of your code before sending any commit to GitHub. Only push changes when + the tests of the change are passing locally. In particular note that it is not a problem + if you send several commits in one push command to GitHub as CI will be run only once then; +* If any conflicts arise due to changes in TrainRuns.jl `main` branch, prefer updating your pull + request branch with `git rebase` (rather than `git merge`), since the latter will introduce a merge + commit that might confuse GitHub when displaying the diff of your PR, which makes your changes more + difficult to review. Alternatively use conflict resolution tool available at GitHub; +* Please try to use descriptive commit messages to simplify the review process; +* Using `git add -p` or `git add -i` can be useful to avoid accidently committing unrelated changes; +* Maintainers get notified of all changes made on GitHub. However, what is useful is writing a short + message after a sequence of changes is made summarizing what has changed and that the PR is ready + for a review; +* When linking to specific lines of code in discussion of an issue or pull request, hit the `y` key + while viewing code on GitHub to reload the page with a URL that includes the specific commit that + you're viewing. That way any lines of code that you refer to will still be correct in the future, even + if additional commits are pushed to the branch you are reviewing; +* Please make sure you follow the code formatting guidelines when submitting a PR; + Also preferably do not modify parts of code that you are not editing as this makes + reviewing the PR harder (it is better to open a separate maintenance PR + if e.g. code layout can be improved); +* If a PR is not finished yet and should not be reviewed yet then it should be opened as DRAFT + (in this way maintainers will know that they can ignore such PR until it is made non-draft or the author + asks for a review). diff --git a/LICENSE b/LICENSE index f71894f..b5a52ad 100644 --- a/LICENSE +++ b/LICENSE @@ -1,6 +1,6 @@ ISC License (ISC) -Copyright 2021 Max Kannenberg +Copyright 2022 Max Kannenberg, Martin Scheidt Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice diff --git a/Project.toml b/Project.toml index c387903..00f601c 100644 --- a/Project.toml +++ b/Project.toml @@ -1,12 +1,24 @@ -name = "TrainRun" +name = "TrainRuns" uuid = "e4541106-d44c-4e00-b50b-ecdf479fcf92" -authors = ["Max Kannenberg"] +authors = ["Max Kannenberg", "Martin Scheidt", "contributors"] version = "0.8.0" [deps] -CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Dates = "ade2ca70-3891-5945-98fb-dc099432e06a" -Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80" -Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" +JSONSchema = "7d188eb4-7ad8-530c-ae41-71a32a6d4692" +Statistics = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" +UUIDs = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" YAML = "ddb6d928-2868-570f-bddf-ab3f9cf99eb6" + +[compat] +DataFrames = "^1" +JSONSchema = "^1" +YAML = "^0" +julia = "^1.6" + +[extras] +Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" + +[targets] +test = ["Test"] diff --git a/README.md b/README.md index 88d15dc..68dd68f 100644 --- a/README.md +++ b/README.md @@ -1,40 +1,43 @@ -# TrainRun +# TrainRuns -[![License: ISC](https://img.shields.io/badge/license-ISC-green.svg)](https://opensource.org/licenses/ISC) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6448563.svg)](https://doi.org/10.5281/zenodo.6448563) +[![License: ISC](https://img.shields.io/badge/license-ISC-green.svg)](https://opensource.org/licenses/ISC) [![DOI](https://zenodo.org/badge/DOI/10.5281/zenodo.6448563.svg)](https://doi.org/10.5281/zenodo.6448563) [![Build Status](https://github.com/railtoolkit/TrainRuns.jl/actions/workflows/CI.yml/badge.svg?branch=main)](https://github.com/railtoolkit/TrainRuns.jl/actions/workflows/CI.yml?query=branch%3Amain) ------------ # About -TrainRun.jl is a step towards open science and open data in railway engineering. Its modular design offers the possibility to serve as a basis for future optimization and development. TrainRun.jl is suitable for qualitative calculations to compare different trains, and it is publicly available, and we invite others to collaborate. +TrainRuns.jl is a step towards open science and open data in railway engineering. Its modular design offers the possibility to serve as a basis for future optimization and development. TrainRuns.jl is suitable for qualitative calculations to compare different trains, and it is publicly available, and we invite others to collaborate. ------------ # Installation -The required julia packages are - - YAML.jl - - Dates.jl - - DataFrames.jl - - CSV.jl - - Plots.jl +Use the package manager provided by julia: +```julia +julia> # use the ] key +(@v1.x) pkg> add TrainRuns +(@v1.x) pkg> # use backspace +julia> using TrainRuns +``` -Review the settings.yaml file for your appropriate settings. +The required julia packages are + - YAML.jl + - JSONSchema.jl + - DataFrames.jl ------------ # Minimal working example ```julia -include("../src/TrainRun.jl") -using .TrainRun +using TrainRuns -train_directory = "data/trains/train_freight_V90withOreConsist.yaml" -running_path_directory = "data/paths/path_1_10km_nConst_vConst.yaml" -settings_directory = "data/settings.yaml" -(train, running_path, settings) = importYamlFiles(train_directory, running_path_directory, setting_directory) +train = Train("test/data/trains/freight.yaml") +path = Path("test/data/paths/const.yaml") -train_run = trainRun(train, running_path, settings) +runtime = trainrun(train, path) + +println("The train needs $runtime seconds for the running path.") ``` ------------ @@ -47,11 +50,11 @@ This work was supervised by South Westphalia University of Applied Sciences and # License - [![Open Source Initiative Approved License logo](https://opensource.org/files/OSIApproved_100X125.png "Open Source Initiative Approved License logo")](https://opensource.org) +[![Open Source Initiative Approved License logo](https://opensource.org/files/OSIApproved_100X125.png "Open Source Initiative Approved License logo")](https://opensource.org) ISC License (ISC) -Copyright 2021 Max Kannenberg +Copyright 2022 Max Kannenberg, Martin Scheidt Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. diff --git a/data/paths/path_1_10km_nConst_vConst.yaml b/data/paths/path_1_10km_nConst_vConst.yaml deleted file mode 100644 index 7b21c6b..0000000 --- a/data/paths/path_1_10km_nConst_vConst.yaml +++ /dev/null @@ -1,9 +0,0 @@ -%YAML 1.2 ---- -path: - name: "10 km, no gradient, 160 km/h" - pointsOfInterest: [999, 2000, 3333.3, 5000, 7777, 9000, 9500.95] # points of interest: positions in m - sectionStarts: # with path speed limt (in m/s) # [s in m, v_limit in m/s, f_Rp in ‰] - sectionStarts_kmh: # with path speed limt (in km/h) # [s in m, v_limit in km/h, f_Rp in ‰] - - [0, 160, 0] - - [10000, 160, 0] diff --git a/data/paths/path_2_10km_nVar_vConst.yaml b/data/paths/path_2_10km_nVar_vConst.yaml deleted file mode 100644 index 28cdad6..0000000 --- a/data/paths/path_2_10km_nVar_vConst.yaml +++ /dev/null @@ -1,19 +0,0 @@ -%YAML 1.2 ---- -path: - name: "10 km, different gradient, 160 km/h" - pointsOfInterest: [999, 2000, 3333.3, 5000, 7777, 9000, 9500.95] # points of interest: positions in m - sectionStarts: # with path speed limt (in m/s) # [s in m, v_limit in m/s, f_Rp in ‰] - sectionStarts_kmh: # with path speed limt (in km/h) # [s in m, v_limit in km/h, f_Rp in ‰] - - [0, 160, 0] - - [1000, 160, 1] - - [2000, 160, 2] - - [3000, 160, 5] - - [4000, 160, -3] - - [5000, 160, 5] - - [6000, 160, -10] - - [7000, 160, 15] - - [8000, 160, -10] - - [8500, 160, 20] - - [9000, 160, 0] - - [10000, 160, 0] diff --git a/data/paths/path_3_10km_nConst_vVar.yaml b/data/paths/path_3_10km_nConst_vVar.yaml deleted file mode 100644 index 77751bd..0000000 --- a/data/paths/path_3_10km_nConst_vVar.yaml +++ /dev/null @@ -1,17 +0,0 @@ -%YAML 1.2 ---- -path: - name: "10 km, no gradient, different speed limits" - pointsOfInterest: [999, 2000, 3333.3, 5000, 7777, 9000, 9500.95] # points of interest: positions in m - sectionStarts: # with path speed limt (in m/s) # [s in m, v_limit in m/s, f_Rp in ‰] - sectionStarts_kmh: # with path speed limt (in km/h) # [s in m, v_limit in km/h, f_Rp in ‰] - - [0, 160, 0.0] - - [3000, 60, 0.0] - - [4000, 160, 0.0] - - [5000, 60, 0.0] - - [6000, 160, 0.0] - - [6500, 60, 0.0] - - [6700, 65, 0.0] - - [6800, 70, 0.0] - - [7000, 120.00, 0] - - [10000, 160.00, 0.0] diff --git a/data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml b/data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml deleted file mode 100644 index aa5cf35..0000000 --- a/data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml +++ /dev/null @@ -1,354 +0,0 @@ -%YAML 1.2 ---- -path: - name: "'infra_Ostsachsen': track id='tr_80.6212_2' name='DG-DN' -> spp_5" - # source: https://www.railml.org/en/user/exampledata.html -> "Real world railway examples from professional tools" -> "East Saxony railway network by FBS" -> "Ostsachsen_V220.railml" -> 'infra_Ostsachsen': track id='tr_80.6212_2' name='DG-DN' -> spp_5 - sectionStarts: # with path speed limt (in m/s) # [s in m, v_limit in m/s, f_Rp in ‰] - sectionStarts_kmh: # with path speed limt (in km/h) # [s in m, v_limit in km/h, f_Rp in ‰] - - [0.0, 40, 0] - - [318.0, 40, 2] - - [399.0, 40, -3] - - [500.0, 40, 0] - - [579.0, 40, 1] - - [784.0, 40, 5.3] - - [868.0, 40, 20] - - [1082.0, 40, 16.1] - - [1287.0, 40, 18.1] - - [1800.0, 110, 18.1] - - [2242.0, 110, 15.4] - - [3295.0, 110, 11] - - [3880.0, 110, 11.1] - - [4680.0, 45, 11.1] - - [4686.0, 90, 11.1] - - [6122.0, 90, 0] - - [6487.0, 90, 1.5] - - [6588.0, 70, 1.5] - - [6589.0, 70, 2.4] - - [6608.0, 130, 2.4] - - [6723.0, 150, 1.3] - - [6928.0, 160, 1.3] - - [7030.0, 160, 7.5] - - [7300.0, 160, 8] - - [7552.0, 160, 5] - - [7675.0, 160, 6.7] - - [7800.0, 160, 7.4] - - [7920.0, 160, 7] - - [8020.0, 140, 7] - - [8100.0, 140, 6.3] - - [8168.0, 140, 7.4] - - [8226.0, 140, 8.4] - - [8300.0, 140, 7.4] - - [8381.0, 150, 7.4] - - [8600.0, 150, 7.8] - - [8900.0, 150, 6.7] - - [9100.0, 150, 7.8] - - [9600.0, 150, 8] - - [9845.0, 150, 7.3] - - [10005.0, 160, 7.3] - - [10600.0, 160, 6] - - [10748.0, 160, 7.3] - - [11100.0, 160, 4.5] - - [11280.0, 160, 3.6] - - [11450.0, 160, 7.2] - - [11800.0, 160, 6.8] - - [12100.0, 160, 7.3] - - [12590.0, 160, 7.6] - - [13100.0, 160, 7.3] - - [13500.0, 160, 7.1] - - [13800.0, 160, 7.3] - - [14138.0, 150, 7.3] - - [14330.0, 150, 0.3] - - [14640.0, 150, -1.8] - - [14764.0, 160, -2.8] - - [15000.0, 160, -3.3] - - [15500.0, 160, -0.9] - - [16000.0, 160, 0] - - [16470.0, 160, 1.2] - - [16572.0, 160, 2.2] - - [16700.0, 160, 3.8] - - [16949.0, 160, 3.5] - - [17086.0, 160, 3.2] - - [17232.0, 160, 1.3] - - [17339.0, 160, 4.5] - - [17406.0, 160, 3.4] - - [17727.0, 150, 3.4] - - [17807.0, 150, 4.6] - - [18049.0, 150, 3] - - [18210.0, 140, 3] - - [18300.0, 140, 4.6] - - [18680.0, 140, 3.2] - - [18761.0, 150, 3.2] - - [19047.0, 150, 5.1] - - [19305.0, 150, 3] - - [19406.0, 160, 3] - - [19414.0, 160, -0.3] - - [19900.0, 160, 3] - - [20150.0, 160, 1.8] - - [20470.0, 160, -4] - - [20940.0, 160, -3.6] - - [21150.0, 160, -1.5] - - [21390.0, 160, 0] - - [21702.0, 160, 1.5] - - [22188.0, 150, 1.5] - - [22294.0, 150, 1.8] - - [22383.0, 160, 1.8] - - [22500.0, 160, 2.6] - - [22900.0, 160, 4.6] - - [23542.0, 160, 0.2] - - [23736.0, 160, 0.9] - - [24124.0, 160, 7] - - [24918.0, 160, 7.6] - - [25100.0, 150, 7.1] - - [25580.0, 150, 7.4] - - [25708.0, 160, 7.4] - - [25810.0, 160, 7.1] - - [26040.0, 160, 3.2] - - [26330.0, 160, 1.8] - - [26593.0, 160, 2.1] - - [27020.0, 160, 3.5] - - [27195.0, 160, 5.8] - - [27253.0, 160, 1.1] - - [27310.0, 160, 3.5] - - [27595.0, 160, 3.4] - - [28530.0, 160, 4.6] - - [29115.0, 160, 0] - - [29700.0, 160, -5.2] - - [30055.0, 120, -4.3] - - [30301.0, 120, -6.2] - - [30487.0, 160, -6.2] - - [30537.0, 160, -4.8] - - [31130.0, 160, -0.3] - - [31293.0, 160, 3.7] - - [31400.0, 160, 2.9] - - [31640.0, 160, 4.1] - - [31795.0, 120, 4.1] - - [32010.0, 120, 3.2] - - [32138.0, 130, 3.2] - - [32365.0, 130, -4] - - [33000.0, 130, 6.1] - - [33426.0, 160, 6.1] - - [33907.0, 160, 7.1] - - [34220.0, 160, 8.4] - - [34300.0, 160, 7.9] - - [34440.0, 160, 7.1] - - [34610.0, 160, 4.4] - - [35000.0, 160, 5.6] - - [35173.0, 150, 5.6] - - [35400.0, 150, -0.2] - - [35597.0, 160, -0.2] - - [35900.0, 160, 0] - - [36700.0, 160, 3.9] - - [36938.0, 160, 0] - - [37700.0, 160, -0.3] - - [37978.0, 150, -5.6] - - [38063.0, 150, -1.9] - - [38141.0, 150, -3.1] - - [38210.0, 150, 0] - - [38406.0, 150, -7] - - [38900.0, 150, -7.5] - - [39200.0, 150, -8.7] - - [39298.0, 150, -6.4] - - [39476.0, 150, -7.2] - - [40400.0, 150, -6.9] - - [40676.0, 130, -6.9] - - [41000.0, 130, -7.3] - - [41406.0, 130, -7.5] - - [41571.0, 160, -7.3] - - [41816.0, 160, -6.8] - - [41923.0, 160, -7.1] - - [42139.0, 160, -1.3] - - [42343.0, 160, -2.4] - - [42432.0, 150, -2.4] - - [42952.0, 160, -2.4] - - [43000.0, 160, -4.6] - - [43264.0, 160, -2.5] - - [43388.0, 160, -0.6] - - [43700.0, 160, 0.8] - - [44030.0, 160, 2.7] - - [44430.0, 160, 0] - - [44708.0, 160, -7.2] - - [45477.0, 160, -7.8] - - [45890.0, 160, -1] - - [46562.0, 160, -1.6] - - [47000.0, 160, -6.9] - - [47500.0, 160, -7.7] - - [47800.0, 160, -6.8] - - [48700.0, 160, -4.3] - - [49218.0, 160, -5.3] - - [49514.0, 160, -2.5] - - [50000.0, 160, -2.2] - - [51150.0, 160, -5.7] - - [51406.0, 160, -6.3] - - [51710.0, 150, -5.8] - - [52000.0, 150, -6.7] - - [52215.0, 150, -6.1] - - [53213.0, 150, -6.8] - - [53567.0, 150, -5.6] - - [53943.0, 150, -6.5] - - [54129.0, 140, -6.5] - - [54212.0, 140, -10.5] - - [54247.0, 140, -5.4] - - [54326.0, 140, -6.1] - - [54450.0, 140, -6.5] - - [54482.0, 120, -6.5] - - [54550.0, 120, -6.2] - - [54855.0, 140, -6.2] - - [55307.0, 140, -0.3] - - [55651.0, 140, -1.2] - - [55788.0, 140, 0] - - [55918.0, 100, 0] - - [56433.0, 150, 0] - - [56560.0, 150, -2.1] - - [56624.0, 150, -6.7] - - [57012.0, 150, 1.3] - - [57260.0, 150, 6.6] - - [57800.0, 150, 5.3] - - [57987.0, 150, 0] - - [57990.0, 150, 7.6] - - [58321.0, 150, 6.4] - - [59090.0, 150, 6.9] - - [59468.0, 150, 9.2] - - [59600.0, 150, 0.2] - - [60683.0, 150, 4.1] - - [61156.0, 150, 2.3] - - [61181.0, 130, 2.3] - - [61325.0, 130, 0] - - [61605.0, 130, 7.3] - - [62108.0, 150, 7.3] - - [62246.0, 150, 6.6] - - [62279.0, 150, 5.1] - - [62454.0, 150, 0.9] - - [62777.0, 150, 5.5] - - [63802.0, 150, 4.6] - - [64344.0, 150, 0.2] - - [64932.0, 150, -0.6] - - [65100.0, 150, 0] - - [65690.0, 150, 1.8] - - [65878.0, 150, 2.5] - - [66266.0, 150, -1] - - [66339.0, 150, 6.3] - - [66448.0, 160, 6.3] - - [66587.0, 160, 0] - - [66856.0, 160, 3.2] - - [67480.0, 160, 3.6] - - [67697.0, 160, 2.2] - - [67800.0, 160, 6] - - [67851.0, 130, 6] - - [68027.0, 130, 2.7] - - [68172.0, 130, 0.6] - - [68328.0, 130, 2.5] - - [68357.0, 130, 0] - - [68479.0, 130, 7.1] - - [68783.0, 130, 7.4] - - [69056.0, 150, 7.4] - - [69500.0, 150, 6.8] - - [69741.0, 160, 6.8] - - [69900.0, 160, 6.6] - - [70757.0, 160, 3.6] - - [71384.0, 160, 6] - - [71568.0, 160, 7.1] - - [71800.0, 160, 7.4] - - [72100.0, 160, 7.3] - - [73919.0, 150, 7.3] - - [74317.0, 140, 7.3] - - [74448.0, 140, 1.5] - - [74590.0, 140, -1.5] - - [74620.0, 140, -5] - - [74950.0, 140, -4.3] - - [75100.0, 140, -1.8] - - [75154.0, 130, -1.8] - - [75260.0, 130, -6.2] - - [75873.0, 130, -5.6] - - [76062.0, 100, -5.6] - - [76100.0, 100, -6.4] - - [76350.0, 100, -5.7] - - [76476.0, 100, -7] - - [76600.0, 100, -6.4] - - [76601.0, 90, -6.4] - - [76726.0, 90, -6.2] - - [77256.0, 90, -2.1] - - [77285.0, 80, -2.1] - - [77299.0, 80, -14] - - [77331.0, 80, -1.6] - - [77379.0, 90, -1.6] - - [77425.0, 110, -1.6] - - [77455.0, 110, -4.9] - - [77498.0, 110, 0] - - [77505.0, 160, 0] - - [77555.0, 160, -5.6] - - [77662.0, 160, 0] - - [78085.0, 160, -4] - - [78223.0, 160, -6.8] - - [78337.0, 130, -6.8] - - [78856.0, 130, -6.6] - - [78875.0, 130, -7.2] - - [79345.0, 150, -7.2] - - [79600.0, 150, -6.5] - - [79792.0, 150, -0.2] - - [80537.0, 150, -5.2] - - [81300.0, 150, -4.8] - - [81634.0, 110, -4.8] - - [81943.0, 110, -5.4] - - [82166.0, 110, 0] - - [82408.0, 110, 4.8] - - [82790.0, 110, 5.9] - - [83137.0, 120, 5.9] - - [83300.0, 120, 0] - - [83519.0, 150, 0] - - [83597.0, 150, -7.8] - - [83827.0, 150, -8.1] - - [84150.0, 150, -7.2] - - [84391.0, 150, 0] - - [84966.0, 150, -4] - - [85529.0, 130, -2.3] - - [85589.0, 130, -4] - - [86081.0, 130, 0] - - [86514.0, 130, 7.8] - - [86577.0, 120, 7.8] - - [87554.0, 90, 7.8] - - [87690.0, 90, 7.9] - - [87842.0, 90, 1.7] - - [88007.0, 110, 1.7] - - [88100.0, 110, 3.4] - - [88260.0, 110, 5.3] - - [88376.0, 160, 5.3] - - [88450.0, 160, 6.7] - - [89050.0, 160, 7.4] - - [89350.0, 160, -7.1] - - [90365.0, 160, 0] - - [90700.0, 160, -7.3] - - [92000.0, 160, -7.9] - - [92166.0, 160, -4] - - [92460.0, 160, -5.4] - - [93330.0, 160, 0] - - [93901.0, 160, 0.7] - - [94156.0, 160, 5.2] - - [94440.0, 160, -2.8] - - [94530.0, 160, -0.8] - - [94630.0, 160, -6.8] - - [94830.0, 160, -4.4] - - [95090.0, 160, -4.6] - - [95500.0, 160, -4.8] - - [96500.0, 160, -4.4] - - [96700.0, 160, -5.6] - - [97000.0, 160, -4.6] - - [97590.0, 160, 0] - - [97858.0, 120, 0] - - [98224.0, 120, -1.5] - - [98264.0, 120, 0] - - [98577.0, 120, 7.5] - - [98738.0, 120, 0] - - [99055.0, 130, 0] - - [99427.0, 130, -2] - - [99610.0, 130, -3.1] - - [99906.0, 120, -3.1] - - [99980.0, 120, -1.3] - - [100190.0, 120, -6.8] - - [100832.0, 120, -7.2] - - [100980.0, 120, -8.1] - - [101100.0, 120, -7.4] - - [101245.0, 120, -6.3] - - [101332.0, 100, -6.3] - - [101365.0, 100, -2.4] - - [101551.0, 110, -2.4] - - [101800.0, 110, 0] diff --git a/data/settings/settings_distanceStep_homStrip.yaml b/data/settings/settings_distanceStep_homStrip.yaml deleted file mode 100644 index 2c8738c..0000000 --- a/data/settings/settings_distanceStep_homStrip.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 ---- -settings: -# settings for the simulation - massModel: "homogeneous strip" # model type of train mass "mass point" or "homogeneous strip" - stepVariable: "s in m" # step variable of the step method "s in m", "t in s" or "v in m/s" - stepSize: 10 # step size (unit depends on stepVariable s in m, t in s and v in m/s) - operationModeMinimumRunningTime: true # operation mode "minimum running time" - operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption" - typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV" - detailOfOutput: "driving course" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? - csvDirectory: "~/Desktop/TrainRun" diff --git a/data/settings/settings_distanceStep_massPoint.yaml b/data/settings/settings_distanceStep_massPoint.yaml deleted file mode 100644 index fc616ed..0000000 --- a/data/settings/settings_distanceStep_massPoint.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 ---- -settings: -# settings for the simulation - massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip" - stepVariable: "s in m" # step variable of the step method "s in m", "t in s" or "v in m/s" - stepSize: 10 # step size (unit depends on stepVariable s in m, t in s and v in m/s) - operationModeMinimumRunningTime: true # operation mode "minimum running time" - operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption" - typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV" - detailOfOutput: "driving course" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? - csvDirectory: "~/Desktop/TrainRun" diff --git a/data/settings/settings_distanceStep_massPoint_runningTime.yaml b/data/settings/settings_distanceStep_massPoint_runningTime.yaml deleted file mode 100644 index 98d7e84..0000000 --- a/data/settings/settings_distanceStep_massPoint_runningTime.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 ---- -settings: -# settings for the simulation - massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip" - stepVariable: "s in m" # step variable of the step method "s in m", "t in s" or "v in m/s" - stepSize: 10 # step size (unit depends on stepVariable s in m, t in s and v in m/s) - operationModeMinimumRunningTime: true # operation mode "minimum running time" - operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption" - typeOfOutput: "CSV" # output as "julia dictionary" or as "CSV" - detailOfOutput: "running time" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? - csvDirectory: "~/Desktop/TrainRun" diff --git a/data/settings/settings_timeStep_homStrip.yaml b/data/settings/settings_timeStep_homStrip.yaml deleted file mode 100644 index 952db02..0000000 --- a/data/settings/settings_timeStep_homStrip.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 ---- -settings: -# settings for the simulation - massModel: "homogeneous strip" # model type of train mass "mass point" or "homogeneous strip" - stepVariable: "t in s" # step variable of the step method "s in m", "t in s" or "v in m/s" - stepSize: 3.0 # step size (unit depends on stepVariable s in m, t in s and v in m/s) - operationModeMinimumRunningTime: true # operation mode "minimum running time" - operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption" - typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV" - detailOfOutput: "driving course" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? - csvDirectory: "~/Desktop/TrainRun" diff --git a/data/settings/settings_timeStep_massPoint.yaml b/data/settings/settings_timeStep_massPoint.yaml deleted file mode 100644 index 6e2eae0..0000000 --- a/data/settings/settings_timeStep_massPoint.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 ---- -settings: -# settings for the simulation - massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip" - stepVariable: "t in s" # step variable of the step method "s in m", "t in s" or "v in m/s" - stepSize: 3.0 # step size (unit depends on stepVariable s in m, t in s and v in m/s) - operationModeMinimumRunningTime: true # operation mode "minimum running time" - operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption" - typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV" - detailOfOutput: "driving course" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? - csvDirectory: "~/Desktop/TrainRun" diff --git a/data/settings/settings_velocityStep_massPoint.yaml b/data/settings/settings_velocityStep_massPoint.yaml deleted file mode 100644 index 54327a2..0000000 --- a/data/settings/settings_velocityStep_massPoint.yaml +++ /dev/null @@ -1,12 +0,0 @@ -%YAML 1.2 ---- -settings: -# settings for the simulation - massModel: "mass point" # model type of train mass "mass point" or "homogeneous strip" - stepVariable: "v in m/s" # step variable of the step method "s in m", "t in s" or "v in m/s" - stepSize: 0.1 # step size (unit depends on stepVariable s in m, t in s and v in m/s) - operationModeMinimumRunningTime: true # operation mode "minimum running time" - operationModeMinimumEnergyConsumption: false # operation mode "minimum energy consumption" - typeOfOutput: "julia dictionary" # output as "julia dictionary" or as "CSV" - detailOfOutput: "driving course" # should the output be only the value of the "running time" or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? - csvDirectory: "~/Desktop/TrainRun" diff --git a/data/trains/train_freight_V90withOreConsist.yaml b/data/trains/train_freight_V90withOreConsist.yaml deleted file mode 100644 index 59c82bb..0000000 --- a/data/trains/train_freight_V90withOreConsist.yaml +++ /dev/null @@ -1,112 +0,0 @@ -%YAML 1.2 ---- -train: - name: "V 90 with 10 ore wagons of type Facs 124" # (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90 and https://dybas.de/dybas/gw/gw_f_1/g124.html) - length: 205.3 # in m (source: FBS: DB 290 with 10x Facs124) - m_td: 80000 # mass on driving axles of the traction unit in kg (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) - m_tc: 0 # mass on carrying axles of the traction unit in kg (no carrying axles; source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) - m_w: 850000 # mass of the consist (set of wagons) in kg (source: FBS: 10x Facs124) - rotationMassFactor_train: - rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit) - rotationMassFactor_w: 1.03 # (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Güterwagenzug beladen" -> 1.03 to 1.04) - powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) - type: freight # "freight" or "passenger" (source: https://dybas.de/dybas/gw/gw_f_1/g124.html) - v_limit: # in m/s - v_limit_kmh: 80 # in km/h (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) - a_braking: -0.4124 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 290 with with 10x Facs124) - - # coefficients for the vehicle resistance - # for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+F_Rt2*((v+Δv_t)/v00)^2) - f_Rtd0: 2.2 # coefficient for basic resistance due to the traction units driving axles (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰) - f_Rtc0: 0 # coefficient for basic resistance due to the traction units carring axles (in ‰) (source: no carrying axles; source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90) - F_Rt2: 7500 # coefficient for air resistance of the traction units (in N) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N) - - # for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_w)/v00)^2)) - f_Rw0: 1.4 # coefficient for the consists basic resistance (in ‰) (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for "roller bearings") - f_Rw1: 0 # coefficient for the consists resistance to rolling (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 -> no f_Rw1 for freight consists) - f_Rw2: 3.9 # coefficient fo the consistsr air resistance (in ‰) (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for "full train loads of coal or ore" modified for the used formula) - - # tractive effort as pairs of speed and tractive effort - F_T_pairs: # [v in m/s, F_T in N] - F_T_pairs_kmh: # [v in km/h, F_T in N] (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 290 with with 10x Facs124) - - [0.0, 186940] - - [1.0, 186940] - - [2.0, 182310] - - [3.0, 177680] - - [4.0, 173050] - - [5.0, 168420] - - [6.0, 163790] - - [7.0, 159160] - - [8.0, 154530] - - [9.0, 149240] - - [10.0, 144120] - - [11.0, 139150] - - [12.0, 134340] - - [13.0, 129690] - - [14.0, 125200] - - [15.0, 120860] - - [16.0, 116680] - - [17.0, 112660] - - [18.0, 108790] - - [19.0, 105080] - - [20.0, 101530] - - [21.0, 98120] - - [22.0, 94840] - - [23.0, 91700] - - [24.0, 88700] - - [25.0, 85840] - - [26.0, 83110] - - [27.0, 80520] - - [28.0, 78070] - - [29.0, 75750] - - [30.0, 73580] - - [31.0, 71600] - - [32.0, 69660] - - [33.0, 67770] - - [34.0, 65930] - - [35.0, 64130] - - [36.0, 62380] - - [37.0, 60670] - - [38.0, 59010] - - [39.0, 57400] - - [40.0, 55830] - - [41.0, 54300] - - [42.0, 52820] - - [43.0, 51390] - - [44.0, 50000] - - [45.0, 48660] - - [46.0, 48080] - - [47.0, 47220] - - [48.0, 46380] - - [49.0, 45550] - - [50.0, 44730] - - [51.0, 43930] - - [52.0, 43140] - - [53.0, 42370] - - [54.0, 41610] - - [55.0, 40870] - - [56.0, 40140] - - [57.0, 39430] - - [58.0, 38730] - - [59.0, 38040] - - [60.0, 37370] - - [61.0, 36720] - - [62.0, 36070] - - [63.0, 35450] - - [64.0, 34830] - - [65.0, 34230] - - [66.0, 33650] - - [67.0, 33080] - - [68.0, 32520] - - [69.0, 31980] - - [70.0, 31450] - - [71.0, 30940] - - [72.0, 30440] - - [73.0, 29960] - - [74.0, 29490] - - [75.0, 29030] - - [76.0, 28590] - - [77.0, 28170] - - [78.0, 27760] - - [79.0, 27360] - - [80.0, 26980] diff --git a/data/trains/train_passenger_IC2.yaml b/data/trains/train_passenger_IC2.yaml deleted file mode 100644 index 89ba344..0000000 --- a/data/trains/train_passenger_IC2.yaml +++ /dev/null @@ -1,192 +0,0 @@ -%YAML 1.2 ---- -train: - name: "Intercity 2 (Traxx P160 AC2 + double deck coaches)" # (source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario#Intercity_2 and https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)) - length: 152 # in m (source: FBS: DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) - m_td: 84000 # mass on driving axles of the traction unit in kg (source: FBS: DB146.5) - m_tc: 0 # mass on carrying axles of the traction unit in kg (no carrying axles; source: FBS: DB146.5) - m_w: 309000 # mass of the consist (set of wagons) in kg (source: FBS: 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) - rotationMassFactor_train: - rotationMassFactor_t: 1.09 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit) - rotationMassFactor_w: 1.06 # (source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for freight wagons) - powerType: electric # diesel or electric (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale) - type: passenger # "freight" or "passenger" (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)) - v_limit: # in m/s - v_limit_kmh: 160 # in km/h (source: https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)#Gemeinsame_Merkmale) - a_braking: -0.3507 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) - - # coefficients for the vehicle resistance - # for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+F_Rt2*((v+Δv_t)/v00)^2) - f_Rtd0: 2.5 # coefficient for basic resistance due to the traction units driving axles (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Hochgeschwindigkeitslok."" -> 2.0 ‰ to 3.0 ‰) - f_Rtc0: 0 # coefficient for basic resistance due to the traction units carring axles (in ‰) (source: no carrying axles; source: FBS: DB146.5) - F_Rt2: 5000 # coefficient for air resistance of the traction units (in N) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform"with "Stromabnehmer" -> 5000 N to 6000 N) - - # for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_w)/v00)^2)) - f_Rw0: 2.0 # coefficient for the consists basic resistance (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge") - f_Rw1: 0.715 # coefficient for the consists resistance to rolling (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge") - f_Rw2: 3.64 # coefficient fo the consistsr air resistance (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge") - - # tractive effort as pairs of speed and tractive effort - F_T_pairs: # [v in m/s, F_T in N] - F_T_pairs_kmh: # [v in km/h, F_T in N] (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB146.5 with 1x DApza687.2, 3x DBpza668.2, 1x DBpbzfa668.2) - - [0.0, 300000] - - [1.0, 300000] - - [2.0, 300000] - - [3.0, 300000] - - [4.0, 300000] - - [5.0, 300000] - - [6.0, 300000] - - [7.0, 300000] - - [8.0, 300000] - - [9.0, 300000] - - [10.0, 300000] - - [11.0, 300000] - - [12.0, 300000] - - [13.0, 300000] - - [14.0, 300000] - - [15.0, 300000] - - [16.0, 300000] - - [17.0, 300000] - - [18.0, 300000] - - [19.0, 300000] - - [20.0, 300000] - - [21.0, 300000] - - [22.0, 300000] - - [23.0, 300000] - - [24.0, 300000] - - [25.0, 300000] - - [26.0, 300000] - - [27.0, 300000] - - [28.0, 300000] - - [29.0, 300000] - - [30.0, 300000] - - [31.0, 300000] - - [32.0, 300000] - - [33.0, 300000] - - [34.0, 300000] - - [35.0, 300000] - - [36.0, 300000] - - [37.0, 300000] - - [38.0, 300000] - - [39.0, 300000] - - [40.0, 300000] - - [41.0, 300000] - - [42.0, 300000] - - [43.0, 300000] - - [44.0, 300000] - - [45.0, 300000] - - [46.0, 300000] - - [47.0, 300000] - - [48.0, 300000] - - [49.0, 300000] - - [50.0, 300000] - - [51.0, 300000] - - [52.0, 300000] - - [53.0, 300000] - - [54.0, 300000] - - [55.0, 300000] - - [56.0, 300000] - - [57.0, 300000] - - [58.0, 300000] - - [59.0, 300000] - - [60.0, 300000] - - [61.0, 300000] - - [62.0, 300000] - - [63.0, 300000] - - [64.0, 300000] - - [65.0, 300000] - - [66.0, 300000] - - [67.0, 297760] - - [68.0, 293380] - - [69.0, 289130] - - [70.0, 285000] - - [71.0, 280990] - - [72.0, 277080] - - [73.0, 273290] - - [74.0, 269590] - - [75.0, 266000] - - [76.0, 262500] - - [77.0, 259090] - - [78.0, 255770] - - [79.0, 252530] - - [80.0, 249380] - - [81.0, 246300] - - [82.0, 243290] - - [83.0, 240360] - - [84.0, 237500] - - [85.0, 234710] - - [86.0, 231980] - - [87.0, 229310] - - [88.0, 226700] - - [89.0, 224160] - - [90.0, 221670] - - [91.0, 219230] - - [92.0, 216850] - - [93.0, 214520] - - [94.0, 212230] - - [95.0, 210000] - - [96.0, 207810] - - [97.0, 205670] - - [98.0, 203570] - - [99.0, 201520] - - [100.0, 199500] - - [101.0, 197520] - - [102.0, 195590] - - [103.0, 193690] - - [104.0, 191830] - - [105.0, 190000] - - [106.0, 188210] - - [107.0, 186450] - - [108.0, 184720] - - [109.0, 183030] - - [110.0, 181360] - - [111.0, 179730] - - [112.0, 178130] - - [113.0, 176550] - - [114.0, 175000] - - [115.0, 173480] - - [116.0, 171980] - - [117.0, 170510] - - [118.0, 169070] - - [119.0, 167650] - - [120.0, 166250] - - [121.0, 164880] - - [122.0, 163520] - - [123.0, 162200] - - [124.0, 160890] - - [125.0, 159600] - - [126.0, 158330] - - [127.0, 157090] - - [128.0, 155860] - - [129.0, 154650] - - [130.0, 153460] - - [131.0, 152290] - - [132.0, 151140] - - [133.0, 150000] - - [134.0, 148880] - - [135.0, 147780] - - [136.0, 146690] - - [137.0, 145620] - - [138.0, 144570] - - [139.0, 143530] - - [140.0, 142500] - - [141.0, 141490] - - [142.0, 140490] - - [143.0, 139510] - - [144.0, 138540] - - [145.0, 137590] - - [146.0, 136640] - - [147.0, 135710] - - [148.0, 134800] - - [149.0, 133890] - - [150.0, 133000] - - [151.0, 132120] - - [152.0, 131250] - - [153.0, 130390] - - [154.0, 129550] - - [155.0, 128710] - - [156.0, 127880] - - [157.0, 127070] - - [158.0, 126270] - - [159.0, 125470] - - [160.0, 124690] diff --git a/data/trains/train_passenger_SiemensDesiroClassic.yaml b/data/trains/train_passenger_SiemensDesiroClassic.yaml deleted file mode 100644 index 666a37e..0000000 --- a/data/trains/train_passenger_SiemensDesiroClassic.yaml +++ /dev/null @@ -1,152 +0,0 @@ -%YAML 1.2 ---- -train: - name: "Siemens Desiro Classic" # (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - length: 41.7 # in m (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - m_td: 52800 # mass on driving axles of the traction unit in kg (source: FBS: DB 642; proportionately to the number of axles: 4 to 2, see: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - m_tc: 35200 # mass on carrying axles of the traction unit in kg (source: FBS: DB 642; proportionately to the number of axles: 4 to 2, see: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - m_w: 0 # mass of the consist (set of wagons) in kg (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic -> no separate wagons) - rotationMassFactor_train: 1.08 # (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Zug, überschlägliche Berechnung") - rotationMassFactor_t: - rotationMassFactor_w: - powerType: diesel # diesel or electric (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - type: passenger # "freight" or "passenger" (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - v_limit: # in m/s - v_limit_kmh: 120 # in km/h (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) - a_braking: -0.4253 # in m/s^2 (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 642) - - # coefficients for the vehicle resistance - # for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+F_Rt2*((v+Δv_t)/v00)^2) - f_Rtd0: 3.0 # coefficient for basic resistance due to the traction units driving axles (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WL0" -> 2.5 ‰ to 3.5 ‰) - f_Rtc0: 1.4 # coefficient for basic resistance due to the traction units carring axles (in ‰) (source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WW0" -> 1.2 ‰ to 1.6 ‰) - F_Rt2: 2600 # coefficient for air resistance of the traction units (in N) (source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N) - - # for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_w)/v00)^2)) - f_Rw0: # coefficient for basic resistance of the set of wagons (in ‰) (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic -> no separate wagons) - f_Rw1: # coefficient for resistance to rolling of the set of wagons (in ‰) (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic -> no separate wagons) - f_Rw2: # coefficient for air resistance of the set of wagons (in ‰) (source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic -> no separate wagons) - - # tractive effort as pairs of speed and tractive effort - F_T_pairs: # [v in m/s, F_T in N] - F_T_pairs_kmh: # [v in km/h, F_T in N] (source: FBS -> using the information from the "Fahrschaubild" of a long path without gradient or speed limit for DB 642) - - [0.0, 94400] - - [1.0, 94400] - - [2.0, 92800] - - [3.0, 91200] - - [4.0, 89600] - - [5.0, 88000] - - [6.0, 86400] - - [7.0, 84800] - - [8.0, 83200] - - [9.0, 81600] - - [10.0, 80000] - - [11.0, 78160] - - [12.0, 76290] - - [13.0, 74420] - - [14.0, 72550] - - [15.0, 70680] - - [16.0, 68810] - - [17.0, 66940] - - [18.0, 65070] - - [19.0, 63200] - - [20.0, 61330] - - [21.0, 59460] - - [22.0, 57590] - - [23.0, 55720] - - [24.0, 53850] - - [25.0, 51980] - - [26.0, 50110] - - [27.0, 48240] - - [28.0, 46370] - - [29.0, 44500] - - [30.0, 42630] - - [31.0, 40760] - - [32.0, 38890] - - [33.0, 38110] - - [34.0, 37330] - - [35.0, 36550] - - [36.0, 35770] - - [37.0, 35600] - - [38.0, 35600] - - [39.0, 35600] - - [40.0, 35600] - - [41.0, 35600] - - [42.0, 35600] - - [43.0, 35550] - - [44.0, 35280] - - [45.0, 35010] - - [46.0, 34740] - - [47.0, 34280] - - [48.0, 33560] - - [49.0, 32880] - - [50.0, 32220] - - [51.0, 31590] - - [52.0, 26300] - - [53.0, 26300] - - [54.0, 26300] - - [55.0, 26300] - - [56.0, 26300] - - [57.0, 25990] - - [58.0, 25840] - - [59.0, 25690] - - [60.0, 25540] - - [61.0, 25390] - - [62.0, 25240] - - [63.0, 25090] - - [64.0, 25140] - - [65.0, 24760] - - [66.0, 24380] - - [67.0, 24020] - - [68.0, 23660] - - [69.0, 23320] - - [70.0, 22990] - - [71.0, 19400] - - [72.0, 19400] - - [73.0, 19400] - - [74.0, 19400] - - [75.0, 19400] - - [76.0, 19400] - - [77.0, 19400] - - [78.0, 19400] - - [79.0, 19400] - - [80.0, 19400] - - [81.0, 19440] - - [82.0, 19310] - - [83.0, 19180] - - [84.0, 19050] - - [85.0, 18920] - - [86.0, 18670] - - [87.0, 18460] - - [88.0, 18250] - - [89.0, 15360] - - [90.0, 15310] - - [91.0, 15260] - - [92.0, 15210] - - [93.0, 15160] - - [94.0, 15110] - - [95.0, 15060] - - [96.0, 15010] - - [97.0, 14960] - - [98.0, 14910] - - [99.0, 14860] - - [100.0, 14810] - - [101.0, 14760] - - [102.0, 14710] - - [103.0, 14660] - - [104.0, 14610] - - [105.0, 14560] - - [106.0, 14510] - - [107.0, 14460] - - [108.0, 14410] - - [109.0, 14360] - - [110.0, 14310] - - [111.0, 14460] - - [112.0, 14340] - - [113.0, 14210] - - [114.0, 14080] - - [115.0, 13960] - - [116.0, 13840] - - [117.0, 13720] - - [118.0, 13610] - - [119.0, 13490] - - [120.0, 13380] diff --git a/docs/DEFAULT.yaml b/docs/DEFAULT.yaml new file mode 100644 index 0000000..1a562d9 --- /dev/null +++ b/docs/DEFAULT.yaml @@ -0,0 +1,10 @@ +%YAML 1.2 +--- +settings: +# default settings for the calculation + massModel: "mass_point" # type of train model used: "mass_point" or "homogeneous_strip" + stepVariable: "distance" # variable of the linear multistep method: "distance", "time" or "velocity" + stepSize: 20 # step size, unit depends on stepVariable - distance in meter, time in seconds and velocity in meter/second. + approxLevel: 3 # value for approximation; used when rounding or interating + outputDetail: "running_time" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" + outputFormat: "dataframe" # output as "dataframe" or as "dict" diff --git a/docs/Project.toml b/docs/Project.toml new file mode 100644 index 0000000..59ca3f3 --- /dev/null +++ b/docs/Project.toml @@ -0,0 +1,3 @@ +[deps] +Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +TrainRuns = "e4541106-d44c-4e00-b50b-ecdf479fcf92" diff --git a/docs/examples/ExtendedWorkingExample.jl b/docs/examples/ExtendedWorkingExample.jl new file mode 100644 index 0000000..1dadfc7 --- /dev/null +++ b/docs/examples/ExtendedWorkingExample.jl @@ -0,0 +1,32 @@ +#!/usr/bin/env julia + +import TrainRuns + +paths=[] +push!(paths, importFromYaml(:path, "data/paths/path_1_10km_nConst_vConst.yaml")) +push!(paths, importFromYaml(:path, "data/paths/path_2_10km_nVar_vConst.yaml")) +push!(paths, importFromYaml(:path, "data/paths/path_3_10km_nConst_vVar.yaml")) +push!(paths, importFromYaml(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml")) + +settings=[] +push!(settings, importFromYaml(:settings, "data/settings/settings_distanceStep_massPoint.yaml")) + +trains=[] +push!(trains, importFromYaml(:train, "data/trains/train_freight_V90withOreConsist.yaml")) +push!(trains, importFromYaml(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml")) +push!(trains, importFromYaml(:train, "data/trains/train_passenger_IC2.yaml")) + +for path in paths + # println(" - - - - - - - - -") + # println("path: ", path[:name]) + for train in trains + # println("train: ", train[:name]) + for settings in settings + resultsDict = trainrun(train, path, settings) + if haskey(settings, :outputFormat) && settings[:outputFormat] == "CSV" + exportToCsv(resultsDict, settings) + sleep(2) + end + end + end +end diff --git a/docs/examples/MinimalWorkingExample.jl b/docs/examples/MinimalWorkingExample.jl new file mode 100644 index 0000000..129bb2b --- /dev/null +++ b/docs/examples/MinimalWorkingExample.jl @@ -0,0 +1,10 @@ +#!/usr/bin/env julia + +using TrainRuns + +train = Train("test/data/trains/freight.yaml") +path = Path("test/data/paths/const.yaml") + +runtime = trainrun(train, path) + +println("The train needs $runtime seconds for the running path.") diff --git a/docs/make.jl b/docs/make.jl new file mode 100644 index 0000000..c9fb66a --- /dev/null +++ b/docs/make.jl @@ -0,0 +1,24 @@ +using TrainRuns +using Documenter + +DocMeta.setdocmeta!(TrainRuns, :DocTestSetup, :(using TrainRuns); recursive=true) + +makedocs(; + modules=[TrainRuns], + authors="Max Kannenberg, Martin Scheidt, and contributors", + repo="https://github.com/railtoolkit/TrainRuns.jl/blob/{commit}{path}#{line}", + sitename="TrainRuns.jl", + format=Documenter.HTML(; + prettyurls=get(ENV, "CI", "false") == "true", + canonical="https://railtoolkit.github.io/TrainRuns.jl", + assets=String[], + ), + pages=[ + "Home" => "index.md", + ], +) + +deploydocs(; + repo="github.com/railtoolkit/TrainRuns.jl", + devbranch="development", +) diff --git a/docs/src/index.md b/docs/src/index.md new file mode 100644 index 0000000..4cd232d --- /dev/null +++ b/docs/src/index.md @@ -0,0 +1,14 @@ +```@meta +CurrentModule = TrainRuns +``` + +# TrainRuns + +Documentation for [TrainRuns](https://github.com/railtoolkit/TrainRuns.jl). + +```@index +``` + +```@autodocs +Modules = [TrainRuns] +``` diff --git a/examples/ExtendedWorkingExample.jl b/examples/ExtendedWorkingExample.jl deleted file mode 100644 index ebb68e3..0000000 --- a/examples/ExtendedWorkingExample.jl +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.0 -# __author__ = "Max Kannenberg" -# __copyright__ = "2021" -# __license__ = "ISC" - -include("../src/TrainRun.jl") -using .TrainRun - -allPaths=[] -push!(allPaths, importFromYaml(:path, "data/paths/path_1_10km_nConst_vConst.yaml")) -push!(allPaths, importFromYaml(:path, "data/paths/path_2_10km_nVar_vConst.yaml")) -push!(allPaths, importFromYaml(:path, "data/paths/path_3_10km_nConst_vVar.yaml")) -push!(allPaths, importFromYaml(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml")) - -allSettings=[] -push!(allSettings, importFromYaml(:settings, "data/settings/settings_distanceStep_massPoint.yaml")) - -allTrains=[] -push!(allTrains, importFromYaml(:train, "data/trains/train_freight_V90withOreConsist.yaml")) -push!(allTrains, importFromYaml(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml")) -push!(allTrains, importFromYaml(:train, "data/trains/train_passenger_IC2.yaml")) - -for path in allPaths - # println(" - - - - - - - - -") - # println("path: ", path[:name]) - for train in allTrains - # println("train: ", train[:name]) - for settings in allSettings - resultsDict = trainRun(train, path, settings) - if haskey(settings, :typeOfOutput) && settings[:typeOfOutput] == "CSV" - exportToCsv(resultsDict, settings) - sleep(2) - end - # println("") - end - end - # println("") -end - -# println("") -# println("________________________") -# println("") diff --git a/examples/MinimalWorkingExample.jl b/examples/MinimalWorkingExample.jl deleted file mode 100644 index 47382f5..0000000 --- a/examples/MinimalWorkingExample.jl +++ /dev/null @@ -1,19 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.0 -# __author__ = "Max Kannenberg" -# __copyright__ = "2021" -# __license__ = "ISC" - -include("../src/TrainRun.jl") -using .TrainRun - -train_directory = "data/trains/train_freight_V90withOreConsist.yaml" -running_path_directory = "data/paths/path_1_10km_nConst_vConst.yaml" -setting_directory = "data/settings/settings_distanceStep_massPoint_runningTime.yaml" -(train, running_path, settings) = importYamlFiles(train_directory, running_path_directory, setting_directory) - -runtime = trainRun(train, running_path, settings) - -exportToCsv(runtime, settings) -println("The V 90 with 10 ore wagons needs $runtime seconds for 10 km with no gradient.") diff --git a/src/AdditionalOutput.jl b/src/AdditionalOutput.jl deleted file mode 100644 index c7079ba..0000000 --- a/src/AdditionalOutput.jl +++ /dev/null @@ -1,210 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 -# __author__ = "Max Kannenberg" -# __copyright__ = "2020-2022" -# __license__ = "ISC" - -# INFO: AdditionalOutput should not be used because it is not completed yet. It was used to show first results during development. -# TODO: It has to be optimized so that the created plots and printed information is clear and understandable. - -module AdditionalOutput - -using Plots - -export plotResults, plotDrivingCourse, printImportantValues, printSectionInformation - -function plotResults(output::Dict) - opModeMinTime = output[:settings][:operationModeMinimumRunningTime] - opModeMinEnergy = output[:settings][:operationModeMinimumEnergyConsumption] - - if opModeMinTime == true && opModeMinEnergy == true - plotDrivingCourse(output[:drivingCourseMinimumRunningTime], output[:drivingCourseMinimumEnergyConsumption]) - elseif opModeMinTime == true - plotDrivingCourse(output[:drivingCourseMinimumRunningTime]) - elseif opModeMinEnergy == true - plotDrivingCourse(output[:drivingCourseMinimumEnergyConsumption]) - else - output[:settings][:detailOfOutput] == "everything" && println("No Output was demanded. So no plot is created.") - end - - return true -end #function plotResults - -function plotResults(drivingCourse::Vector{Dict}) - plotDrivingCourse(drivingCourse) - - return true -end #function plotResults - -function plotResults(singleValue::AbstractFloat) - println("Not able to plot the single value ",singleValue) - - return false -end #function plotResults - -function plotDrivingCourse(drivingCourse::Vector{Dict}) - a=[] - E=[] - s=[] - t=[] - v=[] - for i in 1:length(drivingCourse) - push!(a, drivingCourse[i][:a]) - push!(E, drivingCourse[i][:E]) - push!(s, drivingCourse[i][:s]) - push!(t, drivingCourse[i][:t]) - push!(v, drivingCourse[i][:v]) - end #for - -# p1=plot([s], [v], title = "v in m/s", label = ["v"], xlabel = "s in m") - p1=plot([s/1000], [v*3.6], title = "v in km/h", label = ["v"], xlabel = "s in km") - -# p2=plot([t], [v], title = "v in m/s", label = ["v"], xlabel = "t in s") - p2=plot([t/60], [v*3.6], title = "v in km/h", label = ["v"], xlabel = "t in min") - - # p3=plot([s], [t], title = "t in s", label = ["t"], xlabel = "s in m") - - # p4=plot([t], [s], title = "s in m", label = ["s"], xlabel = "t in s") - - #p5=plot([s], [E], title = "E in Ws", label = ["E"], xlabel = "s in m") - p5=plot([s/1000], [E], title = "E in Ws", label = ["E"], xlabel = "s in km") - - #p6=plot([t], [E], title = "E in Ws", label = ["E"], xlabel = "t in s") - p6=plot([t/60], [E], title = "E in Ws", label = ["E"], xlabel = "t in min") - - all=plot(p1, p2, p5, p6, layout = (2, 2), legend = false) -#= - # p5=plot([s], [E], title = "E in Ws", label = ["E"], xlabel = "s in m") - - # p6=plot([t], [E], title = "E in Ws", label = ["E"], xlabel = "t in s") - - all=plot(p1, p2, layout = (1, 2), legend = false)=# - # all=plot(p1, p2, p3, p4, p5, p6, layout = (3, 2), legend = false) - display(all) - println("Plots for different variables have been created.") -end #function plotDrivingCourse - -function plotDrivingCourse(drivingCourseMinimumRunningTime::Vector{Dict},drivingCourseMinimumEnergyConsumption::Vector{Dict}) - a_minTime=[] - E_minTime=[] - s_minTime=[] - t_minTime=[] - v_minTime=[] - for i in 1:length(drivingCourseMinimumRunningTime) - push!(a_minTime, drivingCourseMinimumRunningTime[i][:a]) - push!(E_minTime, drivingCourseMinimumRunningTime[i][:E]) - push!(s_minTime, drivingCourseMinimumRunningTime[i][:s]) - push!(t_minTime, drivingCourseMinimumRunningTime[i][:t]) - push!(v_minTime, drivingCourseMinimumRunningTime[i][:v]) - end #for - - a_minEnergy=[] - E_minEnergy=[] - s_minEnergy=[] - t_minEnergy=[] - v_minEnergy=[] - for i in 1:length(drivingCourseMinimumEnergyConsumption) - push!(a_minEnergy, drivingCourseMinimumEnergyConsumption[i][:a]) - push!(E_minEnergy, drivingCourseMinimumEnergyConsumption[i][:E]) - push!(s_minEnergy, drivingCourseMinimumEnergyConsumption[i][:s]) - push!(t_minEnergy, drivingCourseMinimumEnergyConsumption[i][:t]) - push!(v_minEnergy, drivingCourseMinimumEnergyConsumption[i][:v]) - end #for - - p1=plot([s_minTime,s_minEnergy], - [v_minTime,v_minEnergy], - title = "v in m/s", - label = ["v for t_min" "v for E_min"], - xlabel = "s in m")# lw = 3) - - p2=plot([t_minTime,t_minEnergy], - [v_minTime,v_minEnergy], - title = "v in m/s", - label = ["v for t_min" "v for E_min"], - xlabel = "t in s") - - # p3=plot([s_minTime,s_minEnergy], - # [t_minTime,t_minEnergy], - # title = "t in s", - # label = ["t for t_min" "t for E_min"], - # xlabel = "s in m") - - # p4=plot([t_minTime,t_minEnergy], - # [s_minTime,s_minEnergy], - # title = "s in m", - # label = ["s for t_min" "s for E_min"], - # xlabel = "t in s") - - p5=plot([s_minTime,s_minEnergy], - [E_minTime,E_minEnergy], - title = "E in Ws", - label = ["E for t_min" "E for E_min"], - xlabel = "s in m") - - p6=plot([t_minTime,t_minEnergy], - [E_minTime,E_minEnergy], - title = "E in Ws", - label = ["E for t_min" "E for E_min"], - xlabel = "t in s") - - # all=plot(p1, p2, p3, p4, p5, p6, layout = (3, 2), legend = false) - all=plot(p1, p2, p5, p6, layout = (2, 2), legend = false) - display(all) - println("Plots for different variables have been created.") -end #function plotDrivingCourse - -function printImportantValues(dataPoints::Vector{Dict}) - println("i behavior s in m v in km/h t in min a in m/s^2 F_R in k N F_T in k N E in k Wh") - for i in 1:length(dataPoints) - println(dataPoints[i][:i],". ",dataPoints[i][:behavior]," ",dataPoints[i][:s]," ",dataPoints[i][:v]*3.6," ",dataPoints[i][:t]/60," ",dataPoints[i][:a]," ",dataPoints[i][:F_R]/1000," ",dataPoints[i][:F_T]/1000," ",dataPoints[i][:E]/3600/1000) - end #for - println("i behavior s in m v in km/h t in min a in m/s^2 F_R in k N F_T in k N E in k Wh") -end #function printImportantValues - -function printSectionInformation(movingSection::Dict) - CSs::Vector{Dict} = movingSection[:characteristicSections] - - println("MS with length=", movingSection[:length]," with t=", movingSection[:t]) - #allBSs=[:breakFree, :clearing, :accelerating, :clearing2, :accelerating2, :clearing3, :accelerating3, :cruising, :downhillBraking, :diminishing, :coasting, :braking, :standstill] - for csId in 1:length(CSs) - println("CS ",csId," with length=", CSs[csId][:length]," with t=", CSs[csId][:t]) - # for bs in 1: length(allBSs) - # if haskey(CSs[csId][:behaviorSections], allBSs[bs]) - # println("BS ",allBSs[bs], " with s_entry=", CSs[csId][:behaviorSections][allBSs[bs]][:s_entry], " and length=",CSs[csId][:behaviorSections][allBSs[bs]][:length]) # and t=", CSs[csId][:behaviorSections][allBSs[bs]][:t]) - # # for point in 1:length(CSs[csId][:behaviorSections][allBSs[bs]][:dataPoints]) - # # println(CSs[csId][:behaviorSections][allBSs[bs]][:dataPoints][point]) - # # end - # end #if - # end #for - - tempBSs = collect(keys(CSs[csId][:behaviorSections])) - while length(tempBSs) > 0 - currentBS = :default - for bs in 1: length(tempBSs) - if currentBS == :default - currentBS = tempBSs[bs] - else - if CSs[csId][:behaviorSections][currentBS][:s_entry] > CSs[csId][:behaviorSections][tempBSs[bs]][:s_entry] - currentBS = tempBSs[bs] - end - end - end #for - - println("BS ",currentBS, " with s_entry=", CSs[csId][:behaviorSections][currentBS][:s_entry], " and length=",CSs[csId][:behaviorSections][currentBS][:length]) # and t=", CSs[csId][:behaviorSections][currentBS][:t]) - # for point in 1:length(CSs[csId][:behaviorSections][currentBS][:dataPoints]) - # println(CSs[csId][:behaviorSections][currentBS][:dataPoints][point]) - # end - - newTempBSs = [] - for bs in 1: length(tempBSs) - if currentBS != tempBSs[bs] - push!(newTempBSs, tempBSs[bs]) - end #if - end #for - tempBSs = newTempBSs - end #while - end #for -end #function printSectionInformation - -end # module AdditionalOutput diff --git a/src/EnergySaving.jl b/src/EnergySaving.jl deleted file mode 100644 index 037f9af..0000000 --- a/src/EnergySaving.jl +++ /dev/null @@ -1,1045 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 -# __author__ = "Max Kannenberg" -# __copyright__ = "2020-2022" -# __license__ = "ISC" - -# INFO: EnergySaving should not be used because it is not completed yet. It was used to show the possibility of calculating different operation modes. -# TODO: It has to be optimized so that each ernergy saving method is working individually for every train on every path. - -# TODO: calculation time for passenger trains on path1 is very long and should be reduced -# TODO from 2022/01/18: Test if enum trainType is working correctly in function calculateRecoveryTime or if only the else-pathis taken -# TODO from 2022/01/19: Are here calculations that should be transferred to Formulary.jl? -# TODO from 2022/01/22: use always copyCharacteristicSection and don't do it manually like "csModified=Dict(:id => csOriginal[:id], ..." three times -# TODO from 2022/03/18: stateFlags need to be added to functions that add behavior sections -# TODO from 2022/03/21: consider previous speed limits during the coasting section in case F_R < 0.0 and the train is getting faster -# TODO from 2002/04/07: the train type is only devided in passenger and freight and not motorCoachTrain anymore because this is only used for EnergySaving. If EnergySaving will be reactivated it the train type also has to change from enum to String or Symbol -module EnergySaving - -# include modules of TrainRunCalc -include("./Behavior.jl") - -# use modules of TrainRunCalc -using .Behavior - -export addOperationModeEnergySaving! - -@enum trainType passenger=1 freight=2 motorCoachTrain=3 - -approximationLevel = 6 # value for approximation to intersections - # TODO: define it in TrainRun and give it to each function? - -## functions for calculating the operation mode for the minimum energy consumption - -# calculate the train run for operation mode "minimum energy consumption" -function addOperationModeEnergySaving!(accumulatedDict::Dict) - if accumulatedDict[:settings][:operationModeMinimumEnergyConsumption] == true - movingSectionMinimumRunningTime = accumulatedDict[:movingSectionMinimumRunningTime] - drivingCourseMinimumRunningTime = accumulatedDict[:drivingCourseMinimumRunningTime] - settings = accumulatedDict[:settings] - train = accumulatedDict[:train] - (movingSectionMinimumEnergyConsumption, drivingCourseMinimumEnergyConsumption)=calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime, drivingCourseMinimumRunningTime, settings, train) - println("The driving course for the lowest energy consumption has been calculated.") - - # accumulate data and create an output dictionary - merge!(accumulatedDict, Dict(:movingSectionMinimumEnergyConsumption => movingSectionMinimumEnergyConsumption, :drivingCourseMinimumEnergyConsumption => drivingCourseMinimumEnergyConsumption)) - else - println("No output for minimum energy consumption has been demanded and so none will be calculated.") - end #if - - return accumulatedDict -end #function addOperationModeEnergySaving! - -function calculateMinimumEnergyConsumption(movingSectionMinimumRunningTime::Dict, drivingCourseMinimumRunningTime::Vector{Dict}, settings::Dict, train::Dict) - # calculate a train run focussing on using the minimum possible energy consumption - # booleans for choosing which methods are used for saving energy - doMethod1=true - #doMethod1=false - - doMethod2=true - #doMethod2=false - - doCombinationOfMethods=true - #doCombinationOfMethods=false - - # create a new driving course for the minimum energy consumption - drivingCourseOriginal = copy(drivingCourseMinimumRunningTime) - - #create a new moving section for the minimum energy consumption - movingSectionOriginal=copyMovingSection(movingSectionMinimumRunningTime) - # 01/09 old not sure if just copy is enough.. : movingSectionOriginal=copy(movingSectionMinimumRunningTime) - CSsOrig::Vector{Dict} = movingSectionOriginal[:characteristicSections] - merge!(movingSectionOriginal, Dict(:energySavingModifications => [])) # list containing all the used energy saving modifications - - # calculate the recovery time - t_recovery=calculateRecoveryTime(movingSectionOriginal[:length], movingSectionOriginal[:t], train) - merge!(movingSectionOriginal, Dict(:t_recovery=>t_recovery)) # total recovery time for energy-saving modifications (in s) - merge!(movingSectionOriginal, Dict(:t_recoveryAvailable => t_recovery)) # still available recovery time for energy-saving modifications (in s) initialized with the total recovery time - - # create arrays for each method with all the available energy saving modifications - energySavingModificationsWithCoasting=Dict[] - energySavingModificationsWithMaximumSpeed=Dict[] - energySavingModificationsWithCombination=Dict[] - - for csId in 1:length(CSsOrig) - # method 1: increase coasting - if doMethod1 == true - modificationType = "increasing coasting" - energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train) - push!(energySavingModificationsWithCoasting, energySavingModification) - end #if doMethod1 - - # method 2: accelerate to a lower v_peak - if doMethod2 == true - modificationType = "decreasing maximum velocity" - energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train) - push!(energySavingModificationsWithMaximumSpeed, energySavingModification) - end #if doMethod2 - - # calculate the combination of the previous methods - if doCombinationOfMethods == true - modificationType = "combination of energy saving methods" - energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csId, modificationType, settings, train) - push!(energySavingModificationsWithCombination, energySavingModification) - end #if - end # for - - # 01/03 old wit too long calculation time: while movingSectionOriginal[:t_recoveryAvailable] > 0.0 - while movingSectionOriginal[:t_recoveryAvailable] >= 1/(10^approximationLevel) - # compare modifications - ratioMax=0.0 - csIdMax=0 - typeMax="none" - (energySavingModificationsWithMaximumSpeed, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithMaximumSpeed, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable]) - (energySavingModificationsWithCoasting, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithCoasting, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable]) - (energySavingModificationsWithCombination, ratioMax, csIdMax, typeMax) = findBestModification(energySavingModificationsWithCombination, ratioMax, csIdMax, typeMax, movingSectionOriginal[:t_recoveryAvailable]) - - - # select the most efficient modification and update the original characteristicSection, drivingCourse and movingSection - # in case none of the modifications has a ratio>0 stop the calculation - if typeMax=="none" - break - elseif typeMax=="increasing coasting" - # println("Energy saving modification number ",length(movingSectionOriginal[:energySavingModifications])+1," (coasting) in CS ",csIdMax ," Δt=",energySavingModificationsWithCoasting[csIdMax][:Δt]," ΔE=", energySavingModificationsWithCoasting[csIdMax][:ΔE]," t_recoveryAvailable=", movingSectionOriginal[:t_recoveryAvailable]-energySavingModificationsWithCoasting[csIdMax][:Δt]) - push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithCoasting[csIdMax]) - # println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=increasing coasting") - elseif typeMax=="decreasing maximum velocity" - push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithMaximumSpeed[csIdMax]) - # println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=decreasing maximum velocity") - elseif typeMax=="combination of energy saving methods" - push!(movingSectionOriginal[:energySavingModifications], energySavingModificationsWithCombination[csIdMax]) - # println("Nr. ",length(movingSectionOriginal[:energySavingModifications]),": typeMax=combination of energy saving methods") - end #if - - movingSectionOriginal[:t_recoveryAvailable] = movingSectionOriginal[:t_recoveryAvailable] - movingSectionOriginal[:energySavingModifications][end][:Δt] - - lastIdOfSelectedCsOriginal = get(CSsOrig[csIdMax][:behaviorSections], :standstill, - get(CSsOrig[csIdMax][:behaviorSections], :braking, - get(CSsOrig[csIdMax][:behaviorSections], :coasting, - get(CSsOrig[csIdMax][:behaviorSections], :cruising, - get(CSsOrig[csIdMax][:behaviorSections], :accelerating, - get(CSsOrig[csIdMax][:behaviorSections], :clearing, - get(CSsOrig[csIdMax][:behaviorSections], :breakFree, - get(CSsOrig[csIdMax][:behaviorSections], :diminishing, - Dict(:dataPoints => [0])))))))))[:dataPoints][end] - - # if there is a diminishing phase its location must be analysed seperately because it could be before accelerating, between accelerating and cruising or after cruising. All the other behavior sections occure in a fixed order. - if haskey(CSsOrig[csIdMax][:behaviorSections], :diminishing) - lastIdOfSelectedCsOriginal = max(lastIdOfSelectedCsOriginal, CSsOrig[csIdMax][:behaviorSections][:diminishing][:dataPoints][end]) - end - - # create new driving course - drivingCourseNew = copy(movingSectionOriginal[:energySavingModifications][end][:drivingCourseModified]) - - #fill up the rest of the driving course with information from the original course - drivingCourseNew[end][:F_T]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:F_T] - drivingCourseNew[end][:R_traction]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_traction] - drivingCourseNew[end][:R_wagons]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_wagons] - drivingCourseNew[end][:R_train]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_train] - drivingCourseNew[end][:R_path]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:R_path] - drivingCourseNew[end][:F_R]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:F_R] - drivingCourseNew[end][:a]=drivingCourseOriginal[lastIdOfSelectedCsOriginal][:a] - - endOfModificationId=drivingCourseNew[end][:i] # is needed for updating the other modified driving courses - difference=endOfModificationId-lastIdOfSelectedCsOriginal - - i=lastIdOfSelectedCsOriginal+1 - while i <= length(drivingCourseOriginal) - push!(drivingCourseNew, copy(drivingCourseOriginal[i])) - drivingCourseNew[end][:i]=length(drivingCourseNew) - drivingCourseNew[end][:t]=drivingCourseNew[end-1][:t]+drivingCourseNew[end][:Δt] - drivingCourseNew[end][:E]=drivingCourseNew[end-1][:E]+drivingCourseNew[end][:ΔE] - drivingCourseNew[end][:W]=drivingCourseNew[end-1][:W]+drivingCourseNew[end][:ΔW] - i=i+1 - end # while - - # replace the original driving course and CS with the new modified ones - drivingCourseOriginal=drivingCourseNew - CSsOrig[csIdMax]=copyCharacteristicSection(movingSectionOriginal[:energySavingModifications][end][:csModified]) - # 01/09 old with copy: CSsOrig[csIdMax]=copy(movingSectionOriginal[:energySavingModifications][end][:csModified]) - movingSectionOriginal[:t]=drivingCourseOriginal[end][:t] # total running time (in s) - movingSectionOriginal[:E]=drivingCourseOriginal[end][:E] # total energy consumption (in Ws) - - # update all the data point references in the behaviour sections of the following characteristic sections and the other modified characteristic sections - if difference!= 0 - # update the data point references in the behaviour sections of the following characteristic sections - allBs=[:breakFree, :clearing, :accelerating, :cruising, :downhillBraking, :diminishing, :coasting, :braking, :standstill] - for csId in csIdMax+1:length(CSsOrig) - for bs in 1: length(allBs) - if haskey(CSsOrig[csId][:behaviorSections], allBs[bs]) - for point in 1:length(CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints]) - CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints][point] = CSsOrig[csId][:behaviorSections][allBs[bs]][:dataPoints][point]+difference - end - end #if - end #for - end #for - - # update the data points in the following modified charateristic sections and the following points in the driving course - energySavingModificationsWithCoasting = updateEnergySavingModifications!(energySavingModificationsWithCoasting, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal) - energySavingModificationsWithMaximumSpeed = updateEnergySavingModifications!(energySavingModificationsWithMaximumSpeed, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal) - energySavingModificationsWithCombination = updateEnergySavingModifications!(energySavingModificationsWithCombination, csIdMax, drivingCourseNew, endOfModificationId, lastIdOfSelectedCsOriginal) - end # if difference - - # modify new CS for the considered methods - # method 1: increase coasting - if doMethod1==true - modificationType = "increasing coasting" - energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train) - energySavingModificationsWithCoasting[csIdMax]=energySavingModification - end #if if doMethod1 - - # method 2: accelerate to a lower v_peak - if doMethod2==true - modificationType = "decreasing maximum velocity" - energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train) - energySavingModificationsWithMaximumSpeed[csIdMax]=energySavingModification - end #if if doMethod - - # combination of both methods - if doCombinationOfMethods==true - modificationType = "combination of energy saving methods" - energySavingModification = modifyCs(movingSectionOriginal, drivingCourseOriginal, csIdMax, modificationType, settings, train) - energySavingModificationsWithCombination[csIdMax]=energySavingModification - end #if doCombinationOfMethods - end # while - - (CSsOrig[end], drivingCourseOriginal) = addStandstill!(CSsOrig[end], drivingCourseOriginal, settings, train, CSsOrig) - - println("t_recoveryAvailable=",movingSectionOriginal[:t_recoveryAvailable]) - return (movingSectionOriginal, drivingCourseOriginal) -end #function calculateMinimumEnergyConsumption - -## copy the different sections the whole path can be devided in -function copyMovingSection(original::Dict) - copiedCSs = Vector{Dict}() - for csId in 1:length(original[:characteristicSections]) - push!(copiedCSs, copyCharacteristicSection(original[:characteristicSections][csId])) - # 01/07 old without copy: push!(copiedCSs, copyCharacteristicSection(original[:characteristicSections][csId])) - end #for - - copiedMS = Dict(:id => original[:id], # identifier - :length => original[:length], # total length (in m) - :s_entry => original[:s_entry], # first position (in m) - :s_exit => original[:s_exit], # last position (in m) - :t => original[:t], # total running time (in s) - :E => original[:E], # total energy consumption (in Ws) - :characteristicSections => copiedCSs) # list of containing characteristic sections - - if haskey(original, :energySavingModifications) # list of containing all the used energy saving modifications - copiedModifications = Dict[] - for modId in 1:length(original[:energySavingModifications]) - push!(copiedModifications, copyEnergySavingModification(original[:energySavingModifications][modId])) - end #for - merge!(copiedMS, Dict(:energySavingModifications => copiedModifications)) - end - - if haskey(original, :t_recovery) # total recovery time for energy-saving modifications (in s) - merge!(copiedMS, Dict(:t_recovery => original[:t_recovery])) - end - - if haskey(original, :t_recoveryAvailable) # still available recovery time for energy-saving modifications (in s) - merge!(copiedMS, Dict(:t_recoveryAvailable => original[:t_recoveryAvailable])) - end - return copiedMS -end #function copyMovingSection - -function copyCharacteristicSection(originalCS::Dict) - allBs=[:breakFree, :clearing, :accelerating, :cruising, :downhillBraking, :diminishing, :coasting, :braking, :standstill] - copiedBSs = Dict() - for bs in 1: length(allBs) - if haskey(originalCS[:behaviorSections], allBs[bs]) - merge!(copiedBSs, Dict(allBs[bs] => originalCS[:behaviorSections][allBs[bs]])) - end #if - end #for - - copiedCS=Dict(:id => originalCS[:id], # identifier - :s_entry => originalCS[:s_entry], # first position (in m) - :s_exit => originalCS[:s_exit], # last position (in m) - :length => originalCS[:length], # total length (in m) - :r_path => originalCS[:r_path], # path resistance (in ‰) - # :behaviorSections => copy(originalCS[:behaviorSections]), # list of containing behavior sections - :behaviorSections => copiedBSs, # list of containing behavior sections - :t => originalCS[:t], # total running time (in s) - :E => originalCS[:E], # total energy consumption (in Ws) - :v_limit => originalCS[:v_limit], # speed limit (in m/s) - :v_peak => originalCS[:v_peak], # maximum reachable speed (in m/s) - :v_entry => originalCS[:v_entry], # maximum entry speed (in m/s) - :v_exit => originalCS[:v_exit], # maximum exit speed (in m/s) - :pointsOfInterest => originalCS[:pointsOfInterest]) # points of interest for which data points should be calculated - - return copiedCS -end # CharacteristicSection - -# smallest section of the path is the behavior section. It relates to the containing data points via their identifier. -function copyBehaviorSection(original::Dict) - bsDataPoints=[] - for i in 1:length(original[:dataPoints]) - push!(bsDataPoints, original[:dataPoints][i]) - end - copiedBS = Dict(#:type => behavior, # type of behavior section: breakFree, clearing, accelerating, cruising, diminishing, coasting, braking or standstill - :type => original[:type], # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "standstill" - :length => original[:length], # total length (in m) - :s_entry => original[:s_entry], # first position (in m) - :s_exit => original[:s_exit], # last position (in m) - :t => original[:t], # total running time (in s) - :E => original[:E], # total energy consumption (in Ws) - :v_entry => original[:v_entry], # entry speed (in m/s) - :v_exit => original[:v_exit], # exit speed (in m/s) - :dataPoints => bsDataPoints) # list of identifiers of the containing data points - return copiedBS -end #function copyBehaviorSection - -## for the energy saving operation mode it is nesserary to compare different energy saving modifications. These are part of the moving section. -function createEnergySavingModification() - energySavingModification = Dict(:csId => 0, # identifier of the characteristic section - :type => "", # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting" - :ΔE => 0.0, # saved energy (in Ws) - :Δt => 0.0, # time loss (in s) - :ratio => 0.0, # ratio of ΔE and Δt (in Ws/s) - :csModified => Dict(), # the modified characteristic section - :drivingCourseModified => []) # drivingCourse for the modified characteristic section -end #createEnergySavingModification - -function updateEnergySavingModifications!(energySavingModifications::Vector{Dict}, csIdMax::Integer, drivingCourseNew::Vector{Dict}, endOfModificationId::Integer, lastIdOfSelectedCsOriginal::Integer) - allBs=[:breakFree, :clearing, :accelerating, :cruising, :downhillBraking, :diminishing, :coasting, :braking, :standstill] - difference = endOfModificationId-lastIdOfSelectedCsOriginal - for modNr in csIdMax+1:length(energySavingModifications) - if energySavingModifications[modNr][:ratio]>0 - BSs = energySavingModifications[modNr][:csModified][:behaviorSections] - # update the behavior sections of the modified charateristic section - for bs in 1: length(allBs) - if haskey(BSs, allBs[bs]) - for point in 1:length(BSs[allBs[bs]][:dataPoints]) - BSs[allBs[bs]][:dataPoints][point] = BSs[allBs[bs]][:dataPoints][point] + difference - end - end #if - end #for - - # correct the points of previous CS in the modified driving course. Copy the new driving course till the beginning of the current CS and change total values of the current modified CS data points accordingly - drivingCourseModifiedNew = copy(drivingCourseNew[1:endOfModificationId]) - - i=lastIdOfSelectedCsOriginal+1 - while i <= length(energySavingModifications[modNr][:drivingCourseModified]) - push!(drivingCourseModifiedNew, copy(energySavingModifications[modNr][:drivingCourseModified][i])) - - drivingCourseModifiedNew[end][:i]=length(drivingCourseModifiedNew) - drivingCourseModifiedNew[end][:t]=drivingCourseModifiedNew[end-1][:t]+drivingCourseModifiedNew[end][:Δt] - drivingCourseModifiedNew[end][:E]=drivingCourseModifiedNew[end-1][:E]+drivingCourseModifiedNew[end][:ΔE] - drivingCourseModifiedNew[end][:W]=drivingCourseModifiedNew[end-1][:W]+drivingCourseModifiedNew[end][:ΔW] - i=i+1 - end # while - - energySavingModifications[modNr][:drivingCourseModified] = drivingCourseModifiedNew - end #if - end #for - - return energySavingModifications -end #function updateEnergySavingModifications! - -function copyEnergySavingModification(modificaionOriginal::Dict) - modificaionCopy = Dict(:csId => modificaionOriginal[:csId], # identifier of the characteristic section - :type => modificaionOriginal[:type], # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting" - :ΔE => modificaionOriginal[:ΔE], # saved energy (in Ws) - :Δt => modificaionOriginal[:Δt], # time loss (in s) - :ratio => modificaionOriginal[:ratio], # ratio of ΔE and Δt (in Ws/s) - :csModified => copyCharacteristicSection(modificaionOriginal[:]), # the modified characteristic section - :drivingCourseModified => copy(modificaionOriginal[:drivingCourseModified])) # drivingCourse for the modified characteristic section - - return modificaionCopy -end # copyEnergySavingModification - -function modifyCs(movingSectionOriginal::Dict, drivingCourseOriginal::Vector{Dict}, csId::Integer, modificationType::String, settings::Dict, train::Dict) - # TODO: refactor and sort this function - CSsOrig::Vector{Dict} = movingSectionOriginal[:characteristicSections] - - if modificationType == "increasing coasting" - # method 1: increase coasting - (characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=increaseCoastingSection(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable]) - elseif modificationType == "decreasing maximum velocity" - # method 2: accelerate to a lower v_peak - (characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=decreaseMaximumVelocity(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable]) - - elseif modificationType == "combination of energy saving methods" - # calculate the combination of the previous methods - (characteristicSectionModified, drivingCourseModifiedUntilEndOfModifiedCS, new)=combineEnergySavingMethods(CSsOrig[csId], drivingCourseOriginal, settings, train, CSsOrig, movingSectionOriginal[:t_recoveryAvailable]) - else - return createEnergySavingModification() - end - - #energySavingModification = createEnergySavingModification() - if new - energySavingModification = Dict(:csId => csId, # identifier of the characteristic section - :type => modificationType, # type of energy saving modification: "increasing coasting" "decreasing maximum velocity" or "combination of decreasing maximum velocity and coasting" - :csModified => characteristicSectionModified, # the modified characteristic section - :drivingCourseModified => drivingCourseModifiedUntilEndOfModifiedCS) # drivingCourse for the modified characteristic section - - merge!(energySavingModification, Dict(:ΔE => CSsOrig[csId][:E] - energySavingModification[:csModified][:E])) # saved energy (in Ws) - merge!(energySavingModification, Dict(:Δt => energySavingModification[:csModified][:t] - CSsOrig[csId][:t])) # time loss (in s) - - - if energySavingModification[:Δt] <= movingSectionOriginal[:t_recoveryAvailable] && energySavingModification[:ΔE] >= 0.0 - #*** TODO: check why "sign" is needed here - # if modificationType == "combination of energy saving methods" - ratio=sign(energySavingModification[:Δt])*energySavingModification[:ΔE]/energySavingModification[:Δt] # ratio of ΔE and Δt (in Ws/s) - - # else - # ratio = energySavingModification[:ΔE] / energySavingModification[:Δt] # ratio of ΔE and Δt (in Ws/s) - # end - # *** - elseif energySavingModification[:Δt] == 0.0 - ratio = energySavingModification[:ΔE]/0.000000001 - else # Δt is to high or ΔE < 0.0 Ws - ratio = 0.0 - end - merge!(energySavingModification, Dict(:ratio => ratio)) # ratio of ΔE and Δt (in Ws/s) - return energySavingModification - else - return createEnergySavingModification() - end -end #function modifyCs - -function findBestModification(energySavingModifications::Vector{Dict}, ratioMax::AbstractFloat, csIdMax::Integer, typeMax::String, t_recoveryAvailable::AbstractFloat) - for modNr in 1:length(energySavingModifications) - if energySavingModifications[modNr][:ratio] > ratioMax - if energySavingModifications[modNr][:Δt] <= t_recoveryAvailable - ratioMax = energySavingModifications[modNr][:ratio] - csIdMax = energySavingModifications[modNr][:csId] - typeMax = energySavingModifications[modNr][:type] - else # Δt is to high - energySavingModifications[modNr][:ratio]=0.0 - end #if - end #if - end #for - return (energySavingModifications, ratioMax, csIdMax, typeMax) -end #function findBestModification - - -## functions for calculating different energy saving methods that are used in calculateMinimumEnergyConsumption - -function calculateRecoveryTime(s_MS::Real, t_MS::AbstractFloat, train::Dict) - # function for calculating the recovery time that can be used for energy saving - # MS: Moving Section - # 01/05 old without enum: if train[:type]=="motor coach train" - if train[:type] == motorCoachTrain::trainType - if s_MS<= 30000 - c_s=0.0 - else s_MS> 30000 - c_s=0.0006 - end # if s_MS - - if train[:v_limit]<=140/3.6 # unit is m/s - c_t=0.03 - elseif train[:v_limit]<=160/3.6 # unit is m/s - c_t=0.04 - elseif train[:v_limit]<=200/3.6 # unit is m/s - c_t=0.05 - elseif train[:v_limit]<=250/3.6 # unit is m/s - c_t=0.06 - else # train[:v_limit]>120/3.6 # unit is m/s - c_t=0.07 - end # if train[:v_limit] - - t_recovery=s_MS*c_s+t_MS*c_t - return t_recovery - # 01/05 old without enum: elseif train[:type]=="freight" && train[:v_limit]<=120/3.6 # unit is m/s - elseif train[:type] == freight::trainType && train[:v_limit] <= 120/3.6 # unit is m/s - t_recovery1=s_MS*0.0006 +t_MS*0.03 - t_recovery2=s_MS*0.0018 +t_MS*0.0 - t_recovery3=s_MS*0.0 +t_MS*0.04 - t_recovery=max(t_recovery1, t_recovery2, t_recovery3) - - return t_recovery - # 01/05 old without enum: else # train[:trainType]=="passenger" || (train[:trainType]=="freight" && train[:v_limit]>120/3.6) # unit is m/s - else # train[:type] == passenger::trainType || (train[:type] == freight::trainType && train[:v_limit]>120/3.6) # unit is m/s - if s_MS<= 30000 - c_s=0.0 - else s_MS> 30000 - c_s=0.0009 - end # if s_MS - if train[:v_limit]<=140/3.6 # unit is m/s - if train[:m_train]<=300000 # unit is kg - c_t=0.03 - elseif train[:m_train]<=500000 # unit is kg - c_t=0.04 - elseif train[:m_train]<=700000 # unit is kg - c_t=0.04 - else # train[:m_train]>700000 # unit is kg - c_t=0.05 - end # if train[:m_train] - elseif train[:v_limit]<=160/3.6 # unit is m/s - if train[:m_train]<=300000 # unit is kg - c_t=0.03 - elseif train[:m_train]<=500000 # unit is kg - c_t=0.04 - else # train[:m_train]>500000 # unit is kg - c_t=0.0 - end # if train[:m_train] - elseif train[:v_limit]<=200/3.6 # unit is m/s - if train[:m_train]<=300000 # unit is kg - c_t=0.04 - elseif train[:m_train]<=500000 # unit is kg - c_t=0.05 - else # train[:m_train]>500000 # unit is kg - c_t=0.06 - end # if train[:m_train] - else # train[:v_limit]>200/3.6 # unit is m/s - if train[:m_train]<=300000 # unit is kg - c_t=0.05 - elseif train[:m_train]<=500000 # unit is kg - c_t=0.06 - else # train[:m_train]>500000 # unit is kg - c_t=0.07 - end # if train[:m_train] - end # if train[:v_limit] - - c_tMin=s_MS/t_MS*0.0012 - c_t=max(c_t, c_tMin) - - t_recovery=s_MS*c_s+t_MS*c_t - return t_recovery - end # if train[:type] -end #function calculateRecoveryTime - -# TODO: a refactoring caused worse drivingsCourses. see the commented function below -function increaseCoastingSection(csOriginal::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, allCSs::Vector{Dict}, t_recoveryAvailable::AbstractFloat) - BSsOriginal = csOriginal[:behaviorSections] - if (haskey(BSsOriginal, :cruising) || (haskey(BSsOriginal, :diminishing) && get(BSsOriginal, :diminishing, Dict(:dataPoints =>[0]))[:dataPoints][1] > get(BSsOriginal, :accelerating, Dict(:dataPoints =>[0]))[:dataPoints][1])) && haskey(BSsOriginal, :braking) - # check if cruising or diminishing should be reduced for coasting - if haskey(BSsOriginal, :cruising) && haskey(BSsOriginal, :diminishing) - if BSsOriginal[:cruising][:dataPoints][1] > BSsOriginal[:diminishing][:dataPoints][1] - reduceCruising=true - reduceDiminishing=false - else - reduceDiminishing=true - reduceCruising=false - end - elseif haskey(BSsOriginal, :cruising) - reduceCruising=true - reduceDiminishing=false - elseif haskey(BSsOriginal, :diminishing) - reduceDiminishing=true - reduceCruising=false - else - error("in increaseCoastingSection") #TODO - end -#= - # copy csOriginal to csModifiedInitial - csModifiedInitial = copyCharacteristicSection(csOriginal) - BSsModified = csModifiedInitial[:behaviorSections] - - # delete bahavior sections that will be recalculated except breakFree, clearing, accelerating, diminishing - # and rest total running time and energy consumption - if haskey(BSsModified, :coasting) - csModifiedInitial[:E] = csModifiedInitial[:E] - BSsModified[:coasting][:E] - csModifiedInitial[:t] = csModifiedInitial[:t] - BSsModified[:coasting][:t] - delete!(BSsModified, :coasting) - end - if haskey(BSsModified, :braking) - csModifiedInitial[:E] = csModifiedInitial[:E] - BSsModified[:braking][:E] - csModifiedInitial[:t] = csModifiedInitial[:t] - BSsModified[:braking][:t] - delete!(BSsModified, :braking) - end - if haskey(BSsModified, :standstill) - csModifiedInitial[:E] = csModifiedInitial[:E] - BSsModified[:standstill][:E] - csModifiedInitial[:t] = csModifiedInitial[:t] - BSsModified[:standstill][:t] - delete!(BSsModified, :standstill) - end - - - if reduceCruising - cruisingReduction = settings[:stepSize] - # 01/07 test for a better calculation time: cruisingReduction = settings[:stepSize]*100 - - # remove old cruising section - csModifiedInitial[:E] = csModifiedInitial[:E] - BSsModified[:cruising][:E] - csModifiedInitial[:t] = csModifiedInitial[:t] - BSsModified[:cruising][:t] - delete!(BSsModified, :cruising) - - # determine the starting point of saving energy (needed for copying the characteristic section's drivingCourse) - energySavingStartId=get(BSsOriginal, :cruising, Dict(:dataPoints=>[0]))[:dataPoints][1] - if energySavingStartId==0 - error("ERROR at creating a new driving course for energy saving with coasting !") - end - - while cruisingReduction>=settings[:stepSize]/10^approximationLevel - #while cruisingReduction>=settings[:stepSize]/100 - while cruisingReduction>=settings[:stepSize]/10^approximationLevel # will be done once and then depending on approximationLevel repeated with smaller cruisingReduction unless !(drivingCourseModified[end][:v]<=csModified[:v_exit] && drivingCourseModified[end][:s] see below at the end of the while loop - # copy the characteristic section for being modified - csModified = copyCharacteristicSection(csModifiedInitial) - - # copy the driving course till the beginning of energy saving - drivingCourseModified = copy(drivingCourse[1:energySavingStartId]) # List of data points till the start of energy saving - - # calculating the new length of the cruising section - if settings[:stepVariable]=="s in m" # distance step method - s_cruising = BSsOriginal[:cruising][:length] - cruisingReduction - elseif settings[:stepVariable]=="t in s" # time step method - # 09/20 old: doesn't work for non constant cruising -> TODO: should work now - # t_cruising=BSsOriginal[:cruising][:t]-cruisingReduction - # s_cruising=t_cruising*drivingCourseModified[end][:v] - distanceReduction = drivingCourse[BSsOriginal[:cruising][:dataPoints][end]][:v] * cruisingReduction - s_cruising = BSsOriginal[:cruising][:length]-distanceReduction - - elseif settings[:stepVariable]=="v in m/s" # velocity step method - s_cruising=BSsOriginal[:cruising][:length]-cruisingReduction*10 # TODO: or better: *100 ? - end #if - s_cruising=max(0.0, s_cruising) - - # calculate the new and now shorter cruising section - if s_cruising>0.0 - (csModified, drivingCourseModified)=addCruisingSection!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") - end - - # calculate the coasting phase until the point the train needs to brake - (csModified, drivingCourseModified)=addCoastingSection!(csModified, drivingCourseModified, settings, train, allCSs) - - if drivingCourseModified[end][:v] < csModified[:v_exit] || drivingCourseModified[end][:s] > csModified[:s_exit] - # the train reaches v_exit before reaching s_exit. The cruising and coasting sections have to be calculated again with a larger cruising section (so with a smaller reduction of the cruising section) - cruisingReduction=cruisingReduction/10 - else - break - end - end # while cruisingReduction - - # calculate the moving phase between coasting and the end of the CS - if drivingCourseModified[end][:v] > csModified[:v_exit] - #(csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) - (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) - end - - if t_recoveryAvailable < csModified[:t]-csOriginal[:t] || drivingCourseModified[end][:v] != csModified[:v_exit] || drivingCourseModified[end][:s] != csModified[:s_exit] # time loss is to high and the CS has to be calculated again with larger cruising section (so with a smaller reduction of the cruising section) or v_exit or s_exit are not reached excatly - cruisingReduction=cruisingReduction/10 - else - return (csModified, drivingCourseModified, true) - end - end #while - - - elseif reduceDiminishing - # TODO: At the moment diminishing is reduced similar to the accelerating in decreaseMaximumVelocity. To reduce code the methods for reducing cruising phase and reducing the diminishing phase can be combined in some parts. - csModified = csModifiedInitial - diminishingSection = BSsModified[:diminishing] - - # remove the last diminishing data point - t_diff = drivingCourse[diminishingSection[:dataPoints][end]][:t] - drivingCourse[diminishingSection[:dataPoints][end-1]][:t] - E_diff = drivingCourse[diminishingSection[:dataPoints][end]][:E] - drivingCourse[diminishingSection[:dataPoints][end-1]][:E] - pop!(diminishingSection[:dataPoints]) - - diminishingSection[:v_exit] = drivingCourse[diminishingSection[:dataPoints][end]][:v] # exit speed (in m/s) - diminishingSection[:s_exit] = drivingCourse[diminishingSection[:dataPoints][end]][:s] # last position (in m) - diminishingSection[:length] = diminishingSection[:s_exit] - diminishingSection[:s_entry] # total length (in m) - diminishingSection[:t] = diminishingSection[:t] - t_diff # total running time (in s) - diminishingSection[:E] = diminishingSection[:E] - E_diff # total energy consumption (in Ws) - - # merge!(BSsModified, Dict(:diminishing => diminishingSection)) - csModified[:E] = csModified[:E] - t_diff - csModified[:t] = csModified[:t] - E_diff - - energySavingStartId = diminishingSection[:dataPoints][end] - - if length(diminishingSection[:dataPoints]) == 2 # The diminishing section was only one step. This step is removed and so the complette diminishing section. - delete!(BSsModified, :diminishing) - end - -#_____________ -=# - - if reduceCruising - cruisingReduction = settings[:stepSize] - # 01/07 test for a better calculation time: cruisingReduction = settings[:stepSize]*100 - while cruisingReduction>=settings[:stepSize]/10^approximationLevel - #while cruisingReduction>=settings[:stepSize]/100 - while cruisingReduction>=settings[:stepSize]/10^approximationLevel # will be done once and then depending on approximationLevel repeated with smaller cruisingReduction unless !(drivingCourseModified[end][:v]<=csModified[:v_exit] && drivingCourseModified[end][:s] see below at the end of the while loop - - # create a copy for the characteristic sections drivingCourse - energySavingStartId=get(BSsOriginal, :cruising, Dict(:dataPoints=>[0]))[:dataPoints][1] - if energySavingStartId==0 - error("ERROR at creating a new driving course for energy saving with coasting !") - end - - # copy the driving course till the beginning of energy saving - drivingCourseModified = copy(drivingCourse[1:energySavingStartId]) # List of data points till the start of energy saving - - # calculating the new length of the cruising section - if settings[:stepVariable]=="s in m" # distance step method - s_cruising = BSsOriginal[:cruising][:length] - cruisingReduction - elseif settings[:stepVariable]=="t in s" # time step method - # 09/20 old: doesn't work for non constant cruising -> TODO: should work now - # t_cruising=BSsOriginal[:cruising][:t]-cruisingReduction - # s_cruising=t_cruising*drivingCourseModified[end][:v] - distanceReduction = drivingCourse[BSsOriginal[:cruising][:dataPoints][end]][:v]*cruisingReduction - s_cruising = BSsOriginal[:cruising][:length]-distanceReduction - - elseif settings[:stepVariable]=="v in m/s" # velocity step method - s_cruising=BSsOriginal[:cruising][:length]-cruisingReduction*10 # TODO: or better: *100 ? - end #if - s_cruising=max(0.0, s_cruising) - - # copy csOriginal to csModified - # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, Dict}()) - #TODO after removing the mutable structs: Is it possible to just "copy"? with some changes - csModified=Dict(:id => csOriginal[:id], # identifier - :s_entry => csOriginal[:s_entry], # first position (in m) - :s_exit => csOriginal[:s_exit], # last position (in m) - :length => csOriginal[:length], # total length (in m) - :r_path => csOriginal[:r_path], # path resistance (in ‰) - :behaviorSections => Dict(), # empty list of containing behavior sections - :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) - :v_limit => csOriginal[:v_limit], # speed limit (in m/s) - :v_peak => csOriginal[:v_peak], # maximum reachable speed (in m/s) - :v_entry => csOriginal[:v_entry], # maximum entry speed (in m/s) - :v_exit => csOriginal[:v_exit], # maximum exit speed (in m/s) - :pointsOfInterest => csOriginal[:pointsOfInterest]) # points of interest for which data points should be calculated - - BSsModified = csModified[:behaviorSections] - if haskey(BSsOriginal, :breakFree) - breakFreeSection=copyBehaviorSection(BSsOriginal[:breakFree]) - merge!(BSsModified, Dict(:breakFree=>breakFreeSection)) - csModified[:E] = csModified[:E] + BSsModified[:breakFree][:E] - csModified[:t] = csModified[:t] + BSsModified[:breakFree][:t] - end - if haskey(BSsOriginal, :clearing) # this section is needed before accelerating if the train wants to accelerate to a speed higher than the limit in a previous CS where parts of the train are still located - clearingSection=copyBehaviorSection(BSsOriginal[:clearing]) - merge!(BSsModified, Dict(:clearing=>clearingSection)) - csModified[:E] = csModified[:E] + BSsModified[:clearing][:E] - csModified[:t] = csModified[:t] + BSsModified[:clearing][:t] - end - if haskey(BSsOriginal, :accelerating) - acceleratingSection=copyBehaviorSection(BSsOriginal[:accelerating]) - merge!(BSsModified, Dict(:accelerating=>acceleratingSection)) - csModified[:E] = csModified[:E] + BSsModified[:accelerating][:E] - csModified[:t] = csModified[:t] + BSsModified[:accelerating][:t] - end - if haskey(BSsOriginal, :diminishing) - diminishingSection=copyBehaviorSection(BSsOriginal[:diminishing]) - merge!(BSsModified, Dict(:diminishing=>diminishingSection)) - csModified[:E] = csModified[:E] + BSsModified[:diminishing][:E] - csModified[:t] = csModified[:t] + BSsModified[:diminishing][:t] - end - - - # calculate the new and now shorter cruising section - if s_cruising>0.0 - (csModified, drivingCourseModified)=addCruisingSection!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") - end - - # calculate the coasting phase until the point the train needs to brake - (csModified, drivingCourseModified)=addCoastingSection!(csModified, drivingCourseModified, settings, train, allCSs) - - if drivingCourseModified[end][:v] < csModified[:v_exit] || drivingCourseModified[end][:s] > csModified[:s_exit] - # the train reaches v_exit before reaching s_exit. The cruising and coasting sections have to be calculated again with a larger cruising section (so with a smaller reduction of the cruising section) - cruisingReduction=cruisingReduction/10 - else - break - end - end # while cruisingReduction - - # calculate the moving phase between coasting and the end of the CS - if drivingCourseModified[end][:v] > csModified[:v_exit] - #(csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) - (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) - end - - if t_recoveryAvailable < csModified[:t]-csOriginal[:t] || drivingCourseModified[end][:v] != csModified[:v_exit] || drivingCourseModified[end][:s] != csModified[:s_exit] # time loss is to high and the CS has to be calculated again with larger cruising section (so with a smaller reduction of the cruising section) or v_exit or s_exit are not reached excatly - cruisingReduction=cruisingReduction/10 - else - return (csModified, drivingCourseModified, true) - end - end #while - - - elseif reduceDiminishing - # TODO: At the moment diminishing is reduced like the accelerating in decreaseMaximumVelocity. To reduce code the methods for reducing cruising phase and reducing the diminishing phase can be combined in some parts. - - # copy csOriginal to csModified - # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, Dict}()) - csModified=Dict(:id => csOriginal[:id], # identifier - :s_entry => csOriginal[:s_entry], # first position (in m) - :s_exit => csOriginal[:s_exit], # last position (in m) - :length => csOriginal[:length], # total length (in m) - :r_path => csOriginal[:r_path], # path resistance (in ‰) - :behaviorSections => Dict(), # empty list of containing behavior sections - :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) - :v_limit => csOriginal[:v_limit], # speed limit (in m/s) - :v_peak => csOriginal[:v_peak], # maximum reachable speed (in m/s) - :v_entry => csOriginal[:v_entry], # maximum entry speed (in m/s) - :v_exit => csOriginal[:v_exit], # maximum exit speed (in m/s) - :pointsOfInterest => csOriginal[:pointsOfInterest]) # points of interest for which data points should be calculated - - BSsModified = csModified[:behaviorSections] - if haskey(BSsOriginal, :breakFree) - breakFreeSection=copyBehaviorSection(BSsOriginal[:breakFree]) - merge!(BSsModified, Dict(:breakFree=>breakFreeSection)) - csModified[:E] = csModified[:E] + BSsModified[:breakFree][:E] - csModified[:t] = csModified[:t] + BSsModified[:breakFree][:t] - end - if haskey(BSsOriginal, :clearing) # this section is needed before accelerating if the train wants to accelerate to a speed higher than the limit in a previous CS where parts of the train are still located - clearingSection=copyBehaviorSection(BSsOriginal[:clearing]) - merge!(BSsModified, Dict(:clearing=>clearingSection)) - csModified[:E] = csModified[:E] + BSsModified[:clearing][:E] - csModified[:t] = csModified[:t] + BSsModified[:clearing][:t] - end - if haskey(BSsOriginal, :accelerating) - acceleratingSection=copyBehaviorSection(BSsOriginal[:accelerating]) - merge!(BSsModified, Dict(:accelerating=>acceleratingSection)) - csModified[:E] = csModified[:E] + BSsModified[:accelerating][:E] - csModified[:t] = csModified[:t] + BSsModified[:accelerating][:t] - end - if haskey(BSsOriginal, :cruising) - cruisingSection=copyBehaviorSection(BSsOriginal[:cruising]) - merge!(BSsModified, Dict(:cruising=>cruisingSection)) - csModified[:E] = csModified[:E] + BSsModified[:cruising][:E] - csModified[:t] = csModified[:t] + BSsModified[:cruising][:t] - end - - diminishingSection=copyBehaviorSection(BSsOriginal[:diminishing]) - if length(diminishingSection[:dataPoints]) > 2 - # remove the last diminishing data point - pop!(diminishingSection[:dataPoints]) - - diminishingSection[:v_exit]=drivingCourse[diminishingSection[:dataPoints][end]][:v] # exit speed (in m/s) - diminishingSection[:s_exit]=drivingCourse[diminishingSection[:dataPoints][end]][:s] # last position (in m) - diminishingSection[:length]=diminishingSection[:s_exit]-diminishingSection[:s_entry] # total length (in m) - diminishingSection[:t]=drivingCourse[diminishingSection[:dataPoints][end]][:t]-drivingCourse[diminishingSection[:dataPoints][1]][:t] # total running time (in s) - diminishingSection[:E]=drivingCourse[diminishingSection[:dataPoints][end]][:E]-drivingCourse[diminishingSection[:dataPoints][1]][:E] # total energy consumption (in Ws) - - merge!(BSsModified, Dict(:diminishing => diminishingSection)) - csModified[:E] = csModified[:E] + BSsModified[:diminishing][:E] - csModified[:t] = csModified[:t] + BSsModified[:diminishing][:t] - - energySavingStartId=diminishingSection[:dataPoints][end] - else - # The diminishing section is only one step. This step is removed and if there is a clearing section it will be combined with the new cruising section. - energySavingStartId=get(BSsOriginal, :clearing, get(BSsOriginal, :diminishing, Dict(:dataPoints =>[0])))[:dataPoints][1] - end - - # copy the driving course till the beginning of energy saving - drivingCourseModified = copy(drivingCourse[1:energySavingStartId]) # List of data points till the start of energy saving - - # calculate the coasting phase until the point the train needs to brake - (csModified, drivingCourseModified)=addCoastingSection!(csModified, drivingCourseModified, settings, train, allCSs) - - # calculate the moving phase between coasting and the end of the CS - if drivingCourseModified[end][:v] > csModified[:v_exit] - (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) - end - - if t_recoveryAvailable >= csModified[:t] - csOriginal[:t] - return (csModified, drivingCourseModified, true) - else # time loss is to high. so there is no energy saving modification for this CS with the available recovery time - # TODO: just return false or take smaller steps? - - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - end - end - - # there is no energy saving modification for this CS with the available recovery time - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - else - # there is no energy saving modification for this CS because a cruising section AND a braking section are needed to be transformed into a coasting section - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - end -end # function increaseCoastingSection - -# method 2 with shortening the accelerating by stepsize -function decreaseMaximumVelocity(csOriginal::Dict, drivingCourse, settings::Dict, train::Dict, allCSs::Vector{Dict}, t_recoveryAvailable::AbstractFloat) - # TODO doesn't work that well alone. works better with combineEnergySavingMethods. why? does a while loop end to early or something like this? - #function decreaseMaximumVelocity(csOriginal::CharacteristicSection, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, allCSs::Vector{CharacteristicSection}, t_recoveryAvailable::AbstractFloat) - BSsOriginal = csOriginal[:behaviorSections] - if haskey(BSsOriginal, :accelerating) && csOriginal[:v_peak] > csOriginal[:v_entry] && csOriginal[:v_peak] > csOriginal[:v_exit] - acceleratingSection = copyBehaviorSection(BSsOriginal[:accelerating]) - - if drivingCourse[acceleratingSection[:dataPoints][end]-1][:v] < csOriginal[:v_exit] - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - # TODO: or calculate a new accelerating phase with v_exit as v_peak? it will be very short, shorter than the step size. - end - - # copy csOriginal to csModified - # 12/28 old: csModified=CharacteristicSection(csOriginal[:id], csOriginal[:length], csOriginal[:s_entry], csOriginal[:s_exit], 0.0, 0.0, csOriginal[:v_limit], csOriginal[:v_peak], csOriginal[:v_entry], csOriginal[:v_exit], csOriginal[:r_path], Dict{Symbol, Dict}()) - csModified=Dict(:id => csOriginal[:id], # identifier - :s_entry => csOriginal[:s_entry], # first position (in m) - :s_exit => csOriginal[:s_exit], # last position (in m) - :length => csOriginal[:length], # total length (in m) - :r_path => csOriginal[:r_path], # path resistance (in ‰) - :behaviorSections => Dict(), # empty list of containing behavior sections - :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) - :v_limit => csOriginal[:v_limit], # speed limit (in m/s) - :v_peak => csOriginal[:v_peak], # maximum reachable speed (in m/s) - :v_entry => csOriginal[:v_entry], # maximum entry speed (in m/s) - :v_exit => csOriginal[:v_exit], # maximum exit speed (in m/s) - :pointsOfInterest => csOriginal[:pointsOfInterest]) # points of interest for which data points should be calculated - - BSsModified = csModified[:behaviorSections] - if haskey(BSsOriginal, :breakFree) - breakFreeSection=copyBehaviorSection(BSsOriginal[:breakFree]) - merge!(BSsModified, Dict(:breakFree=>breakFreeSection)) - csModified[:E] = csModified[:E] + BSsModified[:breakFree][:E] - csModified[:t] = csModified[:t] + BSsModified[:breakFree][:t] - end - if haskey(BSsOriginal, :diminishing) && BSsModified[:diminishing][:dataPoints][1] < BSsModified[:accelerating][:dataPoints][1] - diminishingSection=copyBehaviorSection(BSsOriginal[:diminishing]) - merge!(BSsModified, Dict(:diminishing=>diminishingSection)) - csModified[:E] = csModified[:E] + BSsModified[:diminishing][:E] - csModified[:t] = csModified[:t] + BSsModified[:diminishing][:t] - end - - if length(acceleratingSection[:dataPoints]) > 2 - if haskey(BSsOriginal, :clearing) - clearingSection=copyBehaviorSection(BSsOriginal[:clearing]) - merge!(BSsModified, Dict(:clearing=>clearingSection)) - csModified[:E] = csModified[:E] + BSsModified[:clearing][:E] - csModified[:t] = csModified[:t] + BSsModified[:clearing][:t] - end - - # remove the last data point from the acceleratingSection - pop!(acceleratingSection[:dataPoints]) - energySavingStartId = acceleratingSection[:dataPoints][end] - - acceleratingSection[:v_exit]=drivingCourse[energySavingStartId][:v] # exit speed (in m/s) - acceleratingSection[:s_exit]=drivingCourse[energySavingStartId][:s] # last position (in m) - acceleratingSection[:length]=acceleratingSection[:s_exit]-acceleratingSection[:s_entry] # total length (in m) - acceleratingSection[:t]=drivingCourse[energySavingStartId][:t]-drivingCourse[acceleratingSection[:dataPoints][1]][:t] # total running time (in s) - acceleratingSection[:E]=drivingCourse[energySavingStartId][:E]-drivingCourse[acceleratingSection[:dataPoints][1]][:E] # total energy consumption (in Ws) - - merge!(BSsModified, Dict(:accelerating=>acceleratingSection)) - csModified[:E] = csModified[:E] + acceleratingSection[:E] - csModified[:t] = csModified[:t] + acceleratingSection[:t] - - else - # The accelerating section is only one step. This step is removed and if there is a clearing section it will be combined with the new cruising section. - energySavingStartId=get(BSsOriginal, :clearing, get(BSsOriginal, :accelerating, Dict(:dataPoints =>[0])))[:dataPoints][1] - end - - # TODO: should v_peak be reduced or is it enough to pop the data points? - # characteristicSection[:v_peak]=drivingCourse[end][:v] # setting v_peak to the last data point's velocity which is the highest reachable value in this characteristic section - - # copy the drivingCourse till the beginning of energy saving - drivingCourseModified = copy(drivingCourse[1:energySavingStartId]) # List of data points till the start of energy saving - - s_braking = calcBrakingDistance(drivingCourseModified[end][:v], csModified[:v_exit], train[:a_braking]) - s_cruising = csModified[:s_exit]-drivingCourseModified[end][:s]-s_braking - - if s_cruising > 1/10^approximationLevel - # 01/09 old if s_cruising > 0.001 - (csModified, drivingCourseModified)=addCruisingSection!(csModified, drivingCourseModified, s_cruising, settings, train, allCSs, "cruising") - end #if - - - # s_brakingAfterCruising=ceil((csModified[:v_exit]^2-drivingCourseModified[end][:v]^2)/2/train[:a_braking], digits=10) # TODO: check if s_braking and s_brakingAfterCruising are really always the same - if drivingCourseModified[end][:v]>csModified[:v_exit] - #(csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings[:massModel], train, allCSs) - (csModified, drivingCourseModified)=addBrakingSection!(csModified, drivingCourseModified, settings, train, allCSs) - - elseif drivingCourseModified[end][:s]0.001 - # if (csModified[:s_exit]-drivingCourseModified[end][:s])>10^(-approximationLevel) - # println("INFO: The end of new CS",csModified[:id]," is not reached while saving energy with lowering v_peak.") - # println(" Therefore the calculation of this method can not continue for this CS.") - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - end - println("WARNING: The end of new CS",csModified[:id]," is not reached while saving energy with lowering v_peak.") - println(" Therefore s=",drivingCourseModified[end][:s]," will be set s_exit=",csModified[:s_exit]," because the difference is only ",csModified[:s_exit]-drivingCourseModified[end][:s]," m.") - println(" v=",drivingCourseModified[end][:v]," m/s v_exit=",csOriginal[:v_exit] ," m/s") - - drivingCourseModified[end][:s] = csModified[:s_exit] # rounding up to s_exit - drivingCourseModified[end][:Δs] = drivingCourseModified[end][:s] - drivingCourseModified[end-1][:s] - end #if - - if t_recoveryAvailable >= csModified[:t] - csOriginal[:t] - - return (csModified, drivingCourseModified, true) - else # time loss is to high. so there is no energy saving modification for this CS with the available recovery time - # 09/06 old: else # time loss is to high and the CS has to be calculated again with larger accelerating section (so with a smaller reduction of the accelerating section) - # 09/06 old: acceleratingReduction=min(acceleratingReduction/10, csModified[:v_peak]-csModified[:v_entry], csModified[:v_peak]-csModified[:v_exit]) - # TODO: just return false or take smaller steps? - - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - end - - # 09/06 old: end #while - # - # 09/06 old: # there is no energy saving modification for this CS with the available recovery time - # old: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - # 12/29 new, now not with empty but with original CS and DC: return (csOriginal, drivingCourse, false) - - - else - # there is no energy saving modification for this CS because v_peak can not be lowered below v_entry or v_exit or because there is no accelerating section that can be transformed into a cruising section - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - end #if haskey -end # function decreaseMaximumVelocity - -# combination of method 1 and method 2 -function combineEnergySavingMethods(csOriginal::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, allCSs::Vector{Dict}, t_recoveryAvailable::AbstractFloat) - BSsOriginal = csOriginal[:behaviorSections] - # if haskey(BSsOriginal, :accelerating) && (haskey(BSsOriginal, :braking) || haskey(BSsOriginal, :coasting)) && csOriginal[:v_peak]>csOriginal[:v_entry] && csOriginal[:v_peak]>csOriginal[:v_exit] - if haskey(BSsOriginal, :accelerating) && (haskey(BSsOriginal, :braking) || haskey(BSsOriginal, :coasting)) && drivingCourse[get(BSsOriginal, :accelerating, Dict(:dataPoints =>[0]))[:dataPoints][end]][:v] > max(csOriginal[:v_entry], csOriginal[:v_exit]) - # copy the characteristic section - csCombined = copyCharacteristicSection(csOriginal) - - # copy the drivingCourse - drivingCourseCombined = copy(drivingCourse) - - ΔE=0.0 # saved energy (in Ws) - Δt=0.0 # time loss (in s) - #while (Δt0.0))# && Δt>0.0)) - else - # there is no energy saving modification for this CS because v_peak can not be lowered below v_entry or v_exit or because there is no accelerating section and braking section or coasting section that can be transformed into a cruising section or coasting section - # 12/29 old, now not with empty but with original CS and DC: return (Dict(), [], false) # TODO: Does the empty CS-Dict need default attributes? - return (csOriginal, drivingCourse, false) - end #if -end #function combineEnergySavingMethods - -end #module EnergySaving diff --git a/src/Export.jl b/src/Export.jl deleted file mode 100644 index e88468a..0000000 --- a/src/Export.jl +++ /dev/null @@ -1,220 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 -# __author__ = "Max Kannenberg" -# __copyright__ = "2020-2022" -# __license__ = "ISC" - -module Export - -using CSV, DataFrames, Dates - -export exportToCsv - -function exportToCsv(runningTime::AbstractFloat, settings::Dict) - createCsvFile(runningTime, settings) - - return true -end - -function exportToCsv(dataPointsToExport::Vector{Dict}, settings::Dict) - createCsvFile(dataPointsToExport, settings) - - return true -end - -function exportToCsv(output::Dict) - if output[:settings][:typeOfOutput] == "CSV" - pathName = output[:path][:name] - trainName = output[:train][:name] - - if output[:settings][:operationModeMinimumRunningTime] == true - operationMode = "minimum running time" - if output[:settings][:detailOfOutput] == "points of interest" - dataPointsToExport = output[:pointsOfInterestMinimumRunningTime] - else - dataPointsToExport = output[:drivingCourseMinimumRunningTime] - end - createCsvFile(dataPointsToExport, operationMode, pathName, trainName, output[:settings]) - end - if output[:settings][:operationModeMinimumEnergyConsumption] == true - operationMode = "minimum energy consumption" - if output[:settings][:detailOfOutput] == "points of interest" - dataPointsToExport = output[:pointsOfInterestMinimumEnergyConsumption] - else - dataPointsToExport = output[:drivingCourseMinimumEnergyConsumption] - end - createCsvFile(dataPointsToExport, operationMode, pathName, trainName, output[:settings]) - end - return true - end - return false -end #function exportToCsv - -function createCsvFile(runningTime::AbstractFloat, settings::Dict) - # create DataFrame with running time information - df = DataFrame(column1=["t (in s)", runningTime]) - - # save DataFrame as a CSV-file at csvDirectory - date = Dates.now() - dateString = Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - - csvFilePath = settings[:csvDirectory]*"/"*dateString*"_RunningTime.csv" - - CSV.write(csvFilePath, df, header=false) - println("The output CSV file has been created at ",csvFilePath) - - return true -end #function createCsvFile - - -function createCsvFile(dataPointsToExport::Vector{Dict}, settings::Dict) - detailOfOutput = settings[:detailOfOutput] - - header = ["i", "behavior", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"] - columnSymbols = [:i, :behavior, :Δs, :s, :Δt, :t, :Δv, :v, :F_T, :F_R, :R_path, :R_train, :R_traction, :R_wagons, :ΔW, :W, :ΔE, :E, :a] - - allColumns = Array{Any,1}[] - for column in 1:length(header) - currentColumn = Any[] - push!(currentColumn, header[column]) - for point in dataPointsToExport - push!(currentColumn, point[columnSymbols[column]]) - end - push!(allColumns, currentColumn) - end # for - - - # combine the columns in a data frame and saving it as a CSV-file at csvDirectory - if detailOfOutput == "driving course" || detailOfOutput == "points of interest" - df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19]) - - else - println("") - end - - date = Dates.now() - dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - csvFilePath=settings[:csvDirectory]*"/"*dateString*"_DataPoints.csv" - CSV.write(csvFilePath, df, header=false) - println("The output CSV file has been created at ",csvFilePath) - - return true -end #function createCsvFile - - -function createCsvFile(dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Dict) - detailOfOutput = settings[:detailOfOutput] - - massModel = settings[:massModel] - stepVariable = settings[:stepVariable] - stepSize = string(settings[:stepSize]) - - # create accumulated data block - accumulatedData = Array{Any, 1}[] - push!(accumulatedData, ["i", "behavior", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]) # push header to accumulatedData - for point in dataPointsToExport - row = [point[:i], point[:behavior], point[:Δs], point[:s], point[:Δt], point[:t], point[:Δv], point[:v], point[:F_T], point[:F_R], point[:R_path], point[:R_train], point[:R_traction], point[:R_wagons], point[:ΔW], point[:W], point[:ΔE], point[:E], point[:a]] - push!(accumulatedData, row) # push row to accumulatedData - end - - #create information block - allColumns=Array{Any,1}[] - push!(allColumns, ["path name", "train name", "operation mode", "mass model", "step variable", "step size", ""]) - push!(allColumns, [pathName, trainName, operationMode, massModel, stepVariable, stepSize, ""]) - for column in 3:length(accumulatedData[1]) - push!(allColumns, ["", "", "", "", "", "", ""]) - end # for - - # add driving data to the array - header = accumulatedData[1] - for column in 1:length(accumulatedData[1]) - push!(allColumns[column], header[column]) - for row in accumulatedData[2:end] - push!(allColumns[column], row[column]) - end - end # for - - # combine the columns in a data frame and saving it as a CSV-file at csvDirectory - df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19]) - - date = Dates.now() - dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - if operationMode == "minimum running time" - csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumRunningTime.csv" - elseif operationMode == "minimum energy consumption" - csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumEnergyConsumption.csv" - else - # should not be possible - end - CSV.write(csvFilePath, df, header=false) - println("The output CSV file has been created for ",operationMode," at ",csvFilePath) - - return true -end #function createCsvFile - - - -#= -function createCsvFile(movingSection::Dict, dataPointsToExport::Vector{Dict}, operationMode::String, pathName::String, trainName::String, settings::Dict) - detailOfOutput = settings[:detailOfOutput] - - massModel = settings[:massModel] - stepVariable = settings[:stepVariable] - stepSize = string(settings[:stepSize]) - - # create accumulated data block - accumulatedData = Array{Any, 1}[] - if detailOfOutput == "minimal" - push!(accumulatedData, ["s (in m)", "t (in s)","E (in Ws)"]) # push header to accumulatedData - row = [movingSection[:length], movingSection[:t], movingSection[:E]] - push!(accumulatedData, row) # push row to accumulatedData - elseif detailOfOutput == "driving course" || detailOfOutput == "points of interest" - push!(accumulatedData, ["i", "behavior", "Δs (in m)", "s (in m)", "Δt (in s)","t (in s)","Δv (in m/s)","v (in m/s)","F_T (in N)","F_R (in N)","R_path (in N)","R_train (in N)","R_traction (in N)","R_wagons (in N)", "ΔW (in Ws)","W (in Ws)","ΔE (in Ws)","E (in Ws)","a (in m/s^2)"]) # push header to accumulatedData - for point in dataPointsToExport - row = [point[:i], point[:behavior], point[:Δs], point[:s], point[:Δt], point[:t], point[:Δv], point[:v], point[:F_T], point[:F_R], point[:R_path], point[:R_train], point[:R_traction], point[:R_wagons], point[:ΔW], point[:W], point[:ΔE], point[:E], point[:a]] - push!(accumulatedData, row) # push row to accumulatedData - end - end - - #create information block - allColumns=Array{Any,1}[] - push!(allColumns, ["path name", "train name", "operation mode", "mass model", "step variable", "step size", ""]) - push!(allColumns, [pathName, trainName, operationMode, massModel, stepVariable, stepSize, ""]) - for column in 3:length(accumulatedData[1]) - push!(allColumns, ["", "", "", "", "", "", ""]) - end # for - - # add driving data to the array - header = accumulatedData[1] - for column in 1:length(accumulatedData[1]) - push!(allColumns[column], header[column]) - for row in accumulatedData[2:end] - push!(allColumns[column], row[column]) - end - end # for - - # combine the columns in a data frame and saving it as a CSV-file at csvDirectory - if detailOfOutput == "minimal" - df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3]) - elseif detailOfOutput=="driving course" || detailOfOutput == "points of interest" - df = DataFrame(c1=allColumns[1], c2=allColumns[2],c3=allColumns[3], c4=allColumns[4], c5=allColumns[5], c6=allColumns[6], c7=allColumns[7], c8=allColumns[8], c9=allColumns[9], c10=allColumns[10], c11=allColumns[11], c12=allColumns[12], c13=allColumns[13], c14=allColumns[14], c15=allColumns[15], c16=allColumns[16], c17=allColumns[17], c18=allColumns[18], c19=allColumns[19]) - end - - date = Dates.now() - dateString=Dates.format(date, "yyyy-mm-dd_HH.MM.SS") - if operationMode == "minimum running time" - csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumRunningTime.csv" - elseif operationMode == "minimum energy consumption" - csvFilePath=settings[:csvDirectory]*"/"*dateString*"_MinimumEnergyConsumption.csv" - else - # should not be possible - end - CSV.write(csvFilePath, df, header=false) - println("The output CSV file has been created for ",operationMode," at ",csvFilePath) - - return true -end #function createCsvFile -=# - -end #module Export diff --git a/src/Import.jl b/src/Import.jl deleted file mode 100644 index baeb5e8..0000000 --- a/src/Import.jl +++ /dev/null @@ -1,44 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 -# __author__ = "Max Kannenberg" -# __copyright__ = "2020-2022" -# __license__ = "ISC" - -module Import - -import YAML - -export importYamlFiles, importFromYaml - -""" -Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them. -""" -function importYamlFiles(trainDirectory::String, pathDirectory::String, settingsDirectory::String) - train = importFromYaml(:train, trainDirectory) - path = importFromYaml(:path, pathDirectory) - settings = importFromYaml(:settings, settingsDirectory) - - return (train, path, settings) -end #function importYamlFiles - - """ - Read the train information from a YAML file, save it in a Dict and return it. - """ -function importFromYaml(dataType::Symbol, directory::String) - dataSet = String(dataType) - data = YAML.load(open(directory)) - if collect(keys(data))[1] != dataSet - error("ERROR at reading the ", dataSet, " yaml file: The data set is called ", collect(keys(data))[1]," and not ", dataSet, ".") - end - dataKeys = collect(keys(data[dataSet])) - dataKeys = collect(keys(data[dataSet])) - dataValues = collect(values(data[dataSet])) - dictionary = Dict() - for number in 1:length(dataKeys) - merge!(dictionary, Dict(Symbol(dataKeys[number]) => dataValues[number])) - end - return dictionary -end # function importFromYaml - -end # module Input diff --git a/src/TrainRun.jl b/src/TrainRun.jl deleted file mode 100644 index aaf7f2f..0000000 --- a/src/TrainRun.jl +++ /dev/null @@ -1,55 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 -# __author__ = "Max Kannenberg" -# __copyright__ = "2020-2022" -# __license__ = "ISC" - -module TrainRun - -# include main module TrainRunCalc -include("./TrainRunCalc.jl") - -# include additional modules -include("./Import.jl") -include("./Export.jl") - -# include additional modules that are not recommended to use in this state -include("./AdditionalOutput.jl") -include("./EnergySaving.jl") - -# use main module TrainRunCalc -using .TrainRunCalc - -# use additional modules -using .Import -using .Export - -# use additional modules that are not recommended to use in this state -using .AdditionalOutput -using .EnergySaving - -# main function -export trainRun, - -# import functions -importYamlFiles, importFromYaml, - -# functions for saving energy that are not recommended to use in this state -addOperationModeEnergySaving!, - -# export functions -exportToCsv, - -# functions for visualising results that are not recommended to use in this state -plotResults, plotDrivingCourse, printImportantValues, printSectionInformation - -# approximationLevel = 6 # value for approximation to intersections - # TODO: define it here and give it to each function? (Behavior, EnergySaving, ..) - -""" - TODO: Package description -""" - - -end # module TrainRun diff --git a/src/TrainRuns.jl b/src/TrainRuns.jl new file mode 100644 index 0000000..d6de6ad --- /dev/null +++ b/src/TrainRuns.jl @@ -0,0 +1,64 @@ +#!/usr/bin/env julia +# -*- coding: UTF-8 -*- +# __julia-version__ = 1.7.2 +# __author__ = "Max Kannenberg, Martin Scheidt" +# __copyright__ = "2020-2022" +# __license__ = "ISC" +__precompile__(true) + +module TrainRuns + +## loading standard library packages +using UUIDs, Dates, Statistics +## loading external packages +using YAML, JSONSchema, DataFrames + +export +## Interface +trainrun, Train, Path, Settings + +## global variables +global g = 9.80665 # acceleration due to gravity (in m/s^2) +global μ = 0.2 # friction as constant, todo: implement as function +global Δv_air = 15.0/3.6 # coefficient for velocitiy difference between train and outdoor air (in m/s) + +## include package files +include("types.jl") +include("constructors.jl") +include("formulary.jl") +include("calc.jl") +include("characteristics.jl") +include("behavior.jl") +include("output.jl") + +## main function +""" + trainrun(train::Train, path::Path, settings::Settings) + +Calculate the running time of a `train` on a `path`. +The `settings` provides the choice of models for the calculation. +`settings` can be omitted. If so, a default is used. +The running time will be return in seconds. + +# Examples +```julia-repl +julia> trainrun(train, path) +xxx.xx # in seconds +``` +""" +function trainrun(train::Train, path::Path, settings=Settings()::Settings) + # prepare the input data + movingSection = determineCharacteristics(path, train, settings) + settings.outputDetail == :everything && println("The moving section has been prepared.") + + # calculate the train run for oparation mode "minimum running time" + (movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train) + settings.outputDetail == :everything && println("The driving course for the shortest running time has been calculated.") + + # accumulate data and create an output dictionary + output = createOutput(train, settings, path, movingSection, drivingCourse) + + return output +end # function trainrun + +end # module TrainRuns diff --git a/src/Validate.jl b/src/Validate.jl deleted file mode 100644 index 2c51531..0000000 --- a/src/Validate.jl +++ /dev/null @@ -1,757 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.2 -# __author__ = "Max Kannenberg" -# __copyright__ = "2022" -# __license__ = "ISC" - -# TODO: 2022-04-07: if EnergySaving should be used. The train type has do be defined and checked -module Validate - -export checkAndSetInput! - - -approximationLevel = 6 # value for approximation to intersections TODO further explanation - -""" -Read the input information from YAML files for train, path and settings, save it in different dictionaries and return them. -""" -function checkAndSetInput!(train::Dict, path::Dict, settings::Dict) - checkAndSetTrain!(train) - checkAndSetPath!(path) - checkAndSetSettings!(settings) - - if settings[:detailOfOutput] == "points of interest" && !haskey(path, :pointsOfInterest) - settings[:detailOfOutput] = "driving course" - println("INFO at checking the input for settings and path: settings[:detailOfOutput] is 'points of interest' but the path does not have a list for pointsOfInterest. Therefore the detailOfOut is changed to 'driving course'.") - end - return (train, path, settings) -end #function checkAndSetInput! - -""" -Read the train information from a YAML file, save it in a train Dict and return it. -""" -function checkAndSetTrain!(train::Dict) - # check train information from input dictionary - - checkAndSetString!(train, "train", :name, "") # train's name - # add train's identifier if not existing - if !(haskey(train, :id) && train[:id]!=nothing) - merge!(train, Dict(:id =>1)) - end - checkAndSetString!(train, "train", :type, "passenger", ["passenger", "freight"]) # train type "passenger" or "freight" - - checkAndSetPositiveNumberWithDifferentNames!(train, "train", :length, :l_train, "m", 20.0) # total length (in m) - # TODO: or just use: checkAndSetPositiveNumber!(train, "train", :length, "m", 20.0) - - checkAndSetSpeedLimit!(train) # train's speed limit (in m/s) - checkAndSetBrakingAcceleration!(train) # a_braking - - checkAndSetPositiveNumber!(train, "train", :m_td, "kg", 80000) # mass on the traction unit's driving axles (in kg) - checkAndSetPositiveNumber!(train, "train", :m_tc, "kg", 0.0) # mass on the traction unit's carrying axles (in kg) - checkAndSetSum!(train, "train", :m_t, :m_td, :m_tc) # mass of the traction unit (in kg) - - checkAndSetPositiveNumber!(train, "train", :m_w, "kg", 0.0) # mass of the set of wagons (consist) (in kg) - checkAndSetSum!(train, "train", :m_train, :m_t, :m_w) # total mass (in kg) - if train[:m_train] <= 0.0 - error("ERROR at checking the input for the train: The train's mass has to be higher than 0.0 kg.") - end - - checkAndSetRotationMassFactors!(train) - checkAndSetTractiveEffortVelocityPairs!(train) # pairs of velocity and tractive effort - - # coefficients for the vehicle resistance of the traction unit - checkAndSetRealNumber!(train, "train", :Δv_t, "m/s", 15.0/3.6) # coefficient for velocitiy difference between traction unit and outdoor air (in m/s) - checkAndSetPositiveNumber!(train, "train", :f_Rtd0, "‰", 0.0) # coefficient for basic resistance due to the traction units driving axles (in ‰) - checkAndSetPositiveNumber!(train, "train", :f_Rtc0, "‰", 0.0) # coefficient for basic resistance due to the traction units carring axles (in ‰) - checkAndSetPositiveNumber!(train, "train", :F_Rt2, "N", 0.0) # coefficient for air resistance of the traction units (in N) - - # coefficients for the vehicle resistance of the set of wagons (consist) - checkAndSetRealNumber!(train, "train", :Δv_w, "m/s", getDefault_Δv_w(train[:type])) # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s) - checkAndSetPositiveNumber!(train, "train", :f_Rw0, "‰", 0.0) # coefficient for basic resistance of the set of wagons (consist) (in ‰) - checkAndSetPositiveNumber!(train, "train", :f_Rw1, "‰", 0.0) # coefficient for the consists resistance to rolling (in ‰) - checkAndSetPositiveNumber!(train, "train", :f_Rw2, "‰", 0.0) # coefficient fo the consistsr air resistance (in ‰) - - # inform the user about keys of the input dictionary that are not used in this tool - usedKeys = [:name, :id, :type, - :length, :l_train, :v_limit, :v_limit_kmh, :a_braking, - :m_train, :m_t, :m_td, :m_tc, :m_w, - :ξ_train, :ξ_t, :ξ_w, :rotationMassFactor_train, :rotationMassFactor_t, :rotationMassFactor_w, - :tractiveEffortVelocityPairs, :F_T_pairs, :F_T_pairs_kmh, - :f_Rtd0, :f_Rtc0, :F_Rt2, :Δv_t, - :f_Rw0, :f_Rw1, :f_Rw2, :Δv_w] - informAboutUnusedKeys(collect(keys(train)), usedKeys::Vector{Symbol}, "train") - - return train -end #function checkAndSetTrain! - -function checkAndSetPath!(path::Dict) - # check path information from input dictionary - - checkAndSetString!(path, "path", :name, "") - # TODO checkId ? path[:id] # path identifier - checkAndSetSections!(path) - checkAndSetPOIs!(path) - - # inform the user about keys of the input dictionary that are not used in this tool - usedKeys = [:name, - :sections, :sectionStarts, :sectionStarts_kmh, - :pointsOfInterest] - informAboutUnusedKeys(collect(keys(path)), usedKeys::Vector{Symbol}, "path") - - return path -end # function checkAndSetPath! - - -## settings for the calculation -function checkAndSetSettings!(settings::Dict) - # check settings information from input dictionary - - checkAndSetString!(settings, "settings", :massModel, "mass point", ["mass point", "homogeneous strip"]) # model type of the train's mass "mass point" or "homogeneous strip" - checkAndSetString!(settings, "settings", :stepVariable, "s in m", ["s in m", "t in s", "v in m/s"]) # step variable of the step method "s in m", "t in s" or "v in m/s" - - checkAndSetPositiveNumber!(settings, "settings", :stepSize, "("*settings[:stepVariable]*")", getDefaultStepSize(settings[:stepVariable])) # step size (unit depends on stepVariable: s in m, t in s and v in m/s) - checkAndSetBool!(settings, "settings", :operationModeMinimumRunningTime, true) # operation mode "minimum running time" - checkAndSetBool!(settings, "settings", :operationModeMinimumEnergyConsumption, false) # operation mode "minimum energy consumption" - checkAndSetString!(settings, "settings", :typeOfOutput, "julia dictionary", ["julia dictionary", "CSV"]) # output as "julia dictionary" or as "CSV" - - if settings[:typeOfOutput] == "CSV" - checkAndSetString!(settings, "settings", :csvDirectory, "~/Desktop/TrainRun") - # TODO use correct default directory - # TODO: it could be checked if the path is existing on the pc - end # if - - checkAndSetString!(settings, "settings", :detailOfOutput, "running time", ["running time", "points of interest", "driving course", "everything"]) # should the output be only the value of the "running time", or an array of "points of interest" or the complete "driving course" as array or a dictionary with "everything"? - - # inform the user about keys of the input dictionary that are not used in this tool - usedKeys = [:massModel, :stepVariable, :stepSize, - :operationModeMinimumRunningTime, :operationModeMinimumEnergyConsumption, - :typeOfOutput, :detailOfOutput] - if settings[:typeOfOutput] == "CSV" - push!(usedKeys, :csvDirectory) - end - informAboutUnusedKeys(collect(keys(settings)), usedKeys::Vector{Symbol}, "settings") - - return settings -end # function checkAndSetSettings! - -function checkAndSetBool!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::Bool) - if haskey(dictionary,key) && dictionary[key]!=nothing - if typeof(dictionary[key]) != Bool - error("ERROR at checking the input for the ",dictionaryType,": The value of the key ",String(key)," is not correct. The value has to be of type Bool.") - end - else - merge!(dictionary, Dict(key => defaultValue)) - defaultValue && println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," or its value is missing. Therefore ",String(key),"=",dictionary[key]," is assumed and used.") - end - return dictionary -end #function checkAndSetBool! - -function checkAndSetPositiveNumber!(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String, default::Real) - if haskey(dictionary,key) && dictionary[key]!=nothing - if typeof(dictionary[key]) <: Real && dictionary[key] >= 0.0 - else - error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real floating point number >=0.0.") - end - else - merge!(dictionary, Dict(key => default)) - println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. Therefore ",String(key),"=",default," ",unit," will be assumed and used." ) - end - - return dictionary -end #function checkAndSetPositiveNumber! - -# first method without a default value -function checkAndSetPositiveNumberWithDifferentNames!(dictionary::Dict, dictionaryType::String, mainKey::Symbol, alternativeKey::Symbol, unit::String) - mainKey_temp = -1.0 - alternativeKey_temp = -1.0 - - if haskey(dictionary, mainKey) && dictionary[mainKey]!=nothing - if typeof(dictionary[mainKey]) <: Real && dictionary[mainKey] >= 0.0 - mainKey_temp = dictionary[mainKey] - else - error("ERROR at checking the input for the ",dictionaryType,": The value of ",mainKey," is no real floating point number >=0.0.") - end - end - - if haskey(dictionary, alternativeKey) && dictionary[alternativeKey]!=nothing - if typeof(dictionary[alternativeKey]) <: Real && dictionary[alternativeKey] >= 0.0 - alternativeKey_temp = dictionary[alternativeKey] - else - error("ERROR at checking the input for the ",dictionaryType,": The value of ",alternativeKey," is no real floating point number >=0.0.") - end - else - delete!(dictionary, alternativeKey) - end - - if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0 - difference = abs(mainKey_temp - alternativeKey_temp) - if difference > 1/(10^approximationLevel) # TODO or use difference > 0.0 ? - delete!(dictionary, alternativeKey) - println("WARNING at checking the input for the ",dictionaryType,": The values of ",mainKey," and ",alternativeKey," differ by ",difference," ",unit,". The value ",String(mainKey),"=",default," ",unit," is used." ) - end - elseif mainKey_temp >= 0.0 - # do nothing - elseif alternativeKey_temp >= 0.0 - merge!(dictionary, Dict(mainKey => alternativeKey_temp)) - else - # do nothing - end - - return dictionary -end #function checkAndSetPositiveNumberWithDifferentNames! - -# second method with a default value -function checkAndSetPositiveNumberWithDifferentNames!(dictionary::Dict, dictionaryType::String, mainKey::Symbol, alternativeKey::Symbol, unit::String, default::Real) - mainKey_temp = -1.0 - alternativeKey_temp = -1.0 - - if haskey(dictionary, mainKey) && dictionary[mainKey]!=nothing - if typeof(dictionary[mainKey]) <: Real && dictionary[mainKey] >= 0.0 - mainKey_temp = dictionary[mainKey] - else - error("ERROR at checking the input for the ",dictionaryType,": The value of ",mainKey," is no real floating point number >=0.0.") - end - end - - if haskey(dictionary, alternativeKey) && dictionary[alternativeKey]!=nothing - if typeof(dictionary[alternativeKey]) <: Real && dictionary[alternativeKey] >= 0.0 - alternativeKey_temp = dictionary[alternativeKey] - else - error("ERROR at checking the input for the ",dictionaryType,": The value of ",alternativeKey," is no real floating point number >=0.0.") - end - else - delete!(dictionary, alternativeKey) - end - - if mainKey_temp >= 0.0 && alternativeKey_temp >= 0.0 - difference = abs(mainKey_temp - alternativeKey_temp) - if difference > 1/(10^approximationLevel) # TODO or use difference > 0.0 ? - delete!(dictionary, alternativeKey) - println("WARNING at checking the input for the ",dictionaryType,": The values of ",mainKey," and ",alternativeKey," differ by ",difference," ",unit,". The value ",String(mainKey),"=",default," ",unit," is used." ) - end - elseif mainKey_temp >= 0.0 - # do nothing - elseif alternativeKey_temp >= 0.0 - merge!(dictionary, Dict(mainKey => alternativeKey_temp)) - else - # set a default value - merge!(dictionary, Dict(mainKey, default)) - println("INFO at checking the input for the ",dictionaryType,": The key ",mainKey," or its value is missing. Therefore the value ",String(mainKey),"=",default," ",unit," is used." ) - end - - return dictionary -end #function checkAndSetPositiveNumberWithDifferentNames! - -function checkAndSetRealNumber!(dictionary::Dict, dictionaryType::String, key::Symbol, unit::String, default::Real) - if haskey(dictionary,key) && dictionary[key]!=nothing - if typeof(dictionary[key]) <: Real - else - error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is no real number.") - end - else - merge!(dictionary, Dict(key => default)) - println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. Therefore ",String(key),"=",default," ",unit," will be assumed and used." ) - end - - return dictionary -end #function checkAndSetRealNumber! - -function checkAndSetSum!(dictionary::Dict, dictionaryType::String, sum::Symbol, summand1::Symbol, summand2::Symbol) - if haskey(dictionary,sum) && dictionary[sum]!=nothing - if typeof(dictionary[sum]) <: Real && dictionary[sum] >= 0.0 - difference = abs(dictionary[sum] - (dictionary[summand1]+dictionary[summand2])) - if difference > 1/(10^approximationLevel) - error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is not exactly the sum of ",String(summand1)," and ",String(summand2),". It differs by ",difference,".") - end - else - error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(sum)," is no real floating point number >=0.0.") - end - else - merge!(dictionary, Dict(sum => dictionary[summand1]+dictionary[summand2])) - println("INFO at checking the input for the ",dictionaryType,": The key ",String(sum)," is missing. Therefore ",String(sum)," = ",String(summand1)," + ",String(summand2)," = ",dictionary[sum]," was calculated and will be used." ) - end - - return dictionary -end #function checkAndSetSum! - -function checkAndSetString!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::String, validValues::Vector{String}) - # TODO change checkAndAddString! to checkAndAddSymbol! ? - if haskey(dictionary,key) && dictionary[key]!=nothing - value = dictionary[key] - if typeof(value) == String - for validValue in validValues - if value == validValue - return dictionary - end - end - end - error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is wrong. It has to be one of the following String values: ", validValues) - else - println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. It has to be one of the following String values: ", validValues,". For this calculation the default value '",defaultValue,"' will be used.") - merge!(dictionary, Dict(key => defaultValue)) - end - return dictionary -end #function checkAndSetString! -# second method of function checkAndSetString! without validValues -function checkAndSetString!(dictionary::Dict, dictionaryType::String, key::Symbol, defaultValue::String) - if haskey(dictionary,key) && dictionary[key]!=nothing - value = dictionary[key] - if typeof(value) == String - return dictionary - end - error("ERROR at checking the input for the ",dictionaryType,": The value of ",String(key)," is wrong. It has to be of type String.") - else - println("INFO at checking the input for the ",dictionaryType,": The key ",String(key)," is missing. For this calculation the default value '",defaultValue,"' will be used.") - merge!(dictionary, Dict(key => defaultValue)) - end - return dictionary -end #function checkAndSetString! - -function checkAndSetSpeedLimit!(train::Dict) - v_limit_temp = 0.0 - v_limit_kmh_temp = 0.0 - - if haskey(train, :v_limit) && train[:v_limit]!=nothing - if typeof(train[:v_limit]) <: Real && train[:v_limit] >= 0.0 - v_limit_temp = train[:v_limit] - else - error("ERROR at checking the input for the train: The value of v_limit is no real floating point number >=0.0.") - end - end - - if haskey(train, :v_limit_kmh) && train[:v_limit_kmh]!=nothing - if typeof(train[:v_limit_kmh]) <: Real && train[:v_limit_kmh] >= 0.0 - v_limit_kmh_temp = train[:v_limit_kmh] - else - error("ERROR at checking the input for the train: The value of v_limit_kmh is no real floating point number >=0.0.") - end - else - delete!(train, :v_limit_kmh) - end - - if v_limit_temp > 0.0 && v_limit_kmh_temp > 0.0 - difference = abs(v_limit_temp - v_limit_kmh_temp/3.6) - if difference > 1/(10^approximationLevel) # TODO or use difference > 0.0 ? - delete!(train, :v_limit_kmh) - println("WARNING at checking the input for the train: The values of v_limit and v_limit_kmh differ by ",difference," m/s. The value v_limit=",v_limit_temp," m/s is used." ) - end - elseif v_limit_temp > 0.0 - # do nothing - elseif v_limit_kmh_temp > 0.0 - merge!(train, Dict(:v_limit => v_limit_kmh_temp/3.6)) - else - # set a default value - merge!(train, Dict(:v_limit, 1000.0/3.6)) # set speed limit to 1000 km/h - println("INFO at checking the input for the train: There is no value for the trains speed limit (v_limit or v_limit_kmh). The value v_limit=1000 km/h =",train[:v_limit]," m/s is used." ) - end - - return train -end #function checkAndSetSpeedLimit! - -function checkAndSetBrakingAcceleration!(train::Dict) - if haskey(train, :a_braking) && train[:a_braking]!=nothing - if typeof(train[:a_braking]) <: Real - if train[:a_braking] > 0.0 - train[:a_braking] =-train[:a_braking] - println("INFO at checking the input for the train: The value for a_braking is >0.0. The braking acceleration has to be <0.0. Therefore a_braking=",train[:a_braking]," m/s^2 is used." ) - elseif train[:a_braking] == 0.0 - error("ERROR at checking the input for the train: The value for a_braking is 0.0. The braking acceleration has to be <0.0.") - end - else - error("ERROR at checking the input for the train: The value for a_braking is no real floating point number <0.0.") - end - else - # set a default value depending on the train type - if train[:type] == "freight" - a_braking = -0.225 - elseif train[:type] == "passenger" - a_braking = -0.375 - #elseif train[:type] == "passengerSuburban" - # a_braking = -0.525 - # TODO: add suburban trains to train type? - end - - merge!(train, Dict(:a_braking => a_braking)) - println("INFO at checking the input for the train: The key for a_braking is missing. Because of the train type ",train[:type]," a_braking=",a_braking," m/s^2 will be assumed and used." ) - end - - return train -end #function checkAndSetBrakingAcceleration! - -function checkAndSetRotationMassFactors!(train::Dict) - checkAndSetPositiveNumberWithDifferentNames!(train, "train", :ξ_train, :rotationMassFactor_train, "") - checkAndSetPositiveNumberWithDifferentNames!(train, "train", :ξ_t, :rotationMassFactor_t, "") - checkAndSetPositiveNumberWithDifferentNames!(train, "train", :ξ_w, :rotationMassFactor_w, "") - if haskey(train, :ξ_train) && train[:ξ_train]!=nothing - if train[:ξ_train]>0.0 - if haskey(train, :ξ_t) && train[:ξ_t]!=nothing && train[:ξ_t]>0.0 && (train[:m_w]==0.0 || (haskey(train, :ξ_w) && train[:ξ_w]!=nothing)) - # TODO: is && train[:ξ_t]>0.0 necessary here? - difference = abs(train[:ξ_train] - (train[:ξ_t]*train[:m_t] + train[:ξ_w]*train[:m_w])/train[:m_train]) - if difference > 1/(10^approximationLevel) - error("ERROR at checking the input for the train: The value of ξ_train is not exactly ξ_train=(ξ_t*m_t + ξ_w*m_w)/m_train. It differs by ",difference,".") - end - end - else - error("ERROR at checking the input for the train: The value of :ξ_train is no real floating point number >0.0.") - end - else - checkAndSetPositiveNumber!(train, "train", :ξ_t, "", 1.09) - - if train[:m_w]>0.0 - default_ξ_w = 1.06 - else - default_ξ_w = 0.0 - end - checkAndSetPositiveNumber!(train, "train", :ξ_w, "", default_ξ_w) - - - ξ_train=(train[:ξ_t]*train[:m_t] + train[:ξ_w]*train[:m_w])/train[:m_train] # rotation mass factor of the whole train (without unit) - if ξ_train <= 0.0 - error("ERROR at checking the input for the train: The train's rotations mass factor has to be higher than 0.0 kg.") - end - merge!(train, Dict(:ξ_train => ξ_train)) - end - - return train -end #function checkAndSetRotationMassFactors! - -function checkAndSetTractiveEffortVelocityPairs!(train::Dict) # pairs of velocity and tractive effort - if haskey(train,:tractiveEffortVelocityPairs) && train[:tractiveEffortVelocityPairs]!=nothing - pairs = train[:tractiveEffortVelocityPairs] - velocityMultiplier = 1.0 - - if (haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing) && (haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing) - println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs, F_T_pairs and F_T_pairs_kmh. The values for tractiveEffortVelocityPairs are used." ) - - elseif haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing - println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs and F_T_pairs. The values for tractiveEffortVelocityPairs are used." ) - - elseif haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing - println("WARNING at checking the input for the train: There are values for tractiveEffortVelocityPairs and F_T_pairs_kmh. The values for tractiveEffortVelocityPairs are used." ) - end - - elseif haskey(train,:F_T_pairs) && train[:F_T_pairs]!=nothing - pairs = train[:F_T_pairs] - velocityMultiplier = 1.0 - - if haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing - println("WARNING at checking the input for the train: There are values for F_T_pairs and F_T_pairs_kmh. The values for F_T_pairs are used." ) - end - - elseif haskey(train,:F_T_pairs_kmh) && train[:F_T_pairs_kmh]!=nothing - velocityMultiplier = 1000/3600 - pairs=[] - for row in 1:length(train[:F_T_pairs_kmh]) - push!(pairs, [train[:F_T_pairs_kmh][row][1]*velocityMultiplier, train[:F_T_pairs_kmh][row][2]]) - end # for - - else - error("ERROR at checking the input for the train: There has to be the key tractiveEffortVelocityPairs filled with a list of pairs of velocity and tractive effort.") - end # if - - # check if the elements of the array have the correct type - errorDetected=false - - for row in 1:length(pairs) - if typeof(pairs[row][1]) <: Real && pairs[row][1]>=0.0 - else - errorDetected=true - println("ERROR at checking the input for the train: The speed value of train[:tractiveEffortVelocityPairs] in row ", row ," is no real floating point number >=0.0.") - end - if typeof(pairs[row][2]) <: Real && pairs[row][2]>=0.0 - else - errorDetected=true - println("ERROR at checking the input for the train: The tractive effort value of train[:tractiveEffortVelocityPairs] in row ", row ," is no real floating point number >=0.0.") - end - - if row>=2 && pairs[row][1] <= pairs[row-1][1] - errorDetected=true - println("ERROR at checking the input for the train: The speed value of train[:tractiveEffortVelocityPairs] in row ", row ," (v=",pairs[row][1]," m/s) is not higher than the speed value in the previous row (v=",pairs[row-1][1]," m/s).") - end - end # for - if errorDetected - error("ERROR at checking the input for the train: Only real floating point number >=0.0 are allowed for speed and tractive effort. The speed values have to be listed from low to high.") - end - - # create tractiveEffortVelocityPairs - if pairs[1][1]>0.0 # if there is no F_T for v=0.0, the first known value is used - newPairs=[] - push!(newPairs, [0.0, pairs[1][2]]) - println("INFO at checking the input for the train: The tractive effort for v=0.0 m/s is missing. Therefore the first given value F_T(v=",pairs[1][1]," m/s)=",pairs[1][2]," N will be used." ) - for row in 1:length(pairs) - push!(newPairs, [pairs[row][1], pairs[row][2]]) - end # for - merge!(train, Dict(:tractiveEffortVelocityPairs => newPairs)) - else - merge!(train, Dict(:tractiveEffortVelocityPairs => pairs)) - end - - if length(pairs[1])>2 - println("INFO according the train dictionary: Only the first two columns of train[:tractiveEffortVelocityPairs] are used in this tool.") - end - - return train -end #function checkAndSetTractiveEffortVelocityPairs! - -function getDefault_Δv_w(type::String) # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s) - if type == "passenger" - # TODO if different passenger or freight trains are posiible, use: if startswith(type, "passenger"). exanples: passengerLocomotivehauled and passengerMotorCoachTrain - Δv_w=15.0/3.6 - elseif type == "freight" - Δv_w=0.0 - end # if - - return Δv_w -end #function getDefault_Δv_w! - -function checkAndSetSections!(path::Dict) - # check the section information - if haskey(path,:sections) && path[:sections]!=nothing - # TODO: check typeof(path[:sections]) == Dict - if (haskey(path, :sectionStarts) && path[:sectionStarts]!=nothing) && (haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing) - println("WARNING at checking the input for the path: There are values for sections, sectionStarts and sectionStarts_kmh. The dictionary sections is used." ) - - elseif haskey(path,:sectionStarts) && path[:sectionStarts]!=nothing - println("WARNING at checking the input for the path: There are values for sections and sectionStarts. The dictionary sections is used." ) - - elseif haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing - println("WARNING at checking the input for the path: There are values for sections and sectionStarts_kmh. The dictionary sections is used." ) - end - elseif haskey(path,:sectionStarts) && path[:sectionStarts]!=nothing - # TODO: check typeof(path[:sections]) == Array - createSections!(path, :sectionStarts) - - if haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing - println("WARNING at checking the input for the path: There are values for sectionStarts and sectionStarts_kmh. The array sectionStarts is used." ) - end - elseif haskey(path,:sectionStarts_kmh) && path[:sectionStarts_kmh]!=nothing - # TODO: check typeof(path[:sections]) == Array - createSections!(path, :sectionStarts_kmh) - else - error("ERROR at checking the input for the path: The Symbol :sections is missing. It has to be added with a list of sections. Each has to be a dictionary with the keys :s_tart, :s_end, :v_limit and :f_Rp.") - section = Dict(:s_start => 0.0, - :s_end => 15.0, - :v_limit => 1000.0/3.6, - :f_Rp => 0.0) - merge!(path, Dict(:sections => [section])) - return path - end - - sections = path[:sections] - - checkedSections = [] - increasing = false - decreasing = false - - #TODO: throw error for each issue or collect the issues and use the Bool errorDetected like in createSections? - - # check values for section==1 - checkAndSetRealNumber!(sections[1], "path[:sections][1]", :s_start, "m", 0.0) # first point of the section (in m) - checkAndSetRealNumber!(sections[1], "path[:sections][1]", :s_end, "m", 0.0) # first point of the next section (in m) - checkAndSetPositiveNumber!(sections[1], "path[:sections][1]", :v_limit, "m/s", 1000.0/3.6) # paths speed limt (in m/s) - checkAndSetRealNumber!(sections[1], "path[:sections][1]", :f_Rp, "‰", 0.0) # specific path resistance of the section (in ‰) - - push!(checkedSections, sections[1]) - - if sections[1][:s_start] < sections[1][:s_end] - increasing = true - elseif sections[1][:s_start] > sections[1][:s_end] - decreasing = true - else - pop!(checkedSections) - println("WARNING at checking the input for the path: The first section of :sections has the same position for starting and end point. The section will be deleted and not used in the tool.") - end - - - for sectionNr in 2:length(sections) - checkAndSetRealNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :s_start, "m", sections[sectionNr-1][:s_end]) # first point of the section (in m) - # TODO how to define default values? which has to be checked and defined fist? s_end-1 and s_start need each other as default values - #if sectionNr < length(sections) && haskey(sections[sectionNr], :s_start) && sections[sectionNr][:s_start]!=nothing && typeof(sections[sectionNr][:s_start]) <: Real - # defaultEnd = sections[sectionNr+1][:s_start] - #end - defaultEnd = sections[sectionNr][:s_start] # so the default value for s_end creates a sections of lenght=0.0 #TODO should be changed! - checkAndSetRealNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :s_end, "m", defaultEnd) # first point of the next section (in m) - checkAndSetPositiveNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :v_limit, "m/s", 1000.0/3.6) # paths speed limt (in m/s) - checkAndSetRealNumber!(sections[sectionNr], "path[:sections]["*string(sectionNr)*"]", :f_Rp, "‰", 0.0) # specific path resistance of the section (in ‰) - - push!(checkedSections, sections[sectionNr]) - - # compare the section's start and end position - if sections[sectionNr][:s_start] < sections[sectionNr][:s_end] - increasing = true - elseif sections[sectionNr][:s_start] > sections[sectionNr][:s_end] - decreasing = true - else - pop!(checkedSections) - println("INFO at checking the input for the path: The ",sectionNr,". section of :sections has the same position for starting and end point. The section will be deleted and not used in the tool.") - end - if increasing && decreasing - error("ERROR at checking the input for the path: The positions of the :sections are not increasing/decreasing consistently. The direction in the ",sectionNr,". section differs from the previous.") - end - - - if length(checkedSections)>1 && sections[sectionNr][:s_start] != checkedSections[end-1][:s_end] - error("ERROR at checking the input for the path[:sections]: The starting position of the ",section,". section (s=",sections[sectionNr][:s_start]," m) does not euqal the last position of the previous section(s=",checkedSections[end-1][:s_end]," m). The sections have to be sequential.") - # TODO: maybe if there is a gab create a new section and only if there a jumps in the wrong direction throw an error? - end - end #for - - return path -end #function checkAndSetSections! - -function createSections!(path::Dict, key::Symbol) - # read the section starting positions and corresponding information - if key == :sectionStarts - sectionStartsArray = path[:sectionStarts] - conversionFactor = 1.0 # conversion factor between the units m/s and m/s - - if haskey(path,:sectionStarts) && path[:sectionStarts_kmh]!=nothing - println("WARNING at checking the input for the path: There are values for sectionStarts and sectionStarts_kmh. The values for sectionStarts are used." ) - end - elseif key == :sectionStarts_kmh - sectionStartsArray = path[:sectionStarts_kmh] - conversionFactor = 1/3.6 # conversion factor between the units km/h and m/s - else - error("ERROR at checking the input for the path: The keyword sectionStarts or sectionStarts_kmh is missing. The sections can not be created without them.") - end # if - - # check if the array is correct and if elements of the array have the correct type and valid values - errorDetected = false - if length(sectionStartsArray)<2 - error("ERROR at checking the input for the path: The keyword ",key," needs at least two rows for two points each with the three columns [s, v_limit, f_Rp].") - end - - for row in 1:length(sectionStartsArray) - if length(sectionStartsArray[row])>=3 - if length(sectionStartsArray[row])>3 - println("INFO at checking the input for the path: Only the first three columns of sectionStartsArray are used in this tool.") - end - else - error("ERROR at checking the input for the path: The keyword ",key," needs to be filled with the three columns [s, v_limit, f_Rp].") - end - - if !(typeof(sectionStartsArray[row][1]) <: Real) - errorDetected=true - println("ERROR at checking the input for the path: The position value (column 1) of ",key," in row ", row ," is no real floating point number.") - end - if !(typeof(sectionStartsArray[row][2]) <: Real && sectionStartsArray[row][2] >= 0.0) - errorDetected=true - println("ERROR at checking the input for the path: The speed limit (column 2) of ",key," in row ", row ," is no real floating point number >=0.0.") - end - if !(typeof(sectionStartsArray[row][3]) <: Real) - errorDetected=true - println("ERROR at checking the input for the path: The tractive effort value (column 3) of ",key," in row ", row ," is no real floating point number.") - end - end # for - if errorDetected - error("ERROR at checking the input for the path: The values of ",key," have to be corrected.") - end - - - sections = [] - for row in 2:length(sectionStartsArray) - s_start = sectionStartsArray[row-1][1] # first point of the section (in m) - s_end = sectionStartsArray[row][1] # first point of the next section (in m) - v_limit = sectionStartsArray[row-1][2]*conversionFactor # paths speed limt (in m/s) - f_Rp = sectionStartsArray[row-1][3] # specific path resistance of the section (in ‰) - - section = Dict(:s_start => s_start, - :s_end => s_end, - :v_limit => v_limit, - :f_Rp => f_Rp) - push!(sections, section) - end # for - # s_start in first entry defines the path's beginning - # s_end in last entry defines the path's ending - - merge!(path, Dict(:sections => sections)) - return path -end #function createSections! - -function checkAndSetPOIs!(path::Dict) - # read the section starting positions and corresponding information - if haskey(path, :pointsOfInterest) - if path[:pointsOfInterest] != nothing - pointsOfInterest = path[:pointsOfInterest] - - sortingNeeded = false - errorDetected = false - for element in 1:length(pointsOfInterest) - if typeof(pointsOfInterest[element]) <: Real - if element > 1 - if pointsOfInterest[element] < pointsOfInterest[element-1] - sortingNeeded = true - println("INFO at checking the input for the path: The point of interest in element ", element ," (",pointsOfInterest[element]," m) has to be higher than the value of the previous element (",pointsOfInterest[element-1]," m). The points of interest will be sorted.") - end - end - else - errorDetected = true - println("ERROR at checking the input for the path: The point of interest in element ", element ," is no real floating point number.") - end - end # for - - if errorDetected - error("ERROR at checking the input for the path: The values of pointsOfInterest have to be corrected.") - end - if sortingNeeded == true - sort!(pointsOfInterest) - end - - copiedPOIs = [] - for element in 1:length(pointsOfInterest) - if element == 1 - push!(copiedPOIs, pointsOfInterest[element]) - elseif element > 1 && pointsOfInterest[element] > pointsOfInterest[element-1] - push!(copiedPOIs, pointsOfInterest[element]) - end - end # for - path[:pointsOfInterest] = copiedPOIs - - else - println("INFO at checking the input for the path: The key pointsOfInterest exists but without values.") - delete!(path, :pointsOfInterest) - end - end - - return path -end #function checkAndSetPOIs! - -function getDefaultStepSize(stepVariable::String) - if stepVariable == "s in m" - return 10.0 - elseif stepVariable == "t in s" - return 3.0 - elseif stepVariable == "v in m/s" - return 0.1 - #else - # error("ERROR at getting a default step size. The step variable ",stepVariable," can not be used.") - end -end #function getDefaultStepSize - -#function informAboutUnusedKeys(dictionary::Dict, dictionaryType::String) # inform the user which Symbols of the input dictionary are not used in this tool -function informAboutUnusedKeys(allKeys::AbstractVector, usedKeys::Vector{Symbol}, dictionaryType::String) # inform the user which Symbols of the input dictionary are not used in this tool - unusedKeys = [] - # find unused keys in allKeys - for key in allKeys - used = false - for usedKey in usedKeys - if key == usedKey - used = true - break - end - end - if !used - push!(unusedKeys, key) - end - end - - if length(unusedKeys)>0 - println("INFO at checking the input for the ",dictionaryType,": The following Keywords are not used in this tool:") - for key in unusedKeys - println(" - ",key) - end - end -end #function informAboutUnusedKeys - -end # module Validate diff --git a/src/Behavior.jl b/src/behavior.jl similarity index 81% rename from src/Behavior.jl rename to src/behavior.jl index 8d65c09..7ddae8c 100644 --- a/src/Behavior.jl +++ b/src/behavior.jl @@ -5,23 +5,6 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" -module Behavior - -include("./Formulary.jl") -using .Formulary - -export addBreakFreeSection!, addClearingSection!, addAcceleratingSection!, addCruisingSection!, addDiminishingSection!, addCoastingSection!, addBrakingSection!, addStandstill!, -# addBrakingSectionInOneStep! is not used in the current version of the tool -calculateForces!, createDataPoint, - -# export functions from Formulary -calcBrakingDistance, calcBrakingStartVelocity, calc_Δs_with_Δt - - -approximationLevel = 6 # value for approximation to intersections TODO further explanation (e.g. approximationLevel = 3 -> with stepSize 10 m the approximation will be calculated accurate on 10 mm ; 1s -> 1 ms; 1 km/h -> 3.6 mm/s) - # TODO: define it in TrainRun and give it to each function? - -## functions for calculating tractive effort and resisting forces """ calculateTractiveEffort(v, tractiveEffortVelocityPairs) @@ -30,19 +13,19 @@ Calculate the trains tractive effort with the `tractiveEffortVelocityPairs` depe ... # Arguments - `v::AbstractFloat`: the current velocity in m/s. -- `tractiveEffortVelocityPairs::Array{Array{AbstractFloat,1},1}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair. +- `tractiveEffortVelocityPairs::Array{}`: the trains pairs for velocity in m/s and tractive effort in N as one array containing an array for each pair. ... # Examples ```julia-repl -julia> calculateTractiveEffort(20.0, [[0.0, 180000], [20.0, 100000], [40.0, 60000], [60.0, 40000], [80.0, 30000]]) +julia> calculateTractiveEffort(20.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)]) 100000 -julia> calculateTractiveEffort(30.0, [[0.0, 180000], [20.0, 100000], [40.0, 60000], [60.0, 40000], [80.0, 30000]]) +julia> calculateTractiveEffort(30.0, [(0.0, 180000), (20.0, 100000), (40.0, 60000), (60.0, 40000), (80.0, 30000)]) 80000 ``` """ -function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs) +function calculateTractiveEffort(v::AbstractFloat, tractiveEffortVelocityPairs::Array{}) for row in 1:length(tractiveEffortVelocityPairs) nextPair = tractiveEffortVelocityPairs[row] if nextPair[1] == v @@ -62,18 +45,19 @@ end #function calculateTractiveEffort """ calculate and return the path resistance dependend on the trains position and mass model """ -function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel::String, train::Dict) - if massModel == "mass point" - pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train[:m_train]) - elseif massModel == "homogeneous strip" +function calculatePathResistance(CSs::Vector{Dict}, csId::Integer, s::Real, massModel, train::Train) + + if massModel == :mass_point + pathResistance = calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) + elseif massModel == :homogeneous_strip pathResistance = 0.0 - s_rear = s - train[:length] # position of the rear of the train + s_rear = s - train.length # position of the rear of the train while csId > 0 && s_rear < CSs[csId][:s_exit] - pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train[:length] * calcForceFromCoefficient(CSs[csId][:r_path], train[:m_train]) + pathResistance = pathResistance + (min(s, CSs[csId][:s_exit]) - max(s_rear, CSs[csId][:s_entry])) / train.length * calcForceFromCoefficient(CSs[csId][:r_path], train.m_train_full) csId = csId-1 if csId == 0 # TODO: currently for values < movingSection[:s_entry] the values of movingSection[:s_entry] will be used - return pathResistance + (CSs[1][:s_entry] - s_rear) / train[:length] * calcForceFromCoefficient(CSs[1][:r_path], train[:m_train]) + return pathResistance + (CSs[1][:s_entry] - s_rear) / train.length * calcForceFromCoefficient(CSs[1][:r_path], train.m_train_full) end #if end #while end #if @@ -84,7 +68,7 @@ end #function calculatePathResistance """ calculate and return tractive and resisting forces for a data point """ -function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Dict, massModel::String) +function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bsType::String, train::Train, massModel) # calculate resisting forces dataPoint[:R_traction] = calcTractionUnitResistance(dataPoint[:v], train) dataPoint[:R_wagons] = calcWagonsResistance(dataPoint[:v], train) @@ -96,9 +80,9 @@ function calculateForces!(dataPoint::Dict, CSs::Vector{Dict}, csId::Integer, bs if bsType == "braking" || bsType == "coasting" dataPoint[:F_T] = 0.0 elseif bsType == "cruising" - dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train[:tractiveEffortVelocityPairs])) + dataPoint[:F_T] = min(max(0.0, dataPoint[:F_R]), calculateTractiveEffort(dataPoint[:v], train.tractiveEffort)) else # bsType == "accelerating" || bsType == "diminishing" || 'default' - dataPoint[:F_T] = calculateTractiveEffort(dataPoint[:v], train[:tractiveEffortVelocityPairs]) + dataPoint[:F_T] = calculateTractiveEffort(dataPoint[:v], train.tractiveEffort) end return dataPoint @@ -108,7 +92,7 @@ end #function calculateForces! """ TODO """ -function moveAStep(previousPoint::Dict, stepVariable::String, stepSize::Real, csId::Integer) +function moveAStep(previousPoint::Dict, stepVariable::Symbol, stepSize::Real, csId::Integer) # stepSize is the currentStepSize depending on the accessing function # TODO: csId is only for error messages. Should it be removed? #= 08/31 TODO: How to check if the train stopps during this step? I should throw an error myself that I catch in higher hierarchies. =# @@ -118,7 +102,7 @@ function moveAStep(previousPoint::Dict, stepVariable::String, stepSize::Real, cs newPoint[:i] = previousPoint[:i]+1 # identifier # calculate s, t, v, E - if stepVariable == "s in m" # distance step method + if stepVariable == :distance # distance step method newPoint[:Δs] = stepSize # step size (in m) if previousPoint[:a] == 0.0 if previousPoint[:v] == 0.0 @@ -138,12 +122,12 @@ function moveAStep(previousPoint::Dict, stepVariable::String, stepSize::Real, cs newPoint[:Δv] = calc_Δv_with_Δs(newPoint[:Δs], previousPoint[:a], previousPoint[:v]) # step size (in m/s) end - elseif stepVariable == "t in s" # time step method + elseif stepVariable == :time # time step method newPoint[:Δt] = stepSize # step size (in s) newPoint[:Δs] = calc_Δs_with_Δt(newPoint[:Δt], previousPoint[:a], previousPoint[:v]) # step size (in m) newPoint[:Δv] = calc_Δv_with_Δt(newPoint[:Δt], previousPoint[:a]) # step size (in m/s) - elseif stepVariable == "v in m/s" # velocity step method + elseif stepVariable == :velocity # velocity step method if previousPoint[:a] == 0.0 if previousPoint[:v] == 0.0 error("ERROR: The train tries to cruise at v=0.0 m/s at s=",previousPoint[:s]," in CS",csId,".") @@ -191,9 +175,12 @@ function getCurrentSpeedLimit(CSs::Vector{Dict}, csWithTrainHeadId::Integer, s:: return currentSpeedLimit end #function getCurrentSpeedLimit -function getNextPointOfInterest(pointsOfInterest::Vector{Real}, s::Real) +""" +? +""" +function getNextPointOfInterest(pointsOfInterest::Vector{Tuple}, s::Real) for s_POI in pointsOfInterest - if s_POI > s + if s_POI[1] > s return s_POI end end @@ -203,7 +190,7 @@ end #function getNextPointOfInterest ## This function calculates the data points of the breakFree section. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for breakFree if needed. # Info: currently the values of the breakFree section will be calculated like in the accelerating section -function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) +function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Train, CSs::Vector{Dict}) # conditions for the break free section endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] trainIsHalting = drivingCourse[end][:v] == 0.0 @@ -213,7 +200,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags: drivingCourse[end][:behavior] = BS[:type] # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings[:massModel]) # currently the tractive effort is calculated like in the accelerating section + calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings.massModel) # currently the tractive effort is calculated like in the accelerating section # calculate the breakFree section with calculating the accelerating section and just using the first step and removing the rest try (CS, drivingCourse, stateFlags) = addAcceleratingSection!(CS, drivingCourse, stateFlags, settings, train, CSs) @@ -255,7 +242,7 @@ function addBreakFreeSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags: if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] s_braking = 0.0 else - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end # reset state flags @@ -272,29 +259,29 @@ end #function addBreakFreeSection! ## This function calculates the data points of the clearing section. # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the clearing section. -function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) +function addClearingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Train, CSs::Vector{Dict}) if stateFlags[:previousSpeedLimitReached] - currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length]) + currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length) if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] ignoreBraking = true s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end s_clearing = min(CS[:s_exit]-drivingCourse[end][:s]-s_braking, currentSpeedLimit[:s_end] - drivingCourse[end][:s]) if s_clearing > 0.0 (CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_clearing, settings, train, CSs, "clearing") - calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings.massModel) # stateFlags[:brakingStartReached] = brakingStartReached # stateFlags[:endOfCSReached] = stateFlags[:endOfCSReached] || drivingCourse[end][:s] == CS[:s_exit] else error("ERROR: clearing <=0.0 although it has to be >0.0 in CS ",CS[:id]) end #stateFlags[:previousSpeedLimitReached] = false - currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length]) + currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length) stateFlags[:previousSpeedLimitReached] = currentSpeedLimit[:v] != CS[:v_limit] && drivingCourse[end][:v] >= currentSpeedLimit[:v] else stateFlags[:error] = true @@ -305,21 +292,21 @@ end #function addClearingSection ## This function calculates the data points of the accelerating section. # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the accelerating section -function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) - #function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}, ignoreBraking::Bool) - #=if drivingCourse would also be part of movingSectiong: function addAcceleratingSection!(movingSection::Dict, stateFlags::Dict, csId::Integer, settings::Dict, train::Dict) +function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Train, CSs::Vector{Dict}) + #function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict}, ignoreBraking::Bool) + #=if drivingCourse would also be part of movingSectiong: function addAcceleratingSection!(movingSection::Dict, stateFlags::Dict, csId::Integer, settings::Settings, train::Train) CSs = movingSection[:characteristicSections] CS = CSs[csId] drivingCourse = movingSection[:drivingCourse]=# - calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "accelerating", train, settings.massModel) if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] ignoreBraking = true s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end # conditions for the accelerating section @@ -334,48 +321,48 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla BS = createBehaviorSection("accelerating", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) drivingCourse[end][:behavior] = BS[:type] - currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length]) + currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length) previousSpeedLimitReached = currentSpeedLimit[:v] != CS[:v_limit] && drivingCourse[end][:v] >= currentSpeedLimit[:v] speedLimitReached = drivingCourse[end][:v] >= CS[:v_limit] #speedLimitReached = drivingCourse[end][:v] > currentSpeedLimit[:v] #targetSpeedReached = speedLimitReached while !targetSpeedReached && !endOfCSReached && tractionSurplus && !brakingStartReached && !previousSpeedLimitReached - currentStepSize = settings[:stepSize] # initialize the step size that can be reduced near intersections + currentStepSize = settings.stepSize # initialize the step size that can be reduced near intersections nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] - for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation + for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end while !targetSpeedReached && !speedLimitReached && !brakingStartReached && !pointOfInterestReached && tractionSurplus && !previousSpeedLimitReached - # 03/08 old: while drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:v] <= currentSpeedLimit[:v] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:F_T] > drivingCourse[end][:F_R] # as long as s_i + s_braking < s_CSexit + # 03/08 old: while drivingCourse[end][:v] < CS[:v_peak] && drivingCourse[end][:v] <= currentSpeedLimit[:v] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest[1] && drivingCourse[end][:F_T] > drivingCourse[end][:F_R] # as long as s_i + s_braking < s_CSexit if drivingCourse[end][:s] >= currentSpeedLimit[:s_end] # could be asked after creating an data point. This way here prevents even a minimal exceedance of speed limit will be noticed. On the other hand the train cruises possibly a little to long - currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length]) + currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length) end # acceleration (in m/s^2): - drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) + push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) # conditions for the next while cycle if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] speedLimitReached = drivingCourse[end][:v] > CS[:v_limit] previousSpeedLimitReached = currentSpeedLimit[:v] < CS[:v_limit] && (drivingCourse[end][:v] > currentSpeedLimit[:v] || (drivingCourse[end][:v] == currentSpeedLimit[:v] && drivingCourse[end][:s] < currentSpeedLimit[:s_end])) targetSpeedReached = drivingCourse[end][:v] >= CS[:v_peak] #targetSpeedReached = speedLimitReached - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest # POIs include s_exit as well + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] # POIs include s_exit as well tractionSurplus = drivingCourse[end][:F_T] > drivingCourse[end][:F_R] end #while @@ -386,41 +373,41 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla end # check which limit was reached and adjust the currentStepSize for the next cycle - if cycle < approximationLevel+1 + if cycle < settings.approxLevel+1 if drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," <= F_R=",drivingCourse[end][:F_R]) # for testing - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle elseif s_braking > 0.0 && drivingCourse[end][:s] + s_braking > CS[:s_exit] testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],",+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle - elseif drivingCourse[end][:s] > nextPointOfInterest - testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest) # for testing - if settings[:stepVariable] == "s in m" - currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest[1]) # for testing + if settings.stepVariable == :distance + currentStepSize = nextPointOfInterest[1] - drivingCourse[end-1][:s] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:v] > CS[:v_peak] testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=",CS[:v_peak]) # for testing - if settings[:stepVariable] == "v in m/s" + if settings.stepVariable == :speed currentStepSize = CS[:v_peak]-drivingCourse[end-1][:v] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:v] > currentSpeedLimit[:v] testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: v=", drivingCourse[end][:v]," > v_limitCurrent=",currentSpeedLimit[:v]) # for testing - if settings[:stepVariable] == "v in m/s" + if settings.stepVariable == :velocity currentStepSize = currentSpeedLimit[:v]-drivingCourse[end-1][:v] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end - elseif drivingCourse[end][:s] +s_braking == CS[:s_exit] + elseif drivingCourse[end][:s] + s_braking == CS[:s_exit] testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],",+",s_braking," = ",drivingCourse[end][:s] +s_braking," == s_exit=",CS[:s_exit]) # for testing if s_braking == 0.0 endOfCSReached = true @@ -435,19 +422,19 @@ function addAcceleratingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFla testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: v=", drivingCourse[end][:v]," == v_limitCurrent=",currentSpeedLimit[:v]) # for testing break - elseif drivingCourse[end][:s] == nextPointOfInterest - testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," == nextPOI=",nextPointOfInterest) # for testing - if nextPointOfInterest == CS[:s_exit] + elseif drivingCourse[end][:s] == nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," == nextPOI=",nextPointOfInterest[1]) # for testing + if nextPointOfInterest[1] == CS[:s_exit] endOfCSReached = true end break else println("v=",drivingCourse[end][:v]," v_peak= ", CS[:v_peak] , " v_cLimit=", currentSpeedLimit[:v]) - println("s=" ,drivingCourse[end][:s]," s_exit=", CS[:s_exit], " s+s_braking=", drivingCourse[end][:s] +s_braking," nextPOI=",nextPointOfInterest) + println("s=" ,drivingCourse[end][:s]," s_exit=", CS[:s_exit], " s+s_braking=", drivingCourse[end][:s] +s_braking," nextPOI=",nextPointOfInterest[1]) println("F_T=",drivingCourse[end][:F_T] ," F_R=", drivingCourse[end][:F_R]) - error("ERROR at accelerating section: With the step variable ",settings[:stepVariable]," the while loop will be left although v nextPointOfInterest - testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest=",nextPointOfInterest) # for testing - drivingCourse[end][:s] = nextPointOfInterest # round s down to nextPointOfInterest + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," accelerating cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest[1]=",nextPointOfInterest[1]) # for testing + drivingCourse[end][:s] = nextPointOfInterest[1] # round s down to nextPointOfInterest drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] elseif drivingCourse[end][:F_T] <= drivingCourse[end][:F_R] @@ -551,15 +538,15 @@ end #function addAcceleratingSection! ## This function calculates the data points of the cruising section. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for cruising if needed. -function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, s_cruising::Real, settings::Dict, train::Dict, CSs::Vector{Dict}, cruisingType::String) +function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, s_cruising::Real, settings::Settings, train::Train, CSs::Vector{Dict}, cruisingType::String) trainIsClearing = cruisingType == "clearing" trainIsBrakingDownhill = cruisingType == "downhillBraking" # traction effort and resisting forces (in N) if !trainIsBrakingDownhill # TODO: or just give BS[:type] instead of "cruising"/"braking"? - calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel) else - calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel) end if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] @@ -567,11 +554,11 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end # conditions for cruising section - #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] speedIsValid = drivingCourse[end][:v]>0.0 && drivingCourse[end][:v]<=CS[:v_peak] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] @@ -587,16 +574,16 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: s_cruising = min(s_cruising, CS[:s_exit]-BS[:s_entry]) # traction effort and resisting forces (in N) -#03/25 calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) +#03/25 calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel) if !trainIsBrakingDownhill - calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel) else - calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel) end - if settings[:massModel]=="homogeneous strip" && CS[:id] > 1 + if settings.massModel == :homogeneous_strip && CS[:id] > 1 # conditions for cruising section - trainInPreviousCS = drivingCourse[end][:s] < CS[:s_entry] + train[:length] + trainInPreviousCS = drivingCourse[end][:s] < CS[:s_entry] + train.length targetPositionReached = drivingCourse[end][:s] >= BS[:s_entry] +s_cruising resistingForceNegative = drivingCourse[end][:F_R] < 0.0 # targetSpeedReached = stateFlags[:speedLimitReached] || drivingCourse[end][:v] >= CS[:v_peak] @@ -604,13 +591,13 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: #&& targetSpeedReached # use the conditions for the cruising section while trainInPreviousCS && !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used - currentStepSize = settings[:stepSize] - nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + currentStepSize = settings.stepSize + nextPointOfInterest[1] = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] - for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation + for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation while trainInPreviousCS && !targetPositionReached && !pointOfInterestReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used - # 03/09 old: while drivingCourse[end][:s] < CS[:s_entry] + train[:length] && drivingCourse[end][:s] < BS[:s_entry] +s_cruising && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:F_T]>=drivingCourse[end][:F_R] + # 03/09 old: while drivingCourse[end][:s] < CS[:s_entry] + train.length && drivingCourse[end][:s] < BS[:s_entry] +s_cruising && drivingCourse[end][:s] < nextPointOfInterest[1] && drivingCourse[end][:F_T]>=drivingCourse[end][:F_R] # the tractive effort is lower than the resisiting forces and the train has use the highest possible effort to try to stay at v_peak OR the mass model homogeneous strip is used and parts of the train are still in former CS #TODO: maybe just consider former CS with different path resistance? # tractive effort (in N): @@ -626,70 +613,70 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: drivingCourse[end][:a] = 0.0 # create the next data point - if settings[:stepVariable] =="s in m" || settings[:stepVariable] =="t in s" - push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) + if settings.stepVariable == :distance || settings.stepVariable == time + push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) else - push!(drivingCourse, moveAStep(drivingCourse[end], "s in m", train[:length]/(10.0^cycle), CS[:id])) # TODO which step size should be used? + push!(drivingCourse, moveAStep(drivingCourse[end], position, train.length/(10.0^cycle), CS[:id])) # TODO which step size should be used? end drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) -# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) +# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel) #if !trainIsBrakingDownhill - # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) + # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel) #else - # calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) + # calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel) #end # conditions for the next while cycle - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest # POIs include s_exit as well + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] # POIs include s_exit as well tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] targetPositionReached = drivingCourse[end][:s] >= BS[:s_entry] +s_cruising - trainInPreviousCS = drivingCourse[end][:s] < CS[:s_entry] + train[:length] + trainInPreviousCS = drivingCourse[end][:s] < CS[:s_entry] + train.length resistingForceNegative = drivingCourse[end][:F_R] < 0.0 end #while # check which limit was reached and adjust the currentStepSize for the next cycle - if cycle < approximationLevel+1 + if cycle < settings.approxLevel+1 if drivingCourse[end][:F_T] < drivingCourse[end][:F_R] - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle elseif !trainIsBrakingDownhill && resistingForceNegative - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle elseif trainIsBrakingDownhill && !resistingForceNegative - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle - elseif drivingCourse[end][:s] > nextPointOfInterest - if settings[:stepVariable] == "s in m" - currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + if settings.stepVariable == :distance + currentStepSize = nextPointOfInterest[1] - drivingCourse[end-1][:s] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end - elseif drivingCourse[end][:s] > BS[:s_entry] + s_cruising # TODO also the following? drivingCourse[end][:s] > CSs[CS[:id]][:s_entry] + train[:length])) - if settings[:stepVariable] == "s in m" + elseif drivingCourse[end][:s] > BS[:s_entry] + s_cruising # TODO also the following? drivingCourse[end][:s] > CSs[CS[:id]][:s_entry] + train.length)) + if settings.stepVariable == :distance currentStepSize=BS[:s_entry] + s_cruising-drivingCourse[end-1][:s] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:s] == BS[:s_entry] + s_cruising # || drivingCourse[end][:s]==CS[:s_exit] break - elseif drivingCourse[end][:s] >= CS[:s_entry] + train[:length] + elseif drivingCourse[end][:s] >= CS[:s_entry] + train.length break - elseif drivingCourse[end][:s] == nextPointOfInterest + elseif drivingCourse[end][:s] == nextPointOfInterest[1] break elseif !trainInPreviousCS break else - error("ERROR at cruising section: With the step variable ",settings[:stepVariable]," the while loop will be left although the if cases don't apply in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") + error("ERROR at cruising section: With the step variable ",settings.stepVariable," the while loop will be left although the if cases don't apply in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") end # delete last data point for recalculating the last step with reduced step size @@ -704,8 +691,8 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: resistingForceNegative = drivingCourse[end][:F_R] < 0.0 else # if the level of approximation is reached - if drivingCourse[end][:s] > nextPointOfInterest - drivingCourse[end][:s] = nextPointOfInterest # round s down to nextPointOfInterest + if drivingCourse[end][:s] > nextPointOfInterest[1] + drivingCourse[end][:s] = nextPointOfInterest[1] # round s down to nextPointOfInterest drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] elseif drivingCourse[end][:s] > BS[:s_entry]+s_cruising if BS[:type] != "clearing" @@ -738,7 +725,7 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: while !targetPositionReached && !tractionDeficit && (trainIsClearing || (trainIsBrakingDownhill == resistingForceNegative)) # while clearing tractive or braking force can be used # 03/09 old: while drivingCourse[end][:s] < BS[:s_entry]+s_cruising && drivingCourse[end][:F_T] >= drivingCourse[end][:F_R] - nextPointOfInterest = min(BS[:s_entry]+s_cruising, getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])) + nextPointOfInterest = min(BS[:s_entry]+s_cruising, getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1]) # tractive effort (in N): #03/25 drivingCourse[end][:F_T] = min(drivingCourse[end][:F_T], max(0.0, drivingCourse[end][:F_R])) @@ -754,19 +741,19 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: # calculate the remaining cruising way #s_cruisingRemaining=BS[:s_entry] + s_cruising-drivingCourse[end][:s] - s_cruisingRemaining = min(nextPointOfInterest -drivingCourse[end][:s], BS[:s_entry] +s_cruising -drivingCourse[end][:s]) + s_cruisingRemaining = min(nextPointOfInterest[1] -drivingCourse[end][:s], BS[:s_entry] +s_cruising -drivingCourse[end][:s]) # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], "s in m", s_cruisingRemaining, CS[:id])) + push!(drivingCourse, moveAStep(drivingCourse[end], :distance, s_cruisingRemaining, CS[:id])) drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) - calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) -# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) +# calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel) #if !trainIsBrakingDownhill - # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings[:massModel]) + # calculateForces!(drivingCourse[end], CSs, CS[:id], "cruising", train, settings.massModel) #else - # calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings[:massModel]) + # calculateForces!(drivingCourse[end], CSs, CS[:id], "braking", train, settings.massModel) #end # conditions for the next while cycle @@ -794,12 +781,12 @@ function addCruisingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: # set state flags stateFlags[:endOfCSReached] = drivingCourse[end][:s] == CS[:s_exit] if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end stateFlags[:brakingStartReached] = brakingStartReached || drivingCourse[end][:s] + s_braking >= CS[:s_exit] stateFlags[:tractionDeficit] = tractionDeficit stateFlags[:resistingForceNegative] = drivingCourse[end][:F_R] < 0.0 - currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length]) + currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length) stateFlags[:previousSpeedLimitReached] = currentSpeedLimit[:v] != CS[:v_limit] && drivingCourse[end][:v] >= currentSpeedLimit[:v] stateFlags[:error] = !(targetPositionReached || tractionDeficit || !(cruisingType == "clearing" || ((cruisingType == "downhillBraking") == resistingForceNegative))) @@ -808,22 +795,22 @@ end #function addCruisingSection! ## This function calculates the data points for diminishing run when using maximum tractive effort and still getting slower -function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) - calculateForces!(drivingCourse[end], CSs, CS[:id], "diminishing", train, settings[:massModel]) +function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Train, CSs::Vector{Dict}) + calculateForces!(drivingCourse[end], CSs, CS[:id], "diminishing", train, settings.massModel) if haskey(stateFlags, :usedForDefiningCharacteristics) && stateFlags[:usedForDefiningCharacteristics] ignoreBraking = true s_braking = 0.0 else ignoreBraking = false - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end # conditions for diminishing section targetSpeedReached = drivingCourse[end][:v] <= 0.0 endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] #|| stateFlags[:tractionDeficit] - #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + #s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] # use the conditions for the diminishing section @@ -832,29 +819,29 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag drivingCourse[end][:behavior] = BS[:type] while tractionDeficit && !targetSpeedReached && !endOfCSReached && !brakingStartReached - currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections - nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections + nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s])[1] + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] - for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation + for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation while tractionDeficit && !brakingStartReached && !pointOfInterestReached && !targetSpeedReached - # 03/09 old: while drivingCourse[end][:F_T] < drivingCourse[end][:F_R] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest && drivingCourse[end][:v]>0.0 # as long as s_i + s_braking < s_end + # 03/09 old: while drivingCourse[end][:F_T] < drivingCourse[end][:F_R] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest[1] && drivingCourse[end][:v]>0.0 # as long as s_i + s_braking < s_end # acceleration (in m/s^2): - drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) + push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) # conditions for the next while cycle if !ignoreBraking - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) end brakingStartReached = drivingCourse[end][:s] +s_braking >= CS[:s_exit] - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] targetSpeedReached = drivingCourse[end][:v] <= 0.0 tractionDeficit = drivingCourse[end][:F_T] < drivingCourse[end][:F_R] endOfCSReached = drivingCourse[end][:s] == CS[:s_exit] @@ -867,35 +854,35 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag end # check which limit was reached and adjust the currentStepSize for the next cycle - if cycle < approximationLevel+1 + if cycle < settings.approxLevel+1 if drivingCourse[end][:v] < 0.0 - if settings[:stepVariable] == "v in m/s" + if settings.stepVariable == velocity currentStepSize = drivingCourse[end-1][:v] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:F_T] > drivingCourse[end][:F_R] testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: F_T=", drivingCourse[end][:F_T]," > F_R=",drivingCourse[end][:F_R]) # for testing - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle elseif s_braking > 0.0 && drivingCourse[end][:s] + s_braking > CS[:s_exit] testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle - elseif drivingCourse[end][:s] > nextPointOfInterest - testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest) # for testing - if settings[:stepVariable] == "s in m" - currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPOI=",nextPointOfInterest[1]) # for testing + if settings.stepVariable == :distance + currentStepSize = nextPointOfInterest[1] - drivingCourse[end-1][:s] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:s] + s_braking == CS[:s_exit] testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," == s_exit=",CS[:s_exit]) # for testing break - elseif drivingCourse[end][:s] == nextPointOfInterest - testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," == nextPOI=",nextPointOfInterest) # for testing + elseif drivingCourse[end][:s] == nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," == nextPOI=",nextPointOfInterest[1]) # for testing break elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] @@ -908,7 +895,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag " F_T=",drivingCourse[end-1][:F_T]," N R_traction=",drivingCourse[end-1][:R_traction]," N R_wagons=",drivingCourse[end-1][:R_wagons]," N R_path=",drivingCourse[end-1][:R_path]," N.") else - error("ERROR during diminishing run: With the step variable ",settings[:stepVariable]," the while loop will be left although s+s_braking0.0 in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") + error("ERROR during diminishing run: With the step variable ",settings.stepVariable," the while loop will be left although s+s_braking0.0 in CS",CS[:id]," with s=" ,drivingCourse[end][:s]," m and v=",drivingCourse[end][:v]," m/s") end # delete last data point for recalculating the last step with reduced step size pop!(drivingCourse) @@ -939,9 +926,9 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag tractionDeficit = true endOfCSReached = false - elseif drivingCourse[end][:s] > nextPointOfInterest - testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest=",nextPointOfInterest) # for testing - drivingCourse[end][:s] = nextPointOfInterest # round s down to nextPointOfInterest + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest[1]=",nextPointOfInterest[1]) # for testing + drivingCourse[end][:s] = nextPointOfInterest[1] # round s down to nextPointOfInterest drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] elseif drivingCourse[end][:F_T] >= drivingCourse[end][:F_R] @@ -951,7 +938,7 @@ function addDiminishingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlag else testFlag && println("in CS",CS[:id]," diminishing cycle",cycle," case: else with v=", drivingCourse[end][:v]," > 0.0 and F_T=", drivingCourse[end][:F_T]," <= F_R=", drivingCourse[end][:F_R]) # for testing #println(" and s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," <= s_exit=",CS[:s_exit]) # for testing - #println(" and s=", drivingCourse[end][:s]," <= nextPointOfInterest=",nextPointOfInterest) # for testing + #println(" and s=", drivingCourse[end][:s]," <= nextPointOfInterest[1]=",nextPointOfInterest[1]) # for testing # if drivingCourse[end][:s] + s_braking == CS[:s_exit] # brakingStartReached = true @@ -995,7 +982,7 @@ end #function addDiminishingSection! ## This function calculates the data points of the coasting section. # Therefore it gets its previous driving course and the characteristic section and returns the characteristic section and driving course including the coasting section -function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) +function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Train, CSs::Vector{Dict}) # TODO: if the rear of the train is still located in a former characteristic section it has to be checked if its speed limit can be kept # with getCurrentSpeedLimit @@ -1003,7 +990,7 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] || stateFlags[:brakingStartReached] # use the conditions for the coasting section @@ -1012,61 +999,61 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: drivingCourse[end][:behavior] = BS[:type] while !targetSpeedReached && !endOfCSReached && !brakingStartReached - currentStepSize=settings[:stepSize] # initialize the step size that can be reduced near intersections - nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + currentStepSize=settings.stepSize # initialize the step size that can be reduced near intersections + nextPointOfInterest[1] = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] - for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation + for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation while !targetSpeedReached && !brakingStartReached && !pointOfInterestReached - # 03/09 old : while drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:v] <= CS[:v_peak] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest + # 03/09 old : while drivingCourse[end][:v] > CS[:v_exit] && drivingCourse[end][:v] <= CS[:v_peak] && !brakingStartReached && drivingCourse[end][:s] < nextPointOfInterest[1] # traction effort and resisting forces (in N): - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) # acceleration (in m/s^2): - drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train[:m_train], train[:ξ_train]) + drivingCourse[end][:a] = calcAcceleration(drivingCourse[end][:F_T], drivingCourse[end][:F_R], train.m_train_full, train.ξ_train) # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) + push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) # conditions for the next while cycle - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) brakingStartReached = drivingCourse[end][:s] + s_braking >= CS[:s_exit] - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] || drivingCourse[end][:v] > CS[:v_peak] end # while testFlag = false # check which limit was reached and adjust the currentStepSize for the next cycle - if cycle < approximationLevel+1 + if cycle < settings.approxLevel+1 if drivingCourse[end][:s] + s_braking > CS[:s_exit] testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," > s_exit=",CS[:s_exit]) # for testing - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle - elseif drivingCourse[end][:s] > nextPointOfInterest - testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest=",nextPointOfInterest) # for testing + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s=", drivingCourse[end][:s]," > nextPointOfInterest[1]=",nextPointOfInterest[1]) # for testing - if settings[:stepVariable] == "s in m" - currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] + if settings.stepVariable == :distance + currentStepSize = nextPointOfInterest[1] - drivingCourse[end-1][:s] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:v] < CS[:v_exit] # TODO: if accelereation and coasting functions will be combined this case is only for coasting testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," < v_exit=", CS[:v_exit]) # for testing - if settings[:stepVariable] == "v in m/s" + if settings.stepVariable == velocity currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:v] > CS[:v_peak] testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," > v_peak=", CS[:v_peak]) # for testing - if settings[:stepVariable] == "v in m/s" + if settings.stepVariable == velocity currentStepSize = CS[:v_peak] - drivingCourse[end-1][:v] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:s] + s_braking == CS[:s_exit] testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s +s_braking=", drivingCourse[end][:s],"+",s_braking," = ",drivingCourse[end][:s] +s_braking," == s_exit=",CS[:s_exit]) # for testing @@ -1076,13 +1063,13 @@ function addCoastingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags:: testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: v=", drivingCourse[end][:v]," == v_exit=", CS[:v_exit]) # for testing break - elseif drivingCourse[end][:s] == nextPointOfInterest - testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s =", drivingCourse[end][:s]," > nextPointOfInterest=",nextPointOfInterest) # for testing + elseif drivingCourse[end][:s] == nextPointOfInterest[1] + testFlag && println("in CS",CS[:id]," coasting cycle",cycle," case: s =", drivingCourse[end][:s]," > nextPointOfInterest[1]=",nextPointOfInterest[1]) # for testing break else # TODO: not needed. just for testing - error("ERROR at coasting until braking section: With the step variable ",settings[:stepVariable]," the while loop will be left although v nextPointOfInterest - drivingCourse[end][:s] = nextPointOfInterest # round s down to nextPointOfInterest + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + drivingCourse[end][:s] = nextPointOfInterest[1] # round s down to nextPointOfInterest drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] else # do nothing for example for drivingCourse[end][:s] + s_braking == CS[:s_exit] @@ -1158,7 +1145,7 @@ end #function addCoastingSection! ## This function calculates the data points of the braking section. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the behavior section for braking if needed. -function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Dict, train::Dict, CSs::Vector{Dict}) +function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::Dict, settings::Settings, train::Train, CSs::Vector{Dict}) # conditions for braking section targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] || stateFlags[:endOfCSReached] @@ -1169,21 +1156,21 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D drivingCourse[end][:behavior] = BS[:type] while !targetSpeedReached && !endOfCSReached - currentStepSize = settings[:stepSize] # initialize the step size that can be reduced near intersections + currentStepSize = settings.stepSize # initialize the step size that can be reduced near intersections nextPointOfInterest = getNextPointOfInterest(CS[:pointsOfInterest], drivingCourse[end][:s]) - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] - for cycle in 1:approximationLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation + for cycle in 1:settings.approxLevel+1 # first cycle with normal step size followed by cycles with reduced step size depending on the level of approximation while !targetSpeedReached && !endOfCSReached && !pointOfInterestReached - # 03/09 old: while drivingCourse[end][:v] > CS[:v_exit] && !targetSpeedReached && drivingCourse[end][:s] < CS[:s_exit] && drivingCourse[end][:s] < nextPointOfInterest + # 03/09 old: while drivingCourse[end][:v] > CS[:v_exit] && !targetSpeedReached && drivingCourse[end][:s] < CS[:s_exit] && drivingCourse[end][:s] < nextPointOfInterest[1] # traction effort and resisting forces (in N): - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) # acceleration (in m/s^2): - drivingCourse[end][:a] = train[:a_braking] + drivingCourse[end][:a] = train.a_braking # TODO or: drivingCourse[end][:a] = calcBrakingAcceleration(drivingCourse[end][:v], CS[:v_exit], CS[:s_exit]-drivingCourse[end][:s]) - if settings[:stepVariable] == "s in m" && ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0 + if settings.stepVariable == :distance && ((drivingCourse[end][:v]/drivingCourse[end][:a])^2+2*currentStepSize/drivingCourse[end][:a])<0.0 || (drivingCourse[end][:v]^2+2*currentStepSize*drivingCourse[end][:a])<0.0 # create empty data point and set it for the values of s_exit and v_exit push!(drivingCourse, createDataPoint()) drivingCourse[end][:i] = drivingCourse[end-1][:i]+1 @@ -1192,32 +1179,32 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D recalculateLastBrakingPoint!(drivingCourse, CS[:s_exit], CS[:v_exit]) else # create the next data point - push!(drivingCourse, moveAStep(drivingCourse[end], settings[:stepVariable], currentStepSize, CS[:id])) + push!(drivingCourse, moveAStep(drivingCourse[end], settings.stepVariable, currentStepSize, CS[:id])) drivingCourse[end][:behavior] = BS[:type] push!(BS[:dataPoints], drivingCourse[end][:i]) end #println(drivingCourse[end][:i],". s=",drivingCourse[end][:s]," s_exit=", CS[:s_exit]," v_exit=", CS[:v_exit]," v=",drivingCourse[end][:v]) # conditions for the next while cycle - pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest + pointOfInterestReached = drivingCourse[end][:s] >= nextPointOfInterest[1] endOfCSReached = drivingCourse[end][:s] >= CS[:s_exit] targetSpeedReached = drivingCourse[end][:v] <= CS[:v_exit] end # while # check which limit was reached and adjust the currentStepSize for the next cycle # TODO: is there a better way than rounding like in the following? - if cycle < approximationLevel+1 + if cycle < settings.approxLevel+1 if drivingCourse[end][:v] < CS[:v_exit] - if settings[:stepVariable] == "v in m/s" + if settings.stepVariable == :velocity currentStepSize = drivingCourse[end-1][:v] - CS[:v_exit] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end - elseif drivingCourse[end][:s] > nextPointOfInterest - if settings[:stepVariable] == "s in m" - currentStepSize = nextPointOfInterest - drivingCourse[end-1][:s] + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + if settings.stepVariable == :distance + currentStepSize = nextPointOfInterest[1] - drivingCourse[end-1][:s] else - currentStepSize = settings[:stepSize] / 10.0^cycle + currentStepSize = settings.stepSize / 10.0^cycle end elseif drivingCourse[end][:v] == CS[:v_exit] && drivingCourse[end][:s] == CS[:s_exit] break @@ -1232,7 +1219,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D targetSpeedReached = true # println(" with a=", drivingCourse[end-1][:a]) # for testing break - elseif drivingCourse[end][:s] == nextPointOfInterest + elseif drivingCourse[end][:s] == nextPointOfInterest[1] break end @@ -1258,8 +1245,8 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D # recalculateLastBrakingPoint!(drivingCourse, CS[:s_exit], CS[:v_exit]) drivingCourse[end][:s] = CS[:s_exit] break - elseif drivingCourse[end][:s] > nextPointOfInterest - drivingCourse[end][:s] = nextPointOfInterest # round s down to nextPointOfInterest + elseif drivingCourse[end][:s] > nextPointOfInterest[1] + drivingCourse[end][:s] = nextPointOfInterest[1] # round s down to nextPointOfInterest drivingCourse[end][:Δs] = drivingCourse[end][:s] - drivingCourse[end-1][:s] break elseif drivingCourse[end][:v] == CS[:v_exit] && drivingCourse[end][:s] == CS[:s_exit] @@ -1281,7 +1268,7 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D targetSpeedReached = true break else - # do nothing for example for drivingCourse[end][:s]==nextPointOfInterest + # do nothing for example for drivingCourse[end][:s]==nextPointOfInterest[1] end end end #for @@ -1301,12 +1288,12 @@ function addBrakingSection!(CS::Dict, drivingCourse::Vector{Dict}, stateFlags::D end # else: return the characteristic section without a braking section # set state flags - currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train[:length]) + currentSpeedLimit = getCurrentSpeedLimit(CSs, CS[:id], drivingCourse[end][:s], train.length) stateFlags[:previousSpeedLimitReached] = currentSpeedLimit[:v] != CS[:v_limit] && drivingCourse[end][:v] >= currentSpeedLimit[:v] stateFlags[:speedLimitReached] = drivingCourse[end][:v] >= CS[:v_exit] stateFlags[:endOfCSReached] = endOfCSReached stateFlags[:error] = !(endOfCSReached) - calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) stateFlags[:resistingForceNegative] = drivingCourse[end][:F_R] < 0 return (CS, drivingCourse, stateFlags) @@ -1315,7 +1302,7 @@ end #function addBrakingSection! ## This function calculates the data point of the standstill. # Therefore it gets its first data point and the characteristic section and returns the characteristic section including the standstill if needed. -function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, train::Dict, CSs::Vector{Dict}) +function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Settings, train::Train, CSs::Vector{Dict}) if drivingCourse[end][:v] == 0.0 BS = createBehaviorSection("standstill", drivingCourse[end][:s], drivingCourse[end][:v], drivingCourse[end][:i]) merge!(BS, Dict(:length => 0.0, # total length (in m) @@ -1326,7 +1313,7 @@ function addStandstill!(CS::Dict, drivingCourse::Vector{Dict}, settings::Dict, t drivingCourse[end][:behavior] = BS[:type] # traction effort and resisting forces (in N) - calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings[:massModel]) + calculateForces!(drivingCourse[end], CSs, CS[:id], BS[:type], train, settings.massModel) merge!(CS[:behaviorSections], Dict(:standstill => BS)) end # else: return the characteristic section without a standstillSection section @@ -1347,47 +1334,6 @@ function mergeBehaviorSection!(BSs::Dict, BS::Dict) return BSs end #function mergeBehaviorSection! -function createBehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer) - BS= Dict(#:type => behavior, # type of behavior section: breakFree, clearing, accelerating, cruising, diminishing, coasting, braking or standstill - :type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "braking" or "standstill" - :length => 0.0, # total length (in m) - :s_entry => s_entry, # first position (in m) - :s_exit => 0.0, # last position (in m) - :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) - :v_entry => v_entry, # entry speed (in m/s) - :v_exit => 0.0, # exit speed (in m/s) - :dataPoints => [startingPoint]) # list of identifiers of the containing data points starting with the initial point - return BS -end #function createBehaviorSection - -""" -a data point is the smallest element of the driving course. One step of the step approach is between two data points -""" -function createDataPoint() - dataPoint = Dict(:i => 0, # identifier and counter variable of the dricing course - :behavior => "", # type of behavior section the data point is part of ("breakFree", "clearing", "accelerating", "cruising", "diminishing", "coasting", "braking" or "standstill") - # a data point which is the last point of one behavior section and the first point of the next behavior section will be attached to the latter - :s => 0.0, # position (in m) - :Δs => 0.0, # step size (in m) - :t => 0.0, # point in time (in s) - :Δt => 0.0, # step size (in s) - :v => 0.0, # velocity (in m/s) - :Δv => 0.0, # step size (in m/s) - :a => 0.0, # acceleration (in m/s^2) - :W => 0.0, # mechanical work (in Ws) - :ΔW => 0.0, # mechanical work in this step (in Ws) - :E => 0.0, # energy consumption (in Ws) - :ΔE => 0.0, # energy consumption in this step (in Ws) - :F_T => 0.0, # tractive effort (in N) - :F_R => 0.0, # resisting force (in N) - :R_path => 0.0, # path resistance (in N) - :R_train => 0.0, # train resistance (in N) - :R_traction => 0.0, # traction unit resistance (in N) - :R_wagons => 0.0) # set of wagons resistance (in N) - return dataPoint -end #function createDataPoint - function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target) currentPoint = drivingCourse[end] previousPoint = drivingCourse[end-1] @@ -1400,8 +1346,8 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target) # calculate other values previousPoint[:a] = calcBrakingAcceleration(previousPoint[:v], currentPoint[:v], currentPoint[:Δs]) # # TODO: just for testing -# if previousPoint[:a]=0.0 -# println("Warning: a_braking gets to high in CS ",CS[:id], " with a=",previousPoint[:a] ," > ",train[:a_braking]) +# if previousPoint[:a]=0.0 +# println("Warning: a_braking gets to high in CS ",CS[:id], " with a=",previousPoint[:a] ," > ",train.a_braking) # end currentPoint[:Δt] = calc_Δt_with_Δv(currentPoint[:Δv], previousPoint[:a]) # step size (in s) currentPoint[:t] = previousPoint[:t] + currentPoint[:Δt] # point in time (in s) @@ -1411,5 +1357,3 @@ function recalculateLastBrakingPoint!(drivingCourse, s_target, v_target) currentPoint[:ΔE] = currentPoint[:ΔW] # energy consumption in this step (in Ws) currentPoint[:E] = previousPoint[:E] + currentPoint[:ΔE] # energy consumption (in Ws) end #function recalculateLastBrakingPoint - -end #module Behavior diff --git a/src/TrainRunCalc.jl b/src/calc.jl similarity index 64% rename from src/TrainRunCalc.jl rename to src/calc.jl index e41d5c8..e9ed5ef 100644 --- a/src/TrainRunCalc.jl +++ b/src/calc.jl @@ -5,83 +5,20 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" -module TrainRunCalc - -# include modules of TrainRunCalc -include("./Validate.jl") -include("./Characteristics.jl") -include("./Behavior.jl") -include("./Output.jl") - - -# use modules of TrainRunCalc -using .Validate -using .Characteristics -using .Behavior -using .Output - -# export main function -export trainRun - -approximationLevel = 6 # value for approximation to intersections and precisely calculated digits - # TODO: define it here and give it to each function? (Behavior, ...) - -# Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`. - -""" - trainRun(train::Dict, path::Dict, settings::Dict) - -Calculate the driving dynamics of a train run on a path with special settings with information from the corresponding dictionaries `train`, `path`, `settings`. - -# Examples -```julia-repl -julia> trainRun(trainDict, pathDict, settingsDict) -todo !!! -``` -""" -function trainRun(trainInput::Dict, pathInput::Dict, settingsInput::Dict) - # copy Input data for not changing them - # TODO: or should they be changed? normally it would only make it "better" except for settings[:detailOfOutput] == "points of interest" && !haskey(path, :pointsOfInterest) - train = copy(trainInput) - path = copy(pathInput) - settings = copy(settingsInput) - - # check the input data - (train, path, settings) = checkAndSetInput!(train, path, settings) - settings[:detailOfOutput] == "everything" && println("The input has been checked.") - - # prepare the input data - movingSection = determineCharacteristics(path, train, settings) - settings[:detailOfOutput] == "everything" && println("The moving section has been prepared.") - - # calculate the train run for oparation mode "minimum running time" - if settings[:operationModeMinimumRunningTime] || settings[:operationModeMinimumEnergyConsumption] - (movingSection, drivingCourse) = calculateMinimumRunningTime!(movingSection, settings, train) - settings[:detailOfOutput] == "everything" && println("The driving course for the shortest running time has been calculated.") - - # accumulate data and create an output dictionary - output = createOutput(train, settings, path, movingSection, drivingCourse) - # 30/31 old: output = createOutputDict(train, settings, path, movingSection, drivingCourse) - else - output = nothing - # 30/31 old: output = Dict() - end #if - - return output -end # function trainRun +# Calculate the running time of a train run on a path with special settings with information from the corresponding YAML files with the file paths `trainDirectory`, `pathDirectory`, `settingsDirectory`. # calculate a train run focussing on using the minimum possible running time -function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train::Dict) +function calculateMinimumRunningTime!(movingSection::Dict, settings::Settings, train::Train) CSs::Vector{Dict} = movingSection[:characteristicSections] - if settings[:massModel] == "homogeneous strip" && settings[:stepVariable] == "v in m/s" + if settings.massModel == :homogeneous_strip && settings.stepVariable == speed println("WARNING: ! ! ! TrainRun.jl doesn't work reliably for the mass model homogeneous strip with step size v in m/s. The calculation time can be extremely high when calcutlating paths with steep gradients ! ! !") end startingPoint=createDataPoint() startingPoint[:i]=1 startingPoint[:s]=CSs[1][:s_entry] - calculateForces!(startingPoint, CSs, 1, "default", train, settings[:massModel]) # traction effort and resisting forces (in N) + calculateForces!(startingPoint, CSs, 1, "default", train, settings.massModel) # traction effort and resisting forces (in N) drivingCourse::Vector{Dict} = [startingPoint] # List of data points for csId in 1:length(CSs) @@ -95,8 +32,8 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train end # determine the different flags for switching between the states for creatinge moving phases - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) - calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings[:massModel]) # tractive effort and resisting forces (in N) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) + calculateForces!(drivingCourse[end], CSs, CS[:id], "default", train, settings.massModel) # tractive effort and resisting forces (in N) previousSpeedLimitReached = false stateFlags = Dict(:endOfCSReached => drivingCourse[end][:s] > CS[:s_exit], @@ -122,17 +59,17 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] && !stateFlags[:speedLimitReached] # cruise only one step - if settings[:stepVariable] =="s in m" - s_cruising = settings[:stepSize] - elseif settings[:stepVariable] =="t in s" - s_cruising = calc_Δs_with_Δt(settings[:stepSize], drivingCourse[end][:a], drivingCourse[end][:v]) - elseif settings[:stepVariable] =="v in m/s" - s_cruising = train[:length]/(10.0) # TODO which step size should be used? + if settings.stepVariable == :distance + s_cruising = settings.stepSize + elseif settings.stepVariable == time + s_cruising = calc_Δs_with_Δt(settings.stepSize, drivingCourse[end][:a], drivingCourse[end][:v]) + elseif settings.stepVariable == velocity + s_cruising = train.length/(10.0) # TODO which step size should be used? end (CS, drivingCourse, stateFlags) = addCruisingSection!(CS, drivingCourse, stateFlags, s_cruising, settings, train, CSs, "cruising") elseif drivingCourse[end][:F_R] < 0 && stateFlags[:speedLimitReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking if s_cruising > 0.0 @@ -142,7 +79,7 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train end elseif drivingCourse[end][:F_T] == drivingCourse[end][:F_R] || stateFlags[:speedLimitReached] - s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train[:a_braking]) + s_braking = calcBrakingDistance(drivingCourse[end][:v], CS[:v_exit], train.a_braking) s_cruising = CS[:s_exit] - drivingCourse[end][:s] - s_braking if s_cruising > 0.0 # TODO: define a minimum cruising length? @@ -186,5 +123,3 @@ function calculateMinimumRunningTime!(movingSection::Dict, settings::Dict, train return (movingSection, drivingCourse) end #function calculateMinimumRunningTime - -end # module TrainRunCalc diff --git a/src/Characteristics.jl b/src/characteristics.jl similarity index 60% rename from src/Characteristics.jl rename to src/characteristics.jl index 023e79f..7abcd10 100644 --- a/src/Characteristics.jl +++ b/src/characteristics.jl @@ -5,94 +5,16 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" -module Characteristics - -include("./Behavior.jl") -using .Behavior - -export determineCharacteristics - ## create a moving section and its containing characteristic sections with secured braking, accelerating and cruising behavior -function determineCharacteristics(path::Dict, train::Dict, settings::Dict) - movingSection = createMovingSection(path, train[:v_limit]) - movingSection = secureBrakingBehavior!(movingSection, train[:a_braking]) +function determineCharacteristics(path::Path, train::Train, settings::Settings) + movingSection = createMovingSection(path, train.v_limit, train.length) + movingSection = secureBrakingBehavior!(movingSection, train.a_braking) movingSection = secureAcceleratingBehavior!(movingSection, settings, train) #movingSection = secureCruisingBehavior!(movingSection, settings, train) return movingSection end #function determineCharacteristics -## create a moving section containing characteristic sections -function createMovingSection(path::Dict, v_trainLimit::Real) - # this function creates and returns a moving section dependent on the paths attributes - - s_entry = path[:sections][1][:s_start] # first position (in m) - s_exit = path[:sections][end][:s_end] # last position (in m) - pathLength = s_exit - s_entry # total length (in m) - - CSs=Vector{Dict}() - s_csStart=s_entry - csId=1 - for row in 2:length(path[:sections]) - previousSection = path[:sections][row-1] - currentSection = path[:sections][row] - speedLimitIsDifferent = min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) - pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp] - if speedLimitIsDifferent || pathResistanceIsDifferent - # 03/09 old: if min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) || previousSection[:f_Rp] != currentSection[:f_Rp] - push!(CSs, createCharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), path)) - s_csStart = currentSection[:s_start] - csId = csId+1 - end #if - end #for - push!(CSs, createCharacteristicSection(csId, s_csStart, path[:sections][end], min(path[:sections][end][:v_limit], v_trainLimit), path)) - - movingSection= Dict(:id => 1, # identifier # if there is more than one moving section in a later version of this tool the id should not be constant anymore - :length => pathLength, # total length (in m) - :s_entry => s_entry, # first position (in m) - :s_exit => s_exit, # last position (in m) - :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) - :characteristicSections => CSs) # list of containing characteristic sections - - return movingSection -end #function createMovingSection - - -## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections. -function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, path::Dict) - # Create and return a characteristic section dependent on the paths attributes - characteristicSection= Dict(:id => id, # identifier - :s_entry => s_entry, # first position (in m) - :s_exit => section[:s_end], # last position (in m) - :length => section[:s_end] -s_entry, # total length (in m) - :r_path => section[:f_Rp], # path resistance (in ‰) - :behaviorSections => Dict(), # list of containing behavior sections - :t => 0.0, # total running time (in s) - :E => 0.0, # total energy consumption (in Ws) - :v_limit => v_limit, # speed limit (in m/s) - # initializing :v_entry, :v_peak and :v_exit with :v_limit - :v_peak => v_limit, # maximum reachable speed (in m/s) - :v_entry => v_limit, # maximum entry speed (in m/s) - :v_exit => v_limit) # maximum exit speed (in m/s) - - # list of positions of every point of interest (POI) in this charateristic section for which data points should be calculated - s_exit = characteristicSection[:s_exit] - pointsOfInterest = Vector{Real}() - if haskey(path, :pointsOfInterest) - for POI in path[:pointsOfInterest] - if s_entry < POI && POI < s_exit - push!(pointsOfInterest, POI) - end - end - end - push!(pointsOfInterest, s_exit) # s_exit has to be the last POI so that there will always be a POI to campare the current position with - - merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest)) - - return characteristicSection -end #function createCharacteristicSection - ## define the intersection velocities between the characterisitc sections to secure braking behavior function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) # this function limits the entry and exit velocity of the characteristic sections to secure that the train stops at the moving sections end @@ -123,7 +45,7 @@ function secureBrakingBehavior!(movingSection::Dict, a_braking::Real) end #function secureBrakingBehavior! ## define the intersection velocities between the characterisitc sections to secure accelerating behavior -function secureAcceleratingBehavior!(movingSection::Dict, settings::Dict, train::Dict) +function secureAcceleratingBehavior!(movingSection::Dict, settings::Settings, train::Train) # this function limits the entry and exit velocity of the characteristic sections in case that the train accelerates in every section and cruises aterwards CSs = movingSection[:characteristicSections] @@ -136,7 +58,7 @@ function secureAcceleratingBehavior!(movingSection::Dict, settings::Dict, train: CS[:v_entry] = min(CS[:v_entry], previousCSv_exit) startingPoint[:s] = CS[:s_entry] startingPoint[:v] = CS[:v_entry] - calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings[:massModel]) # traction effort and resisting forces (in N) + calculateForces!(startingPoint, CSs, CS[:id], "accelerating", train, settings.massModel) # traction effort and resisting forces (in N) acceleratingCourse::Vector{Dict} = [startingPoint] # List of data points if CS[:v_entry] < CS[:v_peak] @@ -160,7 +82,7 @@ function secureAcceleratingBehavior!(movingSection::Dict, settings::Dict, train: (CS, acceleratingCourse, stateFlags) = addClearingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the train is not allowed to accelerate because of a previous speed limit end else - if settings[:massModel] == "mass point" || acceleratingCourse[end][:s] > CS[:s_entry] + train[:length] + if settings.massModel == :mass_point || acceleratingCourse[end][:s] > CS[:s_entry] + train.length break else (CS, acceleratingCourse, stateFlags) = addDiminishingSection!(CS, acceleratingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort @@ -190,7 +112,7 @@ end #function secureAcceleratingBehavior! #= ## define the intersection velocities between the characterisitc sections to secure cruising behavior -function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dict) +function secureCruisingBehavior!(movingSection::Dict, settings::Settings, train::Train) # limit the exit velocity of the characteristic sections in case that the train cruises in every section at v_peak CSs = movingSection[:characteristicSections] @@ -225,7 +147,7 @@ function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dic (CS, cruisingCourse, stateFlags) = addCruisingSection!(CS, cruisingCourse, stateFlags, s_cruising, settings, train, CSs, "downhillBraking") end else - if settings[:massModel] == "mass point" || cruisingCourse[end][:s] > CS[:s_entry] + train[:length] + if settings.massModel == :mass_point || cruisingCourse[end][:s] > CS[:s_entry] + train.length break else (CS, cruisingCourse, stateFlags) = addDiminishingSection!(CS, cruisingCourse, stateFlags, settings, train, CSs) # this function is needed in case the resisitng forces are higher than the maximum possible tractive effort @@ -246,4 +168,3 @@ function secureCruisingBehavior!(movingSection::Dict, settings::Dict, train::Dic return movingSection end #function secureCruisingBehavior! =# -end #module Characteristics diff --git a/src/constructors.jl b/src/constructors.jl new file mode 100644 index 0000000..ffa27c1 --- /dev/null +++ b/src/constructors.jl @@ -0,0 +1,741 @@ +#!/usr/bin/env julia +# -*- coding: UTF-8 -*- +# __julia-version__ = 1.7.2 +# __author__ = "Martin Scheidt, Max Kannenberg" +# __copyright__ = "2022" +# __license__ = "ISC" + +""" + Settings(file) + +Settings is a datastruture for calculation context. +The function Settings() will create a set of settings for the train run calculation. +`file` is optinal may be used to load settings in the YAML format. + +# Example +```jldoctest +julia> my_settings = Settings() # will generate default settings +Settings(mass_point, :distance, 20, 3, running_time, :dataframe) +``` +""" +function Settings(file="DEFAULT") + + ## default values + massModel = :mass_point + stepVariable = :distance + stepSize = 20 + approxLevel = 3 + outputDetail = :running_time + outputFormat = :dataframe + + ## load from file + if file != "DEFAULT" + + ## JSON schema for YAML-file validation + schema = Schema("""{ + "properties": { + "massModel": { + "description": "type of train model", + "type": "string", + "enum": [ "mass_point", "homogeneous_strip" ] + }, + "stepVariable": { + "description": "variable of the linear multistep method", + "type": "string", + "enum": [ "distance", "time", "velocity" ] + }, + "stepSize": { + "description": "step size acording to stepVariable", + "type": "number", + "exclusiveMinimum": 0 + }, + "outputDetail": { + "description": "Selecting the detail of the result", + "type": "string", + "enum": [ "running_time", "points_of_interest", "driving_course", "everything" ] + }, + "outputFormat": { + "description": "Output format", + "type": "string", + "enum": [ "dataframe", "dict" ] + } + } + }""") + + settings = YAML.load(open(file))["settings"] + + ## validate the loaded file + try + validate(schema, settings) + catch err + println("Could not load settings file '$file'.\n Format is not recognized - using default as fall back.") + settings = Dict() + end + + ## set the variables in "settings" + haskey(settings, "massModel") ? massModel = Symbol(settings["massModel"]) : nothing + haskey(settings, "stepVariable") ? stepVariable = Symbol(settings["stepVariable"]) : nothing + haskey(settings, "stepSize") ? stepSize = settings["stepSize"] : nothing + haskey(settings, "approxLevel") ? approxLevel = settings["approxLevel"] : nothing + haskey(settings, "outputDetail") ? outputDetail = Symbol(settings["outputDetail"]) : nothing + haskey(settings, "outputFormat") ? outputFormat = Symbol(settings["outputFormat"]) : nothing + end + + Settings(massModel, stepVariable, stepSize, approxLevel, outputDetail, outputFormat) + +end #function Settings() # outer constructor + +""" + Path(file, type = :YAML) + +Path is a datastruture for calculation context. +The function Path() will create a running path for the train. +Supported formats are: railtoolkit/schema (2022.05) + +# Example +```jldoctest +julia> my_path = Path("file.yaml") # will generate a path from a YAML file. +Path(variables) +``` +""" +function Path(file, type = :YAML) + + ## default values + name = "" + id = "" + uuid = UUIDs.uuid4() + poi = [] + sections = [] + + ## process flags + POI_PRESENT = false + + ## load from file + if type == :YAML + + data = YAML.load(open(file)) + if data["schema"] != "https://railtoolkit.org/schema/running-path.json" + error("Could not load path file '$file'.\n + YAML format is not recognized. + Currently supported: railtoolkit/schema/running-path (2022.05)") + end + if data["schema_version"] != "2022.05" + error("Could not load path file '$file'.\n + YAML format is not recognized. + Currently supported: railtoolkit/schema/running-path (2022.05)") + end + + ## JSON schema for YAML-file validation + railtoolkit_schema = Schema("""{ + "required": [ "schema", "schema_version", "paths" ], + "properties": { + "schema": { + "description": "Identifier of the schema", + "enum": [ "https://railtoolkit.org/schema/running-path.json" ] + }, + "schema_version": { + "description": "Version of the schema", + "type": "string", + "pattern": "[2-9][0-9][0-9][0-9].[0-1][0-9]" + }, + "paths": { + "type": "array", + "minItems": 1, + "items": { + "required": [ "name", "id", "characteristic_sections" ], + "type": "object", + "properties": { + "characteristic_sections": { + "description": "", + "type": "array", + "minItems": 2, + "uniqueItems": true, + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "description": "", + "prefixItems": [ + { + "description": "milage in meter", + "type": "number" + }, + { + "description": "speed in kilometers per hour", + "type": "number", + "exclusiveMinimum": 0 + }, + { + "description": "resistance in permil", + "type": "number" + } + ] + } + }, + "id": { + "description": "Identifier of the path", + "type": "string" + }, + "name": { + "description": "Name of the path", + "type": "string" + }, + "points_of_interest": { + "description": "", + "type": "array", + "uniqueItems": true, + "items": { + "type": "array", + "minItems": 3, + "maxItems": 3, + "description": "", + "prefixItems": [ + { "type": "number" }, + { "type": "string" }, + { "enum": [ "front", "rear" ] } + ] + } + }, + "UUID": { + "description": "The unique identifier for a path", + "type": "string", + "format": "uuid" + } + } + } + } + } + }""") + + paths = data["paths"] + try + validate(railtoolkit_schema, paths) + catch err + error("Could not load path file '$file'.\n + YAML format is not recognized. + Currently supported: railtoolkit/schema/running-path (2022.05)") + end + if length(paths) > 1 + println("WARNING: the loaded file contains more than one path. Using only the first!") + end + path = paths[1] + + ## set the variables in "path" + # required + name = path["name"] + id = path["id"] + tmp_sec = path["characteristic_sections"] + # optional + haskey(path, "UUID") ? uuid = parse(UUID, path["UUID"] ) : nothing + haskey(path, "points_of_interest") ? POI_PRESENT = true : nothing + haskey(path, "points_of_interest") ? tmp_points = path["points_of_interest"] : nothing + + else + error("Unknown file type '$type'") + end #if type + + ## process characteristic sections + sort!(tmp_sec, by = x -> x[1]) + for row in 2:length(tmp_sec) + s_start = tmp_sec[row-1][1] # first point of the section (in m) + s_end = tmp_sec[row][1] # first point of the next section (in m) + v_limit = tmp_sec[row-1][2]/3.6 # paths speed limt (in m/s) + f_Rp = tmp_sec[row-1][3] # specific path resistance of the section (in ‰) + + section = Dict(:s_start => s_start, + :s_end => s_end, + :v_limit => v_limit, + :f_Rp => f_Rp) + push!(sections, section) + end #for row + # s_start in first entry defines the path's beginning + # s_end in last entry defines the path's ending + + ## process points of interest + if POI_PRESENT + sort!(tmp_points, by = x -> x[1]) + for elem in tmp_points + station = elem[1] # first point of the section (in m) + label = elem[2] # paths speed limt (in m/s) + measure = elem[3] # specific path resistance of the section (in ‰) + + point = Dict(:station => station, + :label => label, + :measure => measure) + push!(poi, point) + end #for elem + end #if !isempty(points) + + Path(name, id, uuid, poi, sections) + +end #function Path() # outer constructor + +""" + Train(file, type = :YAML) + +Train is a datastruture for calculation context. +The function Train() will create a train to use in calculations. +Supported formats for the YAML files are: railtoolkit/schema (2022.05) + +# Example +```jldoctest +julia> my_train = Train("file.yaml") # will generate a train from a YAML file. +Train(variables) +``` +""" +function Train(file, type = :YAML) + + ## default values + name = "" # + id = "" # + uuid = UUIDs.uuid4() # + length = 0 # in meter + m_train_full = 0 # in kilogram + m_train_empty = 0 # in kilogram + m_loco = 0 # in kilogram + m_td = 0 # in kilogram + m_tc = 0 # in kilogram + m_car_full = 0 # in kilogram + m_car_empty = 0 # in kilogram + ξ_train = 1.08 # rotation mass factor, source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Zug, überschlägliche Berechnung" + ξ_loco = 1.09 # rotation mass factor + ξ_cars = 1.06 # rotation mass factor + transportType = :freight # "freight" or "passenger" for resistance calculation + v_limit = 140 # in m/s (default 504 km/h) + a_braking = 0 # in m/s^2, todo: implement as function + f_Rtd0 = 0 # coefficient for basic resistance due to the traction units driving axles (in ‰) + f_Rtc0 = 0 # coefficient for basic resistance due to the traction units carring axles (in ‰) + F_Rt2 = 3000 # coefficient for air resistance of the traction units (in N) + f_Rw0 = 0 # coefficient for the consists basic resistance (in ‰) + f_Rw1 = 0 # coefficient for the consists resistance to rolling (in ‰) + f_Rw2 = 0 # coefficient fo the consistsr air resistance (in ‰) + F_v_pairs = [] # [v in m/s, F_T in N] + + ## load from file + if type == :YAML + + data = YAML.load(open(file)) + if data["schema"] != "https://railtoolkit.org/schema/rolling-stock.json" + error("Could not load path file '$file'.\n + YAML format is not recognized. + Currently supported: railtoolkit/schema/rolling-stock (2022.05)") + end + if data["schema_version"] != "2022.05" + error("Could not load path file '$file'.\n + YAML format is not recognized. + Currently supported: railtoolkit/schema/rolling-stock (2022.05)") + end + + ## JSON schema for YAML-file validation + railtoolkit_schema = Schema("""{ + "required": [ "schema", "schema_version" ], + "anyOf": [ + {"required": [ "trains" ] }, + {"required": [ "vehicles" ] } + ], + "properties": { + "schema": { + "description": "Identifier of the schema", + "enum": [ "https://railtoolkit.org/schema/rolling-stock.json" ] + }, + "schema_version": { + "description": "Version of the schema", + "type": "string", + "pattern": "[2-9][0-9][0-9][0-9].[0-1][0-9]" + }, + "trains": { + "type": "array", + "minItems": 1, + "items": { + "required": [ "name", "id", "formation" ], + "type": "object", + "properties": { + "id": { + "description": "Identifier of the train", + "type": "string" + }, + "name": { + "description": "Name of the train", + "type": "string" + }, + "UUID": { + "description": "The unique identifier for a train", + "type": "string", + "format": "uuid" + }, + "formation": { + "description": "Collection of vehicles that form the train", + "type": "array", + "minItems": 1, + "uniqueItems": false, + "items": { + "type": "string" + } + } + } + } + }, + "vehicles": { + "type": "array", + "minItems": 1, + "items": { + "required": [ "name", "id", "vehicle_type", "length", "mass" ], + "type": "object", + "properties": { + "air_resistance": { + "description": "coefficient for air resistance in permil", + "type": "number", + "exclusiveMinimum": 0 + }, + "base_resistance": { + "description": "coefficient for basic resistance in permil", + "type": "number", + "exclusiveMinimum": 0 + }, + "id": { + "description": "Identifier of the vehicle", + "type": "string" + }, + "length": { + "description": "The length of the vehicle in meter", + "type": "number", + "exclusiveMinimum": 0 + }, + "load_limit": { + "description": "The maximum permitted load of the vehicle in metric ton", + "type": "number", + "exclusiveMinimum": 0 + }, + "mass_traction": { + "description": "The mass on the powered axles of the vehicle in metric ton", + "type": "number", + "exclusiveMinimum": 0 + }, + "mass": { + "description": "The empty mass of the vehicle in metric ton", + "type": "number", + "exclusiveMinimum": 0 + }, + "name": { + "description": "Name of the vehicle", + "type": "string" + }, + "picture": { + "description": "A URI with a picture for humans", + "type": "string", + "format": "uri" + }, + "power_type": { + "description": "Type of propulsion", + "enum": [ "diesel", "electric", "steam" ] + }, + "rolling_resistance": { + "description": "coefficient for resistance of rolling axles in permil", + "type": "number", + "exclusiveMinimum": 0 + }, + "rotation_mass": { + "description": "Factor for rotating mass; >= 1", + "type": "number", + "minimum": 1 + }, + "speed_limit": { + "description": "Maximum permitted speed in kilometers per hour", + "type": "number", + "exclusiveMinimum": 0 + }, + "tractive_effort": { + "description": "Tractive effort as pairs of speed in kilometers per hour and tractive force in newton", + "type": "array", + "minItems": 3, + "uniqueItems": true, + "items": { + "type": "array", + "minItems": 2, + "maxItems": 2, + "uniqueItems": true, + "items": { + "type": "number", + "minimum": 0 + } + } + }, + "UUID": { + "description": "The unique identifier for a vehicle", + "type": "string", + "format": "uuid" + }, + "vehicle_type": { + "description": "Type of vehicle", + "enum": [ "traction unit", "freight", "passenger", "multiple unit" ] + } + } + } + } + } + }""") + + try + validate(railtoolkit_schema, data) + catch err + error("Could not load path file '$file'.\n + YAML format is not recognized. + Currently supported: railtoolkit/schema/rolling-stock (2022.05)") + end + + else + error("Unknown file type '$type'") + end #if type + + trains = data["trains"] + Base.length(trains) > 1 ? println("WARNING: the loaded file contains more than one train. Using only the first!") : nothing + Base.length(trains) == 0 ? error("No train present in file '$file'") : nothing + train = trains[1] + used_vehicles = unique(train["formation"]) + + included_vehicles = [] + for vehicle in data["vehicles"] + push!(included_vehicles,vehicle["id"]) + end + + ## test if all vehicles of the formation are avilable + for vehicle in used_vehicles + vehicle ∉ included_vehicles ? error("'$vehicle' is not present in '$file'") : nothing + end + + ## gather the count of vehicles and usage in the formation + vehicles = NamedTuple[] + for vehicle in data["vehicles"] + if vehicle["id"] in used_vehicles + n = count(==(vehicle["id"]),train["formation"]) + type = vehicle["vehicle_type"] + type == "traction unit" || type == "multiple unit" ? propulsion = true : propulsion = false + type == "passenger" || type == "multiple unit" ? transportType = :passenger : nothing + push!(vehicles, (data=vehicle, n=n, propulsion=propulsion) ) + end + end + + ## set the variables in "train" + name = train["name"] + id = train["id"] + haskey(train, "UUID") ? uuid = parse(UUID, train["UUID"] ) : nothing + transportType == :freight ? a_braking = -0.225 : a_braking = -0.375 # set a default a_braking value depending on the train type + + ## set the variables for all vehicles + for vehicle in vehicles + length += vehicle.data["length"] * vehicle.n + m_train_full += vehicle.data["mass"] * vehicle.n * 1000 # in kg + m_train_empty += vehicle.data["mass"] * vehicle.n * 1000 # in kg + haskey(vehicle.data, "load_limit") ? + m_train_full += vehicle.data["load_limit"] * vehicle.n * 1000 : # in kg + nothing + haskey(vehicle.data, "speed_limit") ? + v_limit > vehicle.data["speed_limit"]/3.6 ? v_limit = vehicle.data["speed_limit"]/3.6 : nothing : + nothing + end + + ## divide vehicles in propulsion and non-propulsion + loco = [] + for i in 1:Base.length(vehicles) + if vehicles[i].propulsion + push!(loco, vehicles[i]) + deleteat!(vehicles, i) + end + end + Base.length(loco) > 1 ? println("WARNING: the loaded file contains more than one traction unit or multiple unit. Using only the first!") : nothing + loco[1].n > 1 ? println("WARNING: the loaded file contains more than one traction unit or multiple unit. Using only one!") : nothing + Base.length(loco) == 0 ? error("No traction unit or multiple unit present in file '$file'") : nothing + loco = loco[1].data + cars = vehicles + + ## set the variables for locos + m_loco= loco["mass"] * 1000 + haskey(loco, "a_braking") ? a_braking = loco["a_braking"] : nothing + haskey(loco, "base_resistance") ? f_Rtd0 = loco["base_resistance"] : nothing + haskey(loco, "rolling_resistance") ? f_Rtc0 = loco["rolling_resistance"] : nothing + haskey(loco, "air_resistance") ? F_Rt2 = loco["air_resistance"] * g * m_loco : nothing + haskey(loco, "mass_traction") ? m_td = loco["mass_traction"] * 1000 : m_td = m_t + haskey(loco, "rotation_mass") ? ξ_loco = loco["rotation_mass"] : nothing + m_tc = m_loco- m_td + haskey(loco, "tractive_effort") ? F_v_pairs = loco["tractive_effort"] : F_v_pairs = [ [0.0, m_td * g * μ],[v_limit*3.6, m_td * g * μ] ] + F_v_pairs = reduce(hcat,F_v_pairs)' # convert to matrix + F_v_pairs[:,1] ./= 3.6 # convert km/h to m/s + F_v_pairs = tuple.(eachcol(F_v_pairs)...) # convert each row to tuples + + ## set the variables for cars + if !isempty(cars) + resis_base = [] + resis_roll = [] + resis_air = [] + rotMassFac = [] + for car in cars + haskey(car.data, "base_resistance") ? + append!(resis_base,repeat([car.data["base_resistance"]],car.n)) : + append!(resis_base,repeat([f_Rw0],car.n)) + haskey(car.data, "rolling_resistance") ? + append!(resis_roll,repeat([car.data["rolling_resistance"]],car.n)) : + append!(resis_roll,repeat([f_Rw1],car.n)) + haskey(car.data, "air_resistance") ? + append!(resis_air,repeat([car.data["air_resistance"]],car.n)) : + append!(resis_air, repeat([f_Rw2],car.n)) + haskey(car.data, "rotation_mass") ? + append!(rotMassFac,repeat([(car.data["rotation_mass"],car.data["mass"])],car.n)) : + append!(rotMassFac,repeat([(ξ_cars ,car.data["mass"])],car.n)) + m_car_empty += car.data["mass"] * car.n * 1000 # in kg + m_car_full += car.data["mass"] * car.n * 1000 # in kg + haskey(car.data, "load_limit") ? + m_car_full += car.data["load_limit"] * car.n * 1000 : # in kg + nothing + end + f_Rw0 = Statistics.mean(resis_base) + f_Rw1 = Statistics.mean(resis_roll) + f_Rw2 = Statistics.mean(resis_air) + carRotMass = 0 + for elem in rotMassFac + carRotMass += elem[1]*elem[2] * 1000 # in kg + end + ξ_cars = carRotMass/m_car_empty + ξ_train = (ξ_loco * m_loco+ carRotMass)/m_train_empty + else + ξ_cars = 0 + ξ_train = ξ_loco + end + + Train( + name, id, uuid, length, + m_train_full, m_td, m_tc, m_car_full, + ξ_train, ξ_loco, ξ_cars, + transportType, v_limit, + a_braking, + f_Rtd0, f_Rtc0, F_Rt2, f_Rw0, f_Rw1, f_Rw2, + F_v_pairs + ) + +end #function Train() # outer constructor + +## create a moving section containing characteristic sections +function createMovingSection(path::Path, v_trainLimit::Real, s_trainLength::Real) + # this function creates and returns a moving section dependent on the paths attributes + + s_entry = path.sections[1][:s_start] # first position (in m) + s_exit = path.sections[end][:s_end] # last position (in m) + pathLength = s_exit - s_entry # total length (in m) + + CSs=Vector{Dict}() + s_csStart=s_entry + csId=1 + for row in 2:length(path.sections) + previousSection = path.sections[row-1] + currentSection = path.sections[row] + speedLimitIsDifferent = min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) + pathResistanceIsDifferent = previousSection[:f_Rp] != currentSection[:f_Rp] + if speedLimitIsDifferent || pathResistanceIsDifferent + # 03/09 old: if min(previousSection[:v_limit], v_trainLimit) != min(currentSection[:v_limit], v_trainLimit) || previousSection[:f_Rp] != currentSection[:f_Rp] + push!(CSs, createCharacteristicSection(csId, s_csStart, previousSection, min(previousSection[:v_limit], v_trainLimit), s_trainLength, path)) + s_csStart = currentSection[:s_start] + csId = csId+1 + end #if + end #for + push!(CSs, createCharacteristicSection(csId, s_csStart, path.sections[end], min(path.sections[end][:v_limit], v_trainLimit), s_trainLength, path)) + + movingSection= Dict(:id => 1, # identifier # if there is more than one moving section in a later version of this tool the id should not be constant anymore + :length => pathLength, # total length (in m) + :s_entry => s_entry, # first position (in m) + :s_exit => s_exit, # last position (in m) + :t => 0.0, # total running time (in s) + :E => 0.0, # total energy consumption (in Ws) + :characteristicSections => CSs) # list of containing characteristic sections + + return movingSection +end #function createMovingSection + +## create a characteristic section for a path section. A characteristic section is a part of the moving section. It contains behavior sections. +function createCharacteristicSection(id::Integer, s_entry::Real, section::Dict, v_limit::Real, s_trainLength::Real, path::Path) + # Create and return a characteristic section dependent on the paths attributes + characteristicSection= Dict(:id => id, # identifier + :s_entry => s_entry, # first position (in m) + :s_exit => section[:s_end], # last position (in m) + :length => section[:s_end] -s_entry, # total length (in m) + :r_path => section[:f_Rp], # path resistance (in ‰) + :behaviorSections => Dict(), # list of containing behavior sections + :t => 0.0, # total running time (in s) + :E => 0.0, # total energy consumption (in Ws) + :v_limit => v_limit, # speed limit (in m/s) + # initializing :v_entry, :v_peak and :v_exit with :v_limit + :v_peak => v_limit, # maximum reachable speed (in m/s) + :v_entry => v_limit, # maximum entry speed (in m/s) + :v_exit => v_limit) # maximum exit speed (in m/s) + + # list of positions of every point of interest (POI) in this charateristic section for which data points should be calculated + s_exit = characteristicSection[:s_exit] + + ##TODO: use a tuple with naming + pointsOfInterest = Tuple[] + # pointsOfInterest = Real[] + if !isempty(path.poi) + for POI in path.poi + s_poi = POI[:station] + if POI[:measure] == "rear" + s_poi -= s_trainLength + end + if s_entry < s_poi && s_poi < s_exit + push!(pointsOfInterest, (s_poi, POI[:label]) ) + # push!(pointsOfInterest, s_poi ) + end + end + end + push!(pointsOfInterest, (s_exit,"")) # s_exit has to be the last POI so that there will always be a POI to campare the current position with + # push!(pointsOfInterest, s_exit) # s_exit has to be the last POI so that there will always be a POI to campare the current position with + + merge!(characteristicSection, Dict(:pointsOfInterest => pointsOfInterest)) + + return characteristicSection +end #function createCharacteristicSection + +""" +a DataPoint is the smallest element of the driving course. One step of the step approach is between two data points +""" +function createDataPoint() + dataPoint = Dict( + :i => 0, # identifier and counter variable of the driving course + :behavior => "", # type of behavior section the data point is part of - see createBehaviorSection() + # a data point which is the last point of one behavior section and the first point of the next behavior section will be attached to the latter + :s => 0.0, # position (in m) + :Δs => 0.0, # step size (in m) + :t => 0.0, # point in time (in s) + :Δt => 0.0, # step size (in s) + :v => 0.0, # velocity (in m/s) + :Δv => 0.0, # step size (in m/s) + :a => 0.0, # acceleration (in m/s^2) + :W => 0.0, # mechanical work (in Ws) + :ΔW => 0.0, # mechanical work in this step (in Ws) + :E => 0.0, # energy consumption (in Ws) + :ΔE => 0.0, # energy consumption in this step (in Ws) + :F_T => 0.0, # tractive effort (in N) + :F_R => 0.0, # resisting force (in N) + :R_path => 0.0, # path resistance (in N) + :R_train => 0.0, # train resistance (in N) + :R_traction => 0.0, # traction unit resistance (in N) + :R_wagons => 0.0, # set of wagons resistance (in N) + :label => "" # a label for importend points + ) + return dataPoint +end #function createDataPoint + +""" +BehaviorSection() TODO! +""" +function createBehaviorSection(type::String, s_entry::Real, v_entry::Real, startingPoint::Integer) + BS= Dict( + :type => type, # type of behavior section: "breakFree", "clearing", "accelerating", "cruising", "downhillBraking", "diminishing", "coasting", "braking" or "standstill" + :length => 0.0, # total length (in m) + :s_entry => s_entry, # first position (in m) + :s_exit => 0.0, # last position (in m) + :t => 0.0, # total running time (in s) + :E => 0.0, # total energy consumption (in Ws) + :v_entry => v_entry, # entry speed (in m/s) + :v_exit => 0.0, # exit speed (in m/s) + :dataPoints => [startingPoint] # list of identifiers of the containing data points starting with the initial point + ) + return BS +end #function createBehaviorSection diff --git a/src/Formulary.jl b/src/formulary.jl similarity index 65% rename from src/Formulary.jl rename to src/formulary.jl index 2f5f1f0..4bf6125 100644 --- a/src/Formulary.jl +++ b/src/formulary.jl @@ -5,8 +5,6 @@ # __copyright__ = "2022" # __license__ = "ISC" -module Formulary - ######################### ## literature the driving dynamics equations are based on: ## @@ -21,17 +19,6 @@ module Formulary ## isbn = {978-3-777-10462-1}, ## publisher = {Eurailpress DVV Media Group}, ## } -## @article{Jaekel:2014, -## author = {Jaekel, Birgit and Albrecht, Thomas}, -## year = {2014}, -## title = {Comparative analysis of algorithms and models for train running simulation}, -## journal = {Journal of Rail Transport Planning \& Management}, -## doi = {10.1016/j.jrtpm.2014.06.002}, -## volume = {4}, -## number = {1-2}, -## pages = {14--27}, -## publisher = {Elsevier}, -## } ## @Book{Wende:2003, ## author = {Wende, Dietrich}, ## date = {2003}, @@ -41,24 +28,8 @@ module Formulary ## } ######################### -# export resisting forces and acceleration -export calcTractionUnitResistance, calcWagonsResistance, calcForceFromCoefficient, calcAcceleration, - -# export step sizes in different units -calc_Δs_with_Δt, calc_Δs_with_Δv, -calc_Δt_with_Δs, calc_Δt_with_Δv, calc_Δt_with_constant_v, -calc_Δv_with_Δs, calc_Δv_with_Δt, -calc_ΔW, calc_ΔE, - -# export braking information -calcBrakingDistance, calcBrakingStartVelocity, calcBrakingAcceleration - +approxLevel = 6 v00 = 100/3.6 # velocity factor (in m/s) -g = 9.81 # acceleration due to gravity (in m/s^2) # TODO: should more digits of g be used? g=9,80665 m/s^2 - -approximationLevel = 6 # value for approximation to intersections TODO further explanation (e.g. approximationLevel = 3 -> with stepSize 10 m the approximation will be calculated accurate on 10 mm ; 1s -> 1 ms; 1 km/h -> 3.6 mm/s) -# TODO: necessary here? - ## calculate forces @@ -71,7 +42,7 @@ Calculate the vehicle resistance for the traction unit of the `train` dependend ... # Arguments - `v::AbstractFloat`: the current velocity in m/s. -- `train::Dict`: ? ? ? +- `train::Train`: ? ? ? ... # Examples @@ -80,36 +51,34 @@ julia> calcTractionUnitResistance(30.0, ? ? ?) ? ? ? ``` """ -function calcTractionUnitResistance(v::AbstractFloat, train::Dict) +function calcTractionUnitResistance(v::AbstractFloat, train::Train) # equation is based on [Wende:2003, page 151] - f_Rtd0 = train[:f_Rtd0] # coefficient for basic resistance due to the traction units driving axles (in ‰) - f_Rtc0 = train[:f_Rtc0] # coefficient for basic resistance due to the traction units carring axles (in ‰) - F_Rt2 = train[:F_Rt2] # coefficient for air resistance of the traction units (in N) - m_td = train[:m_td] # mass on the traction unit's driving axles (in kg) - m_tc = train[:m_tc] # mass on the traction unit's carrying axles (in kg) - Δv_t = train[:Δv_t] # coefficient for velocitiy difference between traction unit and outdoor air (in m/s) + f_Rtd0 = train.f_Rtd0 # coefficient for basic resistance due to the traction units driving axles (in ‰) + f_Rtc0 = train.f_Rtc0 # coefficient for basic resistance due to the traction units carring axles (in ‰) + F_Rt2 = train.F_Rt2 # coefficient for air resistance of the traction units (in N) + m_td = train.m_td # mass on the traction unit's driving axles (in kg) + m_tc = train.m_tc # mass on the traction unit's carrying axles (in kg) - F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + F_Rt2 * ((v + Δv_t) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰ - # TODO: use calcForceFromCoefficient? F_R_tractionUnit = calcForceFromCoefficient(f_Rtd0, m_td) + calcForceFromCoefficient(f_Rtc0, m_tc) + F_Rt2 * ((v + Δv_t) /v00)^2 # vehicle resistance of the traction unit (in N) + F_R_tractionUnit = f_Rtd0/1000 * m_td * g + f_Rtc0/1000 * m_tc * g + F_Rt2 * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) # /1000 because of the unit ‰ + # TODO: use calcForceFromCoefficient? F_R_tractionUnit = calcForceFromCoefficient(f_Rtd0, m_td) + calcForceFromCoefficient(f_Rtc0, m_tc) + F_Rt2 * ((v + Δv_air) /v00)^2 # vehicle resistance of the traction unit (in N) return F_R_tractionUnit #TODO: same variable name like in the rest of the tool? return R_traction - #TODO: just one line? return train[:f_Rtd0]/1000*train[:m_td]*g+train[:f_Rtc0]/1000*train[:m_tc]*g+train[:F_Rt2]*((v+train[:Δv_t])/v00)^2 # /1000 because of the unit ‰ + #TODO: just one line? return train.f_Rtd0/1000*train.m_td*g+train.f_Rtc0/1000*train.m_tc*g+train.F_Rt2*((v+train.Δv_air)/v00)^2 # /1000 because of the unit ‰ end #function calcTractionUnitResistance """ TODO calculate and return the wagons vehicle resistance dependend on the velocity """ -function calcWagonsResistance(v::AbstractFloat, train::Dict) +function calcWagonsResistance(v::AbstractFloat, train::Train) # equation is based on a combination of the equations of Strahl and Sauthoff [Wende:2003, page 153] with more detailled factors (Lehmann, page 135) - f_Rw0 = train[:f_Rw0] # coefficient for basic resistance of the set of wagons (consist) (in ‰) - f_Rw1 = train[:f_Rw1] # coefficient for the consists resistance to rolling (in ‰) - f_Rw2 = train[:f_Rw2] # coefficient fo the consistsr air resistance (in ‰) - m_w = train[:m_w] # mass of the set of wagons (consist) (in kg) - Δv_w = train[:Δv_w] # coefficient for velocitiy difference between set of wagons (consist) and outdoor air (in m/s) + f_Rw0 = train.f_Rw0 # coefficient for basic resistance of the set of wagons (consist) (in ‰) + f_Rw1 = train.f_Rw1 # coefficient for the consists resistance to rolling (in ‰) + f_Rw2 = train.f_Rw2 # coefficient fo the consistsr air resistance (in ‰) + m_w = train.m_w # mass of the set of wagons (consist) (in kg) - F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_w) /v00)^2) # vehicle resistance of the wagons (in N) # /1000 because of the unit ‰ -# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + calcForceFromCoefficient(f_Rw1, m_w) *v /v00 + calcForceFromCoefficient(f_Rw2, m_w) * ((v + Δv_w) /v00)^2 # vehicle resistance of the wagons (in N) + F_R_wagons = m_w *g *(f_Rw0/1000 + f_Rw1/1000 *v /v00 + f_Rw2/1000 * ((v + Δv_air) /v00)^2) # vehicle resistance of the wagons (in N) # /1000 because of the unit ‰ +# TODO: use calcForceFromCoefficient? F_R_wagons = calcForceFromCoefficient(f_Rw0, m_w) + calcForceFromCoefficient(f_Rw1, m_w) *v /v00 + calcForceFromCoefficient(f_Rw2, m_w) * ((v + Δv_air) /v00)^2 # vehicle resistance of the wagons (in N) return F_R_wagons end #function calcWagonsResistance @@ -213,8 +182,8 @@ function calc_ΔW(F_T_prev::Real, Δs::Real) end #function calc_ΔW function calc_ΔE(ΔW::Real) - # simplified equation is based on [Jaekel:2014, page 6] - + # simplified equation + # TODO! # ΔW: mechanical work in this step (in Ws) ΔE = ΔW # energy consumption in this step (in Ws) return ΔE @@ -228,8 +197,8 @@ function calcBrakingDistance(v_start::Real, v_end::Real, a_braking::Real) # a_braking: constant braking acceleration (in m/s^2) s_braking = (v_end^2 - v_start^2) /2 /a_braking # braking distance (in m) # TODO: also possible: calc_Δs_with_Δv(v_end-v_start, a_braking, v_start) -# return max(0.0, ceil(s_braking, digits=approximationLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors - return max(0.0, ceil(s_braking, digits=approximationLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors +# return max(0.0, ceil(s_braking, digits=approxLevel)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors + return max(0.0, ceil(s_braking, digits=approxLevel +1)) # ceil is used to be sure that the train stops at s_exit in spite of rounding errors end #function calcBrakingDistance function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real) @@ -239,8 +208,8 @@ function calcBrakingStartVelocity(v_end::Real, a_braking::Real, s_braking::Real) # a_braking: constant braking acceleration (in m/s^2) # s_braking: braking distance (in Ws) v_start = sqrt(v_end^2 - 2*a_braking *s_braking) # braking start velocity (in m/s) -# return floor(v_start, digits=approximationLevel) - return floor(v_start, digits=approximationLevel +1) +# return floor(v_start, digits=approxLevel) + return floor(v_start, digits=approxLevel +1) end #function calcBrakingStartVelocity function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) @@ -252,5 +221,3 @@ function calcBrakingAcceleration(v_start::Real, v_end::Real, s_braking::Real) a_braking = (v_end^2 - v_start^2) /2 /s_braking # constant braking acceleration (in m/s^2) return a_braking end #function calcBrakingAcceleration - -end #module Formulary diff --git a/src/Output.jl b/src/output.jl similarity index 73% rename from src/Output.jl rename to src/output.jl index bf2fd21..c7165be 100644 --- a/src/Output.jl +++ b/src/output.jl @@ -5,22 +5,22 @@ # __copyright__ = "2020-2022" # __license__ = "ISC" -module Output - -export createOutput - -function createOutput(train::Dict, settings::Dict, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict}) - if settings[:detailOfOutput] == "running time" +function createOutput(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict}) + if settings.outputDetail == :running_time output = movingSection[:t] # TODO: or use drivingCourse[end][:t] - elseif settings[:detailOfOutput] == "points of interest" + elseif settings.outputDetail == :points_of_interest # add points of interest - if haskey(path, :pointsOfInterest) - output = Vector{Dict}() + if !isempty(path.poi) + + # for elem in 1:length(driving_course) + # end + + output = Dict[] POI = 1 i = 1 - while POI <= length(path[:pointsOfInterest]) && i <= drivingCourse[end][:i] - if path[:pointsOfInterest][POI] == drivingCourse[i][:s] + while POI <= length(path.poi) && i <= drivingCourse[end][:i] + if path.poi[POI][:station] == drivingCourse[i][:s] push!(output, drivingCourse[i]) POI = POI+1 end @@ -28,10 +28,10 @@ function createOutput(train::Dict, settings::Dict, path::Dict, movingSection::Di end end - elseif settings[:detailOfOutput] == "driving course" + elseif settings.outputDetail == :driving_course output = drivingCourse - elseif settings[:detailOfOutput] == "everything" + elseif settings.outputDetail == :everything output = Dict{Symbol,Any}() merge!(output, Dict(:train => train, :path => path, :settings => settings)) @@ -46,12 +46,12 @@ function createOutput(train::Dict, settings::Dict, path::Dict, movingSection::Di end # add points of interest - if haskey(path, :pointsOfInterest) + if !isempty(path.poi) pointsOfInterest = Vector{Dict}() POI = 1 i = 1 - while POI <= length(path[:pointsOfInterest]) && i <= drivingCourse[end][:i] - if path[:pointsOfInterest][POI] == drivingCourse[i][:s] + while POI <= length(path.poi) && i <= drivingCourse[end][:i] + if path.poi[POI] == drivingCourse[i][:s] push!(pointsOfInterest, drivingCourse[i]) POI = POI+1 end @@ -71,7 +71,7 @@ function createOutput(train::Dict, settings::Dict, path::Dict, movingSection::Di end #= -function createOutputDict(train::Dict, settings::Dict, path::Dict, movingSection::Dict, drivingCourse::Vector{Dict}) +function createOutputDict(train::Train, settings::Settings, path::Path, movingSection::Dict, drivingCourse::Vector{Dict}) outputDict = Dict{Symbol,Any}() merge!(outputDict, Dict(:train => train, :path => path, :settings => settings)) @@ -86,12 +86,12 @@ function createOutputDict(train::Dict, settings::Dict, path::Dict, movingSection end # add points of interest - if haskey(path, :pointsOfInterest) + if !isempty(path.poi) pointsOfInterest = Vector{Dict}() POI = 1 i = 1 - while POI <= length(path[:pointsOfInterest]) && i <= drivingCourse[end][:i] - if path[:pointsOfInterest][POI] == drivingCourse[i][:s] + while POI <= length(path.poi) && i <= drivingCourse[end][:i] + if path.poi[POI] == drivingCourse[i][:s] push!(pointsOfInterest, drivingCourse[i]) POI = POI+1 end @@ -108,5 +108,3 @@ function createOutputDict(train::Dict, settings::Dict, path::Dict, movingSection return outputDict end # function createOutputDict =# - -end # module Output diff --git a/src/types.jl b/src/types.jl new file mode 100644 index 0000000..0441086 --- /dev/null +++ b/src/types.jl @@ -0,0 +1,61 @@ +#!/usr/bin/env julia +# -*- coding: UTF-8 -*- +# __julia-version__ = 1.7.2 +# __author__ = "Martin Scheidt, Max Kannenberg" +# __copyright__ = "2022" +# __license__ = "ISC" + +struct Settings + + massModel::Symbol # model type of train mass ":mass_point" or ":homogeneous_strip". + stepVariable::Symbol # variable of the linear multistep method: ":distance", ":time" or ":velocity". + stepSize::Real # step size, unit depends on stepVariable - :distance in meter, time in seconds and velocity in meter/second. + approxLevel::Int # value for approximation; used when rounding or interating. + outputDetail::Symbol # single Float() ":running_time", Array() of ":points_of_interest", + # complete Array() ":driving_course", or Dict() ":everything". + outputFormat::Symbol # output as ":dataframe" or as ":dict". + +end #struct Settings + +struct Path + + name::String # a name or description of the path + id::String # a short string as identifier + uuid::UUID # a unique identifier + poi::Vector # a vector of triples with points along the path + sections::Vector # a vector of the characteristic sections + +end #struct Path + +struct Train + + name::String # a name or description of the train + id::String # a short string as identifier + uuid::UUID # a unique identifier + length::Real # train length in meter + m_train_full::Real # mass of the full loaded train in kilogram + m_td::Real # mass on driving axles of the traction unit in kilogram + m_tc::Real # mass on the traction unit's carrying axles in kilogram + m_w::Real # mass of the set of wagons/cars/consist in kilogram + ξ_train::Real # rotation mass factor + ξ_loco::Real # rotation mass factor + ξ_cars::Real # rotation mass factor + transportType::Symbol # ":freight" or ":passenger" for resistance calculation + v_limit::Real # in m/s + a_braking::Real # in m/s^2 + + # coefficients for the vehicle resistance + # for the traction unit (F_Rt=f_Rtd0*m_td*g+f_Rtc0*m_tc*g+F_Rt2*((v+Δv_air)/v00)^2) + f_Rtd0::Real # coefficient for basic resistance due to the traction units driving axles (in ‰) + f_Rtc0::Real # coefficient for basic resistance due to the traction units carring axles (in ‰) + F_Rt2::Real # coefficient for air resistance of the traction units (in N) + + # for the consist (set of wagons) (F_Rw=m_w*g*(f_Rw0+f_Rw1*v/v00+f_Rw2*((v+Δv_air)/v00)^2)) + f_Rw0::Real # coefficient for the consists basic resistance (in ‰) + f_Rw1::Real # coefficient for the consists resistance to rolling (in ‰) + f_Rw2::Real # coefficient fo the consistsr air resistance (in ‰) + + # tractive effort as pairs of speed and tractive effort + tractiveEffort::Vector{Tuple{Real, Real}} # [v in m/s, F_T in N] + +end #struct Train diff --git a/test/data/paths/const.yaml b/test/data/paths/const.yaml new file mode 100644 index 0000000..9511d70 --- /dev/null +++ b/test/data/paths/const.yaml @@ -0,0 +1,21 @@ +%YAML 1.2 +--- +schema: https://railtoolkit.org/schema/running-path.json +schema_version: "2022.05" +paths: + - name: "10 km, no gradient, 160 km/h" + id: const + UUID: 23ff336e-9b9a-4535-bdb6-9db488b10945 + points_of_interest: + # [ station in m, name, front or rear ] + - [ 999.00, point_1, front ] + - [ 2000.00, point_2, front ] + - [ 3333.30, point_3, rear ] + - [ 5000.00, point_4, front ] + - [ 7777.00, point_5, front ] + - [ 9000.00, point_6, front ] + - [ 9500.95, point_7, front ] + characteristic_sections: + # [ station in m, speed limit in km/h, resistance in ‰ ] + - [ 0.0, 160, 0.00 ] + - [ 10000.0, 160, 0.00 ] diff --git a/test/data/paths/realworld.yaml b/test/data/paths/realworld.yaml new file mode 100644 index 0000000..e19b325 --- /dev/null +++ b/test/data/paths/realworld.yaml @@ -0,0 +1,362 @@ +%YAML 1.2 +--- +schema: https://railtoolkit.org/schema/running-path.json +schema_version: "2022.05" +paths: + - name: "'infra_Ostsachsen': track id='tr_80.6212_2' name='DG-DN' -> spp_5" + id: realworld + UUID: 2b31a0c5-85bc-4721-b7e0-66f9df95f7b6 + # source: https://www.railml.org/en/user/exampledata.html + # -> "Real world railway examples from professional tools" + # -> "East Saxony railway network by FBS" + # -> "Ostsachsen_V220.railml" + # -> 'infra_Ostsachsen': track id='tr_80.6212_2' name='DG-DN' -> spp_5 + characteristic_sections: + # [ s in m, v_limit in km/h, f_Rp in ‰ ] + - [ 0.0, 40, 0.0 ] + - [ 318.0, 40, 2.0 ] + - [ 399.0, 40, -3.0 ] + - [ 500.0, 40, 0.0 ] + - [ 579.0, 40, 1.0 ] + - [ 784.0, 40, 5.3 ] + - [ 868.0, 40, 20.0 ] + - [ 1082.0, 40, 16.1 ] + - [ 1287.0, 40, 18.1 ] + - [ 1800.0, 110, 18.1 ] + - [ 2242.0, 110, 15.4 ] + - [ 3295.0, 110, 11.0 ] + - [ 3880.0, 110, 11.1 ] + - [ 4680.0, 45, 11.1 ] + - [ 4686.0, 90, 11.1 ] + - [ 6122.0, 90, 0.0 ] + - [ 6487.0, 90, 1.5 ] + - [ 6588.0, 70, 1.5 ] + - [ 6589.0, 70, 2.4 ] + - [ 6608.0, 130, 2.4 ] + - [ 6723.0, 150, 1.3 ] + - [ 6928.0, 160, 1.3 ] + - [ 7030.0, 160, 7.5 ] + - [ 7300.0, 160, 8.0 ] + - [ 7552.0, 160, 5.0 ] + - [ 7675.0, 160, 6.7 ] + - [ 7800.0, 160, 7.4 ] + - [ 7920.0, 160, 7.0 ] + - [ 8020.0, 140, 7.0 ] + - [ 8100.0, 140, 6.3 ] + - [ 8168.0, 140, 7.4 ] + - [ 8226.0, 140, 8.4 ] + - [ 8300.0, 140, 7.4 ] + - [ 8381.0, 150, 7.4 ] + - [ 8600.0, 150, 7.8 ] + - [ 8900.0, 150, 6.7 ] + - [ 9100.0, 150, 7.8 ] + - [ 9600.0, 150, 8.0 ] + - [ 9845.0, 150, 7.3 ] + - [ 10005.0, 160, 7.3 ] + - [ 10600.0, 160, 6.0 ] + - [ 10748.0, 160, 7.3 ] + - [ 11100.0, 160, 4.5 ] + - [ 11280.0, 160, 3.6 ] + - [ 11450.0, 160, 7.2 ] + - [ 11800.0, 160, 6.8 ] + - [ 12100.0, 160, 7.3 ] + - [ 12590.0, 160, 7.6 ] + - [ 13100.0, 160, 7.3 ] + - [ 13500.0, 160, 7.1 ] + - [ 13800.0, 160, 7.3 ] + - [ 14138.0, 150, 7.3 ] + - [ 14330.0, 150, 0.3 ] + - [ 14640.0, 150, -1.8 ] + - [ 14764.0, 160, -2.8 ] + - [ 15000.0, 160, -3.3 ] + - [ 15500.0, 160, -0.9 ] + - [ 16000.0, 160, 0.0 ] + - [ 16470.0, 160, 1.2 ] + - [ 16572.0, 160, 2.2 ] + - [ 16700.0, 160, 3.8 ] + - [ 16949.0, 160, 3.5 ] + - [ 17086.0, 160, 3.2 ] + - [ 17232.0, 160, 1.3 ] + - [ 17339.0, 160, 4.5 ] + - [ 17406.0, 160, 3.4 ] + - [ 17727.0, 150, 3.4 ] + - [ 17807.0, 150, 4.6 ] + - [ 18049.0, 150, 3.0 ] + - [ 18210.0, 140, 3.0 ] + - [ 18300.0, 140, 4.6 ] + - [ 18680.0, 140, 3.2 ] + - [ 18761.0, 150, 3.2 ] + - [ 19047.0, 150, 5.1 ] + - [ 19305.0, 150, 3.0 ] + - [ 19406.0, 160, 3.0 ] + - [ 19414.0, 160, -0.3 ] + - [ 19900.0, 160, 3.0 ] + - [ 20150.0, 160, 1.8 ] + - [ 20470.0, 160, -4.0 ] + - [ 20940.0, 160, -3.6 ] + - [ 21150.0, 160, -1.5 ] + - [ 21390.0, 160, 0.0 ] + - [ 21702.0, 160, 1.5 ] + - [ 22188.0, 150, 1.5 ] + - [ 22294.0, 150, 1.8 ] + - [ 22383.0, 160, 1.8 ] + - [ 22500.0, 160, 2.6 ] + - [ 22900.0, 160, 4.6 ] + - [ 23542.0, 160, 0.2 ] + - [ 23736.0, 160, 0.9 ] + - [ 24124.0, 160, 7.0 ] + - [ 24918.0, 160, 7.6 ] + - [ 25100.0, 150, 7.1 ] + - [ 25580.0, 150, 7.4 ] + - [ 25708.0, 160, 7.4 ] + - [ 25810.0, 160, 7.1 ] + - [ 26040.0, 160, 3.2 ] + - [ 26330.0, 160, 1.8 ] + - [ 26593.0, 160, 2.1 ] + - [ 27020.0, 160, 3.5 ] + - [ 27195.0, 160, 5.8 ] + - [ 27253.0, 160, 1.1 ] + - [ 27310.0, 160, 3.5 ] + - [ 27595.0, 160, 3.4 ] + - [ 28530.0, 160, 4.6 ] + - [ 29115.0, 160, 0.0 ] + - [ 29700.0, 160, -5.2 ] + - [ 30055.0, 120, -4.3 ] + - [ 30301.0, 120, -6.2 ] + - [ 30487.0, 160, -6.2 ] + - [ 30537.0, 160, -4.8 ] + - [ 31130.0, 160, -0.3 ] + - [ 31293.0, 160, 3.7 ] + - [ 31400.0, 160, 2.9 ] + - [ 31640.0, 160, 4.1 ] + - [ 31795.0, 120, 4.1 ] + - [ 32010.0, 120, 3.2 ] + - [ 32138.0, 130, 3.2 ] + - [ 32365.0, 130, -4.0 ] + - [ 33000.0, 130, 6.1 ] + - [ 33426.0, 160, 6.1 ] + - [ 33907.0, 160, 7.1 ] + - [ 34220.0, 160, 8.4 ] + - [ 34300.0, 160, 7.9 ] + - [ 34440.0, 160, 7.1 ] + - [ 34610.0, 160, 4.4 ] + - [ 35000.0, 160, 5.6 ] + - [ 35173.0, 150, 5.6 ] + - [ 35400.0, 150, -0.2 ] + - [ 35597.0, 160, -0.2 ] + - [ 35900.0, 160, 0.0 ] + - [ 36700.0, 160, 3.9 ] + - [ 36938.0, 160, 0.0 ] + - [ 37700.0, 160, -0.3 ] + - [ 37978.0, 150, -5.6 ] + - [ 38063.0, 150, -1.9 ] + - [ 38141.0, 150, -3.1 ] + - [ 38210.0, 150, 0.0 ] + - [ 38406.0, 150, -7.0 ] + - [ 38900.0, 150, -7.5 ] + - [ 39200.0, 150, -8.7 ] + - [ 39298.0, 150, -6.4 ] + - [ 39476.0, 150, -7.2 ] + - [ 40400.0, 150, -6.9 ] + - [ 40676.0, 130, -6.9 ] + - [ 41000.0, 130, -7.3 ] + - [ 41406.0, 130, -7.5 ] + - [ 41571.0, 160, -7.3 ] + - [ 41816.0, 160, -6.8 ] + - [ 41923.0, 160, -7.1 ] + - [ 42139.0, 160, -1.3 ] + - [ 42343.0, 160, -2.4 ] + - [ 42432.0, 150, -2.4 ] + - [ 42952.0, 160, -2.4 ] + - [ 43000.0, 160, -4.6 ] + - [ 43264.0, 160, -2.5 ] + - [ 43388.0, 160, -0.6 ] + - [ 43700.0, 160, 0.8 ] + - [ 44030.0, 160, 2.7 ] + - [ 44430.0, 160, 0.0 ] + - [ 44708.0, 160, -7.2 ] + - [ 45477.0, 160, -7.8 ] + - [ 45890.0, 160, -1.0 ] + - [ 46562.0, 160, -1.6 ] + - [ 47000.0, 160, -6.9 ] + - [ 47500.0, 160, -7.7 ] + - [ 47800.0, 160, -6.8 ] + - [ 48700.0, 160, -4.3 ] + - [ 49218.0, 160, -5.3 ] + - [ 49514.0, 160, -2.5 ] + - [ 50000.0, 160, -2.2 ] + - [ 51150.0, 160, -5.7 ] + - [ 51406.0, 160, -6.3 ] + - [ 51710.0, 150, -5.8 ] + - [ 52000.0, 150, -6.7 ] + - [ 52215.0, 150, -6.1 ] + - [ 53213.0, 150, -6.8 ] + - [ 53567.0, 150, -5.6 ] + - [ 53943.0, 150, -6.5 ] + - [ 54129.0, 140, -6.5 ] + - [ 54212.0, 140, -10.5 ] + - [ 54247.0, 140, -5.4 ] + - [ 54326.0, 140, -6.1 ] + - [ 54450.0, 140, -6.5 ] + - [ 54482.0, 120, -6.5 ] + - [ 54550.0, 120, -6.2 ] + - [ 54855.0, 140, -6.2 ] + - [ 55307.0, 140, -0.3 ] + - [ 55651.0, 140, -1.2 ] + - [ 55788.0, 140, 0.0 ] + - [ 55918.0, 100, 0.0 ] + - [ 56433.0, 150, 0.0 ] + - [ 56560.0, 150, -2.1 ] + - [ 56624.0, 150, -6.7 ] + - [ 57012.0, 150, 1.3 ] + - [ 57260.0, 150, 6.6 ] + - [ 57800.0, 150, 5.3 ] + - [ 57987.0, 150, 0.0 ] + - [ 57990.0, 150, 7.6 ] + - [ 58321.0, 150, 6.4 ] + - [ 59090.0, 150, 6.9 ] + - [ 59468.0, 150, 9.2 ] + - [ 59600.0, 150, 0.2 ] + - [ 60683.0, 150, 4.1 ] + - [ 61156.0, 150, 2.3 ] + - [ 61181.0, 130, 2.3 ] + - [ 61325.0, 130, 0.0 ] + - [ 61605.0, 130, 7.3 ] + - [ 62108.0, 150, 7.3 ] + - [ 62246.0, 150, 6.6 ] + - [ 62279.0, 150, 5.1 ] + - [ 62454.0, 150, 0.9 ] + - [ 62777.0, 150, 5.5 ] + - [ 63802.0, 150, 4.6 ] + - [ 64344.0, 150, 0.2 ] + - [ 64932.0, 150, -0.6 ] + - [ 65100.0, 150, 0.0 ] + - [ 65690.0, 150, 1.8 ] + - [ 65878.0, 150, 2.5 ] + - [ 66266.0, 150, -1.0 ] + - [ 66339.0, 150, 6.3 ] + - [ 66448.0, 160, 6.3 ] + - [ 66587.0, 160, 0.0 ] + - [ 66856.0, 160, 3.2 ] + - [ 67480.0, 160, 3.6 ] + - [ 67697.0, 160, 2.2 ] + - [ 67800.0, 160, 6.0 ] + - [ 67851.0, 130, 6.0 ] + - [ 68027.0, 130, 2.7 ] + - [ 68172.0, 130, 0.6 ] + - [ 68328.0, 130, 2.5 ] + - [ 68357.0, 130, 0.0 ] + - [ 68479.0, 130, 7.1 ] + - [ 68783.0, 130, 7.4 ] + - [ 69056.0, 150, 7.4 ] + - [ 69500.0, 150, 6.8 ] + - [ 69741.0, 160, 6.8 ] + - [ 69900.0, 160, 6.6 ] + - [ 70757.0, 160, 3.6 ] + - [ 71384.0, 160, 6.0 ] + - [ 71568.0, 160, 7.1 ] + - [ 71800.0, 160, 7.4 ] + - [ 72100.0, 160, 7.3 ] + - [ 73919.0, 150, 7.3 ] + - [ 74317.0, 140, 7.3 ] + - [ 74448.0, 140, 1.5 ] + - [ 74590.0, 140, -1.5 ] + - [ 74620.0, 140, -5.0 ] + - [ 74950.0, 140, -4.3 ] + - [ 75100.0, 140, -1.8 ] + - [ 75154.0, 130, -1.8 ] + - [ 75260.0, 130, -6.2 ] + - [ 75873.0, 130, -5.6 ] + - [ 76062.0, 100, -5.6 ] + - [ 76100.0, 100, -6.4 ] + - [ 76350.0, 100, -5.7 ] + - [ 76476.0, 100, -7.0 ] + - [ 76600.0, 100, -6.4 ] + - [ 76601.0, 90, -6.4 ] + - [ 76726.0, 90, -6.2 ] + - [ 77256.0, 90, -2.1 ] + - [ 77285.0, 80, -2.1 ] + - [ 77299.0, 80, -14.0 ] + - [ 77331.0, 80, -1.6 ] + - [ 77379.0, 90, -1.6 ] + - [ 77425.0, 110, -1.6 ] + - [ 77455.0, 110, -4.9 ] + - [ 77498.0, 110, 0.0 ] + - [ 77505.0, 160, 0.0 ] + - [ 77555.0, 160, -5.6 ] + - [ 77662.0, 160, 0.0 ] + - [ 78085.0, 160, -4.0 ] + - [ 78223.0, 160, -6.8 ] + - [ 78337.0, 130, -6.8 ] + - [ 78856.0, 130, -6.6 ] + - [ 78875.0, 130, -7.2 ] + - [ 79345.0, 150, -7.2 ] + - [ 79600.0, 150, -6.5 ] + - [ 79792.0, 150, -0.2 ] + - [ 80537.0, 150, -5.2 ] + - [ 81300.0, 150, -4.8 ] + - [ 81634.0, 110, -4.8 ] + - [ 81943.0, 110, -5.4 ] + - [ 82166.0, 110, 0.0 ] + - [ 82408.0, 110, 4.8 ] + - [ 82790.0, 110, 5.9 ] + - [ 83137.0, 120, 5.9 ] + - [ 83300.0, 120, 0.0 ] + - [ 83519.0, 150, 0.0 ] + - [ 83597.0, 150, -7.8 ] + - [ 83827.0, 150, -8.1 ] + - [ 84150.0, 150, -7.2 ] + - [ 84391.0, 150, 0.0 ] + - [ 84966.0, 150, -4.0 ] + - [ 85529.0, 130, -2.3 ] + - [ 85589.0, 130, -4.0 ] + - [ 86081.0, 130, 0.0 ] + - [ 86514.0, 130, 7.8 ] + - [ 86577.0, 120, 7.8 ] + - [ 87554.0, 90, 7.8 ] + - [ 87690.0, 90, 7.9 ] + - [ 87842.0, 90, 1.7 ] + - [ 88007.0, 110, 1.7 ] + - [ 88100.0, 110, 3.4 ] + - [ 88260.0, 110, 5.3 ] + - [ 88376.0, 160, 5.3 ] + - [ 88450.0, 160, 6.7 ] + - [ 89050.0, 160, 7.4 ] + - [ 89350.0, 160, -7.1 ] + - [ 90365.0, 160, 0.0 ] + - [ 90700.0, 160, -7.3 ] + - [ 92000.0, 160, -7.9 ] + - [ 92166.0, 160, -4.0 ] + - [ 92460.0, 160, -5.4 ] + - [ 93330.0, 160, 0.0 ] + - [ 93901.0, 160, 0.7 ] + - [ 94156.0, 160, 5.2 ] + - [ 94440.0, 160, -2.8 ] + - [ 94530.0, 160, -0.8 ] + - [ 94630.0, 160, -6.8 ] + - [ 94830.0, 160, -4.4 ] + - [ 95090.0, 160, -4.6 ] + - [ 95500.0, 160, -4.8 ] + - [ 96500.0, 160, -4.4 ] + - [ 96700.0, 160, -5.6 ] + - [ 97000.0, 160, -4.6 ] + - [ 97590.0, 160, 0.0 ] + - [ 97858.0, 120, 0.0 ] + - [ 98224.0, 120, -1.5 ] + - [ 98264.0, 120, 0.0 ] + - [ 98577.0, 120, 7.5 ] + - [ 98738.0, 120, 0.0 ] + - [ 99055.0, 130, 0.0 ] + - [ 99427.0, 130, -2.0 ] + - [ 99610.0, 130, -3.1 ] + - [ 99906.0, 120, -3.1 ] + - [ 99980.0, 120, -1.3 ] + - [100190.0, 120, -6.8 ] + - [100832.0, 120, -7.2 ] + - [100980.0, 120, -8.1 ] + - [101100.0, 120, -7.4 ] + - [101245.0, 120, -6.3 ] + - [101332.0, 100, -6.3 ] + - [101365.0, 100, -2.4 ] + - [101551.0, 110, -2.4 ] + - [101800.0, 110, 0.0 ] diff --git a/test/data/paths/slope.yaml b/test/data/paths/slope.yaml new file mode 100644 index 0000000..00371a7 --- /dev/null +++ b/test/data/paths/slope.yaml @@ -0,0 +1,29 @@ +%YAML 1.2 +--- +schema: https://railtoolkit.org/schema/running-path.json +schema_version: "2022.05" +paths: + - name: "10 km, different gradient, 160 km/h" + id: slope + UUID: ffd243a9-0223-4210-8c7d-e6c90fde70d3 + points_of_interest: + # [ station in m, name, front or rear ] + - [ 850.00, view_point_1, front ] + - [ 1000.00, distant_signal_1, front ] + - [ 2000.00, main_signal_1, front ] + - [ 9000.00, main_signal_3, front ] + - [ 9050.00, clearing_point_1, rear ] + characteristic_sections: + # [ station in m, speed limit in km/h, resistance in ‰ ] + - [ 0.0, 160, 0.00 ] + - [ 1000.0, 160, 1.00 ] + - [ 2000.0, 160, 2.00 ] + - [ 3000.0, 160, 5.00 ] + - [ 4000.0, 160, -3.00 ] + - [ 5000.0, 160, 5.00 ] + - [ 6000.0, 160, -10.00 ] + - [ 7000.0, 160, 15.00 ] + - [ 8000.0, 160, -10.00 ] + - [ 8500.0, 160, 20.00 ] + - [ 9000.0, 160, 0.00 ] + - [ 10000.0, 160, 0.00 ] diff --git a/test/data/paths/speed.yaml b/test/data/paths/speed.yaml new file mode 100644 index 0000000..378e33f --- /dev/null +++ b/test/data/paths/speed.yaml @@ -0,0 +1,29 @@ +%YAML 1.2 +--- +schema: https://railtoolkit.org/schema/running-path.json +schema_version: "2022.05" +paths: + - name: "10 km, no gradient, different speed limits" + id: speed + UUID: 401b8ce7-fa75-4576-8a4a-43be2eb55e50 + points_of_interest: + # [ station in m, name, front or rear ] + - [ 999.00, point_1, front ] + - [ 2000.00, point_2, front ] + - [ 3333.30, point_3, rear ] + - [ 5000.00, point_4, front ] + - [ 7777.00, point_5, front ] + - [ 9000.00, point_6, front ] + - [ 9500.95, point_7, front ] + characteristic_sections: + # [ station in m, speed limit in km/h, resistance in ‰ ] + - [ 0.0, 160, 0.00 ] + - [ 3000.0, 60, 0.00 ] + - [ 4000.0, 160, 0.00 ] + - [ 5000.0, 60, 0.00 ] + - [ 6000.0, 160, 0.00 ] + - [ 6500.0, 60, 0.00 ] + - [ 6700.0, 65, 0.00 ] + - [ 6800.0, 70, 0.00 ] + - [ 7000.0, 120, 0.00 ] + - [ 10000.0, 160, 0.00 ] diff --git a/test/data/settings/driving_course.yaml b/test/data/settings/driving_course.yaml new file mode 100644 index 0000000..46ac088 --- /dev/null +++ b/test/data/settings/driving_course.yaml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +settings: + outputDetail: "driving_course" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" diff --git a/test/data/settings/everything.yaml b/test/data/settings/everything.yaml new file mode 100644 index 0000000..0e2cdf1 --- /dev/null +++ b/test/data/settings/everything.yaml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +settings: + outputDetail: "everything" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" diff --git a/test/data/settings/points_of_interest.yaml b/test/data/settings/points_of_interest.yaml new file mode 100644 index 0000000..d0784ff --- /dev/null +++ b/test/data/settings/points_of_interest.yaml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +settings: + outputDetail: "points_of_interest" # single value "running_time", array of "points_of_interest",complete array "driving_course", or dict() "everything" diff --git a/test/data/settings/strip.yaml b/test/data/settings/strip.yaml new file mode 100644 index 0000000..57c8abe --- /dev/null +++ b/test/data/settings/strip.yaml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +settings: + massModel: "homogeneous_strip" # type of train model used: "mass_point" or "homogeneous_strip" diff --git a/test/data/settings/time.yaml b/test/data/settings/time.yaml new file mode 100644 index 0000000..c182d22 --- /dev/null +++ b/test/data/settings/time.yaml @@ -0,0 +1,4 @@ +%YAML 1.2 +--- +settings: + stepVariable: "time" # variable of the linear multistep method: "distance", "time" or "velocity" diff --git a/test/data/settings/time_strip.yaml b/test/data/settings/time_strip.yaml new file mode 100644 index 0000000..bc8bed2 --- /dev/null +++ b/test/data/settings/time_strip.yaml @@ -0,0 +1,5 @@ +%YAML 1.2 +--- +settings: + stepVariable: "time" # variable of the linear multistep method: "distance", "time" or "velocity" + massModel: "homogeneous_strip" # type of train model used: "mass_point" or "homogeneous_strip" diff --git a/test/data/settings/velocity.yaml b/test/data/settings/velocity.yaml new file mode 100644 index 0000000..273918f --- /dev/null +++ b/test/data/settings/velocity.yaml @@ -0,0 +1,5 @@ +%YAML 1.2 +--- +settings: + stepVariable: "velocity" # variable of the linear multistep method: "distance", "time" or "velocity" + stepSize: 0.1 # step size, unit depends on stepVariable - position in meter, time in seconds and velocity in meter/second diff --git a/test/data/trains/freight.yaml b/test/data/trains/freight.yaml new file mode 100644 index 0000000..c23db6f --- /dev/null +++ b/test/data/trains/freight.yaml @@ -0,0 +1,123 @@ +%YAML 1.2 +--- +schema: https://railtoolkit.org/schema/rolling-stock.json +schema_version: "2022.05" +trains: + - name: "V 90 with 10 ore wagons of type Facs 124" # (source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90 and https://dybas.de/dybas/gw/gw_f_1/g124.html) + id: Fr100 + formation: [DB_V90,Facs124,Facs124,Facs124,Facs124,Facs124,Facs124,Facs124,Facs124,Facs124,Facs124] + +vehicles: + - name: "Facs 124" # source: https://dybas.de/dybas/gw/gw_f_1/g124.html + id: Facs124 + UUID: 30abe88d-5be7-4c9c-b6a2-61c6b0e9f9bc + picture: https://dybas.de/dybas/gw/gw_f_1/image/124_0042.jpg + vehicle_type: freight # "freight", "passenger", "traction unit" or "multiple unit" + + length: 19.04 # source: https://dybas.de/dybas/gw/gw_f_1/g124.html + mass: 25.00 # source: https://dybas.de/dybas/gw/gw_f_1/g124.html + load_limit: 59.0 # source: https://dybas.de/dybas/gw/gw_f_1/g124.html + speed_limit: 100 # source: https://dybas.de/dybas/gw/gw_f_1/g124.html + + rotation_mass: 1.03 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Güterwagenzug beladen" -> 1.03 to 1.04) + base_resistance: 1.4 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for "roller bearings") + air_resistance: 3.9 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for "full train loads of coal or ore" modified for the used formula + + - name: "DB V90" # source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90 + id: DB_V90 + UUID: 48b99596-98b2-40c8-b31a-3f9266013803 + picture: https://commons.wikimedia.org/wiki/File:DB_294_-_594_side_view.jpg + vehicle_type: traction unit # "freight", "passenger", "traction unit" or "multiple unit" + power_type: diesel # "diesel", "electric", or "steam" + + length: 14.32 # source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90 + mass: 80 # source: https://de.wikipedia.org/wiki/DB-Baureihe_V_90 + mass_traction: 80 # in t # mass on driving axles of the traction unit + speed_limit: 80 # in km/h + + rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit + base_resistance: 2.2 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰ + air_resistance: 0.01 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "MittelfUhrerstand" -> 5000 N to 10000 N; modified for the used formula + + tractive_effort: + - [0.0, 186940] + - [1.0, 186940] + - [2.0, 182310] + - [3.0, 177680] + - [4.0, 173050] + - [5.0, 168420] + - [6.0, 163790] + - [7.0, 159160] + - [8.0, 154530] + - [9.0, 149240] + - [10.0, 144120] + - [11.0, 139150] + - [12.0, 134340] + - [13.0, 129690] + - [14.0, 125200] + - [15.0, 120860] + - [16.0, 116680] + - [17.0, 112660] + - [18.0, 108790] + - [19.0, 105080] + - [20.0, 101530] + - [21.0, 98120] + - [22.0, 94840] + - [23.0, 91700] + - [24.0, 88700] + - [25.0, 85840] + - [26.0, 83110] + - [27.0, 80520] + - [28.0, 78070] + - [29.0, 75750] + - [30.0, 73580] + - [31.0, 71600] + - [32.0, 69660] + - [33.0, 67770] + - [34.0, 65930] + - [35.0, 64130] + - [36.0, 62380] + - [37.0, 60670] + - [38.0, 59010] + - [39.0, 57400] + - [40.0, 55830] + - [41.0, 54300] + - [42.0, 52820] + - [43.0, 51390] + - [44.0, 50000] + - [45.0, 48660] + - [46.0, 48080] + - [47.0, 47220] + - [48.0, 46380] + - [49.0, 45550] + - [50.0, 44730] + - [51.0, 43930] + - [52.0, 43140] + - [53.0, 42370] + - [54.0, 41610] + - [55.0, 40870] + - [56.0, 40140] + - [57.0, 39430] + - [58.0, 38730] + - [59.0, 38040] + - [60.0, 37370] + - [61.0, 36720] + - [62.0, 36070] + - [63.0, 35450] + - [64.0, 34830] + - [65.0, 34230] + - [66.0, 33650] + - [67.0, 33080] + - [68.0, 32520] + - [69.0, 31980] + - [70.0, 31450] + - [71.0, 30940] + - [72.0, 30440] + - [73.0, 29960] + - [74.0, 29490] + - [75.0, 29030] + - [76.0, 28590] + - [77.0, 28170] + - [78.0, 27760] + - [79.0, 27360] + - [80.0, 26980] diff --git a/test/data/trains/local.yaml b/test/data/trains/local.yaml new file mode 100644 index 0000000..5c380e8 --- /dev/null +++ b/test/data/trains/local.yaml @@ -0,0 +1,153 @@ +%YAML 1.2 +--- +schema: https://railtoolkit.org/schema/rolling-stock.json +schema_version: "2022.05" +trains: + - name: Regional Train + id: RB50-1 + formation: [DB_BR_642] + +vehicles: + - name: Siemens Desiro Classic # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic + id: DB_BR_642 + UUID: c915c80d-c63d-490b-879f-c481e4b62b55 + picture: https://commons.wikimedia.org/wiki/File:Liesel_28-11-10_642_055-8_im_Bahnhof_Scharfenstein.JPG + power_type: diesel # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic + vehicle_type: multiple unit # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic + + length: 41.7 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic + mass: 68.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic + load_limit: 20.0 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic + mass_traction: 45.333 # proportionately to the number of axles: 4 to 2, see: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic) + speed_limit: 120 # source: https://de.wikipedia.org/wiki/Siemens_Desiro_Classic + a_braking: -0.4253 # + + # coefficients for the vehicle resistance + rotation_mass: 1.08 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 13 for "Zug, überschlägliche Berechnung" + base_resistance: 3.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WL0" -> 2.5 ‰ to 3.5 ‰ + rolling_resistance: 1.4 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "f_WW0" -> 1.2 ‰ to 1.6 ‰ + air_resistance: 0.0039 # source: the closest parameters are used: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "Fzg. vierachsig, abgerundeter Kopf" plus "Sektion bei Mehrteiligkeit" -> 2200 N + 400 N + + # tractive effort as pairs of speed and tractive effort + tractive_effort: + - [0.0, 94400] + - [1.0, 94400] + - [2.0, 92800] + - [3.0, 91200] + - [4.0, 89600] + - [5.0, 88000] + - [6.0, 86400] + - [7.0, 84800] + - [8.0, 83200] + - [9.0, 81600] + - [10.0, 80000] + - [11.0, 78160] + - [12.0, 76290] + - [13.0, 74420] + - [14.0, 72550] + - [15.0, 70680] + - [16.0, 68810] + - [17.0, 66940] + - [18.0, 65070] + - [19.0, 63200] + - [20.0, 61330] + - [21.0, 59460] + - [22.0, 57590] + - [23.0, 55720] + - [24.0, 53850] + - [25.0, 51980] + - [26.0, 50110] + - [27.0, 48240] + - [28.0, 46370] + - [29.0, 44500] + - [30.0, 42630] + - [31.0, 40760] + - [32.0, 38890] + - [33.0, 38110] + - [34.0, 37330] + - [35.0, 36550] + - [36.0, 35770] + - [37.0, 35600] + - [38.0, 35600] + - [39.0, 35600] + - [40.0, 35600] + - [41.0, 35600] + - [42.0, 35600] + - [43.0, 35550] + - [44.0, 35280] + - [45.0, 35010] + - [46.0, 34740] + - [47.0, 34280] + - [48.0, 33560] + - [49.0, 32880] + - [50.0, 32220] + - [51.0, 31590] + - [52.0, 26300] + - [53.0, 26300] + - [54.0, 26300] + - [55.0, 26300] + - [56.0, 26300] + - [57.0, 25990] + - [58.0, 25840] + - [59.0, 25690] + - [60.0, 25540] + - [61.0, 25390] + - [62.0, 25240] + - [63.0, 25090] + - [64.0, 25140] + - [65.0, 24760] + - [66.0, 24380] + - [67.0, 24020] + - [68.0, 23660] + - [69.0, 23320] + - [70.0, 22990] + - [71.0, 19400] + - [72.0, 19400] + - [73.0, 19400] + - [74.0, 19400] + - [75.0, 19400] + - [76.0, 19400] + - [77.0, 19400] + - [78.0, 19400] + - [79.0, 19400] + - [80.0, 19400] + - [81.0, 19440] + - [82.0, 19310] + - [83.0, 19180] + - [84.0, 19050] + - [85.0, 18920] + - [86.0, 18670] + - [87.0, 18460] + - [88.0, 18250] + - [89.0, 15360] + - [90.0, 15310] + - [91.0, 15260] + - [92.0, 15210] + - [93.0, 15160] + - [94.0, 15110] + - [95.0, 15060] + - [96.0, 15010] + - [97.0, 14960] + - [98.0, 14910] + - [99.0, 14860] + - [100.0, 14810] + - [101.0, 14760] + - [102.0, 14710] + - [103.0, 14660] + - [104.0, 14610] + - [105.0, 14560] + - [106.0, 14510] + - [107.0, 14460] + - [108.0, 14410] + - [109.0, 14360] + - [110.0, 14310] + - [111.0, 14460] + - [112.0, 14340] + - [113.0, 14210] + - [114.0, 14080] + - [115.0, 13960] + - [116.0, 13840] + - [117.0, 13720] + - [118.0, 13610] + - [119.0, 13490] + - [120.0, 13380] diff --git a/test/data/trains/longdistance.yaml b/test/data/trains/longdistance.yaml new file mode 100644 index 0000000..2369208 --- /dev/null +++ b/test/data/trains/longdistance.yaml @@ -0,0 +1,220 @@ +%YAML 1.2 +--- +schema: https://railtoolkit.org/schema/rolling-stock.json +schema_version: "2022.05" +trains: + - name: "Intercity 2 (Traxx P160 AC2 + double deck coaches)" # (source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario#Intercity_2 and https://de.wikipedia.org/wiki/Intercity_2_(Deutsche_Bahn)) + id: IC1011 + formation: [Bombardier_Traxx_2_P160,DABpza68,DABpza68,DABpza68,DABpza68,DABpza668] + +vehicles: + - name: "DBpbzfa 668.2" # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + id: DABpza668 + UUID: a186ea2c-daeb-429b-8254-89e0d6700519 + picture: https://commons.wikimedia.org/wiki/File:Bombardier_IC_Doppelstocksteuerwagen_Innotrans_2014.JPG + vehicle_type: passenger # "freight", "passenger", "traction unit" or "multiple unit" + + length: 27.27 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + mass: 58.00 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + load_limit: 20.0 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + speed_limit: 160 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + + rotation_mass: 1.06 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for freight wagons + base_resistance: 2.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge" + rolling_resistance: 0.715 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge" + air_resistance: 3.64 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge" + + - name: "DApza 687.2 and DBpza 682.2" # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + id: DABpza68 + UUID: 45e83b27-7952-4f34-ad8d-1affcacfe6f2 + picture: https://commons.wikimedia.org/wiki/File:D-DB_50_80_26-81_456-8_DBpza_682.2_Bremen_Hbf_14.11.2015.jpg + vehicle_type: passenger # "freight", "passenger", "traction unit" or "multiple unit" + + length: 26.8 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + mass: 50.00 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + load_limit: 20.0 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + speed_limit: 160 # source: https://de.wikipedia.org/wiki/Bombardier_Twindexx_Vario + + rotation_mass: 1.06 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for freight wagons + base_resistance: 2.0 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge" + rolling_resistance: 0.715 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge" + air_resistance: 3.64 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 153 for "Doppelstockgliederzüge" + + - name: "Bombardier Traxx 2 (P160)" # source: https://en.wikipedia.org/wiki/Bombardier_TRAXX#TRAXX_P160_AC2 + id: Bombardier_Traxx_2_P160 + UUID: bc62a03e-9ec9-41f2-913c-6b315e86cc61 + picture: https://commons.wikimedia.org/wiki/File:146_560-8_(Flickr_26502799445).jpg + vehicle_type: traction unit # "freight", "passenger", "traction unit" or "multiple unit" + power_type: electric # "diesel", "electric", or "steam" + + length: 18.9 # source: https://de.wikipedia.org/wiki/Bombardier_Traxx#P160_AC2 + mass: 85 # source: https://de.wikipedia.org/wiki/Bombardier_Traxx#P160_AC2 + mass_traction: 85 # in t # mass on driving axles of the traction unit + speed_limit: 160 # in km/h + + rotation_mass: 1.09 # source: "Railway Timetabling & Operations" by Hansen, et al., 2014, p. 71 for the traction unit + base_resistance: 2.5 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsige Diesellokomot." -> 2.2 ‰ to 3.5 ‰ + air_resistance: 0.006 # source: "Fahrdynamik des Schienenverkehrs" by Wende, 2003, p. 151 for "4-achsig, eckige Kopfform" with "Stromabnehmer" -> 5000 N to 6000 N; modified for the used formula + + tractive_effort: + - [0.0, 300000] + - [1.0, 300000] + - [2.0, 300000] + - [3.0, 300000] + - [4.0, 300000] + - [5.0, 300000] + - [6.0, 300000] + - [7.0, 300000] + - [8.0, 300000] + - [9.0, 300000] + - [10.0, 300000] + - [11.0, 300000] + - [12.0, 300000] + - [13.0, 300000] + - [14.0, 300000] + - [15.0, 300000] + - [16.0, 300000] + - [17.0, 300000] + - [18.0, 300000] + - [19.0, 300000] + - [20.0, 300000] + - [21.0, 300000] + - [22.0, 300000] + - [23.0, 300000] + - [24.0, 300000] + - [25.0, 300000] + - [26.0, 300000] + - [27.0, 300000] + - [28.0, 300000] + - [29.0, 300000] + - [30.0, 300000] + - [31.0, 300000] + - [32.0, 300000] + - [33.0, 300000] + - [34.0, 300000] + - [35.0, 300000] + - [36.0, 300000] + - [37.0, 300000] + - [38.0, 300000] + - [39.0, 300000] + - [40.0, 300000] + - [41.0, 300000] + - [42.0, 300000] + - [43.0, 300000] + - [44.0, 300000] + - [45.0, 300000] + - [46.0, 300000] + - [47.0, 300000] + - [48.0, 300000] + - [49.0, 300000] + - [50.0, 300000] + - [51.0, 300000] + - [52.0, 300000] + - [53.0, 300000] + - [54.0, 300000] + - [55.0, 300000] + - [56.0, 300000] + - [57.0, 300000] + - [58.0, 300000] + - [59.0, 300000] + - [60.0, 300000] + - [61.0, 300000] + - [62.0, 300000] + - [63.0, 300000] + - [64.0, 300000] + - [65.0, 300000] + - [66.0, 300000] + - [67.0, 297760] + - [68.0, 293380] + - [69.0, 289130] + - [70.0, 285000] + - [71.0, 280990] + - [72.0, 277080] + - [73.0, 273290] + - [74.0, 269590] + - [75.0, 266000] + - [76.0, 262500] + - [77.0, 259090] + - [78.0, 255770] + - [79.0, 252530] + - [80.0, 249380] + - [81.0, 246300] + - [82.0, 243290] + - [83.0, 240360] + - [84.0, 237500] + - [85.0, 234710] + - [86.0, 231980] + - [87.0, 229310] + - [88.0, 226700] + - [89.0, 224160] + - [90.0, 221670] + - [91.0, 219230] + - [92.0, 216850] + - [93.0, 214520] + - [94.0, 212230] + - [95.0, 210000] + - [96.0, 207810] + - [97.0, 205670] + - [98.0, 203570] + - [99.0, 201520] + - [100.0, 199500] + - [101.0, 197520] + - [102.0, 195590] + - [103.0, 193690] + - [104.0, 191830] + - [105.0, 190000] + - [106.0, 188210] + - [107.0, 186450] + - [108.0, 184720] + - [109.0, 183030] + - [110.0, 181360] + - [111.0, 179730] + - [112.0, 178130] + - [113.0, 176550] + - [114.0, 175000] + - [115.0, 173480] + - [116.0, 171980] + - [117.0, 170510] + - [118.0, 169070] + - [119.0, 167650] + - [120.0, 166250] + - [121.0, 164880] + - [122.0, 163520] + - [123.0, 162200] + - [124.0, 160890] + - [125.0, 159600] + - [126.0, 158330] + - [127.0, 157090] + - [128.0, 155860] + - [129.0, 154650] + - [130.0, 153460] + - [131.0, 152290] + - [132.0, 151140] + - [133.0, 150000] + - [134.0, 148880] + - [135.0, 147780] + - [136.0, 146690] + - [137.0, 145620] + - [138.0, 144570] + - [139.0, 143530] + - [140.0, 142500] + - [141.0, 141490] + - [142.0, 140490] + - [143.0, 139510] + - [144.0, 138540] + - [145.0, 137590] + - [146.0, 136640] + - [147.0, 135710] + - [148.0, 134800] + - [149.0, 133890] + - [150.0, 133000] + - [151.0, 132120] + - [152.0, 131250] + - [153.0, 130390] + - [154.0, 129550] + - [155.0, 128710] + - [156.0, 127880] + - [157.0, 127070] + - [158.0, 126270] + - [159.0, 125470] + - [160.0, 124690] diff --git a/test/runtests.jl b/test/runtests.jl index 5e98cc6..167e358 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -1,40 +1,88 @@ #!/usr/bin/env julia # -*- coding: UTF-8 -*- # __julia-version__ = 1.7.0 -# __author__ = "Max Kannenberg" +# __author__ = "Max Kannenberg, Martin Scheidt" # __copyright__ = "2021" # __license__ = "ISC" -using TrainRun, Test +using TrainRuns, Test -allPaths=[] -push!(allPaths, importYamlFile(:path, "data/paths/path_1_10km_nConst_vConst.yaml")) -push!(allPaths, importYamlFile(:path, "data/paths/path_2_10km_nVar_vConst.yaml")) -push!(allPaths, importYamlFile(:path, "data/paths/path_3_10km_nConst_vVar.yaml")) -push!(allPaths, importYamlFile(:path, "data/paths/path_4_real_Germany_EastSaxony_DG-DN.yaml")) +trains = Dict() +paths = Dict() +settings = Dict() +@testset "load data" begin -allSettings=[] -push!(allSettings, importYamlFile(:settings, "data/settings.yaml")) + println("testing load train data") + push!(trains, :freight => @time Train("data/trains/freight.yaml")) + push!(trains, :local => @time Train("data/trains/local.yaml")) + push!(trains, :longdistance => @time Train("data/trains/longdistance.yaml")) -allTrains=[] -push!(allTrains, importYamlFile(:train, "data/trains/train_freight_V90withOreConsist.yaml")) -push!(allTrains, importYamlFile(:train, "data/trains/train_passenger_SiemensDesiroClassic.yaml")) -push!(allTrains, importYamlFile(:train, "data/trains/train_passenger_IC2.yaml")) + println("testing load path data") + push!(paths, :const => @time Path("data/paths/const.yaml")) + push!(paths, :slope => @time Path("data/paths/slope.yaml")) + push!(paths, :speed => @time Path("data/paths/speed.yaml")) + push!(paths, :realworld => @time Path("data/paths/realworld.yaml")) -for path in allPaths - for train in allTrains - for settings in allSettings - testDict=trainRun(train, path, settings) - exportToCsv(testDict) - sleep(2) + println("testing load settings data") + push!(settings, "default" => @time Settings()) + push!(settings, "poi" => @time Settings("data/settings/points_of_interest.yaml")) + push!(settings, "drivingcourse" => @time Settings("data/settings/driving_course.yaml")) + push!(settings, "everything" => @time Settings("data/settings/everything.yaml")) + push!(settings, "strip" => @time Settings("data/settings/strip.yaml")) + push!(settings, "time" => @time Settings("data/settings/time.yaml")) + push!(settings, "timestrip" => @time Settings("data/settings/time_strip.yaml")) + push!(settings, "velocity" => @time Settings("data/settings/velocity.yaml")) + + @test typeof(first(paths)[2]) == Path + @test typeof(first(settings)[2]) == Settings - # TODO: - # compare result to test data set - end - end end -println("test finished") -# TODO: -# print test results +println("====================") + +tests = Base.Iterators.product(trains,paths) + +## routine to generate the anticipated Dict() +# anticipated = Dict() +# for test in tests +# println(test[1][1],"-",test[2][1]) +# result = @time trainrun(test[1][2],test[2][2]) +# push!(anticipated, Symbol(String(test[1][1]) * "_" * String(test[2][1])) => result ) +# end + +anticipated = Dict( + :default => Dict( + :longdistance_speed => 499.96109564970516, + :freight_slope => 831.4768274141168, + :local_slope => 396.99313307033276, + :longdistance_const => 328.83479381353095, + :freight_realworld => 8971.50124080998, + :longdistance_slope => 329.22915822053164, + :freight_const => 727.7969403041934, + :longdistance_realworld => 2900.1198723158523, + :local_speed => 524.3948201513945, + :local_realworld => 3443.917823618831, + :freight_speed => 733.2610572579886, + :local_const => 392.7234008268302 + ) +) + +@testset "function trainrun()" begin + + @testset "Default settings" begin + + for test in tests + test_name = String(test[1][1]) * "_" * String(test[2][1]) + println("testing $test_name") + @time result = trainrun(test[1][2],test[2][2]) + expected = anticipated[:default][Symbol(test_name)] + # compare result to test data set + @test isapprox(result, expected, rtol=0.01) + println("--------------------") + end + + end + println("====================") + +end diff --git a/test/testEnums.jl b/test/testEnums.jl deleted file mode 100644 index 9a0875c..0000000 --- a/test/testEnums.jl +++ /dev/null @@ -1,24 +0,0 @@ -#!/usr/bin/env julia -# -*- coding: UTF-8 -*- -# __julia-version__ = 1.7.0 -# __author__ = "Martin Scheidt" -# __copyright__ = "2021" -# __license__ = "ISC" - -include("../src/types.jl") -include("../src/Validate.jl") - -using .Input -using YAML, Test - -@enum trainType passenger=1 freight=2 motorCoachTrain=3 - -@test Input.getEnum("passenger", trainType) == passenger::trainType -@test Input.getEnum("freight", trainType) == freight::trainType -@test Input.getEnum("motorCoachTrain", trainType) == motorCoachTrain::trainType - -data = YAML.load(open("data/trains/train_passenger_IC2.yaml")) -@test Input.getEnum(data["train"]["trainType"], trainType) == passenger::trainType - -data = YAML.load(open("data/trains/train_freight_V90withOreConsist.yaml")) -@test Input.getEnum(data["train"]["trainType"], trainType) == freight::trainType