diff --git a/.github/workflows/Documentation.yml b/.github/workflows/Documentation.yml index 8455fd46..e18401a2 100644 --- a/.github/workflows/Documentation.yml +++ b/.github/workflows/Documentation.yml @@ -28,7 +28,7 @@ jobs: - name: "Set up Julia" uses: julia-actions/setup-julia@v1 with: - version: '1.9' + version: '1' arch: x64 - name: "Copy examples, readme" diff --git a/.github/workflows/Eval.yml b/.github/workflows/Eval.yml index c5103c37..e569102a 100644 --- a/.github/workflows/Eval.yml +++ b/.github/workflows/Eval.yml @@ -56,4 +56,4 @@ jobs: Pkg.instantiate(); Pkg.add("Test"); Pkg.add(path="./PkgEval.jl")' - julia --project=. ./test/FMI2/eval.jl + julia --project=. ./test/eval.jl diff --git a/.github/workflows/Example.yml b/.github/workflows/Example.yml index 57eaf579..189ecce6 100644 --- a/.github/workflows/Example.yml +++ b/.github/workflows/Example.yml @@ -13,23 +13,23 @@ on: - 'Project.toml' jobs: - sync-files: + jupyter: runs-on: ${{ matrix.os }} strategy: fail-fast: false matrix: os: [windows-latest] # ubuntu-latest file-name: [manipulation, modelica_conference_2021, multiple_instances, multiprocessing, multithreading, parameterize, simulate, parameter_optimization] - julia-version: ['1.8'] + julia-version: ['1.10'] julia-arch: [x64] experimental: [false] steps: - name: "Check out repository" - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: "Set up Julia" - uses: julia-actions/setup-julia@v1 + uses: julia-actions/setup-julia@latest with: version: ${{ matrix.julia-version }} arch: ${{ matrix.julia-arch }} @@ -44,59 +44,47 @@ jobs: env: FILE: examples/src/${{ matrix.file-name }}.ipynb run: | - jupyter nbconvert --ExecutePreprocessor.kernel_name="julia-1.8" --to notebook --inplace --execute ${{ env.FILE }} + jupyter nbconvert --ExecutePreprocessor.kernel_name="julia-${{ matrix.julia-version }}" --to notebook --inplace --execute ${{ env.FILE }} jupyter nbconvert --to script ${{ env.FILE }} jupyter nbconvert --to markdown ${{ env.FILE }} - - name: Archive examples artifacts - if: success() && matrix.os == 'windows-latest' - uses: actions/upload-artifact@v3 - with: - name: examples - path: examples/src/${{ matrix.file-name }}* - - auto-commit: - needs: sync-files - if: github.event_name != 'pull_request' - runs-on: ubuntu-latest - steps: - - name: Check out repository - uses: actions/checkout@v3 + - name: "run generated jl script to determine success of example building" + run: julia --project=examples/ examples/${{ matrix.file-name }}.jl - - name: Download examples - uses: actions/download-artifact@v3 - with: - name: examples - path: examples/src/ - - - name: auto-commit + - name: "auto-commit (retry on merge)" + if: success() && github.event_name != 'pull_request' && github.branch == 'main' + uses: nick-fields/retry@v3 env: - CI_COMMIT_MESSAGE: Jupyter nbconvert synch - modified, paired .ipynb files + CI_COMMIT_MESSAGE: example-${{ matrix.os }}-${{ matrix.file-name }}-${{ matrix.julia-version }}-${{ matrix.julia-arch }}-${{ matrix.experimental }}[${{ github.ref }}] CI_COMMIT_AUTHOR: github-actions[bot] - EXAMPLES_PATH: examples/src - # Fetch all and clear the stash list. Include all files from the examples/src folder to the stash and switch the branch. - # Reset the branch and remove all current files in the examples/src folder. + EXAMPLES_PATH: examples + # Fetch all and clear the stash list. Include all files from the examples folder to the stash and switch the branch. + # Reset the branch and remove all current files in the examples folder. # Checkout the last stash to restore the new notebooks and apply the stash index to restore all other new files in the folder. - run: | - git fetch --all - git stash clear - git stash --include-untracked -- ${{ env.EXAMPLES_PATH }} - git switch examples - git reset --hard origin/examples - rm -rf ${{ env.EXAMPLES_PATH }} - git checkout stash -f -- ${{ env.EXAMPLES_PATH }} - git stash apply --index - git stash drop - git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}" - git config --global user.email "${{ env.CI_COMMIT_AUTHOR }}@users.noreply.github.com" - git config --global core.autocrlf false - git add ${{ env.EXAMPLES_PATH }} - git commit -m "${{ env.CI_COMMIT_MESSAGE }}" - git push origin examples + with: + timeout_minutes: 999 + max_attempts: 10 + warning_on_retry: false + shell: bash + command: | + git fetch --all + git stash clear + git stash --include-untracked -- ${{ env.EXAMPLES_PATH }} + git switch examples + git reset --hard origin/examples + git checkout stash -f -- ${{ env.EXAMPLES_PATH }} + git stash apply --index + git stash drop + git config --global user.name "${{ env.CI_COMMIT_AUTHOR }}" + git config --global user.email "${{ env.CI_COMMIT_AUTHOR }}@users.noreply.github.com" + git config --global core.autocrlf false + git add ${{ env.EXAMPLES_PATH }} + git commit -m "${{ env.CI_COMMIT_MESSAGE }}" + git push origin examples || (git reset --soft HEAD~1 && (exit 1)) call-docu: - needs: auto-commit - if: github.event_name != 'pull_request' + needs: jupyter + if: github.event_name != 'pull_request' && github.branch == 'main' runs-on: ubuntu-latest steps: # Trigger an repoisitory dispath event diff --git a/.github/workflows/Formatter.yml b/.github/workflows/Formatter.yml new file mode 100644 index 00000000..0155d9b6 --- /dev/null +++ b/.github/workflows/Formatter.yml @@ -0,0 +1,14 @@ +name: Format suggestions +on: + pull_request: + # this argument is not required if you don't use the `suggestion-label` input + types: [ opened, reopened, synchronize, labeled, unlabeled ] +jobs: + code-style: + runs-on: ubuntu-latest + steps: + - uses: julia-actions/julia-format@v3 + with: + version: '1' # Set `version` to '1.0.54' if you need to use JuliaFormatter.jl v1.0.54 (default: '1') + suggestion-label: 'format-suggest' # leave this unset or empty to show suggestions for all PRs + diff --git a/Project.toml b/Project.toml index 6d3844f6..21771692 100644 --- a/Project.toml +++ b/Project.toml @@ -1,25 +1,15 @@ name = "FMI" uuid = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" authors = ["TT ", "LM ", "JK "] -version = "0.13.3" +version = "0.14.0" [deps] -DifferentialEquations = "0c46a032-eb83-5123-abaf-570d42b7fbaa" -Downloads = "f43a241f-c20a-4ad4-852c-f6b1247861c6" FMIExport = "31b88311-cab6-44ed-ba9c-fe5a9abbd67a" FMIImport = "9fcbc62e-52a0-44e9-a616-1359a0008194" LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" -ProgressMeter = "92933f4c-e287-5a05-a399-4b506db050ca" -Requires = "ae029012-a4dd-5104-9daa-d747884805df" -ThreadPools = "b189fb0b-2eb5-4ed4-bc0c-d34c51242431" [compat] -DifferentialEquations = "7.7.0 - 7.13" -Downloads = "1" -FMIExport = "0.3.0" -FMIImport = "0.16.0" +FMIExport = "0.4.0" +FMIImport = "1.0.0" LinearAlgebra = "1" -ProgressMeter = "1.7.0 - 1.9" -Requires = "1.3.0" -ThreadPools = "2.1.1" julia = "1.6" diff --git a/README.md b/README.md index 4f6e8a67..5ef86dc4 100644 --- a/README.md +++ b/README.md @@ -2,20 +2,43 @@ # FMI.jl ## What is FMI.jl? -[*FMI.jl*](https://github.com/ThummeTo/FMI.jl) is a free-to-use software library for the Julia programming language which integrates the **F**unctional **M**ock-Up **I**nterface ([fmi-standard.org](https://fmi-standard.org/)): load or create, parameterize, differentiate, simulate and plot FMUs seamlessly inside the Julia programming language! +[*FMI.jl*](https://github.com/ThummeTo/FMI.jl) is a free-to-use software library for the Julia programming language which integrates the **F**unctional **M**ock-Up **I**nterface ([fmi-standard.org](https://fmi-standard.org/)): load or create, parameterize, differentiate, linearize, simulate and plot FMUs seamlessly inside the Julia programming language! -[![Dev Docs](https://img.shields.io/badge/docs-dev-blue.svg)](https://ThummeTo.github.io/FMI.jl/dev) -[![Test (latest)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLatest.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLatest.yml) -[![Test (LTS)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLTS.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLTS.yml) -[![FMI2 Cross Checks (latest)](https://github.com/ThummeTo/FMI.jl/actions/workflows/CrossChecks.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/CrossChecks.yml) -[![Examples (latest)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Example.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Example.yml) -[![Build Docs](https://github.com/ThummeTo/FMI.jl/actions/workflows/Documentation.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Documentation.yml) -[![Run PkgEval](https://github.com/ThummeTo/FMI.jl/actions/workflows/Eval.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Eval.yml) -[![Coverage](https://codecov.io/gh/ThummeTo/FMI.jl/branch/main/graph/badge.svg)](https://codecov.io/gh/ThummeTo/FMI.jl) -[![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor's%20Guide-blueviolet)](https://github.com/SciML/ColPrac) -[![FMI Downloads](https://shields.io/endpoint?url=https://pkgs.genieframework.com/api/v1/badge/FMI)](https://pkgs.genieframework.com?packages=FMI) -[![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) +| | | +|---|---| +| Documentation | [![Build Docs](https://github.com/ThummeTo/FMI.jl/actions/workflows/Documentation.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Documentation.yml) [![Dev Docs](https://img.shields.io/badge/docs-dev-blue.svg)](https://thummeto.github.io/FMI.jl/dev/) | +| Examples | [![Examples (latest)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Example.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Example.yml) | +| Tests | [![Test (latest)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLatest.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLatest.yml) [![Test (LTS)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLTS.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/TestLTS.yml) [![Aqua QA](https://raw.githubusercontent.com/JuliaTesting/Aqua.jl/master/badge.svg)](https://github.com/JuliaTesting/Aqua.jl) | +| FMI cross checks| [![FMI2 Cross Checks](https://github.com/ThummeTo/FMI.jl/actions/workflows/CrossChecks.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/CrossChecks.yml) | +| Package evaluation| [![Run PkgEval](https://github.com/ThummeTo/FMI.jl/actions/workflows/Eval.yml/badge.svg)](https://github.com/ThummeTo/FMI.jl/actions/workflows/Eval.yml) | +| Code coverage | [![Coverage](https://codecov.io/gh/ThummeTo/FMI.jl/branch/main/graph/badge.svg)](https://app.codecov.io/gh/ThummeTo/FMI.jl) | +| Collaboration | [![ColPrac: Contributor's Guide on Collaborative Practices for Community Packages](https://img.shields.io/badge/ColPrac-Contributor's%20Guide-blueviolet)](https://github.com/SciML/ColPrac) | +| Formatting | [![SciML Code Style](https://img.shields.io/static/v1?label=code%20style&message=SciML&color=9558b2&labelColor=389826)](https://github.com/SciML/SciMLStyle) | +## Breaking Changes in FMI.jl (starting from v0.14.0 until release of v1.0.0) +If you want to migrate your project from [*FMI.jl*](https://github.com/ThummeTo/FMI.jl) < v1.0.0 to >= v1.0.0, you will face some breaking changes - but they are worth it as you will see! We decided to do multiple smaller breaking changes starting with v0.14.0, instead of one big one. Some of them are already implemented (checked), some are still on the todo (unchecked) but will be implemented before releasing v1.0.0. + +- [x] Many functions, that are not part of the FMI-standard, had the prefix `fmi2...` or `fmi3...`. This was corrected. Now, only functions that are defined by the standard itself, like e.g. `fmi2Instantiate` are allowed to keep the prefix. Other methods, like `fmi2ValueReferenceToString`, that where added to make this library more comfortable, are now cleaned to be more the Julia way: `valueReferenceToString`. If your code errors, the corresponding function might have lost it's prefix, so try this first. + +- [x] Wrapper functions where removed, because that is not the Julia way. In most cases, this will not affect your code. + +- [x] [*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl) and [*FMIImport.jl*](https://github.com/ThummeTo/FMIImport.jl) were divided into [*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl), [*FMIImport.jl*](https://github.com/ThummeTo/FMIImport.jl) and [*FMIBase.jl*](https://github.com/ThummeTo/FMIBase.jl). [*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl) now holds the pure standard definition (C-types and -functions), while [*FMIBase.jl*](https://github.com/ThummeTo/FMIBase.jl) holds everything that is needed on top of that in [*FMIImport.jl*](https://github.com/ThummeTo/FMIImport.jl) as well as in [*FMIExport.jl*](https://github.com/ThummeTo/FMIExport.jl). + +- [ ] Updated all library tests for a better code coverage. + +- [ ] We tried to document every function, if you find undocumented user-level functions, please open an issue or PR. + +- [ ] Allocations, type stability and code format where optimized and are monitored by CI now. + +- [ ] Dependencies are reduced a little, to make the libraries more light-weight. + +- [ ] RAM for allocated FMUs, their instances and states, is now auto-released. For maximum performance/safety you can use FMUs in blocks (like file reading/writing). + +- [ ] New low-level interfaces are introduced, that fit the SciML-ecosystem. For example, a FMU can still be simulated with `simulate(fmu)`, but one can also decide to create a `prob = FMUProblem(fmu)` (like an `ODEProblem`) and use `solve(prob)` to obtain a solution. Keywords will be adapted to have a fully consistent interface with the remaining SciML-ecosystem. + +- [ ] Optimization for new Julia LTS v1.10, removing code to keep downward compatibility with old LTS v1.6. + +πŸŽ‰ After all listed features are implemented, v1.0.0 will be released! πŸŽ‰ ## How can I use FMI.jl? 1\. Open a Julia-REPL, switch to package mode using `]`, activate your preferred environment. @@ -37,16 +60,16 @@ using FMI, Plots # load and instantiate a FMU -fmu = fmiLoad(pathToFMU) +fmu = loadFMU(pathToFMU) # simulate from t=0.0s until t=10.0s and record the FMU variable named "mass.s" -simData = fmiSimulate(fmu, (0.0, 10.0); recordValues=["mass.s"]) +simData = simulate(fmu, (0.0, 10.0); recordValues=["mass.s"]) # plot it! plot(simData) # free memory -fmiUnload(myFMU) +unloadFMU(myFMU) ``` ## What is currently supported in FMI.jl? @@ -57,21 +80,21 @@ fmiUnload(myFMU) | | **FMI2.0.3** | | **FMI3.0** | | **SSP1.0** | | |-----------------------------------|--------------|--------|------------|--------|------------|--------| | | Import | Export | Import | Export | Import | Export | -| CS | βœ”οΈβœ”οΈ | 🚧 | βœ”οΈ | πŸ“… | πŸ“… | πŸ“… | -| ME (continuous) | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | 🚧 | πŸ“… | πŸ“… | πŸ“… | -| ME (discontinuous) | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | 🚧 | πŸ“… | πŸ“… | πŸ“… | +| CS | βœ”οΈβœ”οΈ | 🚧 | βœ”οΈβœ”οΈ | πŸ“… | πŸ“… | πŸ“… | +| ME (continuous) | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | πŸ“… | πŸ“… | πŸ“… | +| ME (discontinuous) | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | πŸ“… | πŸ“… | πŸ“… | | SE | 🚫 | 🚫 | 🚧 | πŸ“… | 🚫 | 🚫 | -| Explicit solvers | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | βœ”οΈ | πŸ“… | πŸ“… | πŸ“… | -| Implicit solvers (autodiff=false) | βœ”οΈβœ”οΈ | 🚧 | βœ”οΈ | πŸ“… | πŸ“… | πŸ“… | -| Implicit solvers (autodiff=true) | βœ”οΈβœ”οΈ | 🚧 | 🚧 | πŸ“… | πŸ“… | πŸ“… | -| get/setState | βœ”οΈβœ”οΈ | πŸ“… | βœ”οΈ | πŸ“… | 🚫 | 🚫 | -| getDirectionalDerivatives | βœ”οΈβœ”οΈ | πŸ“… | βœ”οΈ | πŸ“… | 🚫 | 🚫 | -| getAdjointDerivatives | 🚫 | 🚫 | βœ”οΈ | πŸ“… | 🚫 | 🚫 | +| Explicit solvers | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | πŸ“… | πŸ“… | πŸ“… | +| Implicit solvers (autodiff=false) | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | βœ”οΈβœ”οΈ | πŸ“… | πŸ“… | πŸ“… | +| Implicit solvers (autodiff=true) | βœ”οΈ | βœ”οΈβœ”οΈ | βœ”οΈ | πŸ“… | πŸ“… | πŸ“… | +| get/setState | βœ”οΈβœ”οΈ | πŸ“… | βœ”οΈβœ”οΈ | πŸ“… | 🚫 | 🚫 | +| getDirectionalDerivatives | βœ”οΈβœ”οΈ | πŸ“… | βœ”οΈβœ”οΈ | πŸ“… | 🚫 | 🚫 | +| getAdjointDerivatives | 🚫 | 🚫 | βœ”οΈβœ”οΈ | πŸ“… | 🚫 | 🚫 | | FMI Cross Checks | βœ”οΈβœ”οΈ | πŸ“… | πŸ“… | πŸ“… | 🚫 | 🚫 | -βœ”οΈβœ”οΈ supported & tested +βœ”οΈβœ”οΈ supported & CI-tested -βœ”οΈ beta supported (implemented), but untested +βœ”οΈ beta supported: implemented, but not CI-tested 🚧 work in progress @@ -87,6 +110,7 @@ To keep dependencies nice and clean, the original package [*FMI.jl*](https://git - [*FMI.jl*](https://github.com/ThummeTo/FMI.jl): High level loading, manipulating, saving or building entire FMUs from scratch - [*FMIImport.jl*](https://github.com/ThummeTo/FMIImport.jl): Importing FMUs into Julia - [*FMIExport.jl*](https://github.com/ThummeTo/FMIExport.jl): Exporting stand-alone FMUs from Julia Code +- [*FMIBase.jl*](https://github.com/ThummeTo/FMIBase.jl): Common concepts for import and export of FMUs - [*FMICore.jl*](https://github.com/ThummeTo/FMICore.jl): C-code wrapper for the FMI-standard - [*FMISensitivity.jl*](https://github.com/ThummeTo/FMISensitivity.jl): Static and dynamic sensitivities over FMUs - [*FMIBuild.jl*](https://github.com/ThummeTo/FMIBuild.jl): Compiler/Compilation dependencies for FMIExport.jl @@ -94,7 +118,7 @@ To keep dependencies nice and clean, the original package [*FMI.jl*](https://git - [*FMIZoo.jl*](https://github.com/ThummeTo/FMIZoo.jl): A collection of testing and example FMUs ## What Platforms are supported? -[*FMI.jl*](https://github.com/ThummeTo/FMI.jl) is tested (and testing) under Julia Versions *1.6 LTS* (64-bit) and *latest* (64-bit) on Windows *latest* (64-bit) and Ubuntu *latest* (64-bit). Mac and Julia (32-bit) should work, but untested. For the best performance, we recommend using Julia >= 1.7. +[*FMI.jl*](https://github.com/ThummeTo/FMI.jl) is tested (and testing) under Julia Versions *1.6 LTS* (64-bit) and *latest* (64-bit) on Windows *latest* (64-bit, 32-bit) and Ubuntu *latest* (64-bit). Mac (64-bit, 32-bit) and Ubuntu (32-bit) should work, but untested. For the best performance, we recommend using Julia >= 1.7, even if we support and test for the official LTS (1.6.7). ## How to cite? Tobias Thummerer, Lars Mikelsons and Josef Kircher. 2021. **NeuralFMU: towards structural integration of FMUs into neural networks.** Martin SjΓΆlund, Lena Buffoni, Adrian Pop and Lennart Ochel (Ed.). Proceedings of 14th Modelica Conference 2021, LinkΓΆping, Sweden, September 20-24, 2021. LinkΓΆping University Electronic Press, LinkΓΆping (LinkΓΆping Electronic Conference Proceedings ; 181), 297-306. [DOI: 10.3384/ecp21181297](https://doi.org/10.3384/ecp21181297) @@ -109,7 +133,4 @@ Contributors are welcome. Before contributing, please read, understand and follo During development of new implementations or optimizations on exisitng code, one will have to make design decissions that influence the library performance and usability. The following priorization should be the basis for decision-making: - **#1 Compliance with standard:** It is the highest priority to be compliant with the FMI standard ([fmi-standard.org](https://fmi-standard.org/)). Identifiers described in the standard must be used. Topologies should follow the specification as far as the possibilities of the Julia programming language allows. - **#2 Performance:** Because [*FMI.jl*](https://github.com/ThummeTo/FMI.jl) is a simulation tool, performance is very important. This applies to the efficient use of CPU and GPU, but also the conscientious use of RAM and disc space. -- **#3 Usability:** The library should be as usable as possible, as long as being fully compliant with the FMI standard. - -## Interested in Hybrid Modelling in Julia using FMUs? -See [*FMIFlux.jl*](https://github.com/ThummeTo/FMIFlux.jl). +- **#3 Usability:** The library should be as usable as possible and feel "the Julia way" (e.g. by using multiple dispatch instead of the "C coding style"), as long as being fully compliant with the FMI standard. diff --git a/cross_checks/README.md b/cross_checks/README.md index 6624f200..652e0845 100644 --- a/cross_checks/README.md +++ b/cross_checks/README.md @@ -8,9 +8,9 @@ More information: https://github.com/modelica/fmi-cross-check ### Automated run using github actions -The `..\.github\workflow` folder contains a `CrossChecks.yml` file that configures the excecution of the fmi cross checks using a github action. +The `..\.github\workflow` folder contains a `CrossChecks.yml` file that configures the execution of the FMI cross checks using a github action. -This action pulls the fmi cross checks from a repository, excecutes them and pushes the result files back to the repository. These specified repository needs to be forked before from https://github.com/modelica/fmi-cross-check. After forking the fmi-cross-check repository, a access token with repo rights needs to be generated (https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) +This action pulls the FMI cross checks from a repository, executes them and pushes the result files back to the repository. These specified repository needs to be forked before from https://github.com/modelica/fmi-cross-check. After forking the fmi-cross-check repository, a access token with repo rights needs to be generated (https://docs.github.com/en/authentication/keeping-your-account-and-data-secure/creating-a-personal-access-token) In order to use the action you need to be set the following information about your fmi-cross-check repository the FMI.jl repository as secrets and variables. @@ -18,7 +18,7 @@ In order to use the action you need to be set the following information about yo * (Variable) `CROSS_CHECK_REPO_USER`: The user that has write access to the fmi-cross-check repository and for which the token was created. (Example: `johndoe`) * (Secret) `CROSS_CHECK_REPO_TOKEN`: The github token that was created for the fmi-cross-check repository (Example: `ghp_IqHJF673SD...`) -Not setting these values correctly will prevent the results to be pushed to your fmi-cross-check repositoy. However you will still be able to see the result summary of your run in the github action logs. +Not setting these values correctly will prevent the results to be pushed to your fmi-cross-check repository. However you will still be able to see the result summary of your run in the github action logs. ### Manual run diff --git a/cross_checks/cross_check.jl b/cross_checks/cross_check.jl index b9dbe710..3408ee24 100644 --- a/cross_checks/cross_check.jl +++ b/cross_checks/cross_check.jl @@ -22,7 +22,7 @@ include("cross_check_lib.jl") # Main Array that holds all information about the excecuted cross checks and results crossChecks = [] -getInputValues = function(t, u) +getInputValues = function (t, u) return nothing end @@ -31,108 +31,158 @@ function parse_commandline() @add_arg_table s begin "--os" - help = "The operating system for which the cross checks should be excecuted" - arg_type = String - default = "windows-latest" + help = "The operating system for which the cross checks should be excecuted" + arg_type = String + default = "windows-latest" "--ccrepo" - help = "The Url to the git repository that contains the cross checks." - arg_type = String - default = "https://github.com/modelica/fmi-cross-check" + help = "The Url to the git repository that contains the cross checks." + arg_type = String + default = "https://github.com/modelica/fmi-cross-check" "--ccbranch" - help = "The name of the branch in which the results will be pushed" - arg_type = String - default = "master" + help = "The name of the branch in which the results will be pushed" + arg_type = String + default = "master" "--tempdir" - help = "temporary directive that is used for cross checks and results" - arg_type = String + help = "temporary directive that is used for cross checks and results" + arg_type = String "--fmiversion" - help = "FMI version that should be used for the cross checks" - arg_type = String - default = "2.0" + help = "FMI version that should be used for the cross checks" + arg_type = String + default = "2.0" "--includefatals" - help = "Include FMUs that have caused the cross check runner to fail and exit" - action = :store_true + help = "Include FMUs that have caused the cross check runner to fail and exit" + action = :store_true "--skipnotcompliant" - help = "Reject officially not compliant FMUs and don't excecute them" - action = :store_true + help = "Reject officially not compliant FMUs and don't excecute them" + action = :store_true "--commitrejected" - help = "Also commit the result file for FMUs that hasn't been excecuted (e.g. officially not compliant FMUs if they are not skipped)" - action = :store_true + help = "Also commit the result file for FMUs that hasn't been excecuted (e.g. officially not compliant FMUs if they are not skipped)" + action = :store_true "--commitfailed" - help = "Also commit the result file for failed FMUs" - action = :store_true + help = "Also commit the result file for failed FMUs" + action = :store_true end println("Arguments used for cross check:") - for (arg,val) in parse_args(s) + for (arg, val) in parse_args(s) println("\t$(arg):\t\t\t$(val)") end return parse_args(s) end -function runCrossCheckFmu(checkPath::String, resultPath::String, check::FmuCrossCheck, skipnotcompliant::Bool, commitrejected::Bool, commitfailed::Bool)::FmuCrossCheck +function runCrossCheckFmu( + checkPath::String, + resultPath::String, + check::FmuCrossCheck, + skipnotcompliant::Bool, + commitrejected::Bool, + commitfailed::Bool, +)::FmuCrossCheck pathToFMU = joinpath(checkPath, "$(check.fmuCheck).fmu") fmuToCheck = nothing - try + try if !(check.notCompliant && skipnotcompliant) - fmuToCheck = fmiLoad(pathToFMU) - fmiInfo(fmuToCheck) + fmuToCheck = loadFMU(pathToFMU) + info(fmuToCheck) hasInputValues = false # Read Options - fmuOptions = CSV.File(joinpath(checkPath, "$(check.fmuCheck)_ref.opt"), header=false) |> Dict + fmuOptions = + CSV.File( + joinpath(checkPath, "$(check.fmuCheck)_ref.opt"), + header = false, + ) |> Dict tStart = fmuOptions["StartTime"] tStop = fmuOptions["StopTime"] relTol = fmuOptions["RelTol"] # Read Ref values - fmuRecordValueNames = map((x) -> replace(strip(x),"\"" => "" ), (readdlm(joinpath(checkPath, "$(check.fmuCheck)_ref.csv"), ',', String)[1, 2:end])) - fmuRefValues = CSV.File(joinpath(checkPath, "$(check.fmuCheck)_ref.csv")) |> Tables.rowtable |> Tables.columntable + fmuRecordValueNames = map( + (x) -> replace(strip(x), "\"" => ""), + (readdlm(joinpath(checkPath, "$(check.fmuCheck)_ref.csv"), ',', String)[ + 1, + 2:end, + ]), + ) + fmuRefValues = + CSV.File(joinpath(checkPath, "$(check.fmuCheck)_ref.csv")) |> + Tables.rowtable |> + Tables.columntable if isfile(joinpath(checkPath, "$(check.fmuCheck)_in.csv")) - inputValues = CSV.File(joinpath(checkPath, "$(check.fmuCheck)_in.csv")) |> Tables.rowtable + inputValues = + CSV.File(joinpath(checkPath, "$(check.fmuCheck)_in.csv")) |> + Tables.rowtable hasInputValues = true - getInputValues = function(t, u) + getInputValues = function (t, u) for (valIndex, val) in enumerate(inputValues) if val.time >= t - u[:] = inputValues[valIndex][2:end] + u[:] = inputValues[valIndex][2:end] # a = collect(inputValues[valIndex])[2:end] # return a - break; + break end end end end - + if hasInputValues if check.type == CS - simData = fmiSimulateCS(fmuToCheck, (tStart, tStop); tolerance=relTol, saveat=fmuRefValues[1], inputFunction=getInputValues, inputValueReferences=:inputs, recordValues=fmuRecordValueNames) + simData = simulateCS( + fmuToCheck, + (tStart, tStop); + tolerance = relTol, + saveat = fmuRefValues[1], + inputFunction = getInputValues, + inputValueReferences = :inputs, + recordValues = fmuRecordValueNames, + ) elseif check.type == ME - simData = fmiSimulateME(fmuToCheck, (tStart, tStop); reltol=relTol, saveat=fmuRefValues[1], inputFunction=getInputValues, inputValueReferences=:inputs, recordValues=fmuRecordValueNames) + simData = simulateME( + fmuToCheck, + (tStart, tStop); + reltol = relTol, + saveat = fmuRefValues[1], + inputFunction = getInputValues, + inputValueReferences = :inputs, + recordValues = fmuRecordValueNames, + ) else @error "Unkown FMU Type. Only 'cs' and 'me' are valid types" end else if check.type == CS - simData = fmiSimulateCS(fmuToCheck, (tStart, tStop); tolerance=relTol, saveat=fmuRefValues[1], recordValues=fmuRecordValueNames) + simData = simulateCS( + fmuToCheck, + (tStart, tStop); + tolerance = relTol, + saveat = fmuRefValues[1], + recordValues = fmuRecordValueNames, + ) elseif check.type == ME - simData = fmiSimulateME(fmuToCheck, (tStart, tStop); reltol=relTol, saveat=fmuRefValues[1], recordValues=fmuRecordValueNames) + simData = simulateME( + fmuToCheck, + (tStart, tStop); + reltol = relTol, + saveat = fmuRefValues[1], + recordValues = fmuRecordValueNames, + ) else @error "Unkown FMU Type. Only 'cs' and 'me' are valid types" end end - + check.result = calucateNRMSE(fmuRecordValueNames, simData, fmuRefValues) check.skipped = false - + if (check.result < NRMSE_THRESHHOLD) check.success = true mkpath(resultPath) cd(resultPath) - rm("failed", force=true) - rm("rejected", force=true) - rm("README.md", force=true) + rm("failed", force = true) + rm("rejected", force = true) + rm("README.md", force = true) touch("passed") touch("README.md") file = open("README.md", "w") @@ -143,9 +193,9 @@ function runCrossCheckFmu(checkPath::String, resultPath::String, check::FmuCross if commitfailed mkpath(resultPath) cd(resultPath) - rm("passed", force=true) - rm("rejected", force=true) - rm("README.md", force=true) + rm("passed", force = true) + rm("rejected", force = true) + rm("README.md", force = true) touch("failed") end end @@ -154,9 +204,9 @@ function runCrossCheckFmu(checkPath::String, resultPath::String, check::FmuCross if commitrejected mkpath(resultPath) cd(resultPath) - rm("failed", force=true) - rm("passed", force=true) - rm("README.md", force=true) + rm("failed", force = true) + rm("passed", force = true) + rm("README.md", force = true) touch("rejected") end end @@ -165,26 +215,26 @@ function runCrossCheckFmu(checkPath::String, resultPath::String, check::FmuCross @warn e check.result = nothing check.skipped = false - io = IOBuffer(); + io = IOBuffer() showerror(io, e) check.error = String(take!(io)) check.success = false mkpath(resultPath) cd(resultPath) - rm("rejected", force=true) - rm("passed", force=true) - rm("README.md", force=true) + rm("rejected", force = true) + rm("passed", force = true) + rm("README.md", force = true) if commitfailed touch("failed") end finally try - fmiUnload(fmuToCheck) + unloadFMU(fmuToCheck) catch end end return check - + end function main() @@ -215,27 +265,37 @@ function main() # set up the github access for the fmi-cross-checks repo and checkout the respective branch github_token = get(ENV, "GITHUB_TOKEN", "") - tmp_dir = mktempdir(; cleanup=true) + tmp_dir = mktempdir(; cleanup = true) pkey_filename = create_ssh_private_key(tmp_dir, github_token, os) if os == "win64" pkey_filename = replace(pkey_filename, "\\" => "/") end - + cross_check_repo_name = get(ENV, "CROSS_CHECK_REPO_NAME", "") cross_check_repo_user = get(ENV, "CROSS_CHECK_REPO_USER", "") if github_token != "" && cross_check_repo_name != "" && cross_check_repo_user != "" withenv( - "GIT_SSH_COMMAND" => isnothing(github_token) ? "ssh" : "ssh -i $pkey_filename -o StrictHostKeyChecking=no" + "GIT_SSH_COMMAND" => + isnothing(github_token) ? "ssh" : + "ssh -i $pkey_filename -o StrictHostKeyChecking=no", ) do run( - Cmd(`$(git()) remote set-url origin git@github.com:$cross_check_repo_user/$cross_check_repo_name`, dir=fmiCrossCheckRepoPath) + Cmd( + `$(git()) remote set-url origin git@github.com:$cross_check_repo_user/$cross_check_repo_name`, + dir = fmiCrossCheckRepoPath, + ), ) end try - run(Cmd(`$(git()) checkout $(crossCheckBranch)`, dir=fmiCrossCheckRepoPath)) + run(Cmd(`$(git()) checkout $(crossCheckBranch)`, dir = fmiCrossCheckRepoPath)) catch - run(Cmd(`$(git()) checkout -b $(crossCheckBranch)`, dir=fmiCrossCheckRepoPath)) + run( + Cmd( + `$(git()) checkout -b $(crossCheckBranch)`, + dir = fmiCrossCheckRepoPath, + ), + ) end end @@ -244,31 +304,64 @@ function main() if !includeFatals crossChecks = filter(c -> (!(c.system in EXCLUDED_SYSTEMS)), crossChecks) end - + for (index, check) in enumerate(crossChecks) - checkPath = joinpath(fmiCrossCheckRepoPath, "fmus", check.fmiVersion, check.type, check.os, check.system, check.systemVersion, check.fmuCheck) - resultPath = joinpath(fmiCrossCheckRepoPath, "results", check.fmiVersion, check.type, check.os, TOOL_ID, TOOL_VERSION, check.system, check.systemVersion, check.fmuCheck) + checkPath = joinpath( + fmiCrossCheckRepoPath, + "fmus", + check.fmiVersion, + check.type, + check.os, + check.system, + check.systemVersion, + check.fmuCheck, + ) + resultPath = joinpath( + fmiCrossCheckRepoPath, + "results", + check.fmiVersion, + check.type, + check.os, + TOOL_ID, + TOOL_VERSION, + check.system, + check.systemVersion, + check.fmuCheck, + ) cd(checkPath) println("Checking $check for $checkPath and expecting $resultPath") - check = runCrossCheckFmu(checkPath, resultPath, check, skipnotcompliant, commitrejected, commitfailed) + check = runCrossCheckFmu( + checkPath, + resultPath, + check, + skipnotcompliant, + commitrejected, + commitfailed, + ) crossChecks[index] = check end println("#################### End FMI Cross checks Run ####################") - + # Write Summary of Cross Check run println("#################### Start FMI Cross check Summary ####################") println("\tTotal Cross checks:\t\t\t$(count(c -> (true), crossChecks))") println("\tSuccessfull Cross checks:\t\t$(count(c -> (c.success), crossChecks))") - println("\tFailed Cross checks:\t\t\t$(count(c -> (!c.success && c.error === nothing && !c.skipped), crossChecks))") - println("\tCross checks with errors:\t\t$(count(c -> (c.error !== nothing), crossChecks))") + println( + "\tFailed Cross checks:\t\t\t$(count(c -> (!c.success && c.error === nothing && !c.skipped), crossChecks))", + ) + println( + "\tCross checks with errors:\t\t$(count(c -> (c.error !== nothing), crossChecks))", + ) println("\tSkipped Cross checks:\t\t\t$(count(c -> (c.skipped), crossChecks))") println("\tList of successfull Cross checks") for (index, success) in enumerate(filter(c -> (c.success), crossChecks)) println("\u001B[32m\t\t$(index):\t$(success)\u001B[0m") end println("\tList of failed Cross checks") - for (index, success) in enumerate(filter(c -> (!c.success && c.error === nothing && !c.skipped), crossChecks)) + for (index, success) in enumerate( + filter(c -> (!c.success && c.error === nothing && !c.skipped), crossChecks), + ) println("\u001B[33m\t\t$(index):\t$(success)\u001B[0m") end println("\tList of Cross checks with errors") @@ -276,21 +369,33 @@ function main() println("\u001B[31m\t\t$(index):\t$(error)\u001B[0m") end println("#################### End FMI Cross check Summary ####################") - + if github_token != "" && cross_check_repo_name != "" && cross_check_repo_user != "" - run(Cmd(`$(git()) add -A`, dir=fmiCrossCheckRepoPath)) - run(Cmd(`$(git()) commit -a --allow-empty -m "Run FMI cross checks for FMI.JL"`, dir=fmiCrossCheckRepoPath)) - + run(Cmd(`$(git()) add -A`, dir = fmiCrossCheckRepoPath)) + run( + Cmd( + `$(git()) commit -a --allow-empty -m "Run FMI cross checks for FMI.JL"`, + dir = fmiCrossCheckRepoPath, + ), + ) + withenv( - "GIT_SSH_COMMAND" => isnothing(github_token) ? "ssh" : "ssh -i $pkey_filename -o StrictHostKeyChecking=no" + "GIT_SSH_COMMAND" => + isnothing(github_token) ? "ssh" : + "ssh -i $pkey_filename -o StrictHostKeyChecking=no", ) do try - run(Cmd(`$(git()) push`, dir=fmiCrossCheckRepoPath)) + run(Cmd(`$(git()) push`, dir = fmiCrossCheckRepoPath)) catch - run(Cmd(`$(git()) push --set-upstream origin $(crossCheckBranch)`, dir=fmiCrossCheckRepoPath)) + run( + Cmd( + `$(git()) push --set-upstream origin $(crossCheckBranch)`, + dir = fmiCrossCheckRepoPath, + ), + ) end end - rm(tmp_dir; force=true, recursive=true) + rm(tmp_dir; force = true, recursive = true) end end diff --git a/cross_checks/cross_check_config.jl b/cross_checks/cross_check_config.jl index 63007057..1cd1d9b8 100644 --- a/cross_checks/cross_check_config.jl +++ b/cross_checks/cross_check_config.jl @@ -9,40 +9,7 @@ const TOOL_VERSION = "0.9.2" const FMI_CROSS_CHECK_REPO_NAME = "fmi-cross-check" const NRMSE_THRESHHOLD = 5 const EXCLUDED_SYSTEMS = ["AMESim", "Test-FMUs", "SimulationX", "Silver"] -const CROSS_CHECK_README_CONTENT = -"# FMI.jl - -## How can I use FMI.jl? -1\\. Open a Julia-REPL, switch to package mode using `]`, activate your preferred environment.\n - -2\\. Install [*FMI.jl*](https://github.com/ThummeTo/FMI.jl):\n -```julia-repl -(@v1.6) pkg> add FMI -``` - -3\\. If you want to check that everything works correctly, you can run the tests bundled with [*FMI.jl*](https://github.com/ThummeTo/FMI.jl):\n -```julia-repl -(@v1.6) pkg> test FMI -``` - -4\\. Have a look inside the [examples folder](https://github.com/ThummeTo/FMI.jl/tree/examples/examples) in the examples branch or the [examples section](https://thummeto.github.io/FMI.jl/dev/examples/overview/) of the documentation. All examples are available as Julia-Script (*.jl*), Jupyter-Notebook (*.ipynb*) and Markdown (*.md*). - -## How can I simulate a FMU and plot values? -```julia -using FMI, Plots - -# load and instantiate a FMU -myFMU = fmiLoad(pathToFMU) - -# simulate from t=0.0s until t=10.0s and record the FMU variable named 'mass.s' -simData = fmiSimulate(myFMU, 0.0, 10.0; recordValues=['mass.s']) - -# plot it! -fmiPlot(simData) - -# free memory -fmiUnload(myFMU) -```" +const CROSS_CHECK_README_CONTENT = "See https://github.com/ThummeTo/FMI.jl for more information." #static strings const ME = "me" diff --git a/cross_checks/cross_check_lib.jl b/cross_checks/cross_check_lib.jl index 726fcc01..78cfb852 100644 --- a/cross_checks/cross_check_lib.jl +++ b/cross_checks/cross_check_lib.jl @@ -13,11 +13,14 @@ Hint: This will not check the cross check repository for integrety # Returns - `repoPath::String`: The path where the repository can be found locally (including the repository name) """ -function getFmuCrossCheckRepo(crossCheckRepo::String, unpackPath::Union{String, Nothing} = nothing)::String +function getFmuCrossCheckRepo( + crossCheckRepo::String, + unpackPath::Union{String,Nothing} = nothing, +)::String @info "Create temporary working directory" if unpackPath === nothing # cleanup=true leads to issues with automatic testing on linux server. - unpackPath = mktempdir(; prefix="fmicrosschecks_", cleanup=false) + unpackPath = mktempdir(; prefix = "fmicrosschecks_", cleanup = false) @info "temporary working directory created at $(unpackPath)" end @@ -25,7 +28,7 @@ function getFmuCrossCheckRepo(crossCheckRepo::String, unpackPath::Union{String, fmiCrossCheckRepoPath = joinpath(unpackPath, FMI_CROSS_CHECK_REPO_NAME) if !isdir(fmiCrossCheckRepoPath) println("Checking out cross-checks from $(crossCheckRepo)...") - run(Cmd(`$(git()) clone $(crossCheckRepo)`, dir=unpackPath)) + run(Cmd(`$(git()) clone $(crossCheckRepo)`, dir = unpackPath)) else println("Using existing cross-checks at $(fmiCrossCheckRepoPath)") end @@ -39,7 +42,11 @@ Returns a array of all available FMI Cross Checks - `fmiVersion::String`: FMI Version used for running the FMUs. Note: Currently only 2.0 officially supported - `os::String`: The operating system that is used for running the FMUs """ -function getFmusToTest(repoPath::String, fmiVersion::String, os::String)::Vector{FmuCrossCheck} +function getFmusToTest( + repoPath::String, + fmiVersion::String, + os::String, +)::Vector{FmuCrossCheck} results = [] fmiTypes = [ME, CS] for type in fmiTypes @@ -65,7 +72,22 @@ function getFmusToTest(repoPath::String, fmiVersion::String, os::String)::Vector @info "$checkPath is not compliant with latest rules" notCompliant = true end - push!(results, FmuCrossCheck(fmiVersion, type, os, system, version, check, notCompliant, missing, missing, missing, missing)) + push!( + results, + FmuCrossCheck( + fmiVersion, + type, + os, + system, + version, + check, + notCompliant, + missing, + missing, + missing, + missing, + ), + ) end end end @@ -78,12 +100,16 @@ Calculate the mean of all normalized root mean square errors for the different v It is normalized to the difference between the smallest and largest values of the respective variable # Arguments - `recordedVariables::Vector{String}`: List of all variable names that were recorded within the FMU simulation -- `simData::FMU2Solution`: The solution data of the FMU (returned values of fmiSimulate()) +- `simData::FMUSolution`: The solution data of the FMU (returned values of fmiSimulate()) - `referenceData::Table`: Reference data that was provided with the cross check FMU that is used as basis for the error calculation # Returns - `nrmse::Float64`: the mean of the nrmse of all recorded variables """ -function calucateNRMSE(recordedVariables::Vector{String}, simData::FMU2Solution, referenceData)::Float64 +function calucateNRMSE( + recordedVariables::Vector{String}, + simData::FMUSolution, + referenceData, +)::Float64 squaredErrorSums = zeros(length(recordedVariables)) valueCount = zeros(length(recordedVariables)) minimalValues = [] @@ -96,16 +122,26 @@ function calucateNRMSE(recordedVariables::Vector{String}, simData::FMU2Solution, if (length(minimalValues) < nameIndex + 1) push!(minimalValues, referenceData[nameIndex+1][valIndex]) else - minimalValues[nameIndex] = min(minimalValues[nameIndex], referenceData[nameIndex+1][valIndex]) + minimalValues[nameIndex] = min( + minimalValues[nameIndex], + referenceData[nameIndex+1][valIndex], + ) end if (length(maximalValues) < nameIndex + 1) push!(maximalValues, referenceData[nameIndex+1][valIndex]) else - maximalValues[nameIndex] = max(maximalValues[nameIndex], referenceData[nameIndex+1][valIndex]) + maximalValues[nameIndex] = max( + maximalValues[nameIndex], + referenceData[nameIndex+1][valIndex], + ) end - squaredErrorSums[nameIndex] += ((simData.values.saveval[simIndex][nameIndex] - referenceData[nameIndex+1][valIndex]))^2 + squaredErrorSums[nameIndex] += + (( + simData.values.saveval[simIndex][nameIndex] - + referenceData[nameIndex+1][valIndex] + ))^2 end - break; + break end end end @@ -115,13 +151,18 @@ function calucateNRMSE(recordedVariables::Vector{String}, simData::FMU2Solution, if (valueRange == 0) valueRange = 1 end - value = (sqrt(squaredErrorSums[recordValue]/valueCount[recordValue])/(valueRange)) + value = + (sqrt(squaredErrorSums[recordValue] / valueCount[recordValue]) / (valueRange)) push!(errors, value) end return mean(errors) end -function create_ssh_private_key(dir::AbstractString, ssh_pkey::AbstractString, os::AbstractString)::String +function create_ssh_private_key( + dir::AbstractString, + ssh_pkey::AbstractString, + os::AbstractString, +)::String is_linux = occursin("linux", os) if is_linux run(`chmod 700 $dir`) @@ -158,10 +199,8 @@ function decode_ssh_private_key(content::AbstractString)::String return content end - @info( - "This doesn't look like a raw SSH private key. - I will assume that it is a Base64-encoded SSH private key." - ) + @info("This doesn't look like a raw SSH private key. + I will assume that it is a Base64-encoded SSH private key.") decoded_content = String(Base64.base64decode(content)) return decoded_content -end \ No newline at end of file +end diff --git a/docs/Project.toml b/docs/Project.toml index 71ee3c6b..7d97ca60 100644 --- a/docs/Project.toml +++ b/docs/Project.toml @@ -2,6 +2,7 @@ CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" +FMIBase = "900ee838-d029-460e-b485-d98a826ceef2" FMICore = "8af89139-c281-408e-bce2-3005eb87462f" FMIImport = "9fcbc62e-52a0-44e9-a616-1359a0008194" JLD2 = "033835bb-8acc-5ee8-8aae-3f567f8a3819" diff --git a/docs/make.jl b/docs/make.jl index f00ca742..e5c39723 100644 --- a/docs/make.jl +++ b/docs/make.jl @@ -4,7 +4,7 @@ # import Pkg; Pkg.develop(path=joinpath(@__DIR__,"../../FMI.jl")) -using Documenter, Plots, JLD2, DataFrames, CSV, MAT, FMI, FMIImport, FMICore +using Documenter, Plots, JLD2, DataFrames, CSV, MAT, FMI, FMIBase, FMIImport, FMICore using Documenter: GitHubActions makedocs(sitename="FMI.jl", @@ -15,10 +15,10 @@ makedocs(sitename="FMI.jl", size_threshold = 512000, size_threshold_ignore = ["deprecated.md"] ), - modules = [FMI, FMIImport, FMICore], + modules = [FMI, FMIImport, FMICore, FMIBase], checkdocs=:exports, linkcheck=true, - linkcheck_ignore=["https://thummeto.github.io/FMI.jl/dev/examples/inputs/", "https://github.com/ThummeTo/FMICore.jl/blob/main/src/FMI2_c.jl#L718"], + #linkcheck_ignore=["https://thummeto.github.io/FMI.jl/dev/examples/inputs/", "https://github.com/ThummeTo/FMICore.jl/blob/main/src/FMI2_c.jl#L718"], pages= Any[ "Introduction" => "index.md" "Features" => "features.md" @@ -36,12 +36,11 @@ makedocs(sitename="FMI.jl", "User Level API - FMI.jl" => "library.md" "Developer Level API" => Any[ "fmi version independent content" => Any[ - "fmi_lowlevel_library_types.md", "fmi_lowlevel_library_constants.md", + "fmi_lowlevel_modeldescription_functions.md", "fmi_lowlevel_library_functions.md" ], "FMI2 specific content" => Any[ - "fmi2_lowlevel_library_types.md", "fmi2_lowlevel_library_constants.md", "FMI2 Functions in FMI Import/Core .jl" => Any[ "fmi2_lowlevel_modeldescription_functions.md", @@ -51,7 +50,6 @@ makedocs(sitename="FMI.jl", ] ], "FMI3 specific content" => Any[ - "fmi3_lowlevel_library_types.md", "fmi3_lowlevel_library_constants.md", "FMI3 Functions in FMI Import/Core .jl" => Any[ "fmi3_lowlevel_modeldescription_functions.md", @@ -61,14 +59,15 @@ makedocs(sitename="FMI.jl", "fmi3_lowlevel_SE_functions.md", ] ], - ] - "API Index" => "index_library.md" - "FMI Tool Information" => "fmi-tool-info.md" - "Related Publication" => "related.md" - "Contents" => "contents.md" - hide("Deprecated" => "deprecated.md") + ], ] - ) + "API Index" => "index_library.md" + "FMI Tool Information" => "fmi-tool-info.md" + "Related Publication" => "related.md" + "Contents" => "contents.md" + hide("Deprecated" => "deprecated.md") + ], +) function deployConfig() github_repository = get(ENV, "GITHUB_REPOSITORY", "") @@ -80,4 +79,8 @@ function deployConfig() return GitHubActions(github_repository, github_event_name, github_ref) end -deploydocs(repo = "github.com/ThummeTo/FMI.jl.git", devbranch = "main", deploy_config = deployConfig()) +deploydocs( + repo = "github.com/ThummeTo/FMI.jl.git", + devbranch = "main", + deploy_config = deployConfig(), +) diff --git a/docs/src/assets/FMI_JL_family.pdf b/docs/src/assets/FMI_JL_family.pdf index 338448d3..bf38dd10 100644 Binary files a/docs/src/assets/FMI_JL_family.pdf and b/docs/src/assets/FMI_JL_family.pdf differ diff --git a/docs/src/assets/FMI_JL_family.png b/docs/src/assets/FMI_JL_family.png index 5e81fd6e..e4e58a13 100644 Binary files a/docs/src/assets/FMI_JL_family.png and b/docs/src/assets/FMI_JL_family.png differ diff --git a/docs/src/deprecated.md b/docs/src/deprecated.md index 0ca063a4..df4ee2de 100644 --- a/docs/src/deprecated.md +++ b/docs/src/deprecated.md @@ -4,53 +4,11 @@ this doc page is necessary as all exported functions must be documented in the m ### internal functions: remove export? ```@docs -fmi2CallbackLogger -fmi2CallbackAllocateMemory -fmi2CallbackFreeMemory -fmi3CallbackLogger fmi2CallbackFunctions -fmi2CallbackStepFinished ``` ### deprecated Mostly wrappers that are not supposed to be used (call specific wrapped functions instead) ```@docs -fmiSetReal -fmiReset -fmiGetGenerationTool -fmiEnterContinuousTimeMode -fmiGetEventIndicators -fmiSetBoolean -fmiFreeInstance! -fmiInstantiate! -fmiTerminate -fmiDoStep -fmiSetInteger -fmiCompletedIntegratorStep -fmiExitInitializationMode -fmiSetupExperiment -fmiSetDebugLogging -fmiSerializedFMUstateSize -fmiSerializeFMUstate -fmiDeSerializeFMUstate -fmiEnterInitializationMode -fmiGetDirectionalDerivative! -fmiNewDiscreteStates -fmiGetDirectionalDerivative -fmiSetRealInputDerivatives -fmiGetGenerationDateAndTime -fmiGetContinuousStates -fmiSetContinuousStates -fmiGetNominalsOfContinuousStates -fmiSetTime -fmiSetString -fmiGetString -fmiGetString! -fmiGetInteger -fmiGetInteger! -fmiGetReal -fmiGetReal! -fmiGetBoolean -fmiGetBoolean! ``` diff --git a/docs/src/examples/overview.md b/docs/src/examples/overview.md index e9443e33..8066db28 100644 --- a/docs/src/examples/overview.md +++ b/docs/src/examples/overview.md @@ -10,7 +10,6 @@ Examples are subdevided into *Basics*, *Advanced* and *Publication appendices*. - [__Simulate__](https://thummeto.github.io/FMI.jl/dev/examples/simulate/): Showing how you can simulate a CS-FMU and a ME-FMU. - [__Parameterize__](https://thummeto.github.io/FMI.jl/dev/examples/parameterize/): A short example explaining how to parameterize a FMU before simulation. -- [__Inputs__](https://thummeto.github.io/FMI.jl/dev/examples/inputs/): A short example explaining how to simulate a FMU with inputs. **Advanced examples:** diff --git a/docs/src/features.md b/docs/src/features.md index e96b08a2..d3813c28 100644 --- a/docs/src/features.md +++ b/docs/src/features.md @@ -1,53 +1,55 @@ # Features Please note, that this guide focuses also on users, that are not familiar with FMI. The following feature explanations are written in an easy-to-read-fashion, so there might be some points that are scientifically only 95% correct. For further information on FMI and FMUs, see [fmi-standard.org](https://fmi-standard.org/). +The term `fmiX...` refers to a value or function that is available along different versions of FMI, for example `fmiXValueReference` is a wildcard for `fmi2ValueReference` and `fmi3ValueReference`. ## Execution Configuration Not all FMUs support all features they should according to the FMI-standard, so *FMI.jl* provides a so called *execution configuration*. This configuration is also respected by *FMIFlux.jl*. The content of the execution configuration may change in future (together with new or deprecated features of linked libraries), but the most important core features will be kept over time. Because not all users need the full potential of this configuration tool, there are three presets given: -- `myFMU.executionConfig = FMU2_EXECUTION_CONFIGURATION_NO_RESET` is the default operation mode for FMUs. FMUs are not reset via `fmi2Reset`, but new instantiated for every simulation run (or training step). This is not the most efficient way, but many FMUs have problems with resetting. -- `myFMU.executionConfig = FMU2_EXECUTION_CONFIGURATION_RESET` is faster for well-implemented FMUs, but needs a fully working `fmi2Reset`-function. So if you know you have a fully working `fmi2Reset`, you may be faster with that option. -- `myFMU.executionConfig = FMU2_EXECUTION_CONFIGURATION_NO_FREEING` should only be the very last choice. If your FMU neither supports `fmi2Reset` nor a proper `fmi2FreeInstance`, you could use this configuration as a last way out. Keep in mind, that new FMU instances are allocated but not freed, as long as your Julia instance is running (memory leak). In general, the amount of leaked memory is small, but you need to know what you are doing, if you do thousands or ten-thousands of simulation runs with such a FMU. -- `myFMU.executionConfig = FMU2_EXECUTION_CONFIGURATION_NOTHING` should be used if you want maximum control over what is done and what not. This means you need to take care of instantiating, initialization, setting up and releasing FMU instances by yourself. +- `myFMU.executionConfig = FMU_EXECUTION_CONFIGURATION_NO_RESET` is the default operation mode for FMUs. FMUs are not reset via `fmi2Reset`, but new instantiated for every simulation run (or training step). This is not the most efficient way, but many FMUs have problems with resetting. +- `myFMU.executionConfig = FMU_EXECUTION_CONFIGURATION_RESET` is faster for well-implemented FMUs, but needs a fully working `fmi2Reset`-function. So if you know you have a fully working `fmi2Reset`, you may be faster with that option. +- `myFMU.executionConfig = FMU_EXECUTION_CONFIGURATION_NO_FREEING` should only be the very last choice. If your FMU neither supports `fmi2Reset` nor a proper `fmi2FreeInstance`, you could use this configuration as a last way out. Keep in mind, that new FMU instances are allocated but not freed, as long as your Julia instance is running (memory leak). In general, the amount of leaked memory is small, but you need to know what you are doing, if you do thousands or ten-thousands of simulation runs with such a FMU. +- `myFMU.executionConfig = FMU_EXECUTION_CONFIGURATION_NOTHING` should be used if you want maximum control over what is done and what not. This means you need to take care of instantiating, initialization, setting up and releasing FMU instances by yourself. +For a more detailed overview, please see the `?FMUExecutionConfig`. ## Debugging / Logging ### Logging FMI-calls -To log all FMI-calls that happen (including "hidden" calls e.g. if you are using `fmiSimulate`) you can enable debugging for *FMICore.jl* using `ENV["JULIA_DEBUG"] = "FMICore"`. This will log any `fmi2xxx`-call, including the given parameters and return value. +To log all FMI-calls that happen (including "hidden" calls e.g. if you are using `simulate`) you can enable debugging for *FMICore.jl* using `ENV["JULIA_DEBUG"] = "FMICore"`. This will log any `fmi2xxx`- and `fmi3xxx`-call, including the given parameters and return value. This can be *a lot* of calls, so you may want to redirect your REPL output to file. ### Printing internal FMU messages -Many FMUs support for printing debugging messages. To force message printing, you can use the keyword `logginOn=true` either ... +Many FMUs support for printing debugging messages. To force message printing, you can use the keyword `loggingOn=true` either ... - in the call `fmiInstantiate`, for example `fmiInstantiate(myFMU; loggingOn=true)` or - as part of the `executionConfig`, for example `myFMU.executionConfig.loggingOn=true` You can further control which message types - like `OK`, `Warning`, `Discard`, `Error`, `Fatal`, `Pending` - should be logged by using the keywords `logStatus{TYPE}=true` as part of `fmiInstantiate` or (soon) the execution configuration. By default, all are activated. -If the FMU uses a variadic callback function for messages (this is not supported by Julia at this time), you may need to activate external callbacks with the keyword `externalCallbacks=true` either ... +If your FMU (for FMI2 only, FMI3 changed this) uses a variadic callback function for messages (this is not supported by Julia at this time), you may need to activate external callbacks with the keyword `externalCallbacks=true` either ... - in the call `fmiInstantiate!`, for example `fmiInstantiate!(myFMU; loggingOn=true, externalCallbacks=true)` or - as part of the `executionConfig`, for example `myFMU.executionConfig.loggingOn=true; myFMU.executionConfig.externalCallbacks=true` -Note, that external callbacks are currently only supported on Windows. +External callbacks are currently only supported on Windows and Linux. ## Model variable identification *FMI.jl* offers multiple ways to retrieve your model variables. Any function that accepts a variable identifier can handle the following argument types: -- `UInt32` or `fmi2ValueReference` for example `1610612742` or `0x16000001`: This is the most performant way of passing a variable identifier, but you need to know the *value reference* (you can determine them by having a look in the `modelDescription.xml`). -- `Array{UInt32}` or `Array{fmi2ValueReference}` for example `[1610612742, 1610612743]` or `[0x16000001, 0x16000002]`: This is the most performant way of passing multiple variable identifiers, but you need to know the *value references*. +- `UInt32` or `fmiXValueReference` for example `1610612742` or `0x16000001`: This is the most performant way of passing a variable identifier, but you need to know the *value reference* (you can determine them by having a look in the `modelDescription.xml`). +- `Vector{UInt32}` or `Vector{fmiXValueReference}` for example `[1610612742, 1610612743]` or `[0x16000001, 0x16000002]`: This is the most performant way of passing multiple variable identifiers, but you need to know the *value references*. - `String` for example `"ball.s"`: This is the most intuitive way, because you might already know the variable name from your modelling environment or model documentation. -- `Array{String}` for example `["ball.s", "der(ball.s)"]`: This is the most intuitive way for multiple variable identifiers, because you might already know the variable names from your modelling environment or model documentation. +- `Vector{String}` for example `["ball.s", "der(ball.s)"]`: This is the most intuitive way for multiple variable identifiers, because you might already know the variable names from your modelling environment or model documentation. - `Symbol` for example `:states`: There are multiple symbol-wildcards for interesting variable groups like `:all`, `:none`, `:states`, `:derivatives`, `:inputs` and `:outputs`. - `nothing`: If you don't want to record anything (same as `:none`) ## Event handling -In FMI2, there are basically two types of events: state and time. +In FMI, there are basically two types of events: state and time. State events are triggered, as soon as one or more *event indicators* - scalar values that describe the "distance" in state space to the next state event - crossing zero. Time events are triggered at known time points during the simulation. If your model has state and/or time events is detected automatically by *FMI.jl* and the event handling happens automatically in the background. -## Model exchange (ME) and co-simulation (CS) -There are two different model types for FMUs in FMI2: Model exchange (ME) and co-simulation (CS). -If you have a FMU and are only interested in getting it simulated, use `fmiSimulate` so *FMI.jl* will automatically pick CS if available and otherwise ME. -If you want to force a specific simulation mode, you can use `fmiSimulateME` (for ME) or `fmiSimulateCS` (for CS). +## Model exchange, co-simulation and scheduled execution +There are two different model types for FMUs in FMI2: Model exchange (ME) and co-simulation (CS). FMI3 further adds the mode scheduled execution (SE). +If you have a FMU and are only interested in getting it simulated, use `simulate` so *FMI.jl* will automatically pick CS if available and otherwise ME. +If you want to force a specific simulation mode, you can use `simulateME` (for ME), `simulateCS` (for CS) or `simulateSE` (for SE). ## Simulate arbitrary time intervals -You can simply simulate arbitrary time intervals by passing a `startTime` unequal zero to `fmi2SetupExperiment`. -Because many FMUs don't support `startTime != 0.0` and will throw an error or warning, a time shifting feature inside *FMI.jl* can be used, that performs all necessary steps in the background - corresponding commands like e.g. `fmi2SetTime` or `fmi2NewDiscreteStates` act like the desired time interval is simulated. +You can simply simulate arbitrary time intervals by passing a `startTime` unequal zero to `fmi2SetupExperiment` or [ToDo: corresponding FMI3 function]. +Because some FMUs don't support `startTime != 0.0` and will throw an error or warning, a time shifting feature inside *FMI.jl* can be used, that performs all necessary steps in the background - corresponding commands like e.g. `fmi2SetTime` or `fmi2NewDiscreteStates` act like the desired time interval is simulated. This feature is disabled by default, but can be activated in the execution configuration using `myFMU.executionConfig.autoTimeShift=true` while providing a `startTime != 0.0`. ## Performance @@ -60,13 +62,13 @@ Of course, you have to use the same piece of memory (to write your return values **Views:** You can use [array-views](https://docs.julialang.org/en/v1/base/arrays/#Views-(SubArrays-and-other-view-types)) instead of array-slices as input for in-place-functions, which further reduces memory allocations. -## AD-Ecosystem (Differentiation over FMUs) -Sensitivities over FMUs are fully integrated into *FMI.jl*, *FMIImport.jl* and *FMIFlux.jl*. Supported are *ForwardDiff.jl* together with all AD-frameworks, that use the interface of *ChainRules.jl* like e.g. *Zygote.jl*. As a result, you can use implicit solvers or you can use FMUs as part of machine learning applications. +## AD-Ecosystem (differentiation over FMUs) +Sensitivites over FMUs are fully integrated into *FMI.jl*, *FMIImport.jl* and *FMIFlux.jl*. Supported are *ForwardDiff.jl* together with all AD-frameworks, that use the interface of *ChainRules.jl* like e.g. *Zygote.jl* and *ReverseDiff.jl*. As a result, you can use implicit solvers or you can use FMUs as part of machine learning applications. ## Watch your progress -When simulating FMUs with *FMI.jl*, a progress meter is shown per default. You can control the appearance via the keyword argument `showProgress` for `fmiSimulate`, `fmiSimulateME` and `fmiSimulateCS`. +When simulating FMUs with *FMI.jl*, a progress meter is shown per default. You can control the appearance via the keyword argument `showProgress` for `simulate`, `simulateME`, `simulateCS` and `simulateSE`. Progress meters are also available for *FMIFlux.jl*, but deactivated by default (during training, this can be a bit too much). When evaluating a NeuralFMU, you can use the same keyword with `showProgress=true` to show a progress bar during training, too. -The simulation trajectory (also called the *solution* of your FMU's ODE system) can be plotted using `fmiPlot(myFMU, solution)`, all axis will be labeled automatically. +The simulation trajectory (also called the *solution* of your FMU's ODE system) can be plotted using `plot(solution)`, all axis will be labeled automatically. ## Parallelization -A native integrated support for multi-threaded and multi-process FMU-simulation will be deployed soon. \ No newline at end of file +A native integrated support for multi-threaded and multi-process FMU-simulation (for example for Monte Carlo experiments) will be deployed soon. \ No newline at end of file diff --git a/docs/src/fmi-tool-info.md b/docs/src/fmi-tool-info.md index 9a3b4eb3..85fd3f38 100644 --- a/docs/src/fmi-tool-info.md +++ b/docs/src/fmi-tool-info.md @@ -27,5 +27,5 @@ Detailed export information and automatically generated FMUs will be deployed so | NeuralFMU | [ME](https://github.com/ThummeTo/FMIExport.jl/tree/main/examples/FMI2/NeuralFMU) | coming soon | ## Validation tools -- [Dassault Dymola 2022X](https://www.3ds.com/de/produkte-und-services/catia/produkte/dymola/) +- [Dassault Dymola 2022X](https://www.3ds.com/products/catia/dymola) - [FMU Check](https://fmu-check.herokuapp.com/) \ No newline at end of file diff --git a/docs/src/fmi2_lowlevel_CS_functions.md b/docs/src/fmi2_lowlevel_CS_functions.md index 2523672b..bab699d4 100644 --- a/docs/src/fmi2_lowlevel_CS_functions.md +++ b/docs/src/fmi2_lowlevel_CS_functions.md @@ -26,6 +26,7 @@ fmi2CancelStep Status information is retrieved from the slave by the following functions: ```@docs +fmi2GetStatus fmi2GetStatus! fmi2GetRealStatus! fmi2GetIntegerStatus! diff --git a/docs/src/fmi2_lowlevel_library_constants.md b/docs/src/fmi2_lowlevel_library_constants.md index c1a79d37..046d51ba 100644 --- a/docs/src/fmi2_lowlevel_library_constants.md +++ b/docs/src/fmi2_lowlevel_library_constants.md @@ -1,12 +1,53 @@ +# FMI2 Types in FMI Import/Core .jl + +```@docs +FMU2 +FMU2Component +FMU2ComponentEnvironment +FMI2Struct +fmi2Initial +fmi2ScalarVariable +fmi2SimpleType +fmi2Type +fmi2BaseUnit +fmi2Unit +fmi2DisplayUnit +fmi2Char +fmi2Variability +fmi2VariableDependency +fmi2DependencyKind +fmi2EventInfo +fmi2Status +fmi2Annotation +fmi2ModelDescription +fmi2FMUstate +fmi2StatusKind +fmi2VariableNamingConvention +fmi2Causality +fmi2ComponentState +``` +fmi2StructMD +FMU2Solution +FMIImport.fmi2ValueReferenceFormat +FMU2Event +FMU2ExecutionConfiguration + # FMI2 Constants in FMI Import/Core .jl ```@docs fmi2True +fmi2ComponentStateInstantiated +fmi2ComponentStateInitializationMode +fmi2ComponentStateEventMode +fmi2ComponentStateContinuousTimeMode +fmi2ComponentStateTerminated +fmi2ComponentStateError +fmi2ComponentStateFatal +``` fmi2False fmi2StatusOK fmi2StatusWarning fmi2StatusPending fmi2StatusError fmi2StatusDiscard -fmi2StatusFatal -``` \ No newline at end of file +fmi2StatusFatal \ No newline at end of file diff --git a/docs/src/fmi2_lowlevel_library_functions.md b/docs/src/fmi2_lowlevel_library_functions.md index d3feb5dc..548764fc 100644 --- a/docs/src/fmi2_lowlevel_library_functions.md +++ b/docs/src/fmi2_lowlevel_library_functions.md @@ -5,18 +5,18 @@ platform dependent header file, several access functions, as well as the schema ## Opening and closing FMUs ```@docs +``` fmi2Unzip fmi2Load fmi2Reload fmi2Unload -``` ## Creation, Destruction and Logging of FMU Instances ```@docs fmi2Instantiate! fmi2Instantiate -fmi2FreeInstance! +fmi2FreeInstance fmi2SetDebugLogging ``` @@ -39,9 +39,6 @@ have identical values but other parts of the variable definition might be differ attributes). ```@docs -fmi2Get -fmi2Get! -fmi2Set fmi2GetReal fmi2GetReal! fmi2GetInteger @@ -55,6 +52,9 @@ fmi2SetInteger fmi2SetBoolean fmi2SetString ``` +fmi2Get +fmi2Get! +fmi2Set ## Getting and Setting the Complete FMU State The FMU has an internal state consisting of all values that are needed to continue a simulation. This internal state consists especially of the values of the continuous-time states, iteration variables, parameter values, input values, delay buffers, file identifiers, and FMU internal status information. With the functions of this section, the internal FMU state can be copied and the pointer to this copy is returned to the environment. The FMU state copy can be set as actual FMU state, in order to continue the simulation from it. @@ -63,7 +63,7 @@ The FMU has an internal state consisting of all values that are needed to contin fmi2GetFMUstate fmi2GetFMUstate! fmi2SetFMUstate -fmi2FreeFMUstate! +fmi2FreeFMUstate fmi2SerializedFMUstateSize fmi2SerializedFMUstateSize! fmi2SerializeFMUstate @@ -83,44 +83,29 @@ fmi2GetDirectionalDerivative fmi2GetDirectionalDerivative! fmi2SetRealInputDerivatives fmi2GetRealOutputDerivatives! +``` fmi2SampleJacobian fmi2SampleJacobian! -``` ## Conversion functions ```@docs -fmi2StringToValueReference -fmi2ValueReferenceToString -fmi2StringToCausality -fmi2CausalityToString -fmi2StringToVariability -fmi2VariabilityToString - -fmi2StatusToString -fmi2StringToDependencyKind -fmi2DependencyKindToString -fmi2StringToInitial -fmi2InitialToString ``` ## External/Additional functions ```@docs +setDiscreteStates +getDiscreteStates +getDiscreteStates! +getSimpleTypeAttributeStruct +getDeclaredType +``` fmi2GetSolutionDerivative fmi2GetSolutionState fmi2GetSolutionValue fmi2GetSolutionTime -fmi2ModelVariablesForValueReference -getCurrentComponent -hasCurrentComponent fmi2GetJacobian fmi2GetJacobian! fmi2GetFullJacobian fmi2GetFullJacobian! -fmi2GetStartValue -fmi2GetUnit -fmi2GetDeclaredType -fmi2GetInitial -fmi2GetSimpleTypeAttributeStruct -``` diff --git a/docs/src/fmi2_lowlevel_library_types.md b/docs/src/fmi2_lowlevel_library_types.md deleted file mode 100644 index b4cbc963..00000000 --- a/docs/src/fmi2_lowlevel_library_types.md +++ /dev/null @@ -1,30 +0,0 @@ -# FMI2 Types in FMI Import/Core .jl - -```@docs -FMU2 -FMU2Component -FMU2ComponentEnvironment -FMU2InputFunction -fmi2Struct -fmi2StructMD -fmi2Initial -FMU2Solution -fmi2ScalarVariable -fmi2SimpleType -fmi2Type -fmi2Unit -fmi2Char -FMIImport.fmi2ValueReferenceFormat -fmi2Variability -fmi2VariableDependency -fmi2DependencyKind -fmi2EventInfo -FMU2Event -FMU2ExecutionConfiguration -fmi2Status -fmi2Annotation -fmi2ModelDescription -fmi2FMUstate -fmi2StatusKind -fmi2Causality -``` \ No newline at end of file diff --git a/docs/src/fmi2_lowlevel_modeldescription_functions.md b/docs/src/fmi2_lowlevel_modeldescription_functions.md index 4a781252..07c5a65d 100644 --- a/docs/src/fmi2_lowlevel_modeldescription_functions.md +++ b/docs/src/fmi2_lowlevel_modeldescription_functions.md @@ -5,95 +5,63 @@ The FMI model description provides all human readable information on the model. ## Loading/Parsing ```@docs -fmi2LoadModelDescription ``` +fmi2LoadModelDescription ## general information about the FMU ```@docs -fmi2GetModelName -fmi2GetGUID -fmi2IsCoSimulation -fmi2IsModelExchange +``` fmi2GetGenerationTool fmi2GetGenerationDateAndTime -``` ## technical information about the FMU ```@docs -fmi2GetModelIdentifier -fmi2GetVariableNamingConvention fmi2GetVersion fmi2GetTypesPlatform -fmi2GetNumberOfEventIndicators -``` - -## default experiment settings - -```@docs -fmi2GetDefaultStartTime -fmi2GetDefaultStopTime -fmi2GetDefaultTolerance -fmi2GetDefaultStepSize ``` ## FMU capabilities ```@docs +canGetSetFMUState +isModelStructureAvailable +isModelStructureDerivativesAvailable +``` fmi2DependenciesSupported fmi2DerivativeDependenciesSupported -fmi2CanGetSetState fmi2CanSerializeFMUstate fmi2ProvidesDirectionalDerivative -``` ## value references ```@docs +getModelVariableIndices +``` fmi2GetValueReferencesAndNames fmi2GetNames -fmi2GetModelVariableIndices -fmi2DataTypeForValueReference -``` ## In-/Outputs ```@docs -fmi2GetInputValueReferencesAndNames -fmi2GetInputNames -fmi2GetOutputValueReferencesAndNames -fmi2GetOutputNames ``` +fmi2GetOutputValueReferencesAndNames -## Parameters - -```@docs -fmi2GetParameterValueReferencesAndNames -fmi2GetParameterNames -``` ## States ```@docs -fmi2GetNumberOfStates -fmi2GetStateValueReferencesAndNames -fmi2GetStateNames ``` ## Derivatives ```@docs -fmi2GetDerivateValueReferencesAndNames -fmi2GetDerivativeNames ``` ## Variables ```@docs -fmi2GetNamesAndDescriptions -fmi2GetNamesAndUnits -fmi2GetNamesAndInitials -fmi2GetInputNamesAndStarts ``` + diff --git a/docs/src/fmi3_lowlevel_CS_functions.md b/docs/src/fmi3_lowlevel_CS_functions.md index 731073f3..a47839cc 100644 --- a/docs/src/fmi3_lowlevel_CS_functions.md +++ b/docs/src/fmi3_lowlevel_CS_functions.md @@ -11,8 +11,8 @@ derivatives of the inputs with respect to time can be provided. Also, higher der higher order interpolation. ```@docs -fmi3CallbackIntermediateUpdate ``` +fmi3CallbackIntermediateUpdate ## Computation The computation of time steps is controlled by the following function. diff --git a/docs/src/fmi3_lowlevel_ME_functions.md b/docs/src/fmi3_lowlevel_ME_functions.md index f28ef4a2..99c2376d 100644 --- a/docs/src/fmi3_lowlevel_ME_functions.md +++ b/docs/src/fmi3_lowlevel_ME_functions.md @@ -9,6 +9,8 @@ Depending on the situation, different variables need to be computed. In order to ```@docs fmi3SetTime fmi3SetContinuousStates +fmi3GetEventIndicators +fmi3GetEventIndicators! ``` ## Evaluation of Model Equations @@ -16,11 +18,12 @@ fmi3SetContinuousStates ```@docs fmi3EnterEventMode fmi3EnterContinuousTimeMode -fmi3CompletedIntegratorStep fmi3CompletedIntegratorStep! -fmi3GetEventIndicators! +fmi3GetContinuousStates fmi3GetContinuousStates! +fmi3GetNominalsOfContinuousStates fmi3GetNominalsOfContinuousStates! fmi3GetNumberOfContinuousStates fmi3GetNumberOfContinuousStates! ``` +fmi3CompletedIntegratorStep diff --git a/docs/src/fmi3_lowlevel_library_constants.md b/docs/src/fmi3_lowlevel_library_constants.md index cb1ea073..24d6cc01 100644 --- a/docs/src/fmi3_lowlevel_library_constants.md +++ b/docs/src/fmi3_lowlevel_library_constants.md @@ -1,3 +1,47 @@ +# FMI3 Types in FMI Import/Core .jl + +```@docs +FMU3 +FMU3Instance +FMU3InstanceEnvironment +FMI3Struct +fmi3Instance +fmi3InstanceEnvironment +fmi3InstanceState +fmi3FMUState +fmi3Initial +fmi3ValueReference +fmi3Variable +fmi3VariableDependency +fmi3Binary +fmi3SimpleType +fmi3Type +fmi3Unit +fmi3Boolean +fmi3Byte +fmi3Char +fmi3Float32 +fmi3Float64 +fmi3Int8 +fmi3Int16 +fmi3Int32 +fmi3Int64 +fmi3UInt8 +fmi3UInt16 +fmi3UInt32 +fmi3UInt64 +fmi3String +fmi3Clock +fmi3IntervalQualifier +fmi3Variability +fmi3DependencyKind +fmi3Status +fmi3Annotation +fmi3ModelDescription +fmi3VariableNamingConvention +fmi3Causality +``` + # FMI3 Constants in FMI Import/Core .jl ```@docs @@ -8,6 +52,24 @@ fmi3StatusWarning fmi3StatusDiscard fmi3StatusError fmi3StatusFatal +fmi3InstanceStateInstantiated +fmi3InstanceStateInitializationMode +fmi3InstanceStateEventMode +fmi3InstanceStateStepMode +fmi3InstanceStateClockActivationMode +fmi3InstanceStateContinuousTimeMode +fmi3InstanceStateConfigurationMode +fmi3InstanceStateReconfigurationMode +fmi3InstanceStateTerminated +fmi3InstanceStateError +fmi3InstanceStateFatal fmi3VariableNamingConventionFlat fmi3VariableNamingConventionStructured -``` +fmi3CausalityParameter +fmi3CausalityCalculatedParameter +fmi3CausalityInput +fmi3CausalityOutput +fmi3CausalityLocal +fmi3CausalityIndependent +fmi3CausalityStructuralParameter +``` \ No newline at end of file diff --git a/docs/src/fmi3_lowlevel_library_functions.md b/docs/src/fmi3_lowlevel_library_functions.md index f3d166a7..1bb0705b 100644 --- a/docs/src/fmi3_lowlevel_library_functions.md +++ b/docs/src/fmi3_lowlevel_library_functions.md @@ -5,11 +5,11 @@ platform dependent header file, several access functions, as well as the schema ## Opening and closing FMUs ```@docs +``` fmi3Unzip fmi3Load fmi3Reload fmi3Unload -``` ## Creation, Destruction and Logging of FMU Instances @@ -20,6 +20,7 @@ fmi3InstantiateModelExchange fmi3InstantiateModelExchange! fmi3InstantiateScheduledExecution fmi3InstantiateScheduledExecution! +fmi3FreeInstance fmi3FreeInstance! fmi3SetDebugLogging ``` @@ -45,8 +46,6 @@ have identical values but other parts of the variable definition might be differ attributes). ```@docs -fmi3Get -fmi3Get! fmi3GetFloat32 fmi3GetFloat32! fmi3GetFloat64 @@ -73,7 +72,6 @@ fmi3GetString fmi3GetString! fmi3GetBinary fmi3GetBinary! -fmi3Set fmi3SetFloat32 fmi3SetFloat64 fmi3SetInt8 @@ -88,6 +86,9 @@ fmi3SetBoolean fmi3SetString fmi3SetBinary ``` +fmi3Get +fmi3Get! +fmi3Set ## Getting and Setting the Complete FMU State The FMU has an internal state consisting of all values that are needed to continue a simulation. This internal state consists especially of the values of the continuous-time states, iteration variables, parameter values, input values, delay buffers, file identifiers, and FMU internal status information. With the functions of this section, the internal FMU state can be copied and the pointer to this copy is returned to the environment. The FMU state copy can be set as actual FMU state, in order to continue the simulation from it. @@ -96,7 +97,7 @@ The FMU has an internal state consisting of all values that are needed to contin fmi3GetFMUState fmi3GetFMUState! fmi3SetFMUState -fmi3FreeFMUState! +fmi3FreeFMUState fmi3SerializeFMUState fmi3SerializeFMUState! fmi3SerializedFMUStateSize @@ -116,18 +117,19 @@ directional derivatives. This function can be used to construct the desired part ```@docs fmi3GetDirectionalDerivative fmi3GetDirectionalDerivative! -fmi3SampleDirectionalDerivative -fmi3SampleDirectionalDerivative! fmi3GetContinuousStateDerivatives fmi3GetContinuousStateDerivatives! +fmi3GetAdjointDerivative fmi3GetAdjointDerivative! fmi3GetOutputDerivatives fmi3GetOutputDerivatives! +``` +fmi3SampleDirectionalDerivative +fmi3SampleDirectionalDerivative! fmi3GetJacobian fmi3GetJacobian! fmi3GetFullJacobian fmi3GetFullJacobian! -``` ## TODO: Clockstuff @@ -142,38 +144,27 @@ fmi3GetClock fmi3GetClock! fmi3SetClock fmi3ActivateModelPartition -fmi3CallbackClockUpdate ``` +fmi3CallbackClockUpdate ## Conversion functions ```@docs -fmi3StringToValueReference -fmi3ValueReferenceToString +stringToType +typeToString +stringToVariableNamingConvention +variableNamingConventionToString +intervalQualifierToString +``` fmi3StringToCausality -fmi3CausalityToString -fmi3StringToVariability -fmi3VariabilityToString -fmi3StringToStatus fmi3StatusToString -fmi3StringToDependencyKind -fmi3DependencyKindToString fmi3StringToInitial -fmi3InitialToString -fmi3IntervalQualifierToString -fmi3StringToIntervalQualifier -fmi3StringToType -fmi3TypeToString -fmi3VariableNamingConventionToString -fmi3StringToVariableNamingConvention -``` ## External/Additional functions ```@docs -fmi3ModelVariablesForValueReference -fmi3GetStartValue - +fmi3GetNumberOfVariableDependencies fmi3GetNumberOfVariableDependencies! +fmi3GetVariableDependencies fmi3GetVariableDependencies! ``` \ No newline at end of file diff --git a/docs/src/fmi3_lowlevel_library_types.md b/docs/src/fmi3_lowlevel_library_types.md deleted file mode 100644 index 6c74452e..00000000 --- a/docs/src/fmi3_lowlevel_library_types.md +++ /dev/null @@ -1,37 +0,0 @@ -# FMI3 Types in FMI Import/Core .jl - -```@docs -FMU3 -FMU3Instance -FMU3InstanceEnvironment -fmi3Struct -fmi3StructMD -fmi3Initial -FMU3Solution -fmi3Variable -fmi3VariableDependency -fmi3SimpleType -fmi3Type -fmi3Unit -fmi3Float32 -fmi3Float64 -fmi3Int8 -fmi3Int16 -fmi3Int32 -fmi3Int64 -fmi3UInt8 -fmi3UInt16 -fmi3UInt32 -fmi3UInt64 -FMIImport.fmi3ValueReferenceFormat -fmi3IntervalQualifier -fmi3Variability -fmi3DependencyKind -FMU3Event -FMU3ExecutionConfiguration -fmi3Status -fmi3Annotation -fmi3ModelDescription -fmi3VariableNamingConvention -fmi3Causality -``` \ No newline at end of file diff --git a/docs/src/fmi3_lowlevel_modeldescription_functions.md b/docs/src/fmi3_lowlevel_modeldescription_functions.md index 164b3965..5cddbde8 100644 --- a/docs/src/fmi3_lowlevel_modeldescription_functions.md +++ b/docs/src/fmi3_lowlevel_modeldescription_functions.md @@ -5,46 +5,28 @@ The FMI model description provides all human readable information on the model. ## Loading/Parsing ```@docs -fmi3LoadModelDescription ``` +fmi3LoadModelDescription ## general information about the FMU ```@docs -fmi3GetModelName -fmi3GetInstantiationToken -fmi3IsCoSimulation -fmi3IsModelExchange -fmi3IsScheduledExecution +``` fmi3GetGenerationTool fmi3GetGenerationDateAndTime -``` ## technical information about the FMU ```@docs -fmi3GetModelIdentifier -fmi3GetVariableNamingConvention fmi3GetVersion fmi3GetNumberOfEventIndicators fmi3GetNumberOfEventIndicators! ``` -## default experiment settings - -```@docs -fmi3GetDefaultStartTime -fmi3GetDefaultStopTime -fmi3GetDefaultTolerance -fmi3GetDefaultStepSize -``` - ## FMU capabilities ```@docs +``` fmi3CanGetSetState -fmi3CanSerializeFMUState -fmi3ProvidesDirectionalDerivatives -fmi3ProvidesAdjointDerivatives -``` \ No newline at end of file +fmi3CanSerializeFMUState \ No newline at end of file diff --git a/docs/src/fmi_lowlevel_library_constants.md b/docs/src/fmi_lowlevel_library_constants.md index 03b7456f..cc8c256e 100644 --- a/docs/src/fmi_lowlevel_library_constants.md +++ b/docs/src/fmi_lowlevel_library_constants.md @@ -1,3 +1,16 @@ +# Types in FMI Import/Core .jl + +```@docs +FMU +FMUInstance +FMUSolution +FMUEvent +FMUSnapshot +FMUExecutionConfiguration +FMULogLevel +FMUInputFunction +``` + # Constants in FMI Import/Core .jl ```@docs diff --git a/docs/src/fmi_lowlevel_library_functions.md b/docs/src/fmi_lowlevel_library_functions.md index a56404e7..067fc4e7 100644 --- a/docs/src/fmi_lowlevel_library_functions.md +++ b/docs/src/fmi_lowlevel_library_functions.md @@ -4,6 +4,48 @@ logInfo logWarning logError +``` loadBinary eval! -``` \ No newline at end of file + +## Conversion functions + +```@docs +stringToStatus +statusToString +stringToDependencyKind +dependencyKindToString +valueReferenceToString +stringToInitial +initialToString +stringToIntervalQualifier +stringToDataType +stringToCausality +causalityToString +stringToVariability +variabilityToString +``` + +fmi2StringToInitial + +## External/Additional functions + +```@docs +getInitial +getStartValue +hasCurrentInstance +getCurrentInstance +modelVariablesForValueReference +setValue +getValue +getValue! +getUnit +``` +fmi2GetSolutionDerivative +fmi2GetSolutionState +fmi2GetSolutionValue +fmi2GetSolutionTime +fmi2GetJacobian +fmi2GetJacobian! +fmi2GetFullJacobian +fmi2GetFullJacobian! diff --git a/docs/src/fmi_lowlevel_library_types.md b/docs/src/fmi_lowlevel_library_types.md deleted file mode 100644 index 12256adb..00000000 --- a/docs/src/fmi_lowlevel_library_types.md +++ /dev/null @@ -1,9 +0,0 @@ -# Types in FMI Import/Core .jl - -```@docs -FMU -FMUSolution -FMUEvent -FMUExecutionConfiguration -FMULogLevel -``` \ No newline at end of file diff --git a/docs/src/fmi_lowlevel_modeldescription_functions.md b/docs/src/fmi_lowlevel_modeldescription_functions.md new file mode 100644 index 00000000..006ff460 --- /dev/null +++ b/docs/src/fmi_lowlevel_modeldescription_functions.md @@ -0,0 +1,98 @@ +# Working with the FMI model description + +The FMI model description provides all human readable information on the model. The following functions can be used to obtain all information provided by the model description, which in turn can be extracted from the fmu. + +## Loading/Parsing + +```@docs +``` +fmi2LoadModelDescription + +## general information about the FMU + +```@docs +getGUID +getInstantiationToken +getGenerationDateAndTime +getGenerationTool +``` + +## technical information about the FMU + +```@docs +getNumberOfEventIndicators +getModelIdentifier +getVariableNamingConvention +``` +fmi2GetVersion +fmi2GetTypesPlatform + +## default experiment settings + +```@docs +getDefaultStartTime +getDefaultStepSize +getDefaultStopTime +getDefaultTolerance +``` + +## FMU capabilities + +```@docs +canSerializeFMUState +providesDirectionalDerivatives +providesAdjointDerivatives +``` +canGetSetFMUState +fmi2DependenciesSupported +fmi2DerivativeDependenciesSupported +fmi2ProvidesDirectionalDerivative + +## value references + +```@docs +getValueReferencesAndNames +getNames +dataTypeForValueReference +prepareValueReference +prepareValue +``` + +## In-/Outputs + +```@docs +getInputNames +getInputValueReferencesAndNames +getInputNamesAndStarts +getOutputNames +getOutputValueReferencesAndNames +``` + +## Parameters + +```@docs +getParameterValueReferencesAndNames +getParameterNames +``` + +## States + +```@docs +getStateNames +getStateValueReferencesAndNames +``` + +## Derivatives + +```@docs +getDerivateValueReferencesAndNames +getDerivativeNames +``` + +## Variables + +```@docs +getNamesAndInitials +getNamesAndDescriptions +getNamesAndUnits +``` diff --git a/docs/src/library.md b/docs/src/library.md index f3af5c7d..5b8126c0 100644 --- a/docs/src/library.md +++ b/docs/src/library.md @@ -5,81 +5,78 @@ Many of the functions in this library are based on already defined functions of # Simulate FMUs ```@docs -fmiLoad -fmiSimulate -fmiSimulateCS -fmiSimulateME -fmiUnload -fmiReload +loadFMU +simulate +simulateCS +simulateSE +simulateME +unloadFMU +reload ``` + # Handling Value References ```@docs -fmiStringToValueReference -fmiGetStartValue +stringToValueReference ``` # External/additional functions ```@docs -fmiInfo +info +getModelName +getNumberOfStates +isModelExchange +isScheduledExecution +isCoSimulation +getState +getTime +getStateDerivative +``` fmiSet fmiGet fmiGet! -fmiGetNumberOfStates fmiCanGetSetState -fmiGetState fmiSetState fmiFreeState! fmiGetDependencies fmiProvidesDirectionalDerivative -fmiGetModelName -fmiGetGUID -fmiIsCoSimulation -fmiIsModelExchange -fmiIsScheduledExecution -``` # Visualize simulation results ```@docs +``` fmiPlot fmiPlot! Plots.plot -``` # Save/load simulation results ```@docs +``` fmiSaveSolution fmiSaveSolutionJLD2 fmiSaveSolutionMAT fmiSaveSolutionCSV fmiLoadSolution fmiLoadSolutionJLD2 -``` # FMI2 specific ```@docs +``` fmi2Info fmi2Simulate -fmi2SimulateME -fmi2SimulateCS fmi2VariableDependsOnVariable fmi2GetDependencies fmi2PrintDependencies -``` # FMI3 specific ```@docs +``` fmi3Info fmi3Simulate -fmi3SimulateME -fmi3SimulateSE -fmi3SimulateCS fmi3VariableDependsOnVariable fmi3GetDependencies -fmi3PrintDependencies -``` \ No newline at end of file +fmi3PrintDependencies \ No newline at end of file diff --git a/examples/pluto-src/FMUExplorer/FMUExplorer.jl b/examples/pluto-src/FMUExplorer/FMUExplorer.jl index 70f214e3..d327fb05 100644 --- a/examples/pluto-src/FMUExplorer/FMUExplorer.jl +++ b/examples/pluto-src/FMUExplorer/FMUExplorer.jl @@ -1,5 +1,5 @@ ### A Pluto.jl notebook ### -# v0.19.43 +# v0.19.46 using Markdown using InteractiveUtils @@ -7,7 +7,14 @@ using InteractiveUtils # This Pluto notebook uses @bind for interactivity. When running this notebook outside of Pluto, the following 'mock version' of @bind gives bound variables a default value (instead of an error). macro bind(def, element) quote - local iv = try Base.loaded_modules[Base.PkgId(Base.UUID("6e696c72-6542-2067-7265-42206c756150"), "AbstractPlutoDingetjes")].Bonds.initial_value catch; b -> missing; end + local iv = try + Base.loaded_modules[Base.PkgId( + Base.UUID("6e696c72-6542-2067-7265-42206c756150"), + "AbstractPlutoDingetjes", + )].Bonds.initial_value + catch + b -> missing + end local el = $(esc(element)) global $(esc(def)) = Core.applicable(Base.get, el) ? Base.get(el) : iv(el) el @@ -48,18 +55,18 @@ FMUExplorer is a *Pluto.jl* notebook that allows - as the name suggests - to exp import PlotlyJS # ╔═║ 57d2a3e8-835d-40bb-8e47-47ea5c0eedf0 -begin - plotlyjs() - - function lastn(str, n::Integer) - if length(str) > n-3 - return "..." * last(str, n-3) - else - return str - end - end - - md""" Source Code. """ +begin + plotlyjs() + + function lastn(str, n::Integer) + if length(str) > n - 3 + return "..." * last(str, n - 3) + else + return str + end + end + + md""" Source Code. """ end # ╔═║ 92514cc6-a468-4d87-9104-d4459025de02 @@ -77,101 +84,104 @@ FMU source: $(@bind mode Select([:zoo => "FMIZoo.jl", :local => "Local file", :u # ╔═║ 9aa11335-eb16-4310-9fc0-0672c64f3be1 begin - if mode == :zoo - tools_path = joinpath((splitpath(FMIZoo.get_model_filename("BouncingBall1D", "Dymola", "2022x"))[1:end-4])...) - tools = readdir(tools_path) - md""" - Exporting-Tool: $(@bind zoo_pick_tool Select(tools)) - """ - else - nothing - end + if mode == :zoo + tools_path = joinpath( + (splitpath(FMIZoo.get_model_filename("BouncingBall1D", "Dymola", "2022x"))[1:end-4])..., + ) + tools = readdir(tools_path) + md""" + Exporting-Tool: $(@bind zoo_pick_tool Select(tools)) + """ + else + nothing + end end # ╔═║ d4769552-4083-4a3e-a477-168ac288b742 begin - if mode == :zoo - versions_path = joinpath(tools_path, zoo_pick_tool) - versions = readdir(versions_path) - md""" - Tool Version: $(@bind zoo_pick_version Select(versions)) - """ - else - nothing - end + if mode == :zoo + versions_path = joinpath(tools_path, zoo_pick_tool) + versions = readdir(versions_path) + md""" + Tool Version: $(@bind zoo_pick_version Select(versions)) + """ + else + nothing + end end # ╔═║ 876653d2-6a68-4c5a-a3c6-a3ca23629989 begin - if mode == :zoo - fmivers_path = joinpath(versions_path, zoo_pick_version) - fmivers = readdir(fmivers_path) - filter!(e->e == "2.0", fmivers) # ToDo! - md""" - FMI version: $(@bind zoo_pick_fmiver Select(fmivers)) - """ - else - nothing - end + if mode == :zoo + fmivers_path = joinpath(versions_path, zoo_pick_version) + fmivers = readdir(fmivers_path) + filter!(e -> e == "2.0", fmivers) # ToDo! + md""" + FMI version: $(@bind zoo_pick_fmiver Select(fmivers)) + """ + else + nothing + end end # ╔═║ 445f18d6-66db-4cf2-9205-f98fc3dd8d83 begin - if mode == :zoo - fmus_path = joinpath(fmivers_path, zoo_pick_fmiver) - fmus = readdir(fmus_path) - filter!(e->endswith(e, ".fmu"), fmus) - md""" - FMU: $(@bind zoo_pick_fmu Select(fmus)) - """ - else - nothing - end + if mode == :zoo + fmus_path = joinpath(fmivers_path, zoo_pick_fmiver) + fmus = readdir(fmus_path) + filter!(e -> endswith(e, ".fmu"), fmus) + md""" + FMU: $(@bind zoo_pick_fmu Select(fmus)) + """ + else + nothing + end end # ╔═║ cd8ddd20-2ce8-4b5e-a431-47078416bbc9 begin - if mode == :local - md""" - Local file path: $(@bind fmu_path confirm(TextField(), label="Load")) - """ - elseif mode == :url - md""" - Online URL: $(@bind fmu_path confirm(TextField(), label="Load")) - """ - elseif mode == :zoo - fmu_path = joinpath(fmus_path, zoo_pick_fmu) - nothing - else - md""" - Fatal error. Unknown mode `$(mode)`. - """ - end + if mode == :local + md""" + Local file path: $(@bind fmu_path confirm(TextField(), label="Load")) + """ + elseif mode == :url + md""" + Online URL: $(@bind fmu_path confirm(TextField(), label="Load")) + """ + elseif mode == :zoo + fmu_path = joinpath(fmus_path, zoo_pick_fmu) + nothing + else + md""" + Fatal error. Unknown mode `$(mode)`. + """ + end end # ╔═║ 6d0232ef-b181-42d4-9160-b2f0ffcee84b -if (mode ∈ (:local, :zoo) && isfile(fmu_path)) || (mode == :url && startswith(fmu_path, "http")) - if endswith(fmu_path, ".fmu") - fmu = fmiLoad(fmu_path) - fmu.executionConfig.loggingOn = true - fmu.executionConfig.externalCallbacks = true - descr = fmu.modelDescription - md""" - βœ”οΈ Sucessfully loaded FMU *$(fmu.modelName)*. - """ - else - fmu = nothing - descr = nothing - md"""❌ *$(fmu_path)* does not end with `.fmu`""" - end +if (mode ∈ (:local, :zoo) && isfile(fmu_path)) || + (mode == :url && startswith(fmu_path, "http")) + if endswith(fmu_path, ".fmu") + fmu = fmiLoad(fmu_path) + fmu.executionConfig.loggingOn = true + fmu.executionConfig.externalCallbacks = true + descr = fmu.modelDescription + md""" + βœ”οΈ Sucessfully loaded FMU *$(fmu.modelName)*. + """ + else + fmu = nothing + descr = nothing + md"""❌ *$(fmu_path)* does not end with `.fmu`""" + end else - fmu = nothing - descr = nothing - if mode == :url - md"""❌ *$(fmu_path)* is not a valid URL!""" - else - md"""❌ *$(fmu_path)* is not a valid file path!""" - end + fmu = nothing + descr = nothing + if mode == :url + md"""❌ *$(fmu_path)* is not a valid URL!""" + else + md"""❌ *$(fmu_path)* is not a valid file path!""" + end end # ╔═║ 98663a7e-69a0-4938-9ac2-b7d8f248592d @@ -182,22 +192,22 @@ md""" # ╔═║ dfaee7a3-03af-45b2-a2e4-84c103b0001a if !isnothing(fmu) - md""" - | | | - | -------- | ------- | - | File path | $(lastn(fmu_path, 48)) | - | File size | $(round(filesize(fmu_path) / 2^20; digits=1))MB | - | Model name | $(lastn(fmu.modelName, 48)) | - | Number of variables | $(length(descr.valueReferences)) | - | Number of continuous states / derivatives | $(length(descr.stateValueReferences)) | - | Number of inputs | $(length(descr.inputValueReferences)) | - | Number of outputs | $(length(descr.outputValueReferences)) | - | Number of parameters | $(length(descr.parameterValueReferences)) | - """ + md""" + | | | + | -------- | ------- | + | File path | $(lastn(fmu_path, 48)) | + | File size | $(round(filesize(fmu_path) / 2^20; digits=1))MB | + | Model name | $(lastn(fmu.modelName, 48)) | + | Number of variables | $(length(descr.valueReferences)) | + | Number of continuous states / derivatives | $(length(descr.stateValueReferences)) | + | Number of inputs | $(length(descr.inputValueReferences)) | + | Number of outputs | $(length(descr.outputValueReferences)) | + | Number of parameters | $(length(descr.parameterValueReferences)) | + """ else - md""" - ⚠️ No FMU loaded. - """ + md""" + ⚠️ No FMU loaded. + """ end # ╔═║ a41ce5ae-4e0c-40de-b63f-e469c982367b @@ -207,17 +217,17 @@ md""" # ╔═║ 1ab6b2c8-d58e-48c5-95cb-cc35936413a9 if !isnothing(fmu) - md""" - | | | - | -------- | ------- | - | ME supported | $(!isnothing(descr.modelExchange) ? "βœ”οΈ" : "❌") | - | Model identifier | $(!isnothing(descr.modelExchange) ? lastn(descr.modelExchange.modelIdentifier, 48) : "n.a.") | - | Directional derivatives | $(!isnothing(descr.modelExchange) && descr.modelExchange.providesDirectionalDerivative == FMI.fmi2True ? "βœ”οΈ" : "❌") | - """ + md""" + | | | + | -------- | ------- | + | ME supported | $(!isnothing(descr.modelExchange) ? "βœ”οΈ" : "❌") | + | Model identifier | $(!isnothing(descr.modelExchange) ? lastn(descr.modelExchange.modelIdentifier, 48) : "n.a.") | + | Directional derivatives | $(!isnothing(descr.modelExchange) && descr.modelExchange.providesDirectionalDerivative == FMI.fmi2True ? "βœ”οΈ" : "❌") | + """ else - md""" - ⚠️ No FMU loaded. - """ + md""" + ⚠️ No FMU loaded. + """ end # ╔═║ 6472cac2-cd31-4272-95cd-8e8e7245058d @@ -227,76 +237,76 @@ md""" # ╔═║ 0cd23f48-18c7-4012-ae77-4a9f77934b60 if !isnothing(fmu) - md""" - | | | - | -------- | ------- | - | CS supported | $(!isnothing(descr.coSimulation) ? "βœ”οΈ" : "❌") | - | Model identifier | $(!isnothing(descr.coSimulation) ? lastn(descr.coSimulation.modelIdentifier, 48) : "n.a.") | - | Directional derivatives | $(!isnothing(descr.coSimulation) && descr.coSimulation.providesDirectionalDerivative == FMI.fmi2True ? "βœ”οΈ" : "❌") | - """ + md""" + | | | + | -------- | ------- | + | CS supported | $(!isnothing(descr.coSimulation) ? "βœ”οΈ" : "❌") | + | Model identifier | $(!isnothing(descr.coSimulation) ? lastn(descr.coSimulation.modelIdentifier, 48) : "n.a.") | + | Directional derivatives | $(!isnothing(descr.coSimulation) && descr.coSimulation.providesDirectionalDerivative == FMI.fmi2True ? "βœ”οΈ" : "❌") | + """ else - md""" - ⚠️ No FMU loaded. - """ + md""" + ⚠️ No FMU loaded. + """ end # ╔═║ 1eb6c4fc-be1b-491b-95e0-bc6ca060216c begin - state_vrs = fmu.modelDescription.stateValueReferences - ders_vrs = fmu.modelDescription.derivativeValueReferences - input_vrs = fmu.modelDescription.inputValueReferences - output_vrs = fmu.modelDescription.outputValueReferences - param_vrs = fmu.modelDescription.parameterValueReferences - - internal_vrs = copy(fmu.modelDescription.valueReferences) - filter!(e->eβˆ‰state_vrs, internal_vrs) - filter!(e->eβˆ‰ders_vrs, internal_vrs) - filter!(e->eβˆ‰input_vrs, internal_vrs) - filter!(e->eβˆ‰output_vrs, internal_vrs) - filter!(e->eβˆ‰param_vrs, internal_vrs) - - modes = Vector{Pair{Symbol, String}}() - if !isnothing(descr.modelExchange) - push!(modes, :ME => "Model Exchange (ME)") - end - if !isnothing(descr.coSimulation) - push!(modes, :CS => "Co-Simulation (CS)") - end - if hasproperty(descr, :scheduledExecution) && !isnothing(descr.scheduledExecution) - push!(modes, :SE => "Scheduled Execution (SE)") - end - - def_start = FMI.fmi2GetDefaultStartTime(descr) - if isnothing(def_start) - def_start = 0.0 - end - - def_stop = FMI.fmi2GetDefaultStopTime(descr) - if isnothing(def_stop) - def_stop = 0.0 - end - - md""" - # Simulation - ## General Setup - Select simulation mode: $(@bind sim_mode Select(modes)) - - Simulate from $(@bind t_start_str TextField(default=string(def_start)))s to $(@bind t_stop_str TextField(default=string(def_stop)))s. - """ + state_vrs = fmu.modelDescription.stateValueReferences + ders_vrs = fmu.modelDescription.derivativeValueReferences + input_vrs = fmu.modelDescription.inputValueReferences + output_vrs = fmu.modelDescription.outputValueReferences + param_vrs = fmu.modelDescription.parameterValueReferences + + internal_vrs = copy(fmu.modelDescription.valueReferences) + filter!(e -> e βˆ‰ state_vrs, internal_vrs) + filter!(e -> e βˆ‰ ders_vrs, internal_vrs) + filter!(e -> e βˆ‰ input_vrs, internal_vrs) + filter!(e -> e βˆ‰ output_vrs, internal_vrs) + filter!(e -> e βˆ‰ param_vrs, internal_vrs) + + modes = Vector{Pair{Symbol,String}}() + if !isnothing(descr.modelExchange) + push!(modes, :ME => "Model Exchange (ME)") + end + if !isnothing(descr.coSimulation) + push!(modes, :CS => "Co-Simulation (CS)") + end + if hasproperty(descr, :scheduledExecution) && !isnothing(descr.scheduledExecution) + push!(modes, :SE => "Scheduled Execution (SE)") + end + + def_start = FMI.fmi2GetDefaultStartTime(descr) + if isnothing(def_start) + def_start = 0.0 + end + + def_stop = FMI.fmi2GetDefaultStopTime(descr) + if isnothing(def_stop) + def_stop = 0.0 + end + + md""" + # Simulation + ## General Setup + Select simulation mode: $(@bind sim_mode Select(modes)) + + Simulate from $(@bind t_start_str TextField(default=string(def_start)))s to $(@bind t_stop_str TextField(default=string(def_stop)))s. + """ end # ╔═║ 831e1919-9ac8-4934-80ce-03a691ea1a41 -if sim_mode == :CS - solver_sym = :none - md""" - ℹ️ For CS, the ODE solver is part of the compiled FMU. Choose ME or SE if you want to pick solvers. - """ +if sim_mode == :CS + solver_sym = :none + md""" + ℹ️ For CS, the ODE solver is part of the compiled FMU. Choose ME or SE if you want to pick solvers. + """ else - md""" - Solver: $(@bind solver_sym Select([:Tsit5 => "Tsit5"])) - ℹ️ Additional solvers will be deployed soon. - """ # :auto => "auto (DifferentialEquations.jl heurisitc)", - #:Rosenbrock23 => "Rosenbrock23" + md""" + Solver: $(@bind solver_sym Select([:Tsit5 => "Tsit5"])) + ℹ️ Additional solvers will be deployed soon. + """ # :auto => "auto (DifferentialEquations.jl heurisitc)", + #:Rosenbrock23 => "Rosenbrock23" end # ╔═║ 43021052-25b4-43a9-a9e6-47f3c56d1341 @@ -307,34 +317,39 @@ Select parameters to change parameterization (select multiple by holding *Ctrl*) # ╔═║ df122e2a-f4af-4ac7-b332-4c07e7aa4b0e if length(param_vrs) > 0 - @bind changeParameters MultiSelect(collect(param_vrs[i] => FMI.fmi2ValueReferenceToString(fmu, param_vrs[i])[1] for i in 1:length(param_vrs))) + @bind changeParameters MultiSelect( + collect( + param_vrs[i] => FMI.fmi2ValueReferenceToString(fmu, param_vrs[i])[1] for + i = 1:length(param_vrs) + ), + ) else - changeParameters = [] - md""" - ℹ️ The FMU doesn't contain parameters. - """ + changeParameters = [] + md""" + ℹ️ The FMU doesn't contain parameters. + """ end # ╔═║ dbaf5ff3-9ee2-4355-aad2-e48c25eee514 -begin - function parameter_input(ps::Vector) - - return PlutoUI.combine() do Child - - inputs = [ - md""" $(FMI.fmi2ValueReferenceToString(fmu, vr)[1]): $( - Child(string(vr), TextField(default=string(FMI.fmi2GetStartValue(fmu, vr)))) - ) default: $(FMI.fmi2GetStartValue(fmu, vr))""" - - for vr in ps - ] - - md""" - $(inputs) - """ - end - end - nothing +begin + function parameter_input(ps::Vector) + + return PlutoUI.combine() do Child + + inputs = [ + md""" $(FMI.fmi2ValueReferenceToString(fmu, vr)[1]): $( + Child(string(vr), TextField(default=string(FMI.fmi2GetStartValue(fmu, vr)))) + ) default: $(FMI.fmi2GetStartValue(fmu, vr))""" + + for vr in ps + ] + + md""" + $(inputs) + """ + end + end + nothing end # ╔═║ 942e6e27-04a1-4dce-9364-ccafd105facb @@ -344,11 +359,11 @@ Change parameter values: # ╔═║ 095b6d5a-58af-4e3a-8ce0-b08a25629b38 if length(changeParameters) == 0 - md""" - ℹ️ No parameters selected above. - """ + md""" + ℹ️ No parameters selected above. + """ else - @bind params parameter_input(changeParameters) + @bind params parameter_input(changeParameters) end # ╔═║ 43cab175-38df-42dd-b012-e28deec442b0 @@ -357,26 +372,26 @@ Changed parameters: """ # ╔═║ 21178414-11ae-479b-9aae-b495f3c9c76e -begin - if length(changeParameters) == 0 - parameters = nothing - md""" - ℹ️ No parameters selected above. - """ - else - # parse named tuple to Dict - parameters = Dict{FMI.fmi2ValueReference, Any}() - for i in 1:length(params) - k = parse(FMI.fmi2ValueReference, string(keys(params)[i])) - v = values(params)[i] - typ = FMI.fmi2DataTypeForValueReference(descr, k) - if typ != FMI.fmi2String - v = parse(typ, v) - end - parameters[k] = v - end - parameters - end +begin + if length(changeParameters) == 0 + parameters = nothing + md""" + ℹ️ No parameters selected above. + """ + else + # parse named tuple to Dict + parameters = Dict{FMI.fmi2ValueReference,Any}() + for i = 1:length(params) + k = parse(FMI.fmi2ValueReference, string(keys(params)[i])) + v = values(params)[i] + typ = FMI.fmi2DataTypeForValueReference(descr, k) + if typ != FMI.fmi2String + v = parse(typ, v) + end + parameters[k] = v + end + parameters + end end # ╔═║ 82c6de3e-66f2-4965-8bad-2faae667fb7e @@ -402,76 +417,94 @@ $(@bind recordInternals MultiSelect(collect(internal_vrs[i] => FMI.fmi2ValueRefe """ # ╔═║ d28612f7-1405-4f6b-87db-56e3ebb852ff -begin - fmu_path; - - solver_sym; - sim_mode; - t_start_str; - t_stop_str; - - recordStates; - recordDerivatives; - recordInputs; - recordOutputs; - recordParameters; - recordInternals; - - parameters; - - md""" - ## Run Simulation - Select to start simulation: $(@bind simulation_trigger CheckBox(default=false)) - """ +begin + fmu_path + + solver_sym + sim_mode + t_start_str + t_stop_str + + recordStates + recordDerivatives + recordInputs + recordOutputs + recordParameters + recordInternals + + parameters + + md""" + ## Run Simulation + Select to start simulation: $(@bind simulation_trigger CheckBox(default=false)) + """ end # ╔═║ 05d51ac1-4804-4641-b8b1-f4f4e10dcae6 -begin - t_start = parse(Float64, t_start_str) - t_stop = parse(Float64, t_stop_str) - - recordValues = Vector{FMI.fmi2ValueReference}([recordStates..., recordDerivatives..., recordInputs..., recordOutputs..., recordParameters..., recordInternals...]) - - if sim_mode == :ME || sim_mode == :SE - if solver_sym == :auto - solver = nothing - elseif solver_sym == :Tsit5 - solver = Tsit5() - elseif solver_sym == :Rosenbrock23 - solver = Rosenbrock23(autodiff=false) - else - md""" - β›” Unknwon solver `$(solver_sym)`. - """ - return nothing - end - end - - if simulation_trigger - try - global solution - if sim_mode == :ME - solution = fmiSimulateME(fmu, (t_start, t_stop); recordValues=recordValues, parameters=parameters, solver=solver) - nothing - elseif sim_mode == :CS - solution = fmiSimulateCS(fmu, (t_start, t_stop); recordValues=recordValues, parameters=parameters) - nothing - elseif sim_mode == :SE - solution = nothing - md"""🚧 SE not supported for now.""" - else - solution = nothing - md"""β›” Unknown simulation mode.""" - end - catch e - global solution - solution = nothing - md"""β›” Simulation failed. Reasons might be $br - the FMU couldn't be initialized because of insufficient default values $br - ... $br The error message is: $br $(e)""" - end - else - solution = nothing - md"""ℹ️ Start simulation to show results.""" - end +begin + t_start = parse(Float64, t_start_str) + t_stop = parse(Float64, t_stop_str) + + recordValues = Vector{FMI.fmi2ValueReference}([ + recordStates..., + recordDerivatives..., + recordInputs..., + recordOutputs..., + recordParameters..., + recordInternals..., + ]) + + if sim_mode == :ME || sim_mode == :SE + if solver_sym == :auto + solver = nothing + elseif solver_sym == :Tsit5 + solver = Tsit5() + elseif solver_sym == :Rosenbrock23 + solver = Rosenbrock23(autodiff = false) + else + md""" + β›” Unknwon solver `$(solver_sym)`. + """ + return nothing + end + end + + if simulation_trigger + try + global solution + if sim_mode == :ME + solution = fmiSimulateME( + fmu, + (t_start, t_stop); + recordValues = recordValues, + parameters = parameters, + solver = solver, + ) + nothing + elseif sim_mode == :CS + solution = fmiSimulateCS( + fmu, + (t_start, t_stop); + recordValues = recordValues, + parameters = parameters, + ) + nothing + elseif sim_mode == :SE + solution = nothing + md"""🚧 SE not supported for now.""" + else + solution = nothing + md"""β›” Unknown simulation mode.""" + end + catch e + global solution + solution = nothing + md"""β›” Simulation failed. Reasons might be $br - the FMU couldn't be initialized because of insufficient default values $br - ... $br The error message is: $br $(e)""" + end + else + solution = nothing + md"""ℹ️ Start simulation to show results.""" + end end # ╔═║ 5058777f-beb6-43f4-b3d2-1127abbe1ac9 @@ -487,76 +520,102 @@ x-axis: $(@bind xaxis Select([0 => "time", collect(recordValues[i] => FMI.fmi2Va # ╔═║ a8b53f45-5ff7-41dd-89d9-040dcf0e9898 begin - function get_xaxis(xaxis, recordValues) - xaxis_vals = nothing - for i in 1:length(recordValues) - rv = recordValues[i] - if xaxis == rv - xaxis_vals = collect(vals[i] for vals in solution.values.saveval) - break; - end - end - return xaxis_vals - end - - if isnothing(solution) - md"""ℹ️ Please run simulation in order to plot.""" - elseif isnothing(solution.values) || length(solution.values.saveval) == 0 || length(solution.values.saveval[1]) == 0 - md"""ℹ️ Simulation successfull, but no values recorded. Please select at least one value to be recorded in order to plot some results.""" - else - if xaxis == 0 # time - xaxis_vals = solution.values.t - nothing - else - xaxis_vals = get_xaxis(xaxis, recordValues) - md""" - ℹ️ Plotting of events is disabled if x-axis is not `time`. - """ - end - end + function get_xaxis(xaxis, recordValues) + xaxis_vals = nothing + for i = 1:length(recordValues) + rv = recordValues[i] + if xaxis == rv + xaxis_vals = collect(vals[i] for vals in solution.values.saveval) + break + end + end + return xaxis_vals + end + + if isnothing(solution) + md"""ℹ️ Please run simulation in order to plot.""" + elseif isnothing(solution.values) || + length(solution.values.saveval) == 0 || + length(solution.values.saveval[1]) == 0 + md"""ℹ️ Simulation successfull, but no values recorded. Please select at least one value to be recorded in order to plot some results.""" + else + if xaxis == 0 # time + xaxis_vals = solution.values.t + nothing + else + xaxis_vals = get_xaxis(xaxis, recordValues) + md""" + ℹ️ Plotting of events is disabled if x-axis is not `time`. + """ + end + end end # ╔═║ 28026b82-83ba-42cc-89f9-a521daef717a -begin - function plotResults() - fig = Plots.plot() - _min = Inf - _max = -Inf - for i in 1:length(recordValues) - rv = recordValues[i] - if xaxis != rv - vals = collect(vals[i] for vals in solution.values.saveval) - _min = min(_min, vals...) - _max = max(_max, vals...) - Plots.plot!(fig, xaxis_vals, vals; label=FMI.fmi2ValueReferenceToString(fmu, rv)[1] * " [" * string(rv) * "]") - end - end - - if xaxis == 0 - firstTime = true - firstState = true - for i in 1:length(solution.events) - event = solution.events[i] - if event.indicator == 0 - plot!(fig, [event.t, event.t], [_min, _max]; label=(firstTime ? "Time-Event" : :none), style=:dash, color=:red) - firstTime = false - else - plot!(fig, [event.t, event.t], [_min, _max]; label=(firstState ? "State-Event" : :none), style=:dash, color=:blue) - firstState = false - end - end - end - - fig - end - - if isnothing(solution) - md"""ℹ️ Please run simulation in order to plot.""" - elseif isnothing(solution.values) || length(solution.values.saveval) == 0 || length(solution.values.saveval[1]) == 0 - md"""ℹ️ Simulation successfull, but no values recorded. Please select at least one value to be recorded in order to plot some results.""" - else - plotResults() - end +begin + function plotResults() + fig = Plots.plot() + _min = Inf + _max = -Inf + for i = 1:length(recordValues) + rv = recordValues[i] + if xaxis != rv + vals = collect(vals[i] for vals in solution.values.saveval) + _min = min(_min, vals...) + _max = max(_max, vals...) + Plots.plot!( + fig, + xaxis_vals, + vals; + label = FMI.fmi2ValueReferenceToString(fmu, rv)[1] * + " [" * + string(rv) * + "]", + ) + end + end + + if xaxis == 0 + firstTime = true + firstState = true + for i = 1:length(solution.events) + event = solution.events[i] + if event.indicator == 0 + plot!( + fig, + [event.t, event.t], + [_min, _max]; + label = (firstTime ? "Time-Event" : :none), + style = :dash, + color = :red, + ) + firstTime = false + else + plot!( + fig, + [event.t, event.t], + [_min, _max]; + label = (firstState ? "State-Event" : :none), + style = :dash, + color = :blue, + ) + firstState = false + end + end + end + + fig + end + + if isnothing(solution) + md"""ℹ️ Please run simulation in order to plot.""" + elseif isnothing(solution.values) || + length(solution.values.saveval) == 0 || + length(solution.values.saveval[1]) == 0 + md"""ℹ️ Simulation successfull, but no values recorded. Please select at least one value to be recorded in order to plot some results.""" + else + plotResults() + end end # ╔═║ c7cceb40-ff26-4d3d-912a-199c6ddd49d2 @@ -566,13 +625,13 @@ md""" # ╔═║ ca0ba941-8eb1-4641-ae4b-0925df73dedd if isnothing(solution) || isnothing(solution.states) - if sim_mode == :ME - md"""ℹ️ Please run simulation in order to display statistics.""" - else - md"""ℹ️ Please switch simulation mode to ME to show solver statistics.""" - end + if sim_mode == :ME + md"""ℹ️ Please run simulation in order to display statistics.""" + else + md"""ℹ️ Please switch simulation mode to ME to show solver statistics.""" + end else - solution.states.destats + solution.states.destats end # ╔═║ 00000000-0000-0000-0000-000000000001 diff --git a/examples/src/simulate.ipynb b/examples/src/simulate.ipynb index 41b8a17b..1b99dcb6 100644 --- a/examples/src/simulate.ipynb +++ b/examples/src/simulate.ipynb @@ -36,7 +36,7 @@ "metadata": {}, "source": [ "## Motivation\n", - "This Julia Package *FMI.jl* is motivated by the use of simulation models in Julia. Here the FMI specification is implemented. FMI (*Functional Mock-up Interface*) is a free standard ([fmi-standard.org](http://fmi-standard.org/)) that defines a container and an interface to exchange dynamic models using a combination of XML files, binaries and C code zipped into a single file. The user can thus use simulation models in the form of an FMU (*Functional Mock-up Units*). Besides loading the FMU, the user can also set values for parameters and states and simulate the FMU both as co-simulation and model exchange simulation.\n", + "This Julia Package *FMI.jl* is motivated by the use of simulation models in Julia. Here the FMI specification is implemented. FMI (*Functional Mock-up Interface*) is a free standard ([fmi-standard.org](https://fmi-standard.org/)) that defines a container and an interface to exchange dynamic models using a combination of XML files, binaries and C code zipped into a single file. The user can thus use simulation models in the form of an FMU (*Functional Mock-up Units*). Besides loading the FMU, the user can also set values for parameters and states and simulate the FMU both as co-simulation and model exchange simulation.\n", "\n", "## Introduction to the example\n", "In this example we want to show how fast and easy the simulation for an FMU is. For this purpose, the FMU is simulated in co-simulation mode and in model-exchange mode. After the FMU has been simulated, the simulation results are displayed in a graph. The graphs of the different modes are compared with each other. The used model is a one-dimensional spring pendulum with friction. The object-orientated structure of the *SpringFrictionPendulum1D* can be seen in the following graphic.\n", diff --git a/src/FMI.jl b/src/FMI.jl index 8d012e58..a93687e5 100644 --- a/src/FMI.jl +++ b/src/FMI.jl @@ -7,1232 +7,11 @@ module FMI @debug "Debugging messages enabled for FMI.jl ..." -using Requires - -using FMIImport - -import FMIImport.FMICore: unsense, getCurrentComponent - -# TODO recheck export import list -# fmi2 imports -import FMIImport: fmi2CallbackLogger, fmi2CallbackAllocateMemory, fmi2CallbackFreeMemory, fmi2CallbackStepFinished -import FMIImport: fmi2ComponentState, fmi2ComponentStateInstantiated, fmi2ComponentStateInitializationMode, fmi2ComponentStateEventMode, fmi2ComponentStateContinuousTimeMode, fmi2ComponentStateTerminated, fmi2ComponentStateError, fmi2ComponentStateFatal -import FMIImport: fmi2Instantiate, fmi2FreeInstance!, fmi2GetTypesPlatform, fmi2GetVersion -import FMIImport: fmi2SetDebugLogging, fmi2SetupExperiment, fmi2EnterInitializationMode, fmi2ExitInitializationMode, fmi2Terminate, fmi2Reset -import FMIImport: fmi2GetReal!, fmi2SetReal, fmi2GetInteger!, fmi2SetInteger, fmi2GetBoolean!, fmi2SetBoolean, fmi2GetString!, fmi2SetString -import FMIImport: fmi2GetFMUstate!, fmi2SetFMUstate, fmi2FreeFMUstate!, fmi2SerializedFMUstateSize!, fmi2SerializeFMUstate!, fmi2DeSerializeFMUstate! -import FMIImport: fmi2GetDirectionalDerivative!, fmi2SetRealInputDerivatives, fmi2GetRealOutputDerivatives -import FMIImport: fmi2DoStep, fmi2CancelStep, fmi2GetStatus!, fmi2GetRealStatus!, fmi2GetIntegerStatus!, fmi2GetBooleanStatus!, fmi2GetStringStatus! -import FMIImport: fmi2SetTime, fmi2SetContinuousStates, fmi2EnterEventMode, fmi2NewDiscreteStates, fmi2EnterContinuousTimeMode, fmi2CompletedIntegratorStep! -import FMIImport: fmi2GetDerivatives, fmi2GetEventIndicators, fmi2GetContinuousStates, fmi2GetNominalsOfContinuousStates -import FMIImport: fmi2StringToValueReference, fmi2ValueReferenceToString, fmi2ModelVariablesForValueReference -import FMIImport: fmi2GetReal, fmi2GetInteger, fmi2GetString, fmi2GetBoolean -import FMIImport: fmi2GetFMUstate, fmi2SerializedFMUstateSize, fmi2SerializeFMUstate, fmi2DeSerializeFMUstate -import FMIImport: fmi2GetDirectionalDerivative -import FMIImport: fmi2GetStartValue, fmi2SampleJacobian, fmi2CompletedIntegratorStep -import FMIImport: fmi2Unzip, fmi2Load, loadBinary, fmi2Reload, fmi2Unload, fmi2Instantiate! -import FMIImport: fmi2SampleJacobian! -import FMIImport: fmi2GetJacobian, fmi2GetJacobian!, fmi2GetFullJacobian, fmi2GetFullJacobian! -import FMIImport: fmi2LoadModelDescription -import FMIImport: fmi2GetDefaultStartTime, fmi2GetDefaultStopTime, fmi2GetDefaultTolerance, fmi2GetDefaultStepSize -import FMIImport: fmi2GetModelName, fmi2GetGUID, fmi2GetGenerationTool, fmi2GetGenerationDateAndTime, fmi2GetVariableNamingConvention, fmi2GetNumberOfEventIndicators, fmi2GetNumberOfStates, fmi2IsCoSimulation, fmi2IsModelExchange -import FMIImport: fmi2DependenciesSupported, fmi2GetModelIdentifier, fmi2CanGetSetState, fmi2CanSerializeFMUstate, fmi2ProvidesDirectionalDerivative -import FMIImport: fmi2Get, fmi2Get!, fmi2Set -import FMIImport: fmi2GetSolutionTime, fmi2GetSolutionState, fmi2GetSolutionValue -export fmi2GetSolutionTime, fmi2GetSolutionState, fmi2GetSolutionValue - -# fmi3 imports -import FMIImport: fmi3CallbackLogger, fmi3CallbackIntermediateUpdate, fmi3CallbackClockUpdate -import FMIImport: fmi3InstanceState, fmi3InstanceStateInstantiated, fmi3InstanceStateInitializationMode, fmi3InstanceStateEventMode, fmi3InstanceStateContinuousTimeMode, fmi3InstanceStateTerminated, fmi3InstanceStateError, fmi3InstanceStateFatal -import FMIImport: fmi3InstantiateModelExchange!, fmi3InstantiateCoSimulation!, fmi3InstantiateScheduledExecution!, fmi3FreeInstance!, fmi3GetVersion -import FMIImport: fmi3SetDebugLogging, fmi3EnterInitializationMode, fmi3ExitInitializationMode, fmi3Terminate, fmi3Reset -import FMIImport: fmi3GetFloat32!, fmi3SetFloat32, fmi3GetFloat64!, fmi3SetFloat64 -import FMIImport: fmi3GetInt8!, fmi3SetInt8, fmi3GetUInt8!, fmi3SetUInt8, fmi3GetInt16!, fmi3SetInt16, fmi3GetUInt16!, fmi3SetUInt16, fmi3GetInt32!, fmi3SetInt32, fmi3GetUInt32!, fmi3SetUInt32, fmi3GetInt64!, fmi3SetInt64, fmi3GetUInt64!, fmi3SetUInt64 -import FMIImport: fmi3GetBoolean!, fmi3SetBoolean, fmi3GetString!, fmi3SetString, fmi3GetBinary!, fmi3SetBinary, fmi3GetClock!, fmi3SetClock -import FMIImport: fmi3GetFMUState!, fmi3SetFMUState, fmi3FreeFMUState!, fmi3SerializedFMUStateSize!, fmi3SerializeFMUState!, fmi3DeSerializeFMUState! -import FMIImport: fmi3SetIntervalDecimal, fmi3SetIntervalFraction, fmi3GetIntervalDecimal!, fmi3GetIntervalFraction!, fmi3GetShiftDecimal!, fmi3GetShiftFraction! -import FMIImport: fmi3ActivateModelPartition -import FMIImport: fmi3GetNumberOfVariableDependencies!, fmi3GetVariableDependencies! -import FMIImport: fmi3GetDirectionalDerivative!, fmi3GetAdjointDerivative!, fmi3GetOutputDerivatives! -import FMIImport: fmi3DoStep! - -import FMIImport: fmi3EnterConfigurationMode, fmi3ExitConfigurationMode, fmi3GetNumberOfContinuousStates!, fmi3GetNumberOfEventIndicators!, fmi3GetContinuousStates!, fmi3GetNominalsOfContinuousStates! -import FMIImport: fmi3EvaluateDiscreteStates, fmi3EnterStepMode -import FMIImport: fmi3SetTime, fmi3SetContinuousStates, fmi3EnterEventMode, fmi3UpdateDiscreteStates, fmi3EnterContinuousTimeMode, fmi3CompletedIntegratorStep! -import FMIImport: fmi3GetContinuousStateDerivatives, fmi3GetContinuousStateDerivatives!, fmi3GetEventIndicators, fmi3GetContinuousStates, fmi3GetNominalsOfContinuousStates -import FMIImport: fmi3StringToValueReference, fmi3ValueReferenceToString, fmi3ModelVariablesForValueReference -import FMIImport: fmi3GetFloat32, fmi3GetFloat64, fmi3GetInt8, fmi3GetUInt8, fmi3GetInt16, fmi3GetUInt16, fmi3GetInt32, fmi3GetUInt32, fmi3GetInt64, fmi3GetUInt64, fmi3GetBoolean, fmi3GetBinary, fmi3GetClock, fmi3GetString -import FMIImport: fmi3SetFloat32, fmi3SetFloat64, fmi3SetInt8, fmi3SetUInt8, fmi3SetInt16, fmi3SetUInt16, fmi3SetInt32, fmi3SetUInt32, fmi3SetInt64, fmi3SetUInt64, fmi3SetBoolean, fmi3SetBinary, fmi3SetClock, fmi3SetString -import FMIImport: fmi3GetFMUState, fmi3SerializedFMUStateSize, fmi3SerializeFMUState, fmi3DeSerializeFMUState -import FMIImport: fmi3GetDirectionalDerivative, fmi3GetAdjointDerivative -import FMIImport: fmi3GetStartValue, fmi3SampleDirectionalDerivative, fmi3CompletedIntegratorStep -import FMIImport: fmi3Unzip, fmi3Load, loadBinary, fmi3Reload, fmi3Unload -import FMIImport: fmi3SampleDirectionalDerivative! -import FMIImport: fmi3GetJacobian, fmi3GetJacobian!, fmi3GetFullJacobian, fmi3GetFullJacobian! -import FMIImport: fmi3LoadModelDescription -import FMIImport: fmi3GetDefaultStartTime, fmi3GetDefaultStopTime, fmi3GetDefaultTolerance, fmi3GetDefaultStepSize -import FMIImport: fmi3GetModelName, fmi3GetInstantiationToken, fmi3GetGenerationTool, fmi3GetGenerationDateAndTime, fmi3GetVariableNamingConvention, fmi3GetNumberOfEventIndicators, fmi3GetNumberOfContinuousStates, fmi3IsCoSimulation, fmi3IsModelExchange, fmi3IsScheduledExecution -# import FMIImport: fmi3DependenciesSupported -import FMIImport:fmi3GetModelIdentifier, fmi3CanGetSetState, fmi3CanSerializeFMUState, fmi3ProvidesDirectionalDerivatives, fmi3ProvidesAdjointDerivatives -import FMIImport: fmi3Get, fmi3Get!, fmi3Set -# import FMIImport: fmi3GetSolutionTime, fmi3GetSolutionState, fmi3GetSolutionValue -# export fmi3GetSolutionTime, fmi3GetSolutionState, fmi3GetSolutionValue -export fmi3InstantiateCoSimulation!, fmi3InstantiateModelExchange!, fmi3InstantiateScheduledExecution! -export fmi3EnterInitializationMode, fmi3ExitInitializationMode -export fmi3GetFloat32, fmi3GetFloat64, fmi3GetInt8, fmi3GetUInt8, fmi3GetInt16, fmi3GetUInt16, fmi3GetInt32, fmi3GetUInt32, fmi3GetInt64, fmi3GetUInt64, fmi3GetBoolean, fmi3GetBinary, fmi3GetClock, fmi3GetString -export fmi3SetFloat64 -export fmi3UpdateDiscreteStates, fmi3GetContinuousStateDerivatives! - -import FMIImport: fmi2TypeModelExchange, fmi2TypeCoSimulation, fmi2Type -export fmi2TypeModelExchange, fmi2TypeCoSimulation, fmi2Type - -export fmiCanGetSetState - -import FMIImport: fmi3TypeModelExchange, fmi3TypeCoSimulation, fmi3TypeScheduledExecution, fmi3Type -export fmi2TypeModelExchange, fmi2TypeCoSimulation, fmi3TypeScheduledExecution, fmi2Type - -using FMIExport -using FMIExport: fmi2Create, fmi2CreateSimple - -using FMIImport.FMICore: fmi2ValueReference, fmi3ValueReference -using FMIImport: fmi2ValueReferenceFormat, fmi3ValueReferenceFormat, fmi2StructMD, fmi3StructMD, fmi2Struct, fmi3Struct - -using FMIImport.FMICore: FMU, FMU2, FMU3, FMU2Component, FMU3Instance, FMUSolution -export FMU, FMU2, FMU3, FMU2Component, FMU3Instance - -using FMIImport.FMICore: FMU2ExecutionConfiguration, FMU2_EXECUTION_CONFIGURATION_RESET, FMU2_EXECUTION_CONFIGURATION_NO_RESET, FMU2_EXECUTION_CONFIGURATION_NO_FREEING -export FMU2ExecutionConfiguration, FMU2_EXECUTION_CONFIGURATION_RESET, FMU2_EXECUTION_CONFIGURATION_NO_RESET, FMU2_EXECUTION_CONFIGURATION_NO_FREEING - -using FMIImport.FMICore: FMU3ExecutionConfiguration, FMU3_EXECUTION_CONFIGURATION_RESET, FMU3_EXECUTION_CONFIGURATION_NO_RESET, FMU3_EXECUTION_CONFIGURATION_NO_FREEING -export FMU3ExecutionConfiguration, FMU3_EXECUTION_CONFIGURATION_RESET, FMU3_EXECUTION_CONFIGURATION_NO_RESET, FMU3_EXECUTION_CONFIGURATION_NO_FREEING - -using FMIImport: prepareValue, prepareValueReference - -export fmi2Real, fmi2Integer, fmi2String, fmi2Boolean -export fmi2Info, fmi3Info -export fmi2VariableDependsOnVariable, fmi2GetDependencies, fmi2PrintDependencies, fmi3VariableDependsOnVariable, fmi3GetDependencies, fmi3PrintDependencies - -include("check.jl") - -include("FMI2/additional.jl") -include("FMI3/additional.jl") -include("assertions.jl") - -include("FMI2/comp_wraps.jl") -include("FMI3/comp_wraps.jl") - -include("FMI2/sim.jl") -include("FMI3/sim.jl") +using FMIImport.FMIBase.Reexport +@reexport using FMIImport +@reexport using FMIExport +include("sim.jl") include("deprecated.jl") -# from FMI2_plot.jl -# function fmiPlot(solution::FMUSolution; kwargs...) -# @assert false "fmiPlot(...) needs `Plots` package. Please install `Plots` and do `using Plots` or `import Plots`." -# end -# function fmiPlot!(fig, solution::FMUSolution; kwargs...) -# @assert false "fmiPlot!(...) needs `Plots` package. Please install `Plots` and do `using Plots` or `import Plots`." -# end -# export fmiPlot, fmiPlot! - -# from FMI2_JLD2.jl -# function fmiSaveSolutionJLD2(solution::FMUSolution, filepath::AbstractString; keyword="solution") -# @assert false "fmiSave(...) needs `JLD2` package. Please install `JLD2` and do `using JLD2` or `import JLD2`." -# end -# function fmiLoadSolutionJLD2(path::AbstractString; keyword="solution") -# @assert false "fmiLoad(...) needs `JLD2` package. Please install `JLD2` and do `using JLD2` or `import JLD2`." -# end -# export fmiSaveSolutionJLD2, fmiLoadSolutionJLD2 - -# from CSV.jl -# function fmiSaveSolutionCSV(solution::FMUSolution, filepath::AbstractString) -# @assert false "fmiSave(...) needs `CSV` and `DataFrames` package. Please install `CSV` and `DataFrames` and do `using CSV, DataFrames` or `import CSV, DataFrames`." -# end -# export fmiSaveSolutionCSV - -# from MAT.jl -# function fmiSaveSolutionMAT(solution::FMUSolution, filepath::AbstractString) -# @assert false "fmiSave(...) needs `MAT` package. Please install `MAT` and do `using MAT` or `import MAT`." -# end -# export fmiSaveSolutionMAT - -# from FMI3_plot.jl -# function fmiPlot(solution::FMU3Solution; kwargs...) -# @warn "fmiPlot(...) needs `Plots` package. Please install `Plots` and do `using Plots` or `import Plots`." -# end -# function fmiPlot!(fig, solution::FMU3Solution; kwargs...) -# @warn "fmiPlot!(...) needs `Plots` package. Please install `Plots` and do `using Plots` or `import Plots`." -# end -# export fmiPlot, fmiPlot! - -# from FMI3_JLD2.jl -# function fmiSaveSolution(solution::FMU3Solution, filepath::AbstractString; keyword="solution") -# @warn "fmiSave(...) needs `JLD2` package. Please install `JLD2` and do `using JLD2` or `import JLD2`." -# end -# function fmiLoadSolution(path::AbstractString; keyword="solution") -# @warn "fmiLoad(...) needs `JLD2` package. Please install `JLD2` and do `using JLD2` or `import JLD2`." -# end - -# Requires init -function __init__() - @require Plots="91a5bcdd-55d7-5caf-9e0b-520d859cae80" begin - import .Plots - include("extensions/Plots.jl") - end - @require JLD2="033835bb-8acc-5ee8-8aae-3f567f8a3819" begin - import .JLD2 - include("extensions/JLD2.jl") - end - @require DataFrames="a93c6f00-e57d-5684-b7b6-d8193f3e46c0" begin - import .DataFrames - @require CSV="336ed68f-0bac-5ca0-87d4-7b16caf5d00b" begin - import .CSV - include("extensions/CSV.jl") - end - end - @require MAT="23992714-dd62-5051-b70f-ba57cb901cac" begin - import .MAT - include("extensions/MAT.jl") - end -end - -### EXPORTING LISTS START ### - -# FMI.jl -export fmiLoad, fmiReload, fmiSimulate, fmiSimulateCS, fmiSimulateME, fmiUnload -export fmiInfo -export fmiGetModelName, fmiGetGUID, fmiGetGenerationTool, fmiGetGenerationDateAndTime - -export fmiProvidesDirectionalDerivative -export fmiIsCoSimulation, fmiIsModelExchange, fmiIsScheduledExecution -export fmiGetDependencies -export fmiGetStartValue, fmiStringToValueReference -export fmiGet, fmiGet!, fmiSet -export fmiGetSolutionTime, fmiGetSolutionState, fmiGetSolutionDerivative, fmiGetSolutionValue -export fmiGetNumberOfStates - -export fmiGetState, fmiSetState, fmiFreeState! - -### EXPORTING LISTS END ### - -""" - (str::Union{fmi2Struct, fmi3Struct})(; t::Tuple{Float64, Float64}, kwargs...) - -Wrapper for dispatch to [`fmiSimulate`](@ref). -""" -function (str::Union{fmi2Struct, fmi3Struct})(; t::Tuple{Float64, Float64}, kwargs...) - fmiSimulate(str, t; kwargs...) -end - -""" - fmiGetState(str::fmi2Struct) - -Wrapper for [`fmi2GetFMUstate`](@ref). - -See also [`fmiSetState`](@ref), [`fmiFreeState!`](@ref). -""" -function fmiGetState(str::fmi2Struct) - fmi2GetFMUstate(str) -end - -""" - fmiGetState(str::fmi3Struct) - -Wrapper for [`fmi3GetFMUState`](@ref). - -See also [`fmiSetState`](@ref), [`fmiFreeState!`](@ref). -""" -function fmiGetState(str::fmi3Struct) - fmi3GetFMUState(str) -end - -""" - fmiFreeState!(str::fmi2Struct, args...; kwargs...) - -Wrapper for [`fmi2FreeFMUstate!`](@ref). - -See also [`fmiSetState`](@ref), [`fmiGetState`](@ref). -""" -function fmiFreeState!(str::fmi2Struct, args...; kwargs...) - fmi2FreeFMUstate!(str, args...; kwargs...) -end - -""" - fmiFreeState!(str::fmi3Struct, args...; kwargs...) - -Wrapper for [`fmi3FreeFMUState!`](@ref). - -See also [`fmiSetState`](@ref), [`fmiGetState`](@ref). -""" -function fmiFreeState!(str::fmi3Struct, args...; kwargs...) - fmi3FreeFMUState!(str, args...; kwargs...) -end - -""" - fmiSetState(str::fmi2Struct, args...; kwargs...) - -Wrapper for [`fmi2SetFMUstate`](@ref). - -See also [`fmiGetState`](@ref), [`fmiFreeState!`](@ref). -""" -function fmiSetState(str::fmi2Struct, args...; kwargs...) - fmi2SetFMUstate(str, args...; kwargs...) -end - -""" - fmiSetState(str::fmi3Struct, args...; kwargs...) - -Wrapper for [`fmi3SetFMUState`](@ref). - -See also [`fmiGetState`](@ref), [`fmiFreeState!`](@ref). -""" -function fmiSetState(str::fmi3Struct, args...; kwargs...) - fmi3SetFMUState(str, args...; kwargs...) -end - -""" - fmiGetDependencies(fmu::FMU2) - -Wrapper for [`fmi2GetDependencies`](@ref). -""" -function fmiGetDependencies(fmu::FMU2) - fmi2GetDependencies(fmu) -end - -""" - fmiGetDependencies(fmu::FMU3) - -Wrapper for [`fmi3GetDependencies`](@ref). -""" -function fmiGetDependencies(fmu::FMU3) - fmi3GetDependencies(fmu) -end - -""" - fmiStringToValueReference(dataStruct::Union{FMU2, fmi2ModelDescription}, identifier::Union{String, AbstractArray{String}}) - -Wrapper for [`fmi2StringToValueReference`](@ref). - -See also [`fmi2ValueReferenceToString`](@ref). -""" -function fmiStringToValueReference(dataStruct::Union{FMU2, fmi2ModelDescription}, identifier::Union{String, AbstractArray{String}}) - fmi2StringToValueReference(dataStruct, identifier) -end - -""" - fmiStringToValueReference(dataStruct::Union{FMU3, fmi3ModelDescription}, identifier::Union{String, AbstractArray{String}}) - -Wrapper for [`fmi3StringToValueReference`](@ref). - -See also [`fmi3ValueReferenceToString`](@ref). -""" -function fmiStringToValueReference(dataStruct::Union{FMU3, fmi3ModelDescription}, identifier::Union{String, AbstractArray{String}}) - fmi3StringToValueReference(dataStruct, identifier) -end - -""" - fmiGetModelName(str::fmi2StructMD) - -Return the `modelName` from `str`'s model description. - -Wrapper for [`fmi2GetModelName`](@ref). -""" -function fmiGetModelName(str::fmi2StructMD) - fmi2GetModelName(str) -end - -""" - fmiGetModelName(str::fmi3StructMD) - -Return the `modelName` from `str`'s model description. - -Wrapper for [`fmi3GetModelName`](@ref). -""" -function fmiGetModelName(str::fmi3StructMD) - fmi3GetModelName(str) -end - -# TODO call differently in fmi3: getInstantationToken -""" - fmiGetGUID(str::fmi2StructMD) - -Return the `guid` from `str`'s model description. - -Wrapper for [`fmi2GetGUID`](@ref). -""" -function fmiGetGUID(str::fmi2StructMD) - fmi2GetGUID(str) -end - -""" - fmiGetGenerationTool(str::fmi2StructMD) - -Returns the `generationtool` from `str`'s model description. - -Wrapper for [`fmi2GetGenerationTool`](@ref). -""" -function fmiGetGenerationTool(str::fmi2StructMD) - fmi2GetGenerationTool(str) -end - -""" - fmiGetGenerationTool(str::fmi3StructMD) - -Returns the `generationtool` from `str`'s model description. - -Wrapper for [`fmi3GetGenerationTool`](@ref). -""" -function fmiGetGenerationTool(str::fmi3StructMD) - fmi3GetGenerationTool(str) -end - -""" - fmiGetGenerationDateAndTime(str::fmi2StructMD) - -Returns the `generationdateandtime` from `str`'s model description. - -Wrapper for [`fmi2GetGenerationDateAndTime`](@ref). -""" -function fmiGetGenerationDateAndTime(str::fmi2StructMD) - fmi2GetGenerationDateAndTime(str) -end - -""" - fmiGetGenerationDateAndTime(str::fmi3StructMD) - -Returns the `generationdateandtime` from `str`'s model description. - -Wrapper for [`fmi3GetGenerationDateAndTime`](@ref). -""" -function fmiGetGenerationDateAndTime(str::fmi3StructMD) - fmi3GetGenerationDateAndTime(str) -end - -""" - fmiGetVariableNamingConvention(str::fmi2StructMD) - -Returns the `varaiblenamingconvention` from `str`'s model description. - -Wrapper for [`fmi2GetVariableNamingConvention`](@ref). -""" -function fmiGetVariableNamingConvention(str::fmi2StructMD) - fmi2GetVariableNamingConvention(str) -end - -""" - fmiGetVariableNamingConvention(str::fmi3StructMD) - -Returns the `varaiblenamingconvention` from `str`'s model description. - -Wrapper for [`fmi3GetVariableNamingConvention`](@ref). -""" -function fmiGetVariableNamingConvention(str::fmi3StructMD) - fmi3GetVariableNamingConvention(str) -end - -""" - fmiGetNumberOfEventIndicators(str::fmi2StructMD) - -Returns the `numberOfEventIndicators` from `str`'s model description. - -Wrapper for [`fmi2GetNumberOfEventIndicators`](@ref). -""" -function fmiGetNumberOfEventIndicators(str::fmi2StructMD) - fmi2GetNumberOfEventIndicators(str) -end - -""" - fmiGetNumberOfEventIndicators(str::fmi3StructMD) - -Returns the `numberOfEventIndicators` from `str`'s model description. - -Wrapper for [`fmi3GetNumberOfEventIndicators`](@ref). -""" -function fmiGetNumberOfEventIndicators(str::fmi3StructMD) - fmi3GetNumberOfEventIndicators(str) -end - -""" - fmiGetModelIdentifier(fmu::Union{FMU2, FMU3}) - -Returns the tag 'modelIdentifier' from CS or ME section. - -# Arguments - - `fmu::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `fmu::FMU3`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 3.0 Standard](https://fmi-standard.org/). -# Returns -- `fmu.modelDescription.coSimulation.modelIdentifier`: The function `fmiGetModelIdentifier` returns the tag 'coSimulation.modelIdentifier' from the model description of the FMU2 or FMU3-struct (`fmu.modelDescription`), if the FMU supports co simulation. -- `fmu.modelDescription.modelExchange.modelIdentifier`: The function `fmiGetModelIdentifier` returns the tag 'modelExchange.modelIdentifier' from the model description of the FMU2 or FMU3-struct (`fmu.modelDescription`), if the FMU supports model exchange -- `fmu.modelDescription.modelExchange.modelIdentifier`: The function `fmiGetModelIdentifier` returns the tag 'scheduledExecution.modelIdentifier' from the model description of the FMU3-struct (`fmu.modelDescription`), if the FMU supports scheduled execution - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - -Also see [`fmi2GetModelIdentifier`](@ref), [`FMU2`](@ref), [`fmi3GetModelIdentifier`](@ref), [`FMU3`](@ref). -""" -function fmiGetModelIdentifier(fmu::FMU2) - fmi2GetModelIdentifier(fmu.modelDescription; type=fmu.type) -end -function fmiGetModelIdentifier(fmu::FMU3) - fmi3GetModelIdentifier(fmu.modelDescription; type=fmu.type) -end -""" - fmiCanGetSetState(str::Union{fmi2StructMD, fmi3StructMD}) - -Returns true, if the FMU supports the getting/setting of states - -# Arguments -- `str::Union{fmi2StructMD, fmi3StructMD}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2StructMD = Union{FMU2, FMU2Component, fmi2ModelDescription}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::fmi2ModelDescription`: Struct witch provides the static information of ModelVariables. - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::fmi3ModelDescription`: Struct witch provides the static information of ModelVariables. - -# Returns - - `::Bool`: The function `fmi2CanGetSetState` returns True, if the FMU supports the getting/setting of states. - -# Source - - FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) - - FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files - - FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - - See also [`fmi2CanGetSetState`](@ref), [`fmi2StructMD`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi2ModelDescription`](@ref), [`fmi3CanGetSetState`](@ref), [`fmi3StructMD`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref), [`fmi3ModelDescription`](@ref). - """ -function fmiCanGetSetState(str::fmi2StructMD) - fmi2CanGetSetState(str) -end -function fmiCanGetSetState(str::fmi3StructMD) - fmi3CanGetSetState(str) -end - -""" - fmiCanSerializeFMUstate(str::Union{fmi2StructMD, fmi3StructMD}) - -Returns true, if the FMU state can be serialized - -# Arguments -- `str::Union{fmi2StructMD, fmi3StructMD}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2StructMD = Union{FMU2, FMU2Component, fmi2ModelDescription}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` -- `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::fmi2ModelDescription`: Struct wich provides the static information of ModelVariables. - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::fmi3ModelDescription`: Struct witch provides the static information of ModelVariables. - -# Returns - - `::Bool`: The function `fmi2CanSerializeFMUstate` returns True, if the FMU state can be serialized. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - -See also [`fmi2CanSerializeFMUstate`](@ref), [`fmi2StructMD`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi2ModelDescription`](@ref), [`fmi3CanSerializeFMUstate`](@ref), [`fmi3StructMD`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref), [`fmi3ModelDescription`](@ref). -""" -function fmiCanSerializeFMUstate(str::fmi2StructMD) - fmi2CanSerializeFMUstate(str) -end -function fmiCanSerializeFMUstate(str::fmi3StructMD) - fmi3CanSerializeFMUState(str) -end - -# TODO fmi3Call fmiProvidesDirectionalDerivatives - -""" - fmiProvidesDirectionalDerivative(str::Union{fmi2StructMD, fmi3StructMD}) - -Returns true, if the FMU provides directional derivatives - -# Arguments -- `str::Union{fmi2StructMD, fmi3StructMD}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2StructMD = Union{FMU2, FMU2Component, fmi2ModelDescription}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::fmi2ModelDescription`: Struct witch provides the static information of ModelVariables. - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::fmi3ModelDescription`: Struct witch provides the static information of ModelVariables. - -# Returns -- `::Bool`: The function `fmi2ProvidesDirectionalDerivative` returns True, if the FMU provides directional derivatives. - -See also [`fmi2ProvidesDirectionalDerivative`](@ref), [`fmi2StructMD`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi2ModelDescription`](@ref), [`fmi3ProvidesDirectionalDerivatives`](@ref), [`fmi3StructMD`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref), [`fmi3ModelDescription`](@ref). -""" -function fmiProvidesDirectionalDerivative(str::fmi2StructMD) - fmi2ProvidesDirectionalDerivative(str) -end -function fmiProvidesDirectionalDerivative(str::fmi3StructMD) - fmi3ProvidesDirectionalDerivatives(str) -end - -""" - fmiProvidesAdjointDerivative(str::fmi3StructMD) - -Returns true, if the FMU provides adjoint derivatives - -# Arguments -- `str::fmi3StructMD`: Representative for an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi3StructMD = Union{FMU3, FMU3Component, fmi3ModelDescription}` - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::fmi3ModelDescription`: Struct witch provides the static information of ModelVariables. - -# Returns -- `::Bool`: The function `fmi3ProvidesAdjointDerivatives` returns True, if the FMU provides adjoint derivatives. - -See also [`fmi3ProvidesAdjointDerivatves`](@ref), [`fmi3StructMD`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref), [`fmi3ModelDescription`](@ref). -""" -function fmiProvidesAdjointDerivative(str::fmi3StructMD) - fmi3ProvidesAdjointDerivatives(str) -end - -""" - fmiIsCoSimulation(str::Union{fmi2StructMD, fmi3StructMD}) - -Returns true, if the FMU supports co simulation - -# Arguments -- `str::Union{fmi2StructMD, fmi3StructMD}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2StructMD = Union{FMU2, FMU2Component, fmi2ModelDescription}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` -- `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::fmi2ModelDescription`: Struct witch provides the static information of ModelVariables. - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::fmi3ModelDescription`: Struct witch provides the static information of ModelVariables. - -# Returns - - `::Bool`: The function `fmi2IsCoSimulation` returns True, if the FMU supports co simulation - -See also [`fmi2IsCoSimulation`](@ref), [`fmi2StructMD`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi2ModelDescription`](@ref), [`fmi3IsCoSimulation`](@ref), [`fmi3StructMD`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref), [`fmi3ModelDescription`](@ref). -""" -function fmiIsCoSimulation(str::fmi2StructMD) - fmi2IsCoSimulation(str) -end -function fmiIsCoSimulation(str::fmi3StructMD) - fmi3IsCoSimulation(str) -end - -""" - fmiIsModelExchange(str::Union{fmi2StructMD, fmi3StructMD}) - -Returns true, if the FMU supports model exchange - -# Arguments -- `str::Union{fmi2StructMD, fmi3StructMD}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2StructMD = Union{FMU2, FMU2Component, fmi2ModelDescription}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::fmi2ModelDescription`: Struct witch provides the static information of ModelVariables. - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::fmi3ModelDescription`: Struct witch provides the static information of ModelVariables. - -# Returns - - `::Bool`: The function `fmi2IsModelExchange` returns True, if the FMU supports model exchange. - - # Source - - FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) - - FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files - - FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - -See also [`fmi2IsModelExchange`](@ref), [`fmi2StructMD`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi2ModelDescription`](@ref), [`fmi3IsModelExchange`](@ref), [`fmi3StructMD`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref), [`fmi3ModelDescription`](@ref). -""" -function fmiIsModelExchange(str::fmi2StructMD) - fmi2IsModelExchange(str) -end -function fmiIsModelExchange(str::fmi3StructMD) - fmi3IsModelExchange(str) -end - -""" - fmiIsScheduledExecution(str::fmi3StructMD) - -Returns true, if the FMU supports scheduled execution - -# Arguments -- `str::fmi3StructMD`: Representative for an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::fmi3ModelDescription`: Struct witch provides the static information of ModelVariables. - -# Returns - - `::Bool`: The function `fmi3IsScheduledExecution` returns True, if the FMU supports scheduled execution. - -See also [`fmi3IsScheduledExecution`](@ref), [`fmi3StructMD`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref), [`fmi3ModelDescription`](@ref). -""" -function fmiIsScheduledExecution(str::fmi3StructMD) - fmi3IsScheduledExecution(str) -end - -# Multiple Dispatch variants for FMUs with version 2.0.X - -""" - fmiLoad(pathToFMU::String; unpackPath=nothing, type=nothing) - -Load FMUs independent of the FMI version, currently supporting version 2.0.X and 3.0. - -# Arguments -- `pathToFMU::String`: String that contains the paths of ziped and unziped FMU folders. - -# Keywords -- `unpackPath=nothing`: Via optional argument ```unpackPath```, a path to unpack the FMU can be specified (default: system temporary directory). -- `type::Union{CS, ME, SE} = nothing`: Via ```type```, a FMU type can be selected. If none of the unified type set is used, the default value `type = nothing` will be used. - -# Returns -- Returns the instance of the FMU struct. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - - -See also [`fmi2Load`](@ref), [`fmi3Load`](@ref). -""" -function fmiLoad(pathToFMU::AbstractString, args...; kwargs...) - version = fmiCheckVersion(pathToFMU) - if version == "2.0" - fmi2Load(pathToFMU, args...; kwargs...) - elseif version == "3.0" - fmi3Load(pathToFMU, args...; kwargs...) - else - @warn "fmiLoad(...): Unknown FMU version" - end -end - -""" - fmiReload(fmu::Union{FMU2, FMU3}) - -Reloads the FMU-binary. This is useful, if the FMU does not support a clean reset implementation. - -# Arguments -- `fmu::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). -- `fmu::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -See also [`fmi2Reload`](@ref), [`fmi3Reload`](@ref). -""" -function fmiReload(fmu::FMU2, args...; kwargs...) - fmi2Reload(fmu, args...; kwargs...) -end -function fmiReload(fmu::FMU3, args...; kwargs...) - fmi3Reload(fmu, args...; kwargs...) -end - -""" - fmiSimulate(str::fmi2Struct, args...; kwargs...) - -Start a simulation of the FMU instance `str` for the matching FMU version and type. - -Wrapper for [`fmi2Simulate`](@ref). -""" -function fmiSimulate(str::fmi2Struct, args...; kwargs...) - fmi2Simulate(str, args...; kwargs...) -end - -""" - fmiSimulate(str::fmi3Struct, args...; kwargs...) - -Start a simulation of the FMU instance `str` for the matching FMU version and type. - -Wrapper for [`fmi3Simulate`](@ref). -""" -function fmiSimulate(str::fmi3Struct, args...; kwargs...) - fmi3Simulate(str, args...; kwargs...) -end - -""" - fmiSimulateCS(str::fmi2Struct, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing, args...; kwargs...) - -Start a simulation of the Co-Simulation FMU instance `str`. - -Wrapper for [`fmi2SimulateCS`](@ref). -""" -function fmiSimulateCS(str::fmi2Struct, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing, args...; kwargs...) - fmi2SimulateCS(str, tspan, args...; kwargs...) -end - -""" - fmiSimulateCS(str::fmi3Struct, args...; kwargs...) - -Start a simulation of the Co-Simulation FMU instance `str`. - -Wrapper for [`fmi3SimulateCS`](@ref). -""" -function fmiSimulateCS(str::fmi3Struct, args...; kwargs...) - fmi3SimulateCS(str, args...; kwargs...) -end - -""" - fmiSimulateME(str::Union{fmi2Struct,fmi3Struct}, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; - tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - solver = nothing, - customFx = nothing, - recordValues::fmi2ValueReferenceFormat = nothing, - saveat = nothing, - x0::Union{AbstractArray{<:Real}, Nothing} = nothing, - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi2ValueReferenceFormat = nothing, - inputFunction = nothing, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing, - dtmax::Union{Real, Nothing} = nothing, - callbacks = [], - showProgress::Bool = true, - kwargs...) - -Simulates a FMU instance for the given simulation time interval. - - -# Arguments -- `str::Union{fmi2StructMD, fmi3StructMD}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` -More detailed: `fmi3Struct = Union{FMU3, FMU3Instance}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - - `tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing`: Sets the time span as a tuple or the default value from the model description is used. - -# Keywords -- `tolerance::Union{Real, Nothing} = nothing`: Real number to set the tolerance for any OED-solver -- `dt::Union{Real, Nothing} = nothing`: Real number to set the step size of the OED-solver. Defaults to an automatic choice if the method is adaptive. More Info: [DifferentialEquations.jl Documentation](https://diffeq.sciml.ai/stable/basics/common_solver_opts/#Stepsize-Control) -- `solver = nothing`: Any Julia-supported OED-solver (default is Tsit5). More Info: [DifferentialEquations.jl Documentation](https://diffeq.sciml.ai/stable/solvers/ode_solve/#ode_solve) -- `customFx = nothing`: [deperecated] Ability to give a custom state derivative function xΜ‡=f(x,t) -- `recordValues::fmi2ValueReferenceFormat = nothing`: AbstractArray of variables (strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` -- `saveat = nothing`: Time points to save values at (interpolated). More Info: [DifferentialEquations.jl Documentation](https://diffeq.sciml.ai/stable/basics/common_solver_opts/#Output-Control) -- `x0::Union{AbstractArray{<:Real}, Nothing} = nothing`: Stores the specific value of `fmi2ScalarVariable` containing the modelVariables with the identical fmi2ValueReference to the input variable vr (vr = vrs[i]). And is therefore passed within prepareSolveFMU to fmi2Set , to set the start state. -- `setup::Bool = true`: Boolean, if FMU should be setup (default: setup=true) -- `reset::Union{Bool, Nothing} = nothing`: Boolean, if FMU should be reset before simulation (default: reset:=auto) -- `instantiate::Union{Bool, Nothing} = nothing`: Boolean value that decides whether to create a new instance of the specified fmu. -- `freeInstance::Union{Bool, Nothing} = nothing`: Boolean value that determines whether to dispose of the given instance, unload the loaded model, and free the allocated memory and other resources allocated by the FMU interface functions. -- `terminate::Union{Bool, Nothing} = nothing`: Boolean value that tells the FMU that the simulation run will be aborted. -- `inputValueReferences::fmi2ValueReferenceFormat = nothing`: AbstractArray of input variables (strings or variableIdentifiers) to set at every simulation step -- `inputFunction = nothing`: Function to retrieve the values to set the inputs to -- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dictionary of parameter variables (strings or variableIdentifiers) and values (Real, Integer, Boolean, String) to set parameters during initialization -- `dtmax::Union{Real, Nothing} = nothing`: Real number for setting maximum dt for adaptive timestepping for the ODE solver. The default values are package dependent. More Info: [DifferentialEquations.jl Documentation](https://diffeq.sciml.ai/stable/basics/common_solver_opts/#Stepsize-Control) -- `callbacks = []`: custom callbacks to add. -- `showProgress::Bool = true`: Boolean value that determines whether a progress bar is generated for a task -- `kwargs...`: Further parameters of already defined functions `solve(args..., kwargs...)` from the library [DifferentialEquations.jl](https://diffeq.sciml.ai/stable/#DifferentialEquations.jl:-Scientific-Machine-Learning-(SciML)-Enabled-Simulation-and-Estimation) - -# Returns -- If keyword `recordValues` is not set, a struct of type `ODESolution`. -- If keyword `recordValues` is set, a tuple of type (ODESolution, DiffEqCallbacks.SavedValues). - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - -See also [`fmi2SimulateME`](@ref) [`fmi2SimulateCS`](@ref), [`fmi2Simulate`](@ref), [`fmi2Struct`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref). - -""" -function fmiSimulateME(str::fmi2Struct, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing, args...; kwargs...) - fmi2SimulateME(str, tspan, args...; kwargs...) -end -function fmiSimulateME(str::fmi3Struct, args...; kwargs...) - fmi3SimulateME(str, args...; kwargs...) -end - -""" - fmiUnload(fmu::Union{FMU2, FMU3}) - -Unloads the FMU and all its instances and frees the allocated memory. - -# Arguments -- `fmu::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). -- `fmu::FMU3`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 3.0 Standard](https://fmi-standard.org/). - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -See also [`fmi2Unload`](@ref), [`fmi3Unload`](@ref). -""" -function fmiUnload(fmu::FMU2) - fmi2Unload(fmu) -end -function fmiUnload(fmu::FMU3) - fmi3Unload(fmu) -end - -#to add to docstring: see also [`fmi3GetNumberOfStates`](@ref) -""" - fmiGetNumberOfStates(str::Union{fmi2Struct, fmi3Struct}) - -Returns the number of states of the FMU. - -# Arguments -- `str::Union{fmi2Struct, fmi3Struct}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - -# Returns -- Returns the length of the `md.valueReferences::Array{fmi2ValueReference}` corresponding to the number of states of the FMU. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - -See also [`fmi2GetNumberOfStates`](@ref), [`fmi2Struct`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), , [`fmi3Struct`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref). -""" -function fmiGetNumberOfStates(str::fmi2Struct) - fmi2GetNumberOfStates(str) -end -function fmiGetNumberOfStates(str::fmi3Struct) - fmi3GetNumberOfStates(str) -end - -# TODO not in FMI3 -""" - fmiGetTypesPlatform(str::fmi2Struct) - -Returns the header file used to compile the FMU. By default returns `default`, version independent. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/). - -# Returns -- Returns the string to uniquely identify the β€œfmi2TypesPlatform.h” header file used for compilation of the functions of the FMU. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - -See also [`fmi2GetVersion`](@ref), [`fmi2Struct`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref). -""" -function fmiGetTypesPlatform(str::fmi2Struct) - fmi2GetTypesPlatform(str) -end - -""" - fmiGetVersion(str::Union{fmi2Struct, fmi3Struct}) - -Returns the version of the FMU, version independent. - -# Arguments -- `str::Union{fmi2Struct, fmi3Struct}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - -# Returns -- Returns a string from the address of a C-style (NUL-terminated) string. The string represents the version of the β€œfmiXFunctions.h” header file which was used to compile the functions of the FMU. The function returns β€œfmiVersion” which is defined in this header file. The standard header file as documented in this specification has version β€œ2.0” or "3.0" - -# Source - - FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) - - FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files - - FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - - FMISpec3.0[p. ]: 2.2.5. Inquire Version Number of Header Files - -See also [`fmi2GetVersion`](@ref), [`unsafe_string`](https://docs.julialang.org/en/v1/base/strings/#Base.unsafe_string), [`fmi2Struct`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi3GetVersion`](@ref), [`fmi3Struct`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref). -""" -function fmiGetVersion(str::fmi2Struct) - fmi2GetVersion(str) -end -function fmiGetVersion(str::fmi3Struct) - fmi3GetVersion(str) -end - -""" - fmiInfo(str::fmi2Struct) - -Prints FMU-specific information into the REPL. - -# Arguments -- `str::Union{fmi2Struct, fmi3Struct}`: Representative for an FMU in the [FMI 2.0.2 Standard](https://fmi-standard.org/) or [FMI 3.0 Standard](https://fmi-standard.org/). Other notation: -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` -More detailed: `fmi3StructMD = Union{FMU3, FMU3Instance, fmi3ModelDescription}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - - `str::FMU3`: Mutable struct representing an FMU in the [FMI 3.0 Standard](https://fmi-standard.org/). - - `str::FMU3Instance`: Mutable struct represents a pointer to an FMU specific data structure that contains the information needed. Also in [FMI 3.0 Standard](https://fmi-standard.org/). - -# Returns -- Prints FMU related information. - - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec3.0 Link: [https://fmi-standard.org/](https://fmi-standard.org/) - -See also [`fmi2Info`](@ref), [`fmi2Struct`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi3Info`](@ref), [`fmi3Struct`](@ref), [`FMU3`](@ref), [`FMU3Instance`](@ref). -""" -function fmiInfo(str::fmi2Struct) - fmi2Info(str) -end -function fmiInfo(str::fmi3Struct) - fmi3Info(str) -end - -""" - fmiGet(str::fmi2Struct, comp::FMU2Component, vrs::fmi2ValueReferenceFormat) - -Returns the specific value of `fmi2ScalarVariable` containing the modelVariables with the identical fmi2ValueReference in an array. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - - `vrs::fmi2ValueReferenceFormat`: wildcards for how a user can pass a fmi[X]ValueReference -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` - -# Returns -- `dstArray::Array{Any,1}(undef, length(vrs))`: Stores the specific value of `fmi2ScalarVariable` containing the modelVariables with the identical fmi2ValueReference to the input variable vr (vr = vrs[i]). `dstArray` is a 1-Dimensional Array that has the same length as `vrs`. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - -""" -function fmiGet(str::fmi2Struct, args...; kwargs...) - fmi2Get(str, args...; kwargs...) -end -function fmiGet(str::fmi3Struct, args...; kwargs...) - fmi3Get(str, args...; kwargs...) -end -""" - fmiGet!(str::fmi2Struct, comp::FMU2Component, vrs::fmi2ValueReferenceFormat, dstArray::AbstractArray) - -Stors the specific value of `fmi2ScalarVariable` containing the modelVariables with the identical fmi2ValueReference in an array. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` -- `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. -- `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `dstArray::AbstractArray`: Stores the specific value of `fmi2ScalarVariable` containing the modelVariables with the identical fmi2ValueReference to the input variable vr (vr = vrs[i]). `dstArray` has the same length as `vrs`. - -# Returns -- `retcodes::Array{fmi2Status}`: Returns an array of length length(vrs) with Type `fmi2Status`. Type `fmi2Status` is an enumeration and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - -""" -function fmiGet!(str::fmi2Struct, args...; kwargs...) - fmi2Get!(str, args...; kwargs...) -end -function fmiGet!(str::fmi3Struct, args...; kwargs...) - fmi3Get!(str, args...; kwargs...) -end -""" - fmiSet(str::fmi2Struct, comp::FMU2Component, vrs::fmi2ValueReferenceFormat, srcArray::AbstractArray; filter=nothing) - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` -- `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. -- `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `srcArray::AbstractArray`: Stores the specific value of `fmi2ScalarVariable` containing the modelVariables with the identical fmi2ValueReference to the input variable vr (vr = vrs[i]). `srcArray` has the same length as `vrs`. - -# Keywords -- `filter=nothing`: whether the individual values of "fmi2ScalarVariable" are to be stored - -# Returns -- `retcodes::Array{fmi2Status}`: Returns an array of length length(vrs) with Type `fmi2Status`. Type `fmi2Status` is an enumeration and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions -""" -function fmiSet(str::fmi2Struct, args...; kwargs...) - fmi2Set(str, args...; kwargs...) -end -function fmiSet(str::fmi3Struct, args...; kwargs...) - fmi3Set(str, args...; kwargs...) -end - -""" - fmiGetReal(str::fmi2Struct, vr::fmi2ValueReferenceFormat) - -Returns the real values of an array of variables - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: wildcards for how a user can pass a fmi[X]ValueReference -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` - -# Returns -- `values::Array{fm2Real}`: returns values of an array of fmi2Real variables with the dimension of fmi2ValueReferenceFormat length. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - -See also [`fmi2GetReal`](@ref),[`fmi2ValueReferenceFormat`](@ref), [`fmi2Struct`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref). - -""" -function fmiGetReal(str::fmi2Struct, args...; kwargs...) - fmi2GetReal(str, args...; kwargs...) -end -function fmiGetReal(str::fmi3Struct, args...; kwargs...) - fmi3GetReal(str, args...; kwargs...) -end - -export fmiGetReal - - -""" - fmiSampleJacobian(str::fmi2Struct, c::FMU2Component, - vUnknown_ref::Array{fmi2ValueReference}, - vKnown_ref::Array{fmi2ValueReference}, - steps::Array{fmi2Real} = ones(fmi2Real, length(vKnown_ref)).*1e-5) - fmiSampleJacobian(str::fmi2Struct, c::FMU2Component, - vUnknown_ref::AbstractArray{fmi2ValueReference}, - vKnown_ref::AbstractArray{fmi2ValueReference}, - steps::Union{AbstractArray{fmi2Real}, Nothing} = nothing) -This function samples the jacobian by manipulating corresponding values (central differences). -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vUnknown_ref::Array{fmi2ValueReference}`: Argument `vUnKnown_ref` contains values of type `fmi2ValueReference` which are identifiers of a variable value of the model.`vKnown_ref` is the Array of the vector values of Real input variables of function h that changes its value in the actual Mode. -- `vKnown_ref::Array{fmi2ValueReference}`: Argument `vKnown_ref` contains values of type `fmi2ValueReference` which are identifiers of a variable value of the model.`vKnown_ref` is the Array of the vector values of Real input variables of function h that changes its value in the actual Mode. -- `steps::Array{fmi2Real} = ones(fmi2Real, length(vKnown_ref)).*1e-5`: Predefined step size vector `steps`, where all entries have the value 1e-5. -- `steps::Union{AbstractArray{fmi2Real}, Nothing} = nothing`: Step size to be used for numerical differentiation. If nothing, a default value will be chosen automatically. - -# Returns -- `dvUnknown::Arrya{fmi2Real}`: -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -See also [`fmi2SampleJacobian`](@ref), [`fmi2Struct`](@ref), [`FMU2`](@ref), [`FMU2Component`](@ref), [`fmi2ValueReference`](@ref). -""" -function fmiSampleJacobian(str::fmi2Struct, args...; kwargs...) - fmi2SampleJacobian(str, args...; kwargs...) -end -function fmiSampleJacobian(str::fmi3Struct, args...; kwargs...) - fmi3SampleJacobian(str, args...; kwargs...) -end - -""" -#TODO -Samples the values of the jacobian (in-place). -""" -function fmiSampleJacobian!(str::fmi3Struct, args...; kwargs...) - fmi3SampleJacobian!(str, args...; kwargs...) -end -function fmiSampleJacobian!(str::fmi2Struct, args...; kwargs...) - fmi2SampleJacobian!(str, args...; kwargs...) -end - -""" - - fmiGetStartValue(s::fmi2Struct, vr::fmi2ValueReferenceFormat) - -Returns the start/default value for a given value reference. - - -# Arguments -- `md::fmi2ModelDescription`: Struct which provides the static information of ModelVariables. -- `vrs::fmi2ValueReferenceFormat = md.valueReferences`: wildcards for how a user can pass a fmi[X]ValueReference (default = md.valueReferences) -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` - -# Returns -- `starts::Array{fmi2ValueReferenceFormat}`: start/default value for a given value reference - -""" -function fmiGetStartValue(s::fmi2Struct, vr::fmi2ValueReferenceFormat) - fmi2GetStartValue(s, vr) -end -function fmiGetStartValue(s::fmi3Struct, vr::fmi3ValueReferenceFormat) - fmi3GetStartValue(s, vr) -end - -""" - fmiSaveSolution(solution::FMUSolution, filepath::AbstractString [; keyword="solution"]) - -Save a `solution` of an FMU simulation at `filepath`. - -Currently .mat, .jld2 and .csv are supported for saving and selected by the ending of `filepath`. -For JLD2 the `keyword` is used as key. -Loading a FMUSolution into FMI.jl is currently only possible for .jld2 files. - -See also [`fmiSaveSolutionCSV`](@ref), [`fmiSaveSolutionMAT`](@ref), [`fmiSaveSolutionJLD2`](@ref), [`fmiLoadSolutionJLD2`](@ref). -""" -function fmiSaveSolution(solution::FMUSolution, filepath::AbstractString; keyword="solution") - ending = split(filepath, ".")[2] - if ending == "mat" - fmiSaveSolutionMAT(solution, filepath) - elseif ending == "jld2" - fmiSaveSolutionJLD2(solution, filepath; keyword="solution") - elseif ending == "csv" - fmiSaveSolutionCSV(solution, filepath) - else - @assert false "This file format is currently not supported, please use *.mat, *.csv, *.JLD2" - end -end - -""" - fmiLoadSolution(filepath::AbstractString; keyword="solution") - -Wrapper for [`fmiLoadSolutionJLD2`](@ref). -""" -function fmiLoadSolution(filepath::AbstractString; keyword="solution") - ending = split(filepath, ".")[2] - if ending == "jld2" - fmiLoadSolutionJLD2(filepath; keyword="solution") - else - @warn "This file format is currently not supported, please use *.jld2" - end -end -export fmiSaveSolution, fmiLoadSolution - end # module FMI diff --git a/src/FMI2/additional.jl b/src/FMI2/additional.jl deleted file mode 100644 index d6be6c2c..00000000 --- a/src/FMI2/additional.jl +++ /dev/null @@ -1,168 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# What is included in the file `FMI2_additional.jl` (FMU add functions)? -# - high-level functions, that are useful, but not part of the FMI-spec [exported] - -using Base.Filesystem: mktempdir - -using FMIImport: FMU2, fmi2ModelDescription -using FMIImport: fmi2Boolean, fmi2Real, fmi2Integer, fmi2Byte, fmi2String, fmi2FMUstate -using FMIImport: fmi2True, fmi2False -using FMIImport: fmi2StatusKind, fmi2Status -using FMIImport: fmi2DependencyKindDependent, fmi2DependencyKindFixed -using FMIImport: fmi2CallbackFunctions, fmi2Component -import FMIImport: fmi2VariableNamingConventionFlat, fmi2VariableNamingConventionStructured - -""" - fmi2VariableDependsOnVariable(fmu::FMU2, vr1::fmi2ValueReference, vr2::fmi2ValueReference) - -Return the dependence of the variable described by `vr1` on another variable described by `vr2` based on the model description of the `fmu`. - -See also [`fmi2GetDependencies`](@ref). -""" -function fmi2VariableDependsOnVariable(fmu::FMU2, vr1::fmi2ValueReference, vr2::fmi2ValueReference) - i1 = fmu.modelDescription.valueReferenceIndicies[vr1] - i2 = fmu.modelDescription.valueReferenceIndicies[vr2] - return fmi2GetDependencies(fmu)[i1, i2] -end - -""" - fmi2GetDependencies(fmu::FMU2) - -Build dependency `Matrix{Union{fmi2DependencyKind, Nothing}}` of dimension `n x n` for fast look-ups on dependencies between value references (`n` is number of states of the `fmu`). - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions - -See also [`fmi2PrintDependencies`](@ref), [`fmi2VariableDependsOnVariable`](@ref). -""" -function fmi2GetDependencies(fmu::FMU2) - if !isdefined(fmu, :dependencies) - dim = length(fmu.modelDescription.valueReferences) - @info "fmi2GetDependencies: Started building dependency matrix $(dim) x $(dim) ..." - - if fmi2DependenciesSupported(fmu.modelDescription) - fmu.dependencies = fill(nothing, dim, dim) - - for i in 1:dim - modelVariable = fmi2ModelVariablesForValueReference(fmu.modelDescription, fmu.modelDescription.valueReferences[i])[1] - - if modelVariable.dependencies !== nothing - indicies = collect(fmu.modelDescription.valueReferenceIndicies[fmu.modelDescription.modelVariables[dependency].valueReference] for dependency in modelVariable.dependencies) - dependenciesKind = modelVariable.dependenciesKind - - k = 1 - for j in 1:dim - if j in indicies - if dependenciesKind[k] == "fixed" - fmu.dependencies[i,j] = fmi2DependencyKindFixed - elseif dependenciesKind[k] == "dependent" - fmu.dependencies[i,j] = fmi2DependencyKindDependent - else - @warn "Unknown dependency kind for index ($i, $j) = `$(dependenciesKind[k])`." - end - k += 1 - end - end - end - end - else - fmu.dependencies = fill(nothing, dim, dim) - end - - @info "fmi2GetDependencies: Building dependency matrix $(dim) x $(dim) finished." - end - - fmu.dependencies -end - -""" - fmi2PrintDependencies(fmu::FMU2) - -Print the dependency matrix for `fmu` as returned by [`fmi2GetDependencies`](@ref). - -See also [`fmi2GetDependencies`](@ref). -""" -function fmi2PrintDependencies(fmu::FMU2) - dep = fmi2GetDependencies(fmu) - ni, nj = size(dep) - - for i in 1:ni - str = "" - for j in 1:nj - str = "$(str) $(Integer(dep[i,j]))" - end - println(str) - end -end - -""" - fmi2Info(fmu::FMU2) - -Print information about the `fmu`. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.4 Inquire Platform and Version Number of Header Files -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -""" -function fmi2Info(fmu::FMU2) - println("#################### Begin information for FMU ####################") - - println("\tModel name:\t\t\t$(fmi2GetModelName(fmu))") - println("\tFMI-Version:\t\t\t$(fmi2GetVersion(fmu))") - println("\tGUID:\t\t\t\t$(fmi2GetGUID(fmu))") - println("\tGeneration tool:\t\t$(fmi2GetGenerationTool(fmu))") - println("\tGeneration time:\t\t$(fmi2GetGenerationDateAndTime(fmu))") - print("\tVar. naming conv.:\t\t") - if fmi2GetVariableNamingConvention(fmu) == fmi2VariableNamingConventionFlat - println("flat") - elseif fmi2GetVariableNamingConvention(fmu) == fmi2VariableNamingConventionStructured - println("structured") - else - println("[unknown]") - end - println("\tEvent indicators:\t\t$(fmi2GetNumberOfEventIndicators(fmu))") - - println("\tInputs:\t\t\t\t$(length(fmu.modelDescription.inputValueReferences))") - for vr in fmu.modelDescription.inputValueReferences - println("\t\t$(vr) $(fmi2ValueReferenceToString(fmu, vr))") - end - - println("\tOutputs:\t\t\t$(length(fmu.modelDescription.outputValueReferences))") - for vr in fmu.modelDescription.outputValueReferences - println("\t\t$(vr) $(fmi2ValueReferenceToString(fmu, vr))") - end - - println("\tStates:\t\t\t\t$(length(fmu.modelDescription.stateValueReferences))") - for vr in fmu.modelDescription.stateValueReferences - println("\t\t$(vr) $(fmi2ValueReferenceToString(fmu, vr))") - end - - println("\tSupports Co-Simulation:\t\t$(fmi2IsCoSimulation(fmu))") - if fmi2IsCoSimulation(fmu) - println("\t\tModel identifier:\t$(fmu.modelDescription.coSimulation.modelIdentifier)") - println("\t\tGet/Set State:\t\t$(fmu.modelDescription.coSimulation.canGetAndSetFMUstate)") - println("\t\tSerialize State:\t$(fmu.modelDescription.coSimulation.canSerializeFMUstate)") - println("\t\tDir. Derivatives:\t$(fmu.modelDescription.coSimulation.providesDirectionalDerivative)") - - println("\t\tVar. com. steps:\t$(fmu.modelDescription.coSimulation.canHandleVariableCommunicationStepSize)") - println("\t\tInput interpol.:\t$(fmu.modelDescription.coSimulation.canInterpolateInputs)") - println("\t\tMax order out. der.:\t$(fmu.modelDescription.coSimulation.maxOutputDerivativeOrder)") - end - - println("\tSupports Model-Exchange:\t$(fmi2IsModelExchange(fmu))") - if fmi2IsModelExchange(fmu) - println("\t\tModel identifier:\t$(fmu.modelDescription.modelExchange.modelIdentifier)") - println("\t\tGet/Set State:\t\t$(fmu.modelDescription.modelExchange.canGetAndSetFMUstate)") - println("\t\tSerialize State:\t$(fmu.modelDescription.modelExchange.canSerializeFMUstate)") - println("\t\tDir. Derivatives:\t$(fmu.modelDescription.modelExchange.providesDirectionalDerivative)") - end - - println("##################### End information for FMU #####################") -end diff --git a/src/FMI2/comp_wraps.jl b/src/FMI2/comp_wraps.jl deleted file mode 100644 index 511ea875..00000000 --- a/src/FMI2/comp_wraps.jl +++ /dev/null @@ -1,618 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# What is included in the file `FMI2_comp_wraps.jl` (FMU component wrappers)? -# - wrappers to call fmi2ComponentFunctions from FMUs (FMI-functions, last instantiated component is used) [exported] -# - wrappers to call fmi2ComponentFunctions from FMUs (additional functions, last instantiated component is used) [exported] - -# FMI-spec -""" - fmi2Simulate(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2Simulate(fmu::FMU2, c::Union{FMU2Component, Nothing}, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets passed as `nothing`) -""" -function fmi2Simulate(fmu::FMU2, args...; kwargs...) - return fmi2Simulate(fmu, nothing, args...; kwargs...) -end - -""" - fmi2SimulateCS(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SimulateCS(fmu::FMU2, c::Union{FMU2Component, Nothing}, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets passed as `nothing`) -""" -function fmi2SimulateCS(fmu::FMU2, args...; kwargs...) - return fmi2SimulateCS(fmu, nothing, args...; kwargs...) -end - -""" - fmi2SimulateME(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SimulateME(fmu::FMU2, c::Union{FMU2Component, Nothing}, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets passed as `nothing`) -""" -function fmi2SimulateME(fmu::FMU2, args...; kwargs...) - return fmi2SimulateME(fmu, nothing, args...; kwargs...) -end - -""" - fmi2FreeInstance!(fmu::FMU2) - -Wrapper for `fmi2FreeInstance!(c::FMU2Component; popComponent::Bool = true)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2FreeInstance!(fmu::FMU2) - fmi2FreeInstance!(getCurrentComponent(fmu)) # this command also removes the component from the array -end - -""" - fmi2SetDebugLogging(fmu::FMU2) - -Wrapper for `fmi2SetDebugLogging(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetDebugLogging(fmu::FMU2) - fmi2SetDebugLogging(getCurrentComponent(fmu)) -end - -""" - fmi2SetupExperiment(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetupExperiment(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetupExperiment(fmu::FMU2, args...; kwargs...) - fmi2SetupExperiment(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2EnterInitializationMode(fmu::FMU2) - -Wrapper for `fmi2EnterInitializationMode(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2EnterInitializationMode(fmu::FMU2) - fmi2EnterInitializationMode(getCurrentComponent(fmu)) -end - -""" - fmi2ExitInitializationMode(fmu::FMU2) - -Wrapper for `fmi2ExitInitializationMode(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2ExitInitializationMode(fmu::FMU2) - fmi2ExitInitializationMode(getCurrentComponent(fmu)) -end - -""" - fmi2Terminate(fmu::FMU2) - -Wrapper for `fmi2Terminate(c::FMU2Component; soft::Bool=false)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2Terminate(fmu::FMU2) - fmi2Terminate(getCurrentComponent(fmu)) -end - -""" - fmi2Reset(fmu::FMU2) - -Wrapper for `fmi2Reset(c::FMU2Component; soft::Bool=false)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2Reset(fmu::FMU2) - fmi2Reset(getCurrentComponent(fmu)) -end - -""" - fmi2GetReal(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetReal(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetReal(fmu::FMU2, args...; kwargs...) - fmi2GetReal(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetReal!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetReal!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetReal!(fmu::FMU2, args...; kwargs...) - fmi2GetReal!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2Get(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2Get(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2Get(fmu::FMU2, args...; kwargs...) - fmi2Get(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2Get!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2Get!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2Get!(fmu::FMU2, args...; kwargs...) - fmi2Get!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2Set(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2Set(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2Set(fmu::FMU2, args...; kwargs...) - fmi2Set(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetRealOutputDerivatives(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetRealOutputDerivatives(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetRealOutputDerivatives(fmu::FMU2, args...; kwargs...) - fmi2GetRealOutputDerivatives(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetReal(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetReal(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetReal(fmu::FMU2, args...; kwargs...) - fmi2SetReal(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetRealInputDerivatives(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetRealInputDerivatives(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetRealInputDerivatives(fmu::FMU2, args...; kwargs...) - fmi2SetRealInputDerivatives(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetInteger(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetInteger(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetInteger(fmu::FMU2, args...; kwargs...) - fmi2GetInteger(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetInteger!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetInteger!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetInteger!(fmu::FMU2, args...; kwargs...) - - fmi2GetInteger!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetInteger(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetInteger(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetInteger(fmu::FMU2, args...; kwargs...) - - fmi2SetInteger(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetBoolean(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetBoolean(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetBoolean(fmu::FMU2, args...; kwargs...) - - fmi2GetBoolean(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetBoolean!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetBoolean!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetBoolean!(fmu::FMU2, args...; kwargs...) - - fmi2GetBoolean!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetBoolean(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetBoolean(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetBoolean(fmu::FMU2, args...; kwargs...) - - fmi2SetBoolean(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetString(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetString(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetString(fmu::FMU2, args...; kwargs...) - - fmi2GetString(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetString!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetString!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetString!(fmu::FMU2, args...; kwargs...) - - fmi2GetString!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetString(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetString(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetString(fmu::FMU2, args...; kwargs...) - - fmi2SetString(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetFMUstate(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetFMUstate(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetFMUstate(fmu::FMU2, args...; kwargs...) - - fmi2GetFMUstate(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetFMUstate(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetFMUstate(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetFMUstate(fmu::FMU2, args...; kwargs...) - - fmi2SetFMUstate(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2FreeFMUstate!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2FreeFMUstate!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2FreeFMUstate!(fmu::FMU2, args...; kwargs...) - - fmi2FreeFMUstate!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SerializedFMUstateSize(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SerializedFMUstateSize(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SerializedFMUstateSize(fmu::FMU2, args...; kwargs...) - - fmi2SerializedFMUstateSize(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SerializeFMUstate(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SerializeFMUstate(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SerializeFMUstate(fmu::FMU2, args...; kwargs...) - - fmi2SerializeFMUstate(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2DeSerializeFMUstate(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2DeSerializeFMUstate(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2DeSerializeFMUstate(fmu::FMU2, args...; kwargs...) - - fmi2DeSerializeFMUstate(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetDirectionalDerivative!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetDirectionalDerivative!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetDirectionalDerivative!(fmu::FMU2, args...; kwargs...) - - fmi2GetDirectionalDerivative!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetDirectionalDerivative(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetDirectionalDerivative(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetDirectionalDerivative(fmu::FMU2, args...; kwargs...) - - fmi2GetDirectionalDerivative(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SampleDirectionalDerivative!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SampleDirectionalDerivative!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SampleDirectionalDerivative!(fmu::FMU2, args...; kwargs...) - - fmi2SampleDirectionalDerivative!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SampleDirectionalDerivative(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SampleDirectionalDerivative(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SampleDirectionalDerivative(fmu::FMU2, args...; kwargs...) - - fmi2SampleDirectionalDerivative(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetJacobian!(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetJacobian!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetJacobian!(fmu::FMU2, args...; kwargs...) - - fmi2GetJacobian!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetJacobian(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetJacobian(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetJacobian(fmu::FMU2, args...; kwargs...) - - fmi2GetJacobian(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2DoStep(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2DoStep(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2DoStep(fmu::FMU2, args...; kwargs...) - - fmi2DoStep(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2CancelStep(fmu::FMU2) - -Wrapper for `fmi2CancelStep(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2CancelStep(fmu::FMU2) - - fmi2CancelStep(getCurrentComponent(fmu)) -end - -""" - fmi2GetStatus(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetStatus!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetStatus(fmu::FMU2, args...; kwargs...) - - fmi2GetStatus!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetRealStatus(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetRealStatus!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetRealStatus(fmu::FMU2, args...; kwargs...) - - fmi2GetRealStatus!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetIntegerStatus(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetIntegerStatus!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetIntegerStatus(fmu::FMU2, args...; kwargs...) - - fmi2GetIntegerStatus!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetBooleanStatus(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetBooleanStatus!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetBooleanStatus(fmu::FMU2, args...; kwargs...) - - fmi2GetBooleanStatus!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetStringStatus(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetStringStatus!(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetStringStatus(fmu::FMU2, args...; kwargs...) - - fmi2GetStringStatus!(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetTime(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetTime(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetTime(fmu::FMU2, args...; kwargs...) - - fmi2SetTime(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2SetContinuousStates(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2SetContinuousStates(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2SetContinuousStates(fmu::FMU2, args...; kwargs...) - - fmi2SetContinuousStates(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2EnterEventMode(fmu::FMU2) - -Wrapper for `fmi2EnterEventMode(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2EnterEventMode(fmu::FMU2) - - fmi2EnterEventMode(getCurrentComponent(fmu)) -end - -""" - fmi2NewDiscreteStates(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2NewDiscreteStates(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2NewDiscreteStates(fmu::FMU2, args...; kwargs...) - - fmi2NewDiscreteStates(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2EnterContinuousTimeMode(fmu::FMU2) - -Wrapper for `fmi2EnterContinuousTimeMode(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2EnterContinuousTimeMode(fmu::FMU2) - - fmi2EnterContinuousTimeMode(getCurrentComponent(fmu)) -end - -""" - fmi2CompletedIntegratorStep(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2CompletedIntegratorStep(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2CompletedIntegratorStep(fmu::FMU2, args...; kwargs...) - - fmi2CompletedIntegratorStep(getCurrentComponent(fmu), args...; kwargs...) -end - -""" - fmi2GetDerivatives(fmu::FMU2) - -Wrapper for `fmi2GetDerivatives(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetDerivatives(fmu::FMU2) - - fmi2GetDerivatives(getCurrentComponent(fmu)) -end - -""" - fmi2GetEventIndicators(fmu::FMU2) - -Wrapper for `fmi2GetEventIndicators()` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetEventIndicators(fmu::FMU2) - - fmi2GetEventIndicators(getCurrentComponent(fmu)) -end - -""" - fmi2GetContinuousStates(fmu::FMU2)fmi2ins - -Wrapper for `fmi2GetContinuousStates(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetContinuousStates(fmu::FMU2) - - fmi2GetContinuousStates(getCurrentComponent(fmu)) -end - -""" - fmi2GetNominalsOfContinuousStates(fmu::FMU2) - -Wrapper for `fmi2GetNominalsOfContinuousStates(c::FMU2Component)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetNominalsOfContinuousStates(fmu::FMU2) - - fmi2GetNominalsOfContinuousStates(getCurrentComponent(fmu)) -end - -# additionals -""" - fmi2GetStartValue(fmu::FMU2, args...; kwargs...) - -Wrapper for `fmi2GetStartValue(c::FMU2Component, args...; kwargs...)` without a provided FMU2Component. -(Component `c` gets selected from `fmu`) -""" -function fmi2GetStartValue(fmu::FMU2, args...; kwargs...) - - fmi2GetStartValue(getCurrentComponent(fmu), args...; kwargs...) -end \ No newline at end of file diff --git a/src/FMI2/sim.jl b/src/FMI2/sim.jl deleted file mode 100644 index 5416a11a..00000000 --- a/src/FMI2/sim.jl +++ /dev/null @@ -1,859 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using DifferentialEquations, DifferentialEquations.DiffEqCallbacks -import DifferentialEquations.SciMLBase: RightRootFind, ReturnCode - -using FMIImport: fmi2SetupExperiment, fmi2EnterInitializationMode, fmi2ExitInitializationMode, fmi2NewDiscreteStates, fmi2GetContinuousStates, fmi2GetNominalsOfContinuousStates, fmi2SetContinuousStates, fmi2GetDerivatives! -using FMIImport.FMICore: fmi2StatusOK, fmi2TypeCoSimulation, fmi2TypeModelExchange -using FMIImport.FMICore: fmi2ComponentState, fmi2ComponentStateInstantiated, fmi2ComponentStateInitializationMode, fmi2ComponentStateEventMode, fmi2ComponentStateContinuousTimeMode, fmi2ComponentStateTerminated, fmi2ComponentStateError, fmi2ComponentStateFatal -using FMIImport: FMU2Solution, FMU2Event - -import FMIImport: prepareSolveFMU, finishSolveFMU, handleEvents - -using FMIImport.FMICore.ChainRulesCore -using FMIImport.FMICore: FMU2InputFunction - -import LinearAlgebra: eigvals - -import ProgressMeter -import ThreadPools - -using FMIImport.FMICore: EMPTY_fmi2Real, EMPTY_fmi2ValueReference, ERR_MSG_CONT_TIME_MODE - -############ Model-Exchange ############ - -# Read next time event from fmu and provide it to the integrator -function time_choice(c::FMU2Component, integrator, tStart, tStop) - - #@info "TC" - - c.solution.evals_timechoice += 1 - - if c.eventInfo.nextEventTimeDefined == fmi2True - - if c.eventInfo.nextEventTime >= tStart && c.eventInfo.nextEventTime <= tStop - return c.eventInfo.nextEventTime - else - # the time event is outside the simulation range! - @debug "Next time event @$(c.eventInfo.nextEventTime)s is outside simulation time range ($(tStart), $(tStop)), skipping." - return nothing - end - else - return nothing - end - -end - -# Returns the event indicators for an FMU. -function condition(c::FMU2Component, out, x, t, integrator, inputFunction) - - @assert c.state == fmi2ComponentStateContinuousTimeMode "condition(...):\n" * ERR_MSG_CONT_TIME_MODE - - indicators!(c, out, x, t, inputFunction) - - return nothing -end - -# Handles the upcoming events. -# Sets a new state for the solver from the FMU (if needed). -function affectFMU!(c::FMU2Component, integrator, idx, inputFunction, solution::FMU2Solution) - - @assert c.state == fmi2ComponentStateContinuousTimeMode "affectFMU!(...):\n" * ERR_MSG_CONT_TIME_MODE - - c.solution.evals_affect += 1 - - # there are fx-evaluations before the event is handled, reset the FMU state to the current integrator step - fx_set(c, integrator.u, integrator.t, inputFunction; force=true) - - fmi2EnterEventMode(c) - - # Event found - handle it - handleEvents(c) - - left_x = nothing - right_x = nothing - - if c.eventInfo.valuesOfContinuousStatesChanged == fmi2True - left_x = integrator.u - right_x = fmi2GetContinuousStates(c) - @debug "affectFMU!(...): Handled event at t=$(integrator.t), new state is $(right_x)" - integrator.u = right_x - - u_modified!(integrator, true) - else - u_modified!(integrator, false) - @debug "affectFMU!(...): Handled event at t=$(integrator.t), no new state." - end - - if c.eventInfo.nominalsOfContinuousStatesChanged == fmi2True - x_nom = fmi2GetNominalsOfContinuousStates(c) - end - - ignore_derivatives() do - if idx != -1 # -1 no event, 0, time event, >=1 state event with indicator - e = FMU2Event(integrator.t, UInt64(idx), left_x, right_x) - push!(solution.events, e) - end - end - - #fmi2EnterContinuousTimeMode(c) -end - -# This callback is called every time the integrator finishes an (accepted) integration step. -function stepCompleted(c::FMU2Component, x, t, integrator, inputFunction, progressMeter, tStart, tStop, solution::FMU2Solution) - - @assert c.state == fmi2ComponentStateContinuousTimeMode "stepCompleted(...):\n" * ERR_MSG_CONT_TIME_MODE - - c.solution.evals_stepcompleted += 1 - - if progressMeter !== nothing - stat = 1000.0*(t-tStart)/(tStop-tStart) - if !isnan(stat) - stat = floor(Integer, stat) - ProgressMeter.update!(progressMeter, stat) - end - end - - (status, enterEventMode, terminateSimulation) = fmi2CompletedIntegratorStep(c, fmi2True) - - if terminateSimulation == fmi2True - @error "stepCompleted(...): FMU requested termination!" - end - - if enterEventMode == fmi2True - affectFMU!(c, integrator, -1, inputFunction, solution) - else - if !isnothing(inputFunction) - u = eval!(inputFunction, c, x, t) - u_refs = inputFunction.vrs - fmi2SetReal(c, u_refs, u) - end - end -end - -# save FMU values -function saveValues(c::FMU2Component, recordValues, x, t, integrator, inputFunction) - - @assert c.state == fmi2ComponentStateContinuousTimeMode "saveValues(...):\n" * ERR_MSG_CONT_TIME_MODE - - c.solution.evals_savevalues += 1 - - fx_set(c, x, t, inputFunction) - - # ToDo: Replace by inplace statement! - return (fmiGet(c, recordValues)...,) -end - -function saveEventIndicators(c::FMU2Component, recordEventIndicators, x, t, integrator, inputFunction) - - @assert c.state == fmi2ComponentStateContinuousTimeMode "saveEventIndicators(...):\n" * ERR_MSG_CONT_TIME_MODE - - c.solution.evals_saveeventindicators += 1 - - out = zeros(fmi2Real, c.fmu.modelDescription.numberOfEventIndicators) - indicators!(c, out, x, t, inputFunction) - - # ToDo: Replace by inplace statement! - return (out[recordEventIndicators]...,) -end - -function saveEigenvalues(c::FMU2Component, x, t, integrator, inputFunction) - - @assert c.state == fmi2ComponentStateContinuousTimeMode "saveEigenvalues(...):\n" * ERR_MSG_CONT_TIME_MODE - - c.solution.evals_saveeigenvalues += 1 - - fx_set(c, x, t, inputFunction) - - # ToDo: Replace this by an directional derivative call! - A = ReverseDiff.jacobian(_x -> FMI.fx(c, _x, [], t), x) - eigs = eigvals(A) - - vals = [] - for e in eigs - push!(vals, real(e)) - push!(vals, imag(e)) - end - - # ToDo: Replace by inplace statement! - return (vals...,) -end - -function fx(c::FMU2Component, - dx::AbstractArray{<:Real}, - x::AbstractArray{<:Real}, - p::Tuple, - t::Real, - inputFunction::Union{Nothing, FMU2InputFunction}) - - c.solution.evals_fx_inplace += 1 - - u = EMPTY_fmi2Real - u_refs = EMPTY_fmi2ValueReference - if !isnothing(inputFunction) - u = eval!(inputFunction, c, x, t) - u_refs = inputFunction.vrs - end - - # for zero state FMUs, don't request a `dx` - if c.fmu.isZeroState - c(;x=x, u=u, u_refs=u_refs, t=t) - else - c(;dx=dx, x=x, u=u, u_refs=u_refs, t=t) - end - - return nothing -end - -function fx(c::FMU2Component, - x::AbstractArray{<:Real}, - p::Tuple, - t::Real, - inputFunction::Union{Nothing, FMU2InputFunction}) - - c.solution.evals_fx_outofplace += 1 - - dx = zeros(fmi2Real, length(x)) - - fx(c, dx, x, p, t) - c.solution.evals_fx_inplace -= 1 # correct statistics, because fx-call above -> this was in fact an out-of-place evaluation - - return dx -end - -function fx_set(c::FMU2Component, - x::AbstractArray{<:Real}, - t::Real, - inputFunction::Union{Nothing, FMU2InputFunction}; force::Bool=false) - - u = EMPTY_fmi2Real - u_refs = EMPTY_fmi2ValueReference - if !isnothing(inputFunction) - u = eval!(inputFunction, c, x, t) - u_refs = inputFunction.vrs - end - - oldForce = c.force - c.force = force - c(;x=x, u=u, u_refs=u_refs, t=t) - c.force = oldForce - - return nothing -end - -function indicators!(c::FMU2Component, - ec, - x::AbstractArray{<:Real}, - t::Real, - inputFunction::Union{Nothing, FMU2InputFunction}) - - c.solution.evals_condition += 1 - - u = EMPTY_fmi2Real - u_refs = EMPTY_fmi2ValueReference - if !isnothing(inputFunction) - u = eval!(inputFunction, c, x, t) - u_refs = inputFunction.vrs - end - - c(;x=x, u=u, u_refs=u_refs, t=t, ec=ec) - - return nothing -end - -""" - fmi2SimulateME(c::FMU2Component, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...) - -Wrapper for `fmi2SimulateME(fmu::FMU2, c::Union{FMU2Component, Nothing}, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...)` without a provided FMU2. -(FMU2 `fmu` is taken from `c`) -""" -function fmi2SimulateME(c::FMU2Component, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...) - fmi2SimulateME(c.fmu, c, tspan; kwargs...) -end - -# sets up the ODEProblem for simulating a ME-FMU -function setupODEProblem(c::FMU2Component, x0::AbstractArray{fmi2Real}, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; p=(), customFx=nothing, inputFunction::Union{FMU2InputFunction, Nothing}=nothing) - - if customFx === nothing - customFx = (dx, x, p, t) -> fx(c, dx, x, p, t, inputFunction) - end - - ff = ODEFunction{true}(customFx, - tgrad=nothing) - c.problem = ODEProblem{true}(ff, x0, tspan, p) - - return c.problem -end - -""" - fmi2SimulateME(fmu::FMU2, - c::Union{FMU2Component, Nothing}=nothing, - tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; - [tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - solver = nothing, - customFx = nothing, - recordValues::fmi2ValueReferenceFormat = nothing, - recordEventIndicators::Union{AbstractArray{<:Integer, 1}, UnitRange{<:Integer}, Nothing} = nothing, - recordEigenvalues::Bool=false, - saveat = nothing, - x0::Union{AbstractArray{<:Real}, Nothing} = nothing, - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi2ValueReferenceFormat = nothing, - inputFunction = nothing, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing, - dtmax::Union{Real, Nothing} = nothing, - callbacksBefore = [], - callbacksAfter = [], - showProgress::Bool = true, - kwargs...]) - -Simulate ME-FMU for the given simulation time interval. - -State- and Time-Events are handled correctly. - -# Arguments -- `fmu::FMU2`: Mutable struct representing a FMU and all it instantiated instances. -- `c::Union{FMU2Component, Nothing}=nothing`: Mutable struct representing an instantiated instance of a FMU. -- `tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing`: Simulation-time-span as tuple (default = nothing: use default value from `fmu`'s model description or (0.0, 1.0)) - -- `tolerance::Union{Real, Nothing} = nothing`: tolerance for the solver (default = nothing: use default value from `fmu`'s model description or -if not available- default from DifferentialEquations.jl) -- `dt::Union{Real, Nothing} = nothing`: stepszie for the solver (default = nothing: use default value from `fmu`'s model description or -if not available- default from DifferentialEquations.jl) -- `solver = nothing`: Any Julia-supported ODE-solver (default = nothing: use DifferentialEquations.jl default solver) -- `customFx`: [deprecated] custom state derivative function xΜ‡=f(x,t) -- `recordValues::fmi2ValueReferenceFormat` = nothing: Array of variables (Strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` -- `recordEventIndicators::Union{AbstractArray{<:Integer, 1}, UnitRange{<:Integer}, Nothing} = nothing`: Array or Range of event indicators to record -- `recordEigenvalues::Bool=false`: compute and record eigenvalues -- `saveat = nothing`: Time points to save (interpolated) values at (default = nothing: save at each solver timestep) -- `x0::Union{AbstractArray{<:Real}, Nothing} = nothing`: initial fmu State (default = nothing: use current or default-initial fmu state) -- `setup::Union{Bool, Nothing} = nothing`: call fmi2SetupExperiment, fmi2EnterInitializationMode and fmi2ExitInitializationMode before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `reset::Union{Bool, Nothing} = nothing`: call fmi2Reset before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `instantiate::Union{Bool, Nothing} = nothing`: call fmi2Instantiate! before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `freeInstance::Union{Bool, Nothing} = nothing`: call fmi2FreeInstance after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `terminate::Union{Bool, Nothing} = nothing`: call fmi2Terminate after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `inputValueReferences::fmi2ValueReferenceFormat = nothing`: Input variables (Strings or variableIdentifiers) to set at each simulation step -- `inputFunction = nothing`: Function to get values for the input variables at each simulation step. - - ## Pattern [`c`: current component, `u`: current state ,`t`: current time, returning array of values to be passed to `fmi2SetReal(..., inputValueReferences, inputFunction(...))`]: - - `inputFunction(t::fmi2Real)` - - `inputFunction(c::FMU2Component, t::fmi2Real)` - - `inputFunction(c::FMU2Component, u::Union{AbstractArray{fmi2Real,1}, Nothing})` - - `inputFunction(u::Union{AbstractArray{fmi2Real,1}, Nothing}, t::fmi2Real)` - - `inputFunction(c::FMU2Component, u::Union{AbstractArray{fmi2Real,1}, Nothing}, t::fmi2Real)` - -- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dict of parameter variables (strings or variableIdentifiers) and values (Real, Integer, Boolean, String) to set parameters during initialization -- `dtmax::Union{Real, Nothing} = nothing`: sets the maximum stepszie for the solver (default = nothing: use `(Simulation-time-span-length)/100.0`) -- `callbacksBefore = [], callbacksAfter = []`: functions that are to be called before and after internal time-event-, state-event- and step-event-callbacks are called -- `showProgress::Bool = true`: print simulation progressmeter in REPL -- `kwargs...`: keyword arguments that get passed onto the solvers solve call - -# Returns: -- If keyword `recordValues` has value `nothing`, a struct of type `ODESolution`. -- If keyword `recordValues` is set, a tuple of type `(ODESolution, DiffEqCallbacks.SavedValues)`. - -See also [`fmi2Simulate`](@ref), [`fmi2SimulateCS`](@ref). -""" -function fmi2SimulateME(fmu::FMU2, c::Union{FMU2Component, Nothing}=nothing, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; - tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - solver = nothing, - customFx = nothing, - recordValues::fmi2ValueReferenceFormat = nothing, - recordEventIndicators::Union{AbstractArray{<:Integer, 1}, UnitRange{<:Integer}, Nothing} = nothing, - recordEigenvalues::Bool=false, - saveat = nothing, - x0::Union{AbstractArray{<:Real}, Nothing} = nothing, - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi2ValueReferenceFormat = nothing, - inputFunction = nothing, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing, - dtmax::Union{Real, Nothing} = nothing, - callbacksBefore = [], - callbacksAfter = [], - showProgress::Bool = true, - kwargs...) - - @assert fmi2IsModelExchange(fmu) "fmi2SimulateME(...): This function supports Model Exchange FMUs only." - #@assert fmu.type == fmi2TypeModelExchange "fmi2SimulateME(...): This FMU supports Model Exchange, but was instantiated in CS mode. Use `fmiLoad(...; type=:ME)`." - - recordValues = prepareValueReference(fmu, recordValues) - inputValueReferences = prepareValueReference(fmu, inputValueReferences) - - savingValues = (length(recordValues) > 0) - savingEventIndicators = !isnothing(recordEventIndicators) - hasInputs = (length(inputValueReferences) > 0) - hasParameters = (parameters !== nothing) - hasStartState = (x0 !== nothing) - - t_start, t_stop = (tspan == nothing ? (nothing, nothing) : tspan) - - cbs = [] - - for cb in callbacksBefore - push!(cbs, cb) - end - - if t_start === nothing - t_start = fmi2GetDefaultStartTime(fmu.modelDescription) - - if t_start === nothing - t_start = 0.0 - @info "No `t_start` chosen, no `t_start` available in the FMU, auto-picked `t_start=0.0`." - end - end - - if t_stop === nothing - t_stop = fmi2GetDefaultStopTime(fmu.modelDescription) - - if t_stop === nothing - t_stop = 1.0 - @warn "No `t_stop` chosen, no `t_stop` availabel in the FMU, auto-picked `t_stop=1.0`." - end - end - - if tolerance === nothing - tolerance = fmi2GetDefaultTolerance(fmu.modelDescription) - # if no tolerance is given, pick auto-setting from DifferentialEquations.jl - end - - if dt === nothing - dt = fmi2GetDefaultStepSize(fmu.modelDescription) - # if no dt is given, pick auto-setting from DifferentialEquations.jl - end - - if dtmax === nothing - dtmax = (t_stop-t_start)/100.0 - end - - # input function handling - _inputFunction = nothing - if inputFunction != nothing - _inputFunction = FMU2InputFunction(inputFunction, inputValueReferences) - end - - # argument `tolerance=nothing` here, because ME-FMUs doesn't support tolerance control (no solver included) - # tolerance for the solver is set-up later in this function - inputs = nothing - if hasInputs - inputValues = eval!(_inputFunction, nothing, nothing, t_start) - inputs = Dict(inputValueReferences .=> inputValues) - end - - c, x0 = prepareSolveFMU(fmu, c, fmi2TypeModelExchange, instantiate, freeInstance, terminate, reset, setup, parameters, t_start, t_stop, nothing; x0=x0, inputs=inputs, handleEvents=FMI.handleEvents) - fmusol = c.solution - - # Zero state FMU: add dummy state - if c.fmu.isZeroState - x0 = [0.0] - end - - # from here on, we are in event mode, if `setup=false` this is the job of the user - #@assert c.state == fmi2ComponentStateEventMode "FMU needs to be in event mode after setup." - - # if x0 === nothing - # x0 = fmi2GetContinuousStates(c) - # x0_nom = fmi2GetNominalsOfContinuousStates(c) - # end - - # initial event handling - #handleEvents(c) - #fmi2EnterContinuousTimeMode(c) - - c.fmu.hasStateEvents = (c.fmu.modelDescription.numberOfEventIndicators > 0) - c.fmu.hasTimeEvents = (c.eventInfo.nextEventTimeDefined == fmi2True) - - setupODEProblem(c, x0, (t_start, t_stop); customFx=customFx, inputFunction=_inputFunction) - - progressMeter = nothing - if showProgress - progressMeter = ProgressMeter.Progress(1000; desc="Simulating ME-FMU ...", color=:blue, dt=1.0) #, barglyphs=ProgressMeter.BarGlyphs("[=> ]")) - ProgressMeter.update!(progressMeter, 0) # show it! - end - - # callback functions - - if c.fmu.hasTimeEvents && c.fmu.executionConfig.handleTimeEvents - timeEventCb = IterativeCallback((integrator) -> time_choice(c, integrator, t_start, t_stop), - (integrator) -> affectFMU!(c, integrator, 0, _inputFunction, fmusol), Float64; - initial_affect = (c.eventInfo.nextEventTime == t_start), - save_positions=(false,false)) - push!(cbs, timeEventCb) - end - - if c.fmu.hasStateEvents && c.fmu.executionConfig.handleStateEvents - - eventCb = VectorContinuousCallback((out, x, t, integrator) -> condition(c, out, x, t, integrator, _inputFunction), - (integrator, idx) -> affectFMU!(c, integrator, idx, _inputFunction, fmusol), - Int64(c.fmu.modelDescription.numberOfEventIndicators); - rootfind = RightRootFind, - save_positions=(false,false), - interp_points=fmu.executionConfig.rootSearchInterpolationPoints) - push!(cbs, eventCb) - end - - # use step callback always if we have inputs or need event handling (or just want to see our simulation progress) - if hasInputs || c.fmu.hasStateEvents || c.fmu.hasTimeEvents || showProgress - stepCb = FunctionCallingCallback((x, t, integrator) -> stepCompleted(c, x, t, integrator, _inputFunction, progressMeter, t_start, t_stop, fmusol); - func_everystep = true, - func_start = true) - push!(cbs, stepCb) - end - - if savingValues - dtypes = collect(fmi2DataTypeForValueReference(c.fmu.modelDescription, vr) for vr in recordValues) - fmusol.values = SavedValues(fmi2Real, Tuple{dtypes...}) - fmusol.valueReferences = copy(recordValues) - - savingCB = nothing - if saveat === nothing - savingCB = SavingCallback((u,t,integrator) -> saveValues(c, recordValues, u, t, integrator, _inputFunction), - fmusol.values) - else - savingCB = SavingCallback((u,t,integrator) -> saveValues(c, recordValues, u, t, integrator, _inputFunction), - fmusol.values, - saveat=saveat) - end - - push!(cbs, savingCB) - end - - if savingEventIndicators - dtypes = collect(fmi2Real for ei in recordEventIndicators) - fmusol.eventIndicators = SavedValues(fmi2Real, Tuple{dtypes...}) - fmusol.recordEventIndicators = copy(recordEventIndicators) - - savingCB = nothing - if saveat === nothing - savingCB = SavingCallback((u,t,integrator) -> saveEventIndicators(c, recordEventIndicators, u, t, integrator, _inputFunction), - fmusol.eventIndicators) - else - savingCB = SavingCallback((u,t,integrator) -> saveEventIndicators(c, recordEventIndicators, u, t, integrator, _inputFunction), - fmusol.eventIndicators, - saveat=saveat) - end - - push!(cbs, savingCB) - end - - if recordEigenvalues - dtypes = collect(Float64 for _ in 1:2*length(c.fmu.modelDescription.stateValueReferences)) - fmusol.eigenvalues = SavedValues(fmi2Real, Tuple{dtypes...}) - - savingCB = nothing - if saveat === nothing - savingCB = SavingCallback((u,t,integrator) -> saveEigenvalues(c, u, t, integrator, _inputFunction), - fmusol.eigenvalues) - else - savingCB = SavingCallback((u,t,integrator) -> saveEigenvalues(c, u, t, integrator, _inputFunction), - fmusol.eigenvalues, - saveat=saveat) - end - - push!(cbs, savingCB) - end - - for cb in callbacksAfter - push!(cbs, cb) - end - - # if auto_dt == true - # @assert solver !== nothing "fmi2SimulateME(...): `auto_dt=true` but no solver specified, this is not allowed." - # tmpIntegrator = init(c.problem, solver) - # dt = auto_dt_reset!(tmpIntegrator) - # end - - solveKwargs = Dict{Symbol, Any}() - - if dt !== nothing - solveKwargs[:dt] = dt - end - - if tolerance !== nothing - solveKwargs[:reltol] = tolerance - end - - if saveat !== nothing - solveKwargs[:saveat] = saveat - end - - if isnothing(solver) - fmusol.states = solve(c.problem; callback = CallbackSet(cbs...), dtmax=dtmax, solveKwargs..., kwargs...) - else - fmusol.states = solve(c.problem, solver; callback = CallbackSet(cbs...), dtmax=dtmax, solveKwargs..., kwargs...) - end - - fmusol.success = (fmusol.states.retcode == ReturnCode.Success) - - if !fmusol.success - @warn "FMU simulation failed with solver return code `$(fmusol.states.retcode)`, please check log for hints." - end - - # ZeroStateFMU: remove dummy state - if c.fmu.isZeroState - c.solution.states = nothing - end - - # cleanup progress meter - if showProgress - ProgressMeter.finish!(progressMeter) - end - - finishSolveFMU(fmu, c, freeInstance, terminate) - - return fmusol -end - -export fmi2SimulateME - -# function fmi2SimulateME(fmu::FMU2, -# c::Union{AbstractArray{<:Union{FMU2Component, Nothing}}, Nothing}=nothing, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; -# x0::Union{AbstractArray{<:AbstractArray{<:Real}}, AbstractArray{<:Real}, Nothing} = nothing, -# parameters::Union{AbstractArray{<:Dict{<:Any, <:Any}}, Dict{<:Any, <:Any}, Nothing} = nothing, -# kwargs...) - -# return ThreadPool.foreach((c, x0, parameters) -> fmi2SimulateME(fmu, c; x0=x0, parameters=parameters, kwargs...), zip()) -# end - -############ Co-Simulation ############ - -""" - fmi2SimulateCS(c::FMU2Component, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...) - -Wrapper for `fmi2SimulateCS(fmu::FMU2, c::Union{FMU2Component, Nothing}, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...)` without a provided FMU2. -(FMU2 `fmu` is taken from `c`) -""" -function fmi2SimulateCS(c::FMU2Component, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...) - fmi2SimulateCS(c.fmu, c, tspan; kwargs...) -end - -""" - fmi2SimulateCS(fmu::FMU2, - c::Union{FMU2Component, Nothing}=nothing, - tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; - [tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - recordValues::fmi2ValueReferenceFormat = nothing, - saveat = [], - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi2ValueReferenceFormat = nothing, - inputFunction = nothing, - showProgress::Bool=true, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing]) - -Simulate CS-FMU for the given simulation time interval. - -# Arguments -- `fmu::FMU2`: Mutable struct representing a FMU and all it instantiated instances. -- `c::Union{FMU2Component, Nothing}=nothing`: Mutable struct representing an instantiated instance of a FMU. -- `tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing`: Simulation-time-span as tuple (default = nothing: use default value from `fmu`'s model description or (0.0, 1.0)) - -- `tolerance::Union{Real, Nothing} = nothing`: tolerance for the solver (default = nothing: use default value from `fmu`'s model description or 0.0) -- `dt::Union{Real, Nothing} = nothing`: stepszie for the solver (default = nothing: use default value from `fmu`'s model description or 1e-3) -- `recordValues::fmi2ValueReferenceFormat` = nothing: Array of variables (Strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` -- `saveat = nothing`: Time points to save values at (default = nothing: save at each communication timestep) -- `setup::Union{Bool, Nothing} = nothing`: call fmi2SetupExperiment, fmi2EnterInitializationMode and fmi2ExitInitializationMode before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `reset::Union{Bool, Nothing} = nothing`: call fmi2Reset before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `instantiate::Union{Bool, Nothing} = nothing`: call fmi2Reset before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `freeInstance::Union{Bool, Nothing} = nothing`: call fmi2FreeInstance after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `terminate::Union{Bool, Nothing} = nothing`: call fmi2Terminate after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) -- `inputValueReferences::fmi2ValueReferenceFormat = nothing`: Input variables (Strings or variableIdentifiers) to set at each communication step -- `inputFunction = nothing`: Function to get values for the input variables at each communication step. - - ## Pattern [`c`: current component, `t`: current time, returning array of values to be passed to `fmi2SetReal(..., inputValueReferences, inputFunction(...))`]: - - `inputFunction(t::fmi2Real)` - - `inputFunction(c::FMU2Component, t::fmi2Real)` - -- `showProgress::Bool = true`: print simulation progressmeter in REPL -- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dict of parameter variables (strings or variableIdentifiers) and values (Real, Integer, Boolean, String) to set parameters during initialization - -# Returns: -- `fmusol::FMU2Solution`, containing bool `fmusol.success` and if keyword `recordValues` is set, the saved values as `fmusol.values`. - -See also [`fmi2Simulate`](@ref), [`fmi2SimulateME`](@ref). -""" -function fmi2SimulateCS(fmu::FMU2, c::Union{FMU2Component, Nothing}=nothing, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; - tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - recordValues::fmi2ValueReferenceFormat = nothing, - saveat = [], - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi2ValueReferenceFormat = nothing, - inputFunction = nothing, - showProgress::Bool=true, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing) - - @assert fmi2IsCoSimulation(fmu) "fmi2SimulateCS(...): This function supports Co-Simulation FMUs only." - #@assert fmu.type == fmi2TypeCoSimulation "fmi2SimulateCS(...): This FMU supports Co-Simulation, but was instantiated in ME mode. Use `fmiLoad(...; type=:CS)`." - - # input function handling - inputValueReferences = prepareValueReference(fmu, inputValueReferences) - hasInputs = (length(inputValueReferences) > 0) - - _inputFunction = nothing - u = EMPTY_fmi2Real - u_refs = EMPTY_fmi2ValueReference - if hasInputs - _inputFunction = FMU2InputFunction(inputFunction, inputValueReferences) - u_refs = _inputFunction.vrs - end - - # outputs - y_refs = EMPTY_fmi2ValueReference - y = EMPTY_fmi2Real - if !isnothing(recordValues) - y_refs = prepareValueReference(fmu, recordValues) - y = zeros(fmi2Real, length(y_refs)) - end - - - t_start, t_stop = (tspan == nothing ? (nothing, nothing) : tspan) - - # pull default values from the model description - if not given by user - variableSteps = fmi2IsCoSimulation(fmu) && fmu.modelDescription.coSimulation.canHandleVariableCommunicationStepSize - t_start = t_start === nothing ? fmi2GetDefaultStartTime(fmu.modelDescription) : t_start - t_start = t_start === nothing ? 0.0 : t_start - t_stop = t_stop === nothing ? fmi2GetDefaultStopTime(fmu.modelDescription) : t_stop - t_stop = t_stop === nothing ? 1.0 : t_stop - tolerance = tolerance === nothing ? fmi2GetDefaultTolerance(fmu.modelDescription) : tolerance - tolerance = tolerance === nothing ? 0.0 : tolerance - dt = dt === nothing ? fmi2GetDefaultStepSize(fmu.modelDescription) : dt - dt = dt === nothing ? 1e-3 : dt - - inputs = nothing - if hasInputs - inputValues = eval!(_inputFunction, nothing, nothing, t_start) - inputs = Dict(inputValueReferences .=> inputValues) - end - c, _ = prepareSolveFMU(fmu, c, fmi2TypeCoSimulation, instantiate, freeInstance, terminate, reset, setup, parameters, t_start, t_stop, tolerance; inputs=inputs) - fmusol = c.solution - - # default setup - if length(saveat) == 0 - saveat = t_start:dt:t_stop - end - - # setup if no variable steps - if variableSteps == false - if length(saveat) >= 2 - dt = saveat[2] - saveat[1] - end - end - - t = t_start - - progressMeter = nothing - if showProgress - progressMeter = ProgressMeter.Progress(1000; desc="Simulating CS-FMU ...", color=:blue, dt=1.0) - ProgressMeter.update!(progressMeter, 0) # show it! - end - - first_step = true - - fmusol.values = SavedValues(Float64, Tuple{collect(Float64 for i in 1:length(y_refs))...} ) - fmusol.valueReferences = copy(y_refs) - - i = 1 - - while t < t_stop - if variableSteps - if length(saveat) > (i+1) - dt = saveat[i+1] - saveat[i] - else - dt = t_stop - t - end - end - - if !first_step - fmi2DoStep(c, dt; currentCommunicationPoint=t) - t = t + dt - i += 1 - else - first_step = false - end - - if hasInputs - u = eval!(_inputFunction, c, nothing, t) - end - - c(u=u, u_refs=u_refs, y=y, y_refs=y_refs) - - svalues = (y...,) - DiffEqCallbacks.copyat_or_push!(fmusol.values.t, i, t) - DiffEqCallbacks.copyat_or_push!(fmusol.values.saveval, i, svalues, Val{false}) - - if progressMeter !== nothing - ProgressMeter.update!(progressMeter, floor(Integer, 1000.0*(t-t_start)/(t_stop-t_start)) ) - end - end - - if progressMeter !== nothing - ProgressMeter.finish!(progressMeter) - end - - fmusol.success = true # ToDo: Check successful simulation! - - finishSolveFMU(fmu, c, freeInstance, terminate) - - return fmusol -end - -export fmi2SimulateCS - -##### CS & ME ##### - -""" - fmi2Simulate(c::FMU2Component, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...) - -Wrapper for `fmi2Simulate(fmu::FMU2, c::Union{FMU2Component, Nothing}, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...)` without a provided FMU2. -(FMU2 `fmu` is taken from `c`) -""" -function fmi2Simulate(c::FMU2Component, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...) - fmi2Simulate(c.fmu, c, tspan; kwargs...) -end - -# function (c::FMU2Component)(; t::Tuple{Float64, Float64}, kwargs...) -# fmi2Simulate(c, t; kwargs...) -# end - -# function (f::FMU2)(; t::Tuple{Float64, Float64}, kwargs...) -# fmi2Simulate(c.fmu, t; kwargs...) -# end - -""" - fmi2Simulate(args...) - -Starts a simulation of the `FMU2` for the matching type (`fmi2SimulateCS(args...)` or `fmi2SimulateME(args...)`); if both types are available, CS is preferred. - -See also [`fmi2SimulateCS`](@ref), [`fmi2SimulateME`](@ref). -""" -function fmi2Simulate(fmu::FMU2, c::Union{FMU2Component, Nothing}=nothing, tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing; kwargs...) - - if fmu.type == fmi2TypeCoSimulation - return fmi2SimulateCS(fmu, c, tspan; kwargs...) - elseif fmu.type == fmi2TypeModelExchange - return fmi2SimulateME(fmu, c, tspan; kwargs...) - else - error(unknownFMUType) - end -end - -export fmi2Simulate \ No newline at end of file diff --git a/src/FMI3/additional.jl b/src/FMI3/additional.jl deleted file mode 100644 index dce30415..00000000 --- a/src/FMI3/additional.jl +++ /dev/null @@ -1,175 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# What is included in the file `FMI3_additional.jl` (FMU add functions)? -# - high-level functions, that are useful, but not part of the FMI-spec [exported] - -using Base.Filesystem: mktempdir - -using FMIImport: FMU3, fmi3ModelDescription -using FMIImport: fmi3Float32, fmi3Float64, fmi3Int8, fmi3Int16, fmi3Int32, fmi3Int64, fmi3Boolean, fmi3String, fmi3Binary, fmi3UInt8, fmi3UInt16, fmi3UInt32, fmi3UInt64, fmi3Byte -using FMIImport: fmi3Clock, fmi3FMUState -using FMIImport: fmi3True, fmi3False -using FMIImport: fmi3DependencyKindDependent, fmi3DependencyKindFixed -using FMIImport: fmi3CallbackLogger, fmi3CallbackIntermediateUpdate, fmi3CallbackClockUpdate, fmi3Instance -import FMIImport: fmi3VariableNamingConventionFlat, fmi3VariableNamingConventionStructured - -""" - fmi3VariableDependsOnVariable(fmu::FMU3, vr1::fmi3ValueReference, vr2::fmi3ValueReference) - -Return the dependence of the variable described by `vr1` on another variable described by `vr2` based on the model description of the `fmu`. - -See also [`fmi3GetDependencies`](@ref). -""" -function fmi3VariableDependsOnVariable(fmu::FMU3, vr1::fmi3ValueReference, vr2::fmi3ValueReference) - i1 = fmu.modelDescription.valueReferenceIndicies[vr1] - i2 = fmu.modelDescription.valueReferenceIndicies[vr2] - return fmi3GetDependencies(fmu)[i1, i2] -end - -""" - fmi3GetDependencies(fmu::FMU3) - -Build dependency `Matrix{Union{fmi3DependencyKind, Nothing}}` of dimension `n x n` for fast look-ups on dependencies between value references (`n` is number of states of the `fmu`). - -See also [`fmi3PrintDependencies`](@ref), [`fmi3VariableDependsOnVariable`](@ref). -""" -function fmi3GetDependencies(fmu::FMU3) - if !isdefined(fmu, :dependencies) - dim = length(fmu.modelDescription.valueReferences) - @info "fmi3GetDependencies: Started building dependency matrix $(dim) x $(dim) ..." - - if fmi3DependenciesSupported(fmu.modelDescription) - fmu.dependencies = fill(nothing, dim, dim) - - for i in 1:dim - modelVariable = fmi3ModelVariablesForValueReference(fmu.modelDescription, fmu.modelDescription.valueReferences[i])[1] - - if modelVariable.dependencies !== nothing - indicies = collect(fmu.modelDescription.valueReferenceIndicies[fmu.modelDescription.modelVariables[dependency].valueReference] for dependency in modelVariable.dependencies) - dependenciesKind = modelVariable.dependenciesKind - - k = 1 - for j in 1:dim - if j in indicies - if dependenciesKind[k] == "fixed" - fmu.dependencies[i,j] = fmi3DependencyKindFixed - elseif dependenciesKind[k] == "dependent" - fmu.dependencies[i,j] = fmi3DependencyKindDependent - else - @warn "Unknown dependency kind for index ($i, $j) = `$(dependenciesKind[k])`." - end - k += 1 - end - end - end - end - else - fmu.dependencies = fill(nothing, dim, dim) - end - - @info "fmi3GetDependencies: Building dependency matrix $(dim) x $(dim) finished." - end - - fmu.dependencies -end - -""" - fmi3PrintDependencies(fmu::FMU3) - -Print the dependency matrix for `fmu` as returned by [`fmi3GetDependencies`](@ref). - -See also [`fmi3GetDependencies`](@ref). -""" -function fmi3PrintDependencies(fmu::FMU3) - dep = fmi3GetDependencies(fmu) - ni, nj = size(dep) - - for i in 1:ni - str = "" - for j in 1:nj - str = "$(str) $(Integer(dep[i,j]))" - end - println(str) - end -end - -""" - fmi3Info(fmu::FMU3) - -Print information about the `fmu`. -""" -function fmi3Info(fmu::FMU3) - println("#################### Begin information for FMU ####################") - - println("\tModel name:\t\t\t$(fmi3GetModelName(fmu))") - println("\tFMI-Version:\t\t\t$(fmi3GetVersion(fmu))") - println("\tInstantiation Token:\t\t\t\t$(fmi3GetInstantiationToken(fmu))") - println("\tGeneration tool:\t\t$(fmi3GetGenerationTool(fmu))") - println("\tGeneration time:\t\t$(fmi3GetGenerationDateAndTime(fmu))") - print("\tVar. naming conv.:\t\t") - if fmi3GetVariableNamingConvention(fmu) == fmi3VariableNamingConventionFlat - println("flat") - elseif fmi3GetVariableNamingConvention(fmu) == fmi3VariableNamingConventionStructured - println("structured") - else - println("[unknown]") - end - println("\tEvent indicators:\t\t$(fmi3GetNumberOfEventIndicators(fmu))") - - println("\tInputs:\t\t\t\t$(length(fmu.modelDescription.inputValueReferences))") - for vr in fmu.modelDescription.inputValueReferences - println("\t\t$(vr) $(fmi3ValueReferenceToString(fmu, vr))") - end - - println("\tOutputs:\t\t\t$(length(fmu.modelDescription.outputValueReferences))") - for vr in fmu.modelDescription.outputValueReferences - println("\t\t$(vr) $(fmi3ValueReferenceToString(fmu, vr))") - end - - println("\tStates:\t\t\t\t$(length(fmu.modelDescription.stateValueReferences))") - for vr in fmu.modelDescription.stateValueReferences - println("\t\t$(vr) $(fmi3ValueReferenceToString(fmu, vr))") - end - - println("\tSupports Co-Simulation:\t\t$(fmi3IsCoSimulation(fmu))") - if fmi3IsCoSimulation(fmu) - println("\t\tModel identifier:\t$(fmu.modelDescription.coSimulation.modelIdentifier)") - println("\t\tGet/Set State:\t\t$(fmu.modelDescription.coSimulation.canGetAndSetFMUstate)") - println("\t\tSerialize State:\t$(fmu.modelDescription.coSimulation.canSerializeFMUstate)") - println("\t\tDir. Derivatives:\t$(fmu.modelDescription.coSimulation.providesDirectionalDerivatives)") - println("\t\tAdj. Derivatives:\t$(fmu.modelDescription.coSimulation.providesAdjointDerivatives)") - println("\t\tEvent Mode:\t$(fmu.modelDescription.coSimulation.hasEventMode)") - - println("\t\tVar. com. steps:\t$(fmu.modelDescription.coSimulation.canHandleVariableCommunicationStepSize)") - println("\t\tInput interpol.:\t$(fmu.modelDescription.coSimulation.canInterpolateInputs)") - println("\t\tMax order out. der.:\t$(fmu.modelDescription.coSimulation.maxOutputDerivativeOrder)") - end - - println("\tSupports Model-Exchange:\t$(fmi3IsModelExchange(fmu))") - if fmi3IsModelExchange(fmu) - println("\t\tModel identifier:\t$(fmu.modelDescription.modelExchange.modelIdentifier)") - println("\t\tGet/Set State:\t\t$(fmu.modelDescription.modelExchange.canGetAndSetFMUstate)") - println("\t\tSerialize State:\t$(fmu.modelDescription.modelExchange.canSerializeFMUstate)") - println("\t\tDir. Derivatives:\t$(fmu.modelDescription.modelExchange.providesDirectionalDerivatives)") - println("\t\tAdj. Derivatives:\t$(fmu.modelDescription.modelExchange.providesAdjointDerivatives)") - end - - println("\tSupports Scheduled-Execution:\t$(fmi3IsScheduledExecution(fmu))") - if fmi3IsScheduledExecution(fmu) - println("\t\tModel identifier:\t$(fmu.modelDescription.scheduledExecution.modelIdentifier)") - println("\t\tGet/Set State:\t\t$(fmu.modelDescription.scheduledExecution.canGetAndSetFMUstate)") - println("\t\tSerialize State:\t$(fmu.modelDescription.scheduledExecution.canSerializeFMUstate)") - println("\t\tNeeds Execution Tool:\t$(fmu.modelDescription.scheduledExecution.needsExecutionTool)") - println("\t\tInstantiated Once Per Process:\t$(fmu.modelDescription.scheduledExecution.canBeInstantiatedOnlyOncePerProcess)") - println("\t\tPer Element Dependencies:\t$(fmu.modelDescription.scheduledExecution.providesPerElementDependencies)") - - println("\t\tDir. Derivatives:\t$(fmu.modelDescription.scheduledExecution.providesDirectionalDerivatives)") - println("\t\tAdj. Derivatives:\t$(fmu.modelDescription.scheduledExecution.providesAdjointDerivatives)") - end - - println("##################### End information for FMU #####################") -end - diff --git a/src/FMI3/comp_wraps.jl b/src/FMI3/comp_wraps.jl deleted file mode 100644 index 437d356f..00000000 --- a/src/FMI3/comp_wraps.jl +++ /dev/null @@ -1,977 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# What is included in the file `FMI3_comp_wraps.jl` (FMU instance wrappers)? -# - wrappers to call fmi3InstanceFunctions from FMUs (FMI-functions, last instantiated instance is used) [exported] -# - wrappers to call fmi3InstanceFunctions from FMUs (additional functions, last instantiated instance is used) [exported] - -# fmi-spec -""" - fmi3Simulate(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3Simulate(fmu::FMU3, c::Union{FMU3Instance, Nothing}, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets passed as `nothing`) -""" -function fmi3Simulate(fmu::FMU3, args...; kwargs...) - return fmi3Simulate(fmu, nothing, args...; kwargs...) -end - -""" - fmi3SimulateCS(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SimulateCS(fmu::FMU3, c::Union{FMU3Instance, Nothing}, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets passed as `nothing`) -""" -function fmi3SimulateCS(fmu::FMU3, args...; kwargs...) - return fmi3SimulateCS(fmu, nothing, args...; kwargs...) -end - -""" - fmi3SimulateME(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SimulateME(fmu::FMU3, c::Union{FMU3Instance, Nothing}, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets passed as `nothing`) -""" -function fmi3SimulateME(fmu::FMU3, args...; kwargs...) - return fmi3SimulateME(fmu, nothing, args...; kwargs...) -end - -""" - fmi3FreeInstance!(fmu::FMU3) - -Wrapper for `fmi3FreeInstance!(c::FMU3Instance; popInstance::Bool = true)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3FreeInstance!(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3FreeInstance!(fmu.instances[end]) # this command also removes the instance from the array -end - -""" - fmi3SetDebugLogging(fmu::FMU3) - -Wrapper for `fmi3SetDebugLogging(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetDebugLogging(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetDebugLogging(fmu.instances[end]) -end - -""" - fmi3EnterInitializationMode(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3EnterInitializationMode(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3EnterInitializationMode(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3EnterInitializationMode(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3ExitInitializationMode(fmu::FMU3) - -Wrapper for `fmi3ExitInitializationMode(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3ExitInitializationMode(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3ExitInitializationMode(fmu.instances[end]) -end - -""" - fmi3Terminate(fmu::FMU3) - -Wrapper for `fmi3Terminate(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3Terminate(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3Terminate(fmu.instances[end]) -end - -""" - fmi3Reset(fmu::FMU3) - -Wrapper for `fmi3Reset(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3Reset(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3Reset(fmu.instances[end]) -end - -""" - fmi3GetFloat32(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetFloat32(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetFloat32(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetFloat32(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetFloat32!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetFloat32!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetFloat32!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetFloat32!(fmu.instances[end], args...; kwargs...) -end - -""" -fmi3SetFloat32(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetFloat32(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetFloat32(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetFloat32(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetFloat64(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetFloat64(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetFloat64(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetFloat64(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetFloat64!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetFloat64!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetFloat64!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetFloat64!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetFloat64(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetFloat64(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetFloat64(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetFloat64(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt8(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt8(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt8(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt8(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt8!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt8!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt8!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt8!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetInt8(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetInt8(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetInt8(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetInt8(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt8(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt8(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt8(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt8(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt8!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt8!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt8!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt8!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetUInt8(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetUInt8(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetUInt8(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetUInt8(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt16(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt16(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt16(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt16(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt16!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt16!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt16!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt16!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetInt16(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetInt16(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetInt16(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetInt16(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt16(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt16(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt16(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt16(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt16!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt16!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt16!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt16!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetUInt16(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetUInt16(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetUInt16(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetUInt16(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt32(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt32(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt32(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt32(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt32!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt32!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt32!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt32!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetInt32(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetInt32(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetInt32(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetInt32(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt32(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt32(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt32(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt32(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt32!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt32!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt32!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt32!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetUInt32(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetUInt32(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetUInt32(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetUInt32(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt64(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt64(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt64(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt64(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetInt64!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetInt64!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetInt64!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetInt64!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetInt64(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetInt64(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetInt64(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetInt64(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt64(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt64(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt64(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt64(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetUInt64!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetUInt64!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetUInt64!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetUInt64!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetUInt64(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetUInt64(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetUInt64(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetUInt64(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetBoolean(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetBoolean(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetBoolean(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetBoolean(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetBoolean!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetBoolean!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetBoolean!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetBoolean!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetBoolean(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetBoolean!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetBoolean(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetBoolean(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetString(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetString(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetString(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetString(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetString!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetString!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetString!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetString!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetString(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetString(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetString(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetString(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetBinary(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetBinary(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetBinary(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetBinary(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetBinary!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetBinary!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetBinary!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetBinary!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetBinary(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetBinary(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetBinary(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetBinary(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetClock(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetClock(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetClock(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetClock(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetClock!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetClock!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetClock!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetClock!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetClock(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetClock(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetClock(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetClock(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3Get(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3Get(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3Get(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3Get(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3Get!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3Get!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3Get!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3Get!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3Set(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3Set(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3Set(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3Set(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetFMUstate(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetFMUstate(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetFMUState(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetFMUState(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetFMUState(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetFMUState(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetFMUState(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetFMUState(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3FreeFMUState!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3FreeFMUState!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3FreeFMUState!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3FreeFMUState!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SerializedFMUStateSize(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SerializedFMUStateSize(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SerializedFMUStateSize(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SerializedFMUStateSize(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SerializeFMUState(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SerializeFMUState(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SerializeFMUState(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SerializeFMUState(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3DeSerializeFMUState(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3DeSerializeFMUState(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3DeSerializeFMUState(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3DeSerializeFMUState(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetDirectionalDerivative(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetDirectionalDerivative(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetDirectionalDerivative(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetDirectionalDerivative(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetDirectionalDerivative!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetDirectionalDerivative!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetDirectionalDerivative!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetDirectionalDerivative!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetAdjointDerivative(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetAdjointDerivative(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetAdjointDerivative(fmu::FMU3, args...; kwargs...) - - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetAdjointDerivative(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetAdjointDerivative!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetAdjointDerivative!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetAdjointDerivative!(fmu::FMU3, args...; kwargs...) - - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetAdjointDerivative!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SampleDirectionalDerivative!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SampleDirectionalDerivative!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SampleDirectionalDerivative!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SampleDirectionalDerivative!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SampleDirectionalDerivative(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SampleDirectionalDerivative(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SampleDirectionalDerivative(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SampleDirectionalDerivative(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetJacobian!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetJacobian!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetJacobian!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetJacobian!(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetJacobian(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetJacobian(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetJacobian(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetJacobian(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetOutputDerivatives(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetOutputDerivatives(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetOutputDerivatives(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetOutputDerivatives(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3EnterConfigurationMode(fmu::FMU3) - -Wrapper for `fmi3EnterConfigurationMode(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3EnterConfigurationMode(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3EnterConfigurationMode(fmu.instances[end]) -end - -""" - fmi3GetNumberOfContinuousStates(fmu::FMU3) - -Wrapper for `fmi3GetNumberOfContinuousStates(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetNumberOfContinuousStates(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetNumberOfContinuousStates(fmu.instances[end]) -end - -""" - fmi3GetNumberOfVariableDependencies(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetNumberOfVariableDependencies(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetNumberOfVariableDependencies(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetNumberOfVariableDependencies(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetVariableDependencies(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetVariableDependencies(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetVariableDependencies(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetVariableDependencies(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3GetContinuousStates(fmu::FMU3) - -Wrapper for `fmi3GetContinuousStates(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetContinuousStates(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetContinuousStates(fmu.instances[end]) -end - -""" - fmi3GetNominalsOfContinuousStates(fmu::FMU3) - -Wrapper for `fmi3GetNominalsOfContinuousStates(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetNominalsOfContinuousStates(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetNominalsOfContinuousStates(fmu.instances[end]) -end - -""" -fmi3EvaluateDiscreteStates(fmu::FMU3) - -Wrapper for `fmi3EvaluateDiscreteStates(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3EvaluateDiscreteStates(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3EvaluateDiscreteStates(fmu.instances[end]) -end - -""" - fmi3UpdateDiscreteStates(fmu::FMU3) - -Wrapper for `fmi3UpdateDiscreteStates(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3UpdateDiscreteStates(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3UpdateDiscreteStates(fmu.instances[end]) -end - -""" - fmi3EnterContinuousTimeMode(fmu::FMU3) - -Wrapper for `fmi3EnterContinuousTimeMode(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3EnterContinuousTimeMode(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3EnterContinuousTimeMode(fmu.instances[end]) -end - -""" - fmi3EnterStepMode(fmu::FMU3) - -Wrapper for `fmi3EnterStepMode(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3EnterStepMode(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3EnterStepMode(fmu.instances[end]) -end - -""" - fmi3ExitConfigurationMode(fmu::FMU3) - -Wrapper for `fmi3ExitConfigurationMode(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3ExitConfigurationMode(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3ExitConfigurationMode(fmu.instances[end]) -end - -""" - fmi3SetTime(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetTime(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetTime(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetTime(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3SetContinuousStates(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3SetContinuousStates(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3SetContinuousStates(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3SetContinuousStates(fmu.instances[end], args...; kwargs...) -end - -""" -fmi3GetContinuousStateDerivatives(fmu::FMU3) - -Wrapper for `fmi3GetContinuousStateDerivatives(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetContinuousStateDerivatives(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetContinuousStateDerivatives(fmu.instances[end]) -end - -""" - fmi3GetEventIndicators(fmu::FMU3) - -Wrapper for `fmi3GetEventIndicators(c::FMU3Instance)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetEventIndicators(fmu::FMU3) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetEventIndicators(fmu.instances[end]) -end - -""" -fmi3CompletedIntegratorStep(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3CompletedIntegratorStep(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3CompletedIntegratorStep(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3CompletedIntegratorStep(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3EnterEventMode(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3EnterEventMode(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3EnterEventMode(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3EnterEventMode(fmu.instances[end], args...; kwargs...) -end - -""" - fmi3DoStep!(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3DoStep!(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3DoStep!(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3DoStep!(fmu.instances[end], args...; kwargs...) -end - - -""" - fmi3GetStartValue(fmu::FMU3, args...; kwargs...) - -Wrapper for `fmi3GetStartValue(c::FMU3Instance, args...; kwargs...)` without a provided FMU3Instance. -(Instance `c` gets selected from `fmu`) -""" -function fmi3GetStartValue(fmu::FMU3, args...; kwargs...) - @assert length(fmu.instances) > 0 ["No FMU instance allocated, have you already called fmiInstantiate?"] - fmi3GetStartValue(fmu.instances[end], args...; kwargs...) -end \ No newline at end of file diff --git a/src/FMI3/sim.jl b/src/FMI3/sim.jl deleted file mode 100644 index f436f998..00000000 --- a/src/FMI3/sim.jl +++ /dev/null @@ -1,1261 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using DifferentialEquations, DifferentialEquations.DiffEqCallbacks -import DifferentialEquations.SciMLBase: RightRootFind, ReturnCode - -using FMIImport: fmi3EnterInitializationMode, fmi3ExitInitializationMode, fmi3UpdateDiscreteStates, fmi3GetContinuousStates, fmi3GetNominalsOfContinuousStates, fmi3SetContinuousStates, fmi3GetContinuousStateDerivatives! -using FMIImport.FMICore: fmi3StatusOK, fmi3TypeCoSimulation, fmi3TypeModelExchange -using FMIImport.FMICore: fmi3InstanceState, fmi3InstanceStateInstantiated, fmi3InstanceStateInitializationMode, fmi3InstanceStateEventMode, fmi3InstanceStateContinuousTimeMode, fmi3InstanceStateTerminated, fmi3InstanceStateError, fmi3InstanceStateFatal -using FMIImport: FMU3Solution, FMU3Event - -using FMIImport.FMICore.ChainRulesCore - -import ProgressMeter - -############ Model-Exchange ############ - -# Read next time event from FMU and provide it to the integrator -function time_choice(c::FMU3Instance, integrator, tStart, tStop) - #@info "TC" - - discreteStatesNeedUpdate, terminateSimulation, nominalsOfContinuousStatesChanged, valuesOfContinuousStatesChanged, nextEventTimeDefined, nextEventTime = fmi3UpdateDiscreteStates(c) - - if nextEventTimeDefined == fmi3True - - if nextEventTime >= tStart && nextEventTime <= tStop - return nextEventTime - else - # the time event is outside the simulation range! - @debug "Next time event @$(c.eventInfo.nextEventTime)s is outside simulation time range ($(tStart), $(tStop)), skipping." - return nothing - end - else - return nothing - end -end - -# Handles events and returns the values and nominals of the changed continuous states. -function handleEvents(c::FMU3Instance) - # @assert c.state == fmi3InstanceStateEventMode "handleEvents(...): Must be in event mode!" - - # trigger the loop - discreteStatesNeedUpdate = fmi3True - nominalsChanged = fmi3False - valuesChanged = fmi3False - nextEventTimeDefined = fmi3False - nextEventTime = 0.0 - - while discreteStatesNeedUpdate == fmi3True - - # TODO set inputs - discreteStatesNeedUpdate, terminateSimulation, nominalsOfContinuousStatesChanged, valuesOfContinuousStatesChanged, nextEventTimeDefined, nextEventTime = fmi3UpdateDiscreteStates(c) - - if c.state != fmi3InstanceStateEventMode - fmi3EnterEventMode(c, c.stepEvent, c.stateEvent, c.rootsFound, Csize_t(c.fmu.modelDescription.numberOfEventIndicators), c.timeEvent) - end - # TODO inputEvent handling - discreteStatesNeedUpdate = fmi3True - while discreteStatesNeedUpdate == fmi3True - # update discrete states - discreteStatesNeedUpdate, terminateSimulation, nominalsOfContinuousStatesChanged, valuesOfContinuousStatesChanged, nextEventTimeDefined, nextEventTime = fmi3UpdateDiscreteStates(c) - - if valuesOfContinuousStatesChanged == fmi3True - valuesChanged = true - end - - if nominalsOfContinuousStatesChanged == fmi3True - nominalsChanged = true - end - - if terminateSimulation == fmi3True - @error "fmi3UpdateDiscreteStates returned error!" - end - end - end - fmi3EnterContinuousTimeMode(c) - @debug "handleEvents(_, $(enterEventMode), $(exitInContinuousMode)): rootsFound: $(c.rootsFound) valuesChanged: $(valuesChanged) continuousStates: $(fmi3GetContinuousStates(c))", - return valuesChanged, nominalsChanged - -end - -# Returns the event indicators for an FMU. -function condition(c::FMU3Instance, out::AbstractArray{<:Real}, x, t, integrator, inputFunction, inputValues::AbstractArray{fmi3ValueReference}) - if inputFunction !== nothing - fmi3SetFloat64(c, inputValues, inputFunction(c, x, t)) - end - - @assert c.state == fmi3InstanceStateContinuousTimeMode "condition(...): Must be called in mode continuous time." - - fmi3SetContinuousStates(c, x) - fmi3SetTime(c, t) - if inputFunction !== nothing - fmi3SetFloat64(c, inputValues, inputFunction(c, x, t)) - end - - # TODO check implementation of fmi3GetEventIndicators! mit abstract array - fmi3GetEventIndicators!(c, out, UInt(length(out))) - - # if length(indicators) > 0 - # for i in 1:length(indicators) - # if c.z_prev[i] < 0 && indicators[i] >= 0 - # c.rootsFound[i] = 1 - # elseif c.z_prev[i] > 0 && indicators[i] <= 0 - # c.rootsFound[i] = -1 - # else - # c.rootsFound[i] = 0 - # end - # c.stateEvent |= (c.rootsFound[i] != 0) - # # c.z_prev[i] = indicators[i] - # end - # end - - return nothing -end - -# Handles the upcoming events. -function affectFMU!(c::FMU3Instance, integrator, idx, inputFunction, inputValues::Array{fmi3ValueReference}, solution::FMU3Solution) - - @assert c.state == fmi3InstanceStateContinuousTimeMode "affectFMU!(...): Must be in continuous time mode!" - - # there are fx-evaluations before the event is handled, reset the FMU state to the current integrator step - fmi3SetContinuousStates(c, integrator.u) - fmi3SetTime(c, integrator.t) - if inputFunction !== nothing - fmi3SetFloat64(c, inputValues, inputFunction(c, integrator.u, integrator.t)) - end - - fmi3EnterEventMode(c, c.stepEvent, c.stateEvent, c.rootsFound, Csize_t(c.fmu.modelDescription.numberOfEventIndicators), c.timeEvent) - - # Event found - handle it - handleEvents(c) - - left_x = nothing - right_x = nothing - - if c.eventInfo.valuesOfContinuousStatesChanged == fmi3True - left_x = integrator.u - right_x = fmi3GetContinuousStates(c) - @debug "affectFMU!(...): Handled event at t=$(integrator.t), new state is $(new_u)" - integrator.u = right_x - - u_modified!(integrator, true) - #set_proposed_dt!(integrator, 1e-10) - else - u_modified!(integrator, false) - @debug "affectFMU!(...): Handled event at t=$(integrator.t), no new state." - end - - if c.eventInfo.nominalsOfContinuousStatesChanged == fmi3True - x_nom = fmi3GetNominalsOfContinuousStates(c) - end - - ignore_derivatives() do - if idx != -1 # -1 no event, 0, time event, >=1 state event with indicator - e = FMU3Event(integrator.t, UInt64(idx), left_x, right_x) - push!(solution.events, e) - end - end - - #fmi3EnterContinuousTimeMode(c) -end - -# Does one step in the simulation. -function stepCompleted(c::FMU3Instance, x, t, integrator, inputFunction, inputValues::AbstractArray{fmi3ValueReference}, progressMeter, tStart, tStop, solution::FMU3Solution) - - @assert c.state == fmi3InstanceStateContinuousTimeMode "stepCompleted(...): Must be in continuous time mode." - #@info "Step completed" - if progressMeter !== nothing - stat = 1000.0*(t-tStart)/(tStop-tStart) - if !isnan(stat) - stat = floor(Integer, stat) - ProgressMeter.update!(progressMeter, stat) - end - end - - # if length(indicators) > 0 - # c.stateEvent = fmi3False - - # for i in 1:length(indicators) - # if c.z_prev[i] < 0 && indicators[i] >= 0 - # c.rootsFound[i] = 1 - # elseif c.z_prev[i] > 0 && indicators[i] <= 0 - # c.rootsFound[i] = -1 - # else - # c.rootsFound[i] = 0 - # end - # c.stateEvent |= (c.rootsFound[i] != 0) - # c.z_prev[i] = indicators[i] - # end - # end - (status, enterEventMode, terminateSimulation) = fmi3CompletedIntegratorStep(c, fmi3True) - - if terminateSimulation == fmi3True - @error "stepCompleted(...): FMU requested termination!" - end - - if enterEventMode == fmi3True - affectFMU!(c, integrator, -1, inputFunction, inputValues, solution) - else - if inputFunction !== nothing - fmi3SetFloat64(c, inputValues, inputFunction(c, x, t)) - end - end -end - -# save FMU values -function saveValues(c::FMU3Instance, recordValues, x, t, integrator, inputFunction, inputValues) - - @assert c.state == fmi3InstanceStateContinuousTimeMode "saveValues(...): Must be in continuous time mode." - - #x_old = fmi3GetContinuousStates(c) - #t_old = c.t - - fmi3SetContinuousStates(c, x) - fmi3SetTime(c, t) - if inputFunction !== nothing - fmi3SetFloat64(c, inputValues, inputFunction(c, x, t)) - end - - #fmi3SetContinuousStates(c, x_old) - #fmi3SetTime(c, t_old) - - return (fmi3GetFloat64(c, recordValues)...,) -end - -# Returns the state derivatives of the FMU. -function fx(c::FMU3Instance, - dx::AbstractArray{<:Real}, - x::AbstractArray{<:Real}, - p::Tuple, - t::Real) - - # if isa(t, ForwardDiff.Dual) - # t = ForwardDiff.value(t) - # end - @debug "fx($(x), _, $(t))" - fmi3SetTime(c, t) - fmi3SetContinuousStates(c, x) - dx = fmi3GetContinuousStateDerivatives(c) - - # if all(isa.(dx, ForwardDiff.Dual)) - # dx_tmp = collect(ForwardDiff.value(e) for e in dx) - # fmi3GetContinuousStateDerivatives!(c, dx_tmp) - # T, V, N = fd_eltypes(dx) - # dx[:] = collect(ForwardDiff.Dual{T, V, N}(dx_tmp[i], ForwardDiff.partials(dx[i]) ) for i in 1:length(dx)) - # else - # fmi3GetContinuousStateDerivatives!(c, dx) - # end - - # y, dx = FMIImport.eval!(c, dx, nothing, nothing, x, nothing, nothing, t) - - return dx -end - -# same function as in FMI2_sim.jl -function _fx_fd(comp, dx, x, p, t) - - aΜ‡rgs = [] - args = [] - - push!(aΜ‡rgs, NoTangent()) - push!(args, fx) - - push!(aΜ‡rgs, NoTangent()) - push!(args, comp) - - T = nothing - V = nothing - - dx_set = length(dx) > 0 && all(isa.(dx, ForwardDiff.Dual)) - x_set = length(x) > 0 && all(isa.(x, ForwardDiff.Dual)) - p_set = length(p) > 0 && all(isa.(p, ForwardDiff.Dual)) - t_set = isa(t, ForwardDiff.Dual) - - if dx_set - T, V, N = fd_eltypes(dx) - push!(aΜ‡rgs, collect(ForwardDiff.partials(e) for e in dx)) - push!(args, collect(ForwardDiff.value(e) for e in dx)) - #@info "dx_set num=$(length(dx)) partials=$(length(ForwardDiff.partials(dx[1])))" - else - push!(aΜ‡rgs, NoTangent()) - push!(args, dx) - end - - if x_set - T, V, N = fd_eltypes(x) - push!(aΜ‡rgs, collect(ForwardDiff.partials(e) for e in x)) - push!(args, collect(ForwardDiff.value(e) for e in x)) - #@info "x_set num=$(length(x)) partials=$(length(ForwardDiff.partials(x[1])))" - else - push!(aΜ‡rgs, NoTangent()) - push!(args, x) - end - - if p_set - T, V, N = fd_eltypes(p) - push!(aΜ‡rgs, collect(ForwardDiff.partials(e) for e in p)) - push!(args, collect(ForwardDiff.value(e) for e in p)) - else - push!(aΜ‡rgs, NoTangent()) - push!(args, p) - end - - if t_set - T, V, N = fd_eltypes(t) - push!(aΜ‡rgs, ForwardDiff.partials(t)) - push!(args, ForwardDiff.value(t)) - else - push!(aΜ‡rgs, NoTangent()) - push!(args, t) - end - - aΜ‡rgs = (aΜ‡rgs...,) - args = (args...,) - - y, _, sdx, sx, sp, st = ChainRulesCore.frule(aΜ‡rgs, args...) - - ys = [] - - #[collect( ForwardDiff.Dual{Tx, Vx, Nx}(y[i], ForwardDiff.partials(x_partials[i], t_partials[i])) for i in 1:length(y) )...] - for i in 1:length(y) - is = NoTangent() - - if dx_set - is = sdx[i]#.values - end - if x_set - is = sx[i]#.values - end - - if p_set - is = sp[i]#.values - end - if t_set - is = st[i]#.values - end - - #display("dx: $dx") - #display("sdx: $sdx") - - #partials = (isdx, isx, isp, ist) - - #display(partials) - - - #V = Float64 - #N = length(partials) - #display("$T $V $N") - - #display(is) - - @assert is != ZeroTangent() && is != NoTangent() "is: $(is)" - - push!(ys, ForwardDiff.Dual{T, V, N}(y[i], is ) ) # ForwardDiff.Partials{N, V}(partials) - end - - ys -end - -import FMIImport: fmi3VariabilityConstant, fmi3InitialApprox, fmi3InitialExact -function setBeforeInitialization(mv::FMIImport.fmi3Variable) - return mv.variability != fmi3VariabilityConstant && mv.initial ∈ (fmi3InitialApprox, fmi3InitialExact) -end - -import FMIImport: fmi3CausalityInput, fmi3CausalityParameter, fmi3VariabilityTunable -function setInInitialization(mv::FMIImport.fmi3Variable) - return mv.causality == fmi3CausalityInput || (mv.causality != fmi3CausalityParameter && mv.variability == fmi3VariabilityTunable) || (mv.variability != fmi3VariabilityConstant && mv.initial == fmi3InitialExact) -end - -function prepareFMU(fmu::FMU3, c::Union{Nothing, FMU3Instance}, type::fmi3Type, instantiate::Union{Nothing, Bool}, terminate::Union{Nothing, Bool}, reset::Union{Nothing, Bool}, setup::Union{Nothing, Bool}, parameters::Union{Dict{<:Any, <:Any}, Nothing}, t_start, t_stop, tolerance; - x0::Union{AbstractArray{<:Real}, Nothing}=nothing, inputFunction=nothing, inputValueReferences=nothing) - - if instantiate === nothing - instantiate = fmu.executionConfig.instantiate - end - - if terminate === nothing - terminate = fmu.executionConfig.terminate - end - - if reset === nothing - reset = fmu.executionConfig.reset - end - - if setup === nothing - setup = fmu.executionConfig.setup - end - - c = nothing - - # instantiate (hard) - if instantiate - if type == fmi3TypeCoSimulation - c = fmi3InstantiateCoSimulation!(fmu) - elseif type == fmi3TypeModelExchange - c = fmi3InstantiateModelExchange!(fmu) - else - c = fmi3InstantiateScheduledExecution!(fmu) - end - else - if c === nothing - if length(fmu.instances) > 0 - c = fmu.instances[end] - else - @warn "Found no FMU instance, but executionConfig doesn't force allocation. Allocating one. Use `fmi3Instantiate(fmu)` to prevent this message." - if type == fmi3TypeCoSimulation - c = fmi3InstantiateCoSimulation!(fmu) - elseif type == fmi3TypeModelExchange - c = fmi3InstantiateModelExchange!(fmu) - else - c = fmi3InstantiateScheduledExecution!(fmu) - end - end - end - end - - @assert c !== nothing "No FMU instance available, allocate one or use `fmu.executionConfig.instantiate=true`." - - # soft terminate (if necessary) - if terminate - retcode = fmi3Terminate(c; soft=true) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Termination failed with return code $(retcode)." - end - - # soft reset (if necessary) - if reset - retcode = fmi3Reset(c; soft=true) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Reset failed with return code $(retcode)." - end - - # setup experiment (hard) - # TODO this part is handled by fmi3EnterInitializationMode - # if setup - # retcode = fmi2SetupExperiment(c, t_start, t_stop; tolerance=tolerance) - # @assert retcode == fmi3StatusOK "fmi3Simulate(...): Setting up experiment failed with return code $(retcode)." - # end - - # parameters - if parameters !== nothing - retcodes = fmi3Set(c, collect(keys(parameters)), collect(values(parameters)); filter=setBeforeInitialization) - @assert all(retcodes .== fmi3StatusOK) "fmi3Simulate(...): Setting initial parameters failed with return code $(retcode)." - end - - # inputs - inputs = nothing - if inputFunction !== nothing && inputValueReferences !== nothing - # set inputs - inputs = Dict{fmi3ValueReference, Any}() - - inputValues = nothing - if hasmethod(inputFunction, Tuple{FMU3Instance, fmi3Float64}) # CS - inputValues = inputFunction(c, t_start) - else # ME - inputValues = inputFunction(c, nothing, t_start) - end - - for i in 1:length(inputValueReferences) - vr = inputValueReferences[i] - inputs[vr] = inputValues[i] - end - end - - # inputs - if inputs !== nothing - retcodes = fmi3Set(c, collect(keys(inputs)), collect(values(inputs)); filter=setBeforeInitialization) - @assert all(retcodes .== fmi3StatusOK) "fmi3Simulate(...): Setting initial inputs failed with return code $(retcode)." - end - - # start state - if x0 !== nothing - #retcode = fmi3SetContinuousStates(c, x0) - #@assert retcode == fmi3StatusOK "fmi3Simulate(...): Setting initial state failed with return code $(retcode)." - retcodes = fmi3Set(c, fmu.modelDescription.stateValueReferences, x0; filter=setBeforeInitialization) - @assert all(retcodes .== fmi3StatusOK) "fmi3Simulate(...): Setting initial inputs failed with return code $(retcode)." - end - - # enter (hard) - if setup - retcode = fmi3EnterInitializationMode(c, t_start, t_stop; tolerance = tolerance) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Entering initialization mode failed with return code $(retcode)." - end - - # parameters - if parameters !== nothing - retcodes = fmi3Set(c, collect(keys(parameters)), collect(values(parameters)); filter=setInInitialization) - @assert all(retcodes .== fmi3StatusOK) "fmi3Simulate(...): Setting initial parameters failed with return code $(retcode)." - end - - if inputs !== nothing - retcodes = fmi3Set(c, collect(keys(inputs)), collect(values(inputs)); filter=setInInitialization) - @assert all(retcodes .== fmi3StatusOK) "fmi3Simulate(...): Setting initial inputs failed with return code $(retcode)." - end - - # start state - if x0 !== nothing - #retcode = fmi3SetContinuousStates(c, x0) - #@assert retcode == fmi3StatusOK "fmi3Simulate(...): Setting initial state failed with return code $(retcode)." - retcodes = fmi3Set(c, fmu.modelDescription.stateValueReferences, x0; filter=setInInitialization) - @assert all(retcodes .== fmi3StatusOK) "fmi3Simulate(...): Setting initial inputs failed with return code $(retcode)." - end - - # exit setup (hard) - if setup - retcode = fmi3ExitInitializationMode(c) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Exiting initialization mode failed with return code $(retcode)." - end - - if type == fmi3TypeModelExchange - if x0 === nothing - x0 = fmi3GetContinuousStates(c) - end - end - - return c, x0 -end - -function prepareFMU(fmu::Vector{FMU3}, c::Vector{Union{Nothing, FMU3Instance}}, type::Vector{fmi3Type}, instantiate::Union{Nothing, Bool}, freeInstance::Union{Nothing, Bool}, terminate::Union{Nothing, Bool}, reset::Union{Nothing, Bool}, setup::Union{Nothing, Bool}, parameters::Union{Vector{Union{Dict{<:Any, <:Any}, Nothing}}, Nothing}, t_start, t_stop, tolerance; - x0::Union{Vector{Union{Array{<:Real}, Nothing}}, Nothing}=nothing, initFct=nothing) - - ignore_derivatives() do - for i in 1:length(fmu) - - if instantiate === nothing - instantiate = fmu[i].executionConfig.instantiate - end - - if freeInstance === nothing - freeInstance = fmu[i].executionConfig.freeInstance - end - - if terminate === nothing - terminate = fmu[i].executionConfig.terminate - end - - if reset === nothing - reset = fmu[i].executionConfig.reset - end - - if setup === nothing - setup = fmu[i].executionConfig.setup - end - - # instantiate (hard) - if instantiate - # remove old one if we missed it (callback) - if c[i] !== nothing - if freeInstance - fmi3FreeInstance!(c[i]) - @debug "[AUTO-RELEASE INST]" - end - end - - if type[i] == fmi3TypeCoSimulation - c[i] = fmi3InstantiateCoSimulation!(fmu[i]) - elseif type[i] == fmi3TypeModelExchange - c[i] = fmi3InstantiateModelExchange!(fmu[i]) - else - c[i] = fmi3InstantiateScheduledExecution!(fmu[i]) - end - @debug "[NEW INST]" - else - if c[i] === nothing - c[i] = fmu[i].instances[end] - end - end - - # soft terminate (if necessary) - if terminate - retcode = fmi3Terminate(c[i]; soft=true) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Termination failed with return code $(retcode)." - end - - # soft reset (if necessary) - if reset - retcode = fmi3Reset(c[i]; soft=true) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Reset failed with return code $(retcode)." - end - - # enter setup (hard) - if setup - # retcode = fmi2SetupExperiment(c[i], t_start, t_stop; tolerance=tolerance) - # @assert retcode == fmi2StatusOK "fmi2Simulate(...): Setting up experiment failed with return code $(retcode)." - - retcode = fmi3EnterInitializationMode(c[i], t_start, t_stop; tolerance=tolerance) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Entering initialization mode failed with return code $(retcode)." - end - - if x0 !== nothing - if x0[i] !== nothing - retcode = fmi3SetContinuousStates(c[i], x0[i]) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Setting initial state failed with return code $(retcode)." - end - end - - if parameters !== nothing - if parameters[i] !== nothing - retcodes = fmi3Set(c[i], collect(keys(parameters[i])), collect(values(parameters[i])) ) - @assert all(retcodes .== fmi3StatusOK) "fmi3Simulate(...): Setting initial parameters failed with return code $(retcode)." - end - end - - if initFct !== nothing - initFct() - end - - # exit setup (hard) - if setup - retcode = fmi3ExitInitializationMode(c[i]) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Exiting initialization mode failed with return code $(retcode)." - end - - if type == fmi3TypeModelExchange - if x0 === nothing - if x0[i] === nothing - x0[i] = fmi3GetContinuousStates(c[i]) - end - end - end - end - - end # ignore_derivatives - - return c, x0 -end - -function finishFMU(fmu::FMU3, c::FMU3Instance, terminate::Union{Nothing, Bool}, freeInstance::Union{Nothing, Bool}) - - if c === nothing - return - end - - if terminate === nothing - terminate = fmu.executionConfig.terminate - end - - if freeInstance === nothing - freeInstance = fmu.executionConfig.freeInstance - end - - # soft terminate (if necessary) - if terminate - retcode = fmi3Terminate(c; soft=true) - @assert retcode == fmi3StatusOK "fmi3Simulate(...): Termination failed with return code $(retcode)." - end - - # freeInstance (hard) - if freeInstance - fmi3FreeInstance!(c) - end -end - -""" - fmi3SimulateME(c::FMU3Instance, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...) - -Wrapper for `fmi3SimulateME(fmu::FMU3, c::Union{FMU3Instance, Nothing}, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...)` without a provided FMU3. -(FMU3 `fmu` is taken from `c`) -""" -function fmi3SimulateME(c::FMU3Instance, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...) - fmi3SimulateME(c.fmu, c, t_start, t_stop; kwargs...) -end - -# sets up the ODEProblem for simulating a ME-FMU -function setupODEProblem(c::FMU3Instance, x0::AbstractArray{fmi3Float64}, t_start::fmi3Float64, t_stop::fmi3Float64; p=(), customFx=nothing) - if customFx === nothing - customFx = (dx, x, p, t) -> fx(c, dx, x, p, t) - end - - p = () - c.problem = ODEProblem(customFx, x0, (t_start, t_stop), p,) - - return c.problem -end - -""" - fmi3SimulateME(fmu::FMU3, - c::Union{FMU3Instance, Nothing}=nothing, - t_start::Union{Real, Nothing} = nothing, - t_stop::Union{Real, Nothing} = nothing; - [tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - solver = nothing, - customFx = nothing, - recordValues::fmi3ValueReferenceFormat = nothing, - saveat = nothing, - x0::Union{AbstractArray{<:Real}, Nothing} = nothing, - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi3ValueReferenceFormat = nothing, - inputFunction = nothing, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing, - dtmax::Union{Real, Nothing} = nothing, - callbacks = [], - showProgress::Bool = true, - kwargs...]) - -Simulate ME-FMU for the given simulation time interval. - -State- and Time-Events are handled correctly. - -# Arguments -- `fmu::FMU3`: Mutable struct representing a FMU and all it instantiated instances. -- `c::Union{FMU3Instance, Nothing}=nothing`: Mutable struct representing an instantiated instance of a FMU. -- `t_start::Union{Real, Nothing} = nothing`: Simulation-time-span start time (default = nothing: use default value from `fmu`'s model description or 0.0) -- `t_stop::Union{Real, Nothing} = nothing`: Simulation-time-span stop time (default = nothing: use default value from `fmu`'s model description or 1.0) - -- `tolerance::Union{Real, Nothing} = nothing`: tolerance for the solver (default = nothing: use default value from `fmu`'s model description or -if not available- default from DifferentialEquations.jl) -- `dt::Union{Real, Nothing} = nothing`: stepszie for the solver (default = nothing: use default value from `fmu`'s model description or -if not available- default from DifferentialEquations.jl) -- `solver = nothing`: Any Julia-supported ODE-solver (default = nothing: use DifferentialEquations.jl default solver) -- `customFx`: [deprecated] custom state derivative function xΜ‡=f(x,t) -- `recordValues::fmi3ValueReferenceFormat` = nothing: Array of variables (Strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` -- `saveat = nothing`: Time points to save (interpolated) values at (default = nothing: save at each solver timestep) -- `x0::Union{AbstractArray{<:Real}, Nothing} = nothing`: initial fmu State (default = nothing: use current or default-initial fmu state) -- `setup::Union{Bool, Nothing} = nothing`: call fmi3EnterInitializationMode and fmi3ExitInitializationMode before each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `reset::Union{Bool, Nothing} = nothing`: call fmi3Reset before each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `instantiate::Union{Bool, Nothing} = nothing`: call fmi3Instantiate! before each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `freeInstance::Union{Bool, Nothing} = nothing`: call fmi3FreeInstance after each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `terminate::Union{Bool, Nothing} = nothing`: call fmi3Terminate after each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `inputValueReferences::fmi3ValueReferenceFormat = nothing`: Input variables (Strings or variableIdentifiers) to set at each simulation step -- `inputFunction = nothing`: Function to get values for the input variables at each simulation step. - - ## Pattern [`c`: current instance, `u`: current state ,`t`: current time, returning array of values to be passed to `fmi3SetFloat64(..., inputValueReferences, inputFunction(...))`]: - - `inputFunction(t::fmi3Float64)` - - `inputFunction(c::FMU3Instance, t::fmi3Float64)` - - `inputFunction(c::FMU3Instance, u::Union{AbstractArray{fmi3Float64,1}, Nothing})` - - `inputFunction(u::Union{AbstractArray{fmi3Float64,1}, Nothing}, t::fmi3Float64)` - - `inputFunction(c::FMU3Instance, u::Union{AbstractArray{fmi3Float64,1}, Nothing}, t::fmi3Float64)` - -- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dict of parameter variables (strings or variableIdentifiers) and values (Real, Integer, Boolean, String) to set parameters during initialization -- `dtmax::Union{Real, Nothing} = nothing`: sets the maximum stepszie for the solver (default = nothing: use `(Simulation-time-span-length)/100.0`) -- `callbacks = []`: functions that are to be called at each solver time step -- `showProgress::Bool = true`: print simulation progressmeter in REPL -- `kwargs...`: keyword arguments that get passed onto the solvers solve call - -# Returns: -- If keyword `recordValues` has value `nothing`, a struct of type `ODESolution`. -- If keyword `recordValues` is set, a tuple of type `(ODESolution, DiffEqCallbacks.SavedValues)`. - -See also [`fmi3Simulate`](@ref), [`fmi3SimulateCS`](@ref), [`fmi3SimulateSE`](@ref). -""" -function fmi3SimulateME(fmu::FMU3, c::Union{FMU3Instance, Nothing}=nothing, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; - tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - solver = nothing, - customFx = nothing, - recordValues::fmi3ValueReferenceFormat = nothing, - saveat = nothing, - x0::Union{AbstractArray{<:Real}, Nothing} = nothing, - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi3ValueReferenceFormat = nothing, - inputFunction = nothing, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing, - dtmax::Union{Real, Nothing} = nothing, - callbacks = [], - showProgress::Bool = true, - kwargs...) - @warn "ME-simulation is not working properly right now!" - - @assert fmi3IsModelExchange(fmu) "fmi3SimulateME(...): This function supports Model Exchange FMUs only." - #@assert fmu.type == fmi3TypeModelExchange "fmi3SimulateME(...): This FMU supports Model Exchange, but was instantiated in CS mode. Use `fmiLoad(...; type=:ME)`." # TODO why not using this?? - - # input function handling - _inputFunction = nothing - if inputFunction !== nothing - if hasmethod(inputFunction, Tuple{fmi3Float64}) - _inputFunction = (c, u, t) -> inputFunction(t) - elseif hasmethod(inputFunction, Tuple{Union{FMU3Instance, Nothing}, fmi3Float64}) - _inputFunction = (c, u, t) -> inputFunction(c, t) - elseif hasmethod(inputFunction, Tuple{Union{FMU3Instance, Nothing}, AbstractArray{fmi3Float64,1}}) - _inputFunction = (c, u, t) -> inputFunction(c, u) - elseif hasmethod(inputFunction, Tuple{AbstractArray{fmi3Float64,1}, fmi3Float64}) - _inputFunction = (c, u, t) -> inputFunction(u, t) - else - _inputFunction = inputFunction - end - @assert hasmethod(_inputFunction, Tuple{FMU3Instance, Union{AbstractArray{fmi3Float64,1}, Nothing}, fmi3Float64}) "The given input function does not fit the needed input function pattern for ME-FMUs, which are: \n- `inputFunction(t::fmi3Float64)`\n- `inputFunction(comp::FMU3Instance, t::fmi3Float64)`\n- `inputFunction(comp::FMU3Instance, u::Union{AbstractArray{fmi3Float64,1}, Nothing})`\n- `inputFunction(u::Union{AbstractArray{fmi3Float64,1}, Nothing}, t::fmi3Float64)`\n- `inputFunction(comp::FMU3Instance, u::Union{AbstractArray{fmi3Float64,1}, Nothing}, t::fmi3Float64)`" - end - - recordValues = prepareValueReference(fmu, recordValues) - inputValueReferences = prepareValueReference(fmu, inputValueReferences) - - fmusol = FMU3Solution(fmu) - - savingValues = (length(recordValues) > 0) - hasInputs = (length(inputValueReferences) > 0) - hasParameters = (parameters !== nothing) - hasStartState = (x0 !== nothing) - - cbs = [] - - for cb in callbacks - push!(cbs, cb) - end - - if t_start === nothing - t_start = fmi3GetDefaultStartTime(fmu.modelDescription) - - if t_start === nothing - t_start = 0.0 - @info "No `t_start` chosen, no `t_start` available in the FMU, auto-picked `t_start=0.0`." - end - end - - if t_stop === nothing - t_stop = fmi3GetDefaultStopTime(fmu.modelDescription) - - if t_stop === nothing - t_stop = 1.0 - @warn "No `t_stop` chosen, no `t_stop` available in the FMU, auto-picked `t_stop=1.0`." - end - end - - if tolerance === nothing - tolerance = fmi3GetDefaultTolerance(fmu.modelDescription) - # if no tolerance is given, pick auto-setting from DifferentialEquations.jl - end - - if dt === nothing - dt = fmi3GetDefaultStepSize(fmu.modelDescription) - # if no dt is given, pick auto-setting from DifferentialEquations.jl - end - - if dtmax === nothing - dtmax = (t_stop-t_start)/100.0 - end - - # argument `tolerance=nothing` here, because ME-FMUs doesn't support tolerance control (no solver included) - # tolerance for the solver is set-up later in this function - c, x0 = prepareFMU(fmu, c, fmi3TypeModelExchange, instantiate, terminate, reset, setup, parameters, t_start, t_stop, nothing; x0=x0, inputFunction=_inputFunction, inputValueReferences=inputValueReferences) - - # from here on, we are in event mode, if `setup=false` this is the job of the user - #@assert c.state == fmi3InstanceStateEventMode "FMU needs to be in event mode after setup." - - # if x0 === nothing - # x0 = fmi3GetContinuousStates(c) - # x0_nom = fmi3GetNominalsOfContinuousStates(c) - # end - - # initial event handling - # fmi3EnterEventMode(c, c.stepEvent, c.stateEvent, c.rootsFound, Csize_t(c.fmu.modelDescription.numberOfEventIndicators), c.timeEvent) - handleEvents(c) - #fmi3EnterContinuousTimeMode(c) - - c.fmu.hasStateEvents = (c.fmu.modelDescription.numberOfEventIndicators > 0) - # c.fmu.hasTimeEvents = (c.eventInfo.nextEventTimeDefined == fmi2True) - c.fmu.hasTimeEvents = fmi3False - - setupODEProblem(c, x0, t_start, t_stop; customFx=customFx) - - progressMeter = nothing - if showProgress - progressMeter = ProgressMeter.Progress(1000; desc="Simulating ME-FMU ...", color=:blue, dt=1.0) #, barglyphs=ProgressMeter.BarGlyphs("[=> ]")) - ProgressMeter.update!(progressMeter, 0) # show it! - end - - # callback functions - - if c.fmu.hasTimeEvents - timeEventCb = IterativeCallback((integrator) -> time_choice(c, integrator, t_start, t_stop), - (integrator) -> affectFMU!(c, integrator, 0, _inputFunction, inputValueReferences, fmusol), Float64; - initial_affect = false, # (c.eventInfo.nextEventTime == t_start) - save_positions=(false,false)) - push!(cbs, timeEventCb) - end - - if c.fmu.hasStateEvents - - eventCb = VectorContinuousCallback((out, x, t, integrator) -> condition(c, out, x, t, integrator, _inputFunction, inputValueReferences), - (integrator, idx) -> affectFMU!(c, integrator, idx, _inputFunction, inputValueReferences, fmusol), - Int64(c.fmu.modelDescription.numberOfEventIndicators); - rootfind = RightRootFind, - save_positions=(false,false)) - push!(cbs, eventCb) - end - - # use step callback always if we have inputs or need event handling (or just want to see our simulation progress) - if hasInputs || c.fmu.hasStateEvents || c.fmu.hasTimeEvents || showProgress - stepCb = FunctionCallingCallback((x, t, integrator) -> stepCompleted(c, x, t, integrator, _inputFunction, inputValueReferences, progressMeter, t_start, t_stop, fmusol); - func_everystep = true, - func_start = true) - push!(cbs, stepCb) - end - - if savingValues - fmusol.values = SavedValues(Float64, Tuple{collect(Float64 for i in 1:length(recordValues))...}) - fmusol.valueReferences = copy(recordValues) - - if saveat === nothing - savingCB = SavingCallback((u,t,integrator) -> saveValues(c, recordValues, u, t, integrator, _inputFunction, inputValueReferences), - fmusol.values) - else - savingCB = SavingCallback((u,t,integrator) -> saveValues(c, recordValues, u, t, integrator, _inputFunction, inputValueReferences), - fmusol.values, - saveat=saveat) - end - - push!(cbs, savingCB) - end - - # if auto_dt == true - # @assert solver !== nothing "fmi2SimulateME(...): `auto_dt=true` but no solver specified, this is not allowed." - # tmpIntegrator = init(c.problem, solver) - # dt = auto_dt_reset!(tmpIntegrator) - # end - - solveKwargs = Dict{Symbol, Any}() - - if dt !== nothing - solveKwargs[:dt] = dt - end - - if tolerance !== nothing - solveKwargs[:reltol] = tolerance - end - - if saveat !== nothing - solveKwargs[:saveat] = saveat - end - - if solver === nothing - fmusol.states = solve(c.problem; callback = CallbackSet(cbs...), dtmax=dtmax, solveKwargs..., kwargs...) - else - fmusol.states = solve(c.problem, solver; callback = CallbackSet(cbs...), dtmax=dtmax, solveKwargs..., kwargs...) - end - - fmusol.success = (fmusol.states.retcode == ReturnCode.Success) - - # cleanup progress meter - if showProgress - ProgressMeter.finish!(progressMeter) - end - - finishFMU(fmu, c, terminate, freeInstance) - - return fmusol -end - -export fmi3SimulateME - -############ Co-Simulation ############ - -""" - fmi3SimulateCS(c::FMU3Instance, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...) - -Wrapper for `fmi3SimulateCS(fmu::FMU3, c::Union{FMU3Instance, Nothing}=nothing, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...)` without a provided FMU3. -(FMU3 `fmu` is taken from `c`) -""" -function fmi3SimulateCS(c::FMU3Instance, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...) - fmi3SimulateCS(c.fmu, c, t_start, t_stop; kwargs...) -end - -""" - fmi3SimulateCS(fmu::FMU3, - c::Union{FMU3Instance, Nothing}=nothing, - t_start::Union{Real, Nothing} = nothing, - t_stop::Union{Real, Nothing} = nothing; - [tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - recordValues::fmi3ValueReferenceFormat = nothing, - saveat = [], - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi3ValueReferenceFormat = nothing, - inputFunction = nothing, - showProgress::Bool=true, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing]) - -Simulate CS-FMU for the given simulation time interval. - -# Arguments -- `fmu::FMU3`: Mutable struct representing a FMU and all it instantiated instances. -- `c::Union{FMU3Instance, Nothing}=nothing`: Mutable struct representing an instantiated instance of a FMU. -- `t_start::Union{Real, Nothing} = nothing`: Simulation-time-span start time (default = nothing: use default value from `fmu`'s model description or 0.0) -- `t_stop::Union{Real, Nothing} = nothing`: Simulation-time-span stop time (default = nothing: use default value from `fmu`'s model description or 1.0) - -- `tolerance::Union{Real, Nothing} = nothing`: tolerance for the solver (default = nothing: use default value from `fmu`'s model description or 0.0) -- `dt::Union{Real, Nothing} = nothing`: stepszie for the solver (default = nothing: use default value from `fmu`'s model description or 1e-3) -- `solver = nothing`: Any Julia-supported ODE-solver (default = nothing: use DifferentialEquations.jl default solver) -- `recordValues::fmi3ValueReferenceFormat` = nothing: Array of variables (Strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` -- `saveat = nothing`: Time points to save values at (default = nothing: save at each communication timestep) -- `setup::Union{Bool, Nothing} = nothing`: call fmi3EnterInitializationMode and fmi3ExitInitializationMode before each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `reset::Union{Bool, Nothing} = nothing`: call fmi3Reset before each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `instantiate::Union{Bool, Nothing} = nothing`: call fmi3Instantiate! before each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `freeInstance::Union{Bool, Nothing} = nothing`: call fmi3FreeInstance after each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `terminate::Union{Bool, Nothing} = nothing`: call fmi3Terminate after each step (default = nothing: use value from `fmu`'s `FMU3ExecutionConfiguration`) -- `inputValueReferences::fmi3ValueReferenceFormat = nothing`: Input variables (Strings or variableIdentifiers) to set at each communication step -- `inputFunction = nothing`: Function to get values for the input variables at each communication step. - - ## Pattern [`c`: current instance, `t`: current time, returning array of values to be passed to `fmi3SetFloat64(..., inputValueReferences, inputFunction(...))`]: - - `inputFunction(t::fmi3Float64)` - - `inputFunction(c::FMU3Instance, t::fmi3Float64)` - -- `showProgress::Bool = true`: print simulation progressmeter in REPL -- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dict of parameter variables (strings or variableIdentifiers) and values (Boolean, String, Float64, ...) to set parameters during initialization - -# Returns: -- `fmusol::FMU3Solution`, containing bool `fmusol.success` and if keyword `recordValues` is set, the saved values as `fmusol.values`. - -See also [`fmi3Simulate`](@ref), [`fmi3SimulateME`](@ref), [`fmi3SimulateSE`](@ref). -""" -function fmi3SimulateCS(fmu::FMU3, c::Union{FMU3Instance, Nothing}=nothing, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; - tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - recordValues::fmi3ValueReferenceFormat = nothing, - saveat = [], - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi3ValueReferenceFormat = nothing, - inputFunction = nothing, - showProgress::Bool=true, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing) - - @assert fmi3IsCoSimulation(fmu) "fmi3SimulateCS(...): This function supports Co-Simulation FMUs only." - - # input function handling - _inputFunction = nothing - if inputFunction != nothing - if hasmethod(inputFunction, Tuple{fmi3Float64}) - _inputFunction = (c, t) -> inputFunction(t) - else - _inputFunction = inputFunctiont - end - @assert hasmethod(_inputFunction, Tuple{FMU3Instance, fmi3Float64}) "The given input function does not fit the needed input function pattern for CS-FMUs, which are: \n- `inputFunction(t::fmi3Float64)`\n- `inputFunction(comp::FMU3Instance, t::fmi3Float64)`" - end - - fmusol = FMU3Solution(fmu) - - - recordValues = prepareValueReference(fmu, recordValues) - inputValueReferences = prepareValueReference(fmu, inputValueReferences) - hasInputs = (length(inputValueReferences) > 0) - - variableSteps = fmi3IsCoSimulation(fmu) && fmu.modelDescription.coSimulation.canHandleVariableCommunicationStepSize - - t_start = t_start === nothing ? fmi3GetDefaultStartTime(fmu.modelDescription) : t_start - t_start = t_start === nothing ? 0.0 : t_start - t_stop = t_stop === nothing ? fmi3GetDefaultStopTime(fmu.modelDescription) : t_stop - t_stop = t_stop === nothing ? 1.0 : t_stop - tolerance = tolerance === nothing ? fmi3GetDefaultTolerance(fmu.modelDescription) : tolerance - tolerance = tolerance === nothing ? 0.0 : tolerance - dt = dt === nothing ? fmi3GetDefaultStepSize(fmu.modelDescription) : dt - dt = dt === nothing ? 1e-3 : dt - - c, _ = prepareFMU(fmu, c, fmi3TypeCoSimulation, instantiate, terminate, reset, setup, parameters, t_start, t_stop, tolerance; inputFunction=_inputFunction, inputValueReferences=inputValueReferences) - - # default setup - if length(saveat) == 0 - saveat = t_start:dt:t_stop - end - - # setup if no variable steps - if variableSteps == false - if length(saveat) >= 2 - dt = saveat[2] - saveat[1] - end - end - - t = t_start - - record = length(recordValues) > 0 - - progressMeter = nothing - if showProgress - progressMeter = ProgressMeter.Progress(1000; desc="Simulating CS-FMU ...", color=:blue, dt=1.0) #, barglyphs=ProgressMeter.BarGlyphs("[=> ]")) - ProgressMeter.update!(progressMeter, 0) # show it! - end - - #numDigits = length(string(round(Integer, 1/dt))) - noSetFMUStatePriorToCurrentPoint = fmi3False - eventEncountered = fmi3False - terminateSimulation = fmi3False - earlyReturn = fmi3False - lastSuccessfulTime = fmi3Float64(0.0) - - if record - fmusol.values = SavedValues(Float64, Tuple{collect(Float64 for i in 1:length(recordValues))...} ) - fmusol.valueReferences = copy(recordValues) - - i = 1 - - svalues = (fmi3GetFloat64(c, recordValues)...,) - DiffEqCallbacks.copyat_or_push!(fmusol.values.t, i, t) - DiffEqCallbacks.copyat_or_push!(fmusol.values.saveval, i, svalues, Val{false}) - - while t < t_stop - if variableSteps - if length(saveat) > i - dt = saveat[i+1] - saveat[i] - else - dt = t_stop - saveat[i] - end - end - - if _inputFunction !== nothing - fmi3SetFloat64(fmu, inputValueReferences, _inputFunction(c, t)) - end - - fmi3DoStep!(fmu, t, dt, true, eventEncountered, terminateSimulation, earlyReturn, lastSuccessfulTime) - if eventEncountered == fmi3True - @warn "Event handling" - end - if terminateSimulation == fmi3True - @error "fmi3DoStep returned error!" - end - if earlyReturn == fmi3True - @warn "early Return" - end - t = t + dt #round(t + dt, digits=numDigits) - i += 1 - - svalues = (fmi3GetFloat64(c, recordValues)...,) - DiffEqCallbacks.copyat_or_push!(fmusol.values.t, i, t) - DiffEqCallbacks.copyat_or_push!(fmusol.values.saveval, i, svalues, Val{false}) - - if progressMeter !== nothing - ProgressMeter.update!(progressMeter, floor(Integer, 1000.0*(t-t_start)/(t_stop-t_start)) ) - end - end - - if progressMeter !== nothing - ProgressMeter.finish!(progressMeter) - end - - fmusol.success = true - - else - i = 1 - while t < t_stop - if variableSteps - if length(saveat) > i - dt = saveat[i+1] - saveat[i] - else - dt = t_stop - saveat[i] - end - end - - if _inputFunction !== nothing - fmi3SetFloat64(fmu, inputValues, _inputFunction(c, t)) - end - - fmi3DoStep!(fmu, t, dt, true, eventEncountered, terminateSimulation, earlyReturn, lastSuccessfulTime) - if eventEncountered == fmi3True - @warn "Event handling" - end - if terminateSimulation == fmi3True - @error "fmi3DoStep returned error!" - end - if earlyReturn == fmi3True - @warn "early Return" - end - t = t + dt #round(t + dt, digits=numDigits) - i += 1 - - if progressMeter !== nothing - ProgressMeter.update!(progressMeter, floor(Integer, 1000.0*(t-t_start)/(t_stop-t_start)) ) - end - end - - if progressMeter !== nothing - ProgressMeter.finish!(progressMeter) - end - - fmusol.success = true - end - - finishFMU(fmu, c, terminate, freeInstance) - - return fmusol -end - -export fmi3SimulateCS - -# TODO simulate ScheduledExecution -""" - fmi3SimulateSE(fmu::FMU3, - c::Union{FMU3Instance, Nothing}=nothing, - t_start::Union{Real, Nothing} = nothing, - t_stop::Union{Real, Nothing} = nothing; - [tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - recordValues::fmi3ValueReferenceFormat = nothing, - saveat = [], - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi3ValueReferenceFormat = nothing, - inputFunction = nothing, - showProgress::Bool=true, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing]) - -Simulate SE-FMU; not yet implemented in library - -See also [`fmi3Simulate`](@ref), [`fmi3SimulateME`](@ref), [`fmi3SimulateCS`](@ref). -""" -function fmi3SimulateSE(fmu::FMU3, c::Union{FMU3Instance, Nothing}=nothing, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; - tolerance::Union{Real, Nothing} = nothing, - dt::Union{Real, Nothing} = nothing, - recordValues::fmi3ValueReferenceFormat = nothing, - saveat = [], - setup::Union{Bool, Nothing} = nothing, - reset::Union{Bool, Nothing} = nothing, - instantiate::Union{Bool, Nothing} = nothing, - freeInstance::Union{Bool, Nothing} = nothing, - terminate::Union{Bool, Nothing} = nothing, - inputValueReferences::fmi3ValueReferenceFormat = nothing, - inputFunction = nothing, - showProgress::Bool=true, - parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing) @assert false "Not implemented" -end - -export fmi3SimulateSE - -##### CS & ME ##### - -""" - fmi3Simulate(c::FMU3Instance, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...) - -Wrapper for `fmi3Simulate(fmu::FMU3, c::Union{FMU3Instance, Nothing}=nothing, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...)` without a provided FMU3. -(FMU3 `fmu` is taken from `c`) -""" -function fmi3Simulate(c::FMU3Instance, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...) - fmi3Simulate(c.fmu, c, t_start, t_stop; kwargs...) -end - -""" - fmi3Simulate(args...) - -Starts a simulation of the `FMU3` for the matching type (`fmi3SimulateCS(args...)`, `fmi3SimulateME(args...)` or `fmi3SimulateSE(args...)`); if multiple types are available, CS is preferred over ME, over SE. - -See also [`fmi3SimulateCS`](@ref), [`fmi3SimulateME`](@ref), [`fmi3SimulateSE`](@ref). -""" -function fmi3Simulate(fmu::FMU3, c::Union{FMU3Instance, Nothing}=nothing, t_start::Union{Real, Nothing} = nothing, t_stop::Union{Real, Nothing} = nothing; kwargs...) - - if fmu.type == fmi3TypeCoSimulation - return fmi3SimulateCS(fmu, c, t_start, t_stop; kwargs...) - elseif fmu.type == fmi3TypeModelExchange - return fmi3SimulateME(fmu, c, t_start, t_stop; kwargs...) - elseif fmu.type == fmi3TypeScheduledExecution - return fmi3SimulateSE(fmu, c, t_start, t_stop; kwargs...) - else - error(unknownFMUType) - end -end - -export fmi3Simulate diff --git a/src/assertions.jl b/src/assertions.jl deleted file mode 100644 index f28cf1a7..00000000 --- a/src/assertions.jl +++ /dev/null @@ -1,31 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -@enum errorType begin - unsupportedFMU - unknownFMUType - unknown -end - -# Format the fmi2Status into a String -function errorTypeString(type::errorType) - fname = StackTraces.stacktrace()[3].func # index 3 to step into calling function! - - if type == unsupportedFMU - return "$fname() doesn't support FMUs with this version." - elseif type == unknownFMUType - return "Unknown FMU type in $fname(), is neigther CS nor ME." - end - - "Unknown Assertion in $fname()." -end - -function assert(cond::Bool, type::errorType = unknown) - @assert cond [errorTypeString(type)] -end - -function error(type::errorType = unknown) - @assert false [errorTypeString(type)] -end diff --git a/src/check.jl b/src/check.jl deleted file mode 100644 index 22a303cd..00000000 --- a/src/check.jl +++ /dev/null @@ -1,85 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMIImport.EzXML -using FMIImport.ZipFile - -function fmiCheckVersion(pathToFMU::String; unpackPath=nothing) - # Unzip MD - - # Download FMU if necessary - if startswith(pathToFMU, "http") - @info "Downloading FMU for Version extraction from `$(pathToFMU)`." - pathToFMU = download(pathToFMU) - end - - pathToFMU = normpath(pathToFMU) - - fileNameExt = basename(pathToFMU) - (fileName, fileExt) = splitext(fileNameExt) - - if unpackPath === nothing - # cleanup=true leads to issues with automatic testing on linux server. - unpackPath = mktempdir(; prefix="fmijl_", cleanup=false) - end - - zipPath = joinpath(unpackPath, fileName * ".zip") - unzippedPath = joinpath(unpackPath, fileName) - - # only copy ZIP if not already there - if !isfile(zipPath) - cp(pathToFMU, zipPath; force=true) - end - - @assert isfile(zipPath) ["fmiCheckVersion(...): ZIP-Archive couldn't be copied to `$zipPath`."] - - zipAbsPath = isabspath(zipPath) ? zipPath : joinpath(pwd(), zipPath) - unzippedAbsPath = isabspath(unzippedPath) ? unzippedPath : joinpath(pwd(), unzippedPath) - - @assert isfile(zipAbsPath) ["fmiCheckVersion(...): Can't deploy ZIP-Archive at `$(zipAbsPath)`."] - - # only unzip if not already done - if !isdir(unzippedAbsPath) - mkpath(unzippedAbsPath) - - zarchive = ZipFile.Reader(zipAbsPath) - for f in zarchive.files - if f.name == "modelDescription.xml" - fileAbsPath = normpath(joinpath(unzippedAbsPath, f.name)) - - # create directory if not forced by zip file folder - mkpath(dirname(fileAbsPath)) - - numBytes = write(fileAbsPath, read(f)) - - @assert numBytes > 0 "fmiCheckVersion(...): Can't unzip file `$(f.name)` at `$(fileAbsPath)`, file is empty." - @assert isfile(fileAbsPath) "fmiCheckVersion(...): Can't unzip file `$(f.name)` at `$(fileAbsPath)`, file does not exist in target directory." - end - - end - close(zarchive) - end - - @assert isdir(unzippedAbsPath) ["fmiCheckVersion(...): ZIP-Archive couldn't be unzipped at `$(unzippedPath)`."] - # @info "fmiUnzipVersion(...): Successfully unzipped modelDescription.xml at `$unzippedAbsPath`." - - # read version tag - - doc = readxml(normpath(joinpath(unzippedAbsPath, "modelDescription.xml"))) - - root = doc.root - version = root["fmiVersion"] - - # cleanup unzipped modelDescription - try - rm(unzippedAbsPath; recursive = true, force = true) - rm(zipAbsPath; recursive = true, force = true) - catch e - @warn "Cannot delete unpacked data on disc. Maybe some files are opened in another application." - end - - # return version - return version -end \ No newline at end of file diff --git a/src/deprecated.jl b/src/deprecated.jl index dd88d2e4..3c4bef58 100644 --- a/src/deprecated.jl +++ b/src/deprecated.jl @@ -3,1511 +3,105 @@ # Licensed under the MIT license. See LICENSE file in the project root for details. # -""" -DEPRECATED -fmiInstantiate!(fmu::FMU2; pushComponents::Bool = true, visible::Bool = false, loggingOn::Bool = false, externalCallbacks::Bool = false, - logStatusOK::Bool=true, logStatusWarning::Bool=true, logStatusDiscard::Bool=true, logStatusError::Bool=true, logStatusFatal::Bool=true, logStatusPending::Bool=true) - -Creates a new instance of the FMU, version independent. - -Create a new instance of the given fmu, adds a logger if logginOn == true. - -# Arguments -- `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - -# Keywords -- `pushComponents::Bool = true`: `pushComponents` if the item `component` should be inserted in `fmu.components`(default = `true`). -- `visible::Bool = false`: `visible` if the FMU should be started with graphic interface, if supported (default=`false`) -- `loggingOn::Bool = false`: `loggingOn` if the FMU should log and display function calls (default=`false`) -- `externalCallbacks::Bool = false`: `externalCallbacks` if an external DLL should be used for the fmi2CallbackFunctions, this may improve readability of logging messages (default=`false`) -- `logStatusOK::Bool=true`: `logStatusOK` whether to log status of kind `fmi2OK` (default=`true`) -- `logStatusWarning::Bool=true`: `logStatusWarning` whether to log status of kind `fmi2Warning` (default=`true`) -- `logStatusDiscard::Bool=true`: `logStatusDiscard` whether to log status of kind `fmi2Discard` (default=`true`) -- `logStatusError::Bool=true`: `logStatusError` whether to log status of kind `fmi2Error` (default=`true`) -- `logStatusFatal::Bool=true`: `logStatusFatal` whether to log status of kind `fmi2Fatal` (default=`true`) -- `logStatusPending::Bool=true`: `logStatusPending` whether to log status of kind `fmi2Pending` (default=`true`) - -# Returns -- `nothing`: if the instantiation failed. In addition, an error message appears. -- `component`: Returns the instance of a new FMU component. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.19]: 2.1.5 Creation, Destruction and Logging of FMU Instances - - -""" -function fmiInstantiate!(fmu::FMU2, args...; kwargs...) - fmi2Instantiate!(fmu, args...; kwargs...) -end -export fmiInstantiate! - -""" -DEPRECATED - fmiFreeInstance!(str::fmi2Struct) - -Frees the allocated memory of the last instance of the FMU. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiFreeInstance!(str::fmi2Struct) - fmi2FreeInstance!(str) -end -export fmiFreeInstance! - -""" -DEPRECATED fmiSetDebugLogging(str::fmi2Struct) - -Control the use of the logging callback function, version independent. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.22]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.22]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.22]: 2.1.5 Creation, Destruction and Logging of FMU Instances - -""" -function fmiSetDebugLogging(str::fmi2Struct) - fmi2SetDebugLogging(str) -end -export fmiSetDebugLogging - -""" -DEPRECATED - fmiSetupExperiment(str::fmi2Struct, c::FMU2Component, startTime::Union{Real, Nothing} = nothing, stopTime::Union{Real, Nothing} = nothing; tolerance::Union{Real, Nothing} = nothing) - -Initialize the Simulation boundries - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `startTime::Union{Real, Nothing} = nothing`: `startTime` is a real number which sets the value of starting time of the experiment. The default value is set automatically if doing nothing (default = `nothing`). -- `stopTime::Union{Real, Nothing} = nothing`: `stopTime` is a real number which sets the value of ending time of the experiment. The default value is set automatically if doing nothing (default = `nothing`). - -# Keywords -- `tolerance::Union{Real, Nothing} = nothing`: `tolerance` is a real number which sets the value of tolerance range. The default value is set automatically if doing nothing (default = `nothing`). - -# Returns -- Returns a warning if `str.state` is not called in `fmi2ComponentStateInstantiated`. -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiSetupExperiment(str::fmi2Struct, args...; kwargs...) - fmi2SetupExperiment(str, args...; kwargs...) -end -export fmiSetupExperiment - -""" -DEPRECATED - fmiEnterInitializationMode(str::fmi2Struct) - -Informs the FMU to enter initializaton mode, version independent. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- Returns a warning if `str.state` is not called in `fmi2ComponentStateInstantiated`. -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiEnterInitializationMode(str::fmi2Struct) - fmi2EnterInitializationMode(str) -end -export fmiEnterInitializationMode - -""" -DEPRECATED - fmiExitInitializationMode(str::fmi2Struct) - -Informs the FMU to exit initialization mode, version independent. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- Returns a warning if `str.state` is not called in `fmi2ComponentStateInitializationMode`. -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiExitInitializationMode(str::fmi2Struct) - fmi2ExitInitializationMode(str) -end -export fmiExitInitializationMode - -""" -DEPRECATED - fmiTerminate(str::fmi2Struct) - -Informs the FMU that the simulation run is terminated, version independent. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- Returns a warning if `str.state` is not called in `fmi2ComponentStateContinuousTimeMode` or `fmi2ComponentStateEventMode`. -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - - - -""" -function fmiTerminate(str::fmi2Struct) - fmi2Terminate(str) -end -export fmiTerminate - -""" -DEPRECATED - fmiReset(str::fmi2Struct) - -Resets the FMU after a simulation run, version independent. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- Returns a warning if `str.state` is not called in `fmi2ComponentStateTerminated` or `fmi2ComponentStateError`. -- Returns an error if the reinstantiation failed. -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.23]: 2.1.6 Initialization, Termination, and Resetting an FMU -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - - -""" -function fmiReset(str::fmi2Struct) - fmi2Reset(str) -end -export fmiReset - -""" -DEPRECATED - fmi2GetRealOutputDerivatives(c::FMU2Component, vr::fmi2ValueReferenceFormat, order::AbstractArray{fmi2Integer}) - - -Sets the n-th time derivative of real input variables. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::Array{fmi2ValueReference}`: Argument `vr` is an array of `nvr` value handels called "ValueReference" that define the variables whose derivatives shall be set. -- `order::Array{fmi2Integer}`: Argument `order` is an array of fmi2Integer values witch specifys the corresponding order of derivative of the real input variable. -- - -# Returns -- `value::AbstactArray{fmi2Integer}`: Return `value` is an array which represents a vector with the values of the derivatives. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.104]: 4.2.1 Transfer of Input / Output Values and Parameters - - -""" -DEPRECATED -function fmiGetRealOutputDerivatives(str::fmi2Struct, args...; kwargs...) - fmi2GetRealOutputDerivatives(str, args...; kwargs...) -end -export fmiGetRealOutputDerivatives - -""" -DEPRECATED - fmiGetReal!(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Array{fmi2Real}) - - fmiGetReal!(str::fmi2Struct, c::FMU2Component, vr::Array{fmi2ValueReference}, nvr::Csize_t, value::Array{fmi2Real}) - -Writes the real values of an array of variables in the given field - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Wildcards for how a user can pass a fmi[X]ValueReference -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Argument `vr` is an array of `nvr` value handels called "ValueReference" that define the variable that shall be inquired. -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Array{fm2Real}`: Argument `values` is an array with the actual values of these variables. -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiGetReal!(str::fmi2Struct, args...; kwargs...) - fmi2GetReal!(str, args...; kwargs...) -end -export fmiGetReal! - -""" -DEPRECATED - fmiSetReal(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Union{Array{<:Real}, <:Real}) - - fmiSetReal(str::fmi2Struct, c::FMU2Component, vr::Array{fmi2ValueReference}, nvr::Csize_t, value::Array{fmi2Real}) - -Set the values of an array of real variables - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Wildcards for how a user can pass a fmi[X]ValueReference -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Argument `vr` is an array of `nvr` value handels called "ValueReference" that define the variable that shall be inquired. -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Union{Array{<:Real}, <:Real}`: Argument `values` is an array with the actual values of these variables. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiSetReal(str::fmi2Struct, args...; kwargs...) - fmi2SetReal(str, args...; kwargs...) -end -export fmiSetReal - -""" -DEPRECATED#Todo: Add types according spec - - fmiSetRealInputDerivatives(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, order, values) - - fmiSetRealInputDerivatives(str::fmi2Struct, c::FMU2Component, vr::Array{fmi2ValueReference}, nvr::Csize_t, order::Array{fmi2Integer}, value::Array{fmi2Real}) - -Sets the n-th time derivative of real input variables. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Argument `vr` is an array of `nvr` value handels called "ValueReference" that define the variable that shall be inquired. -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `order::Array{fmi2Integer}`: Argument `order` is an array of fmi2Integer values witch specifys the corresponding order of derivative of the real input variable. -- `values::Array{fmi2Real}`: Argument `values` is an array with the actual values of these variables. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.104]: 4.2.1 Transfer of Input / Output Values and Parameters - - -""" -function fmiSetRealInputDerivatives(str::fmi2Struct, args...; kwargs...) - fmi2SetRealInputDerivatives(str, args...; kwargs...) -end -export fmiSetRealInputDerivatives - -""" -DEPRECATED - fmiGetInteger(str::fmi2Struct,c::FMU2Component, vr::fmi2ValueReferenceFormat) - -Returns the integer values of an array of variables - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` - -# Returns -- `values::Array{fmi2Integer}`: Return `values` is an array with the actual values of these variables. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - - -""" -function fmiGetInteger(str::fmi2Struct,args...; kwargs...) - fmi2GetInteger(str, args...; kwargs...) -end -export fmiGetInteger - -""" -DEPRECATED - function fmiGetInteger!(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Array{fmi2Integer}) - - function fmiGetInteger!(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Array{fmi2Integer}) - -Writes the integer values of an array of variables in the given field - -fmi2GetInteger! is only possible for arrays of values, please use an array instead of a scalar. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Argument `vr` is an array of `nvr` value handels called "ValueReference" that define the variable that shall be inquired. -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Array{fmi2Integer}`: Argument `values` is an array with the actual values of these variables. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - - -""" -function fmiGetInteger!(str::fmi2Struct, args...; kwargs...) - fmi2GetInteger!(str, args...; kwargs...) -end -export fmiGetInteger! - -""" -DEPRECATED - fmiSetInteger(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Union{Array{<:Integer}, <:Integer}) - - fmiSetInteger(str::fmi2Struct, c::FMU2Component, vr::Array{fmi2ValueReference}, nvr::Csize_t, value::Array{fmi2Integer}) - -Set the values of an array of integer variables - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Argument `vr` is an array of `nvr` value handels called "ValueReference" that define the variable that shall be inquired. -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Union{Array{<:Integer}, <:Integer}`: Argument `values` is an array or a single value with type Integer or any subtyp -- `value::Array{fmi2Integer}`: Argument `values` is an array with the actual values of these variables. -# Returns -- `status::fmi2Status`: Return `status` indicates the success of the function call. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiSetInteger(str::fmi2Struct, args...; kwargs...) - fmi2SetInteger(str, args...; kwargs...) -end -export fmiSetInteger - -""" -DEPRECATED - fmiGetBoolean(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat) - -Returns the boolean values of an array of variables - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` - -# Returns -- `values::Array{fmi2Boolean}`: Return `values` is an array with the actual values of these variables. - -""" -function fmiGetBoolean(str::fmi2Struct, args...; kwargs...) - fmi2GetBoolean(str, args...; kwargs...) -end -export fmiGetBoolean - -""" -DEPRECATED - fmiGetBoolean!(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Array{fmi2Boolean}) - -Writes the boolean values of an array of variables in the given field - -fmi2GetBoolean! is only possible for arrays of values, please use an array instead of a scalar. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Argument `vr` is an array of `nvr` value handels called "ValueReference" that define the variable that shall be inquired. -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Union{Array{<:Integer}, <:Integer}`: Argument `values` is an array or a single value with type Integer or any subtyp -- `value::Array{fmi2Integer}`: Argument `values` is an array with the actual values of these variables. -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - -""" -function fmiGetBoolean!(str::fmi2Struct, args...; kwargs...) - fmi2GetBoolean!(str, args...; kwargs...) -end -export fmiGetBoolean! - -""" -DEPRECATED - fmiSetBoolean(str::fmi2Struct, c::FMU2Component, vr::Array{fmi2ValueReference}, nvr::Csize_t, value::Array{fmi2Boolean}) - - fmiSetBoolean(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Union{Array{Bool}, Bool}) - -Set the values of an array of boolean variables - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Array of the FMI2 Data Typ `fmi2ValueReference` -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Union{Array{Bool}, Bool}`: Argument `values` is an array or a single value with type Boolean or any subtyp -- `value::Array{fmi2Boolean}`: Argument `values` is an array with the actual values of these variables. -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - -""" -function fmiSetBoolean(str::fmi2Struct, args...; kwargs...) - fmi2SetBoolean(str, args...; kwargs...) -end -export fmiSetBoolean - -""" -DEPRECATED - fmiGetString(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat) - -Returns the string values of an array of variables - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` - -# Returns -- `values::Array{fmi2String}`: Return `values` is an array with the actual values of these variables. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - - -""" -function fmiGetString(str::fmi2Struct, args...; kwargs...) - fmi2GetString(str, args...; kwargs...) -end -export fmiGetString - -""" -DEPRECATED - fmiGetString!(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Array{fmi2String}) - - fmiGetString!(str::fmi2Struct, c::FMU2Component, vr::Array{fmi2ValueReference}, nvr::Csize_t, value::Vector{Ptr{Cchar}}) - -Writes the string values of an array of variables in the given field - -These functions are especially used to get the actual values of output variables if a model is connected with other -models. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Array of the FMI2 Data Typ `fmi2ValueReference` -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Union{Array{Bool}, Bool}`: Argument `values` is an array or a single value with type Boolean or any subtyp. -- `value::Vector{Ptr{Cchar}}`: Argument `values` is an vector with the actual values of these variables. -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions - -""" -function fmiGetString!(str::fmi2Struct, args...; kwargs...) - fmi2GetString!(str, args...; kwargs...) -end -export fmiGetString! - -""" -DEPRECATED - fmiSetString(str::fmi2Struct, c::FMU2Component, vr::fmi2ValueReferenceFormat, values::Union{Array{String}, String}) - - fmiSetString(str::fmi2Struct, c::FMU2Component, vr::Array{fmi2ValueReference}, nvr::Csize_t, value::Union{Array{Ptr{Cchar}}, Array{Ptr{UInt8}}}) - -Set the values of an array of string variables - -For the exact rules on which type of variables fmi2SetXXX -can be called see FMISpec2.0.2 section 2.2.7 , as well as FMISpec2.0.2 section 3.2.3 in case of ModelExchange and FMISpec2.0.2 section 4.2.4 in case of -CoSimulation. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vr::fmi2ValueReferenceFormat`: Argument `vr` defines the value references of the variables. -More detailed: `fmi2ValueReferenceFormat = Union{Nothing, String, Array{String,1}, fmi2ValueReference, Array{fmi2ValueReference,1}, Int64, Array{Int64,1}, Symbol}` -- `vr::Array{fmi2ValueReference}`: Array of the FMI2 Data Typ `fmi2ValueReference` -- `nvr::Csize_t`: Argument `nvr` defines the size of `vr`. -- `values::Union{Array{String}, String}`: Argument `values` is an array or a single value with type String. -- `value::Vector{Ptr{Cchar}}`: Argument `values` is an vector with the actual values of these variables. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions -- FMISpec2.0.2[p.18]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.24]: 2.1.7 Getting and Setting Variable Values -- FMISpec2.0.2[p.46]: 2.2.7 Definition of Model Variables -- FMISpec2.0.2[p.46]: 3.2.3 State Machine of Calling Sequence -- FMISpec2.0.2[p.108]: 4.2.4 State Machine of Calling Sequence from Master to Slave - -""" -function fmiSetString(str::fmi2Struct, args...; kwargs...) - fmi2SetString(str, args...; kwargs...) +function warnDeprecated(oldStr, newStr, additional = "") + @warn "`$(oldStr)` is deprecated, use `$(newStr)` instead. $(additional)\n(this message is printed 3 times)." maxlog = + 3 end -export fmiSetString - -""" -DEPRECATED - fmiSerializedFMUstateSize(str::fmi2Struct, c::FMU2Component, state::fmi2FMUstate) - - -Returns the size of the byte vector in which the FMUstate can be stored. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `state::fmi2FMUstate`: Argument `state` is a pointer to a data structure in the FMU that saves the internal FMU state of the actual or a previous time instant. - -# Returns -- Return `size` is an object that safely references a value of type `Csize_t`. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.25]: 2.1.8 Getting and Setting the Complete FMU State - - -""" -function fmiSerializedFMUstateSize(str::fmi2Struct, args...; kwargs...) - fmi2SerializedFMUstateSize(str, args...; kwargs...) +function fmi2Simulate(args...; kwargs...) + warnDeprecated("fmi2Simulate", "simulate", "FMI version is determined automatically.") + simulate(args...; kwargs...) end -export fmiSerializedFMUstateSize - -""" -DEPRECATED - fmiSerializeFMUstate(str::fmi2Struct, c::FMU2Component, state::fmi2FMUstate) - -Serializes the data referenced by the pointer FMUstate and copies this data into the byte vector serializedState of length size to be provided by the environment. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `state::fmi2FMUstate`: Argument `state` is a pointer to a data structure in the FMU that saves the internal FMU state of the actual or a previous time instant. +export fmi2Simulate -# Returns -- `serialized:: Array{fmi2Byte}`: Return `serializedState` contains the copy of the serialized data referenced by the pointer FMUstate - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.25]: 2.1.8 Getting and Setting the Complete FMU State - - -""" -function fmiSerializeFMUstate(str::fmi2Struct, args...; kwargs...) - fmi2SerializeFMUstate(str, args...; kwargs...) +function fmiSimulate(args...; kwargs...) + warnDeprecated("fmiSimulate", "simulate") + simulate(args...; kwargs...) end -export fmiSerializeFMUstate - -""" -DEPRECATEDTODO - fmiDeSerializeFMUstate(str::fmi2Struct, c::FMU2Component, serializedState::Array{fmi2Byte}) - -Deserialize the data in the serializedState fmi2Byte field +export fmiSimulate -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `serializedState::Array{fmi2Byte}`: Argument `serializedState` contains the fmi2Byte field to be deserialized. - -# Returns -- Return `state` is a pointer to a copy of the internal FMU state. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.25]: 2.1.8 Getting and Setting the Complete FMU State - - -""" -function fmiDeSerializeFMUstate(str::fmi2Struct, args...; kwargs...) - fmi2DeSerializeFMUstate(str, args...; kwargs...) +function fmi2SimulateME(args...; kwargs...) + warnDeprecated( + "fmi2SimulateME", + "simulateME", + "FMI version is determined automatically.", + ) + simulateME(args...; kwargs...) end -export fmiDeSerializeFMUstate - -""" -DEPRECATED - fmiGetDirectionalDerivative(str::fmi2Struct, c::FMU2Component, - vUnknown_ref::AbstractArray{fmi2ValueReference}, - vKnown_ref::AbstractArray{fmi2ValueReference}, - dvKnown::Union{AbstractArray{fmi2Real}, Nothing} = nothing) - - fmi2GetDirectionalDerivative(str::fmi2Struct, c::FMU2Component, - vUnknown_ref::fmi2ValueReference, - vKnown_ref::fmi2ValueReference, - dvKnown::fmi2Real = 1.0) - -The Wrapper Function and the Direct function call to compute the partial derivative with respect to `vKnown_ref`. - -Computes the directional derivatives of an FMU. An FMU has different Modes and in every Mode an FMU might be described by different equations and different unknowns.The precise definitions are given in the mathematical descriptions of Model Exchange (section 3.1) and Co-Simulation (section 4.1). In every Mode, the general form of the FMU equations are: -𝐯_unknown = 𝐑(𝐯_known, 𝐯_rest) - -- `v_unknown`: vector of unknown Real variables computed in the actual Mode: - - Initialization Mode: unkowns kisted under `` that have type Real. - - Continuous-Time Mode (ModelExchange): The continuous-time outputs and state derivatives. (= the variables listed under `` with type Real and variability = `continuous` and the variables listed as state derivatives under `)`. - - Event Mode (ModelExchange): The same variables as in the Continuous-Time Mode and additionally variables under `` with type Real and variability = `discrete`. - - Step Mode (CoSimulation): The variables listed under `` with type Real and variability = `continuous` or `discrete`. If `` is present, also the variables listed here as state derivatives. -- `v_known`: Real input variables of function h that changes its value in the actual Mode. -- `v_rest`:Set of input variables of function h that either changes its value in the actual Mode but are non-Real variables, or do not change their values in this Mode, but change their values in other Modes - -Computes a linear combination of the partial derivatives of h with respect to the selected input variables 𝐯_known: - - Ξ”v_unknown = (Ξ΄h / Ξ΄v_known) Ξ”v_known +export fmi2SimulateME -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vUnknown_ref::AbstractArray{fmi2ValueReference}`: Argument `vUnknown_ref` contains values of type`fmi2ValueReference` which are identifiers of a variable value of the model. `vUnknown_ref` can be equated with `v_unknown`(variable described above). - - `vUnknown_ref::fmi2ValueReference`: Argument `vUnknown_ref` contains a value of type`fmi2ValueReference` which is an identifier of a variable value of the model. `vUnknown_ref` can be equated with `v_unknown`(variable described above). -- `vKnown_ref::AbstractArray{fmi2ValueReference}`: Argument `vKnown_ref` contains values of type `fmi2ValueReference` which are identifiers of a variable value of the model.`vKnown_ref` can be equated with `v_known`(variable described above). -- `vKnown_ref::fmi2ValueReference`: Argument `vKnown_ref` contains a value of type`fmi2ValueReference` which is an identifier of a variable value of the model. `vKnown_ref` can be equated with `v_known`(variable described above). -- `dvKnown::Union{AbstractArray{fmi2Real}, Nothing} = nothing`: If no seed vector is passed the value `nothing` is used. The vector values Compute the partial derivative with respect to the given entries in vector `vKnown_ref` with the matching evaluate of `dvKnown`. -- `dvKnown::Fmi2Real = 1.0`: If no seed value is passed the value `dvKnown = 1.0` is used. Compute the partial derivative with respect to `vKnown_ref` with the value `dvKnown = 1.0`. # gehΓΆrt das zu den v_rest values - -# Returns -- `dvUnknown::Array{fmi2Real}`: Return `dvUnknown` contains the directional derivative vector values. - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.25]: 2.1.9 Getting Partial Derivatives - -""" -function fmiGetDirectionalDerivative(str::fmi2Struct, args...; kwargs...) - fmi2GetDirectionalDerivative(str, args...; kwargs...) +function fmiSimulateME(args...; kwargs...) + warnDeprecated("fmiSimulateME", "simulateME") + simulateME(args...; kwargs...) end -export fmiGetDirectionalDerivative - -""" -DEPRECATEDTODO -> Arguments - fmiGetDirectionalDerivative!(str::fmi2Struct, c::FMU2Component, - vUnknown_ref::AbstractArray{fmi2ValueReference}, - vKnown_ref::AbstractArray{fmi2ValueReference}, - dvUnknown::AbstractArray, - dvKnown::Union{Array{fmi2Real}, Nothing} = nothing) - - fmiGetDirectionalDerivative!(str::fmi2Struct, c::FMU2Component, - vUnknown_ref::AbstractArray{fmi2ValueReference}, - nUnknown::Csize_t, - vKnown_ref::AbstractArray{fmi2ValueReference}, - nKnown::Csize_t, - dvKnown::AbstractArray{fmi2Real}, - dvUnknown::AbstractArray) - - -Wrapper Function call to compute the partial derivative with respect to the variables `vKnown_ref`. - -Computes the directional derivatives of an FMU. An FMU has different Modes and in every Mode an FMU might be described by different equations and different unknowns.The precise definitions are given in the mathematical descriptions of Model Exchange (section 3.1) and Co-Simulation (section 4.1). In every Mode, the general form of the FMU equations are: -𝐯_unknown = 𝐑(𝐯_known, 𝐯_rest) - -- `v_unknown`: vector of unknown Real variables computed in the actual Mode: - - Initialization Mode: unkowns kisted under `` that have type Real. - - Continuous-Time Mode (ModelExchange): The continuous-time outputs and state derivatives. (= the variables listed under `` with type Real and variability = `continuous` and the variables listed as state derivatives under `)`. - - Event Mode (ModelExchange): The same variables as in the Continuous-Time Mode and additionally variables under `` with type Real and variability = `discrete`. - - Step Mode (CoSimulation): The variables listed under `` with type Real and variability = `continuous` or `discrete`. If `` is present, also the variables listed here as state derivatives. -- `v_known`: Real input variables of function h that changes its value in the actual Mode. -- `v_rest`:Set of input variables of function h that either changes its value in the actual Mode but are non-Real variables, or do not change their values in this Mode, but change their values in other Modes - -Computes a linear combination of the partial derivatives of h with respect to the selected input variables 𝐯_known: +export fmiSimulateME - Ξ”v_unknown = (Ξ΄h / Ξ΄v_known) Ξ”v_known - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `vUnknown_ref::AbstracArray{fmi2ValueReference}`: Argument `vUnknown_ref` contains values of type`fmi2ValueReference` which are identifiers of a variable value of the model. `vUnknown_ref` can be equated with `v_unknown`(variable described above). -- `vKnown_ref::AbstractArray{fmi2ValueReference}`: Argument `vKnown_ref` contains values of type `fmi2ValueReference` which are identifiers of a variable value of the model.`vKnown_ref` can be equated with `v_known`(variable described above). -- `dvUnknown::AbstractArray`: Stores the directional derivative vector values. -- `dvKnown::Union{Array{fmi2Real}, Nothing} = nothing`: If no seed vector is passed the value `nothing` is used. The vector values Compute the partial derivative with respect to the given entries in vector `vKnown_ref` with the matching evaluate of `dvKnown`. -- `dvKnown::AbstractArray{fmi2Real}`:The vector values Compute the partial derivative with respect to the given entries in vector `vKnown_ref` with the matching evaluate of `dvKnown`. -- `nUnknown::Csize_t`: -- `nKnown::Csize_t`: - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.25]: 2.1.9 Getting Partial Derivatives - -""" -function fmiGetDirectionalDerivative!(str::fmi2Struct, args...; kwargs...) - fmi2GetDirectionalDerivative!(str, args...; kwargs...) +function fmi2SimulateCS(args...; kwargs...) + warnDeprecated( + "fmi2SimulateCS", + "simulateCS", + "FMI version is determined automatically.", + ) + simulateCS(args...; kwargs...) end -export fmiGetDirectionalDerivative! - -""" -DEPRECATED - fmiDoStep(str::fmi2Struct, c::FMU2Component, communicationStepSize::Union{Real, Nothing} = nothing; currentCommunicationPoint::Union{Real, Nothing} = nothing, noSetFMUStatePriorToCurrentPoint::Bool = true) - - fmiDoStep(str::fmi2Struct, c::FMU2Component, currentCommunicationPoint::fmi2Real, communicationStepSize::fmi2Real, noSetFMUStatePriorToCurrentPoint::fmi2Boolean) - -Does one step in the CoSimulation FMU - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `communicationStepSize::Union{Real, Nothing} = nothing`: Argument `communicationStepSize` contains a value of type `Real` or `Nothing` , if no argument is passed the default value `nothing` is used. `communicationStepSize` defines the communiction step size. -- `currentCommunicationPoint::fmi2Real`: Argument `currentCommunicationPoint` contains a value of type `fmi2Real` which is a identifier for a variable value . `currentCommunicationPoint` defines the current communication point of the master. -- `communicationStepSize::fmi2Real`: Argument `communicationStepSize` contains a value of type `fmi2Real` which is a identifier for a variable value. `communicationStepSize` defines the communiction step size. -- `noSetFMUStatePriorToCurrentPoint::fmi2Boolean`: Argument `noSetFMUStatePriorToCurrentPoint` contains a value of type `fmi2Boolean` which is a identifier for a variable value. `noSetFMUStatePriorToCurrentPoint` indicates whether `fmi2SetFMUState`will no longer be called for time instants prior to `currentCommunicationPoint` in this simulation run. - -# Keywords -- `currentCommunicationPoint::Union{Real, Nothing} = nothing`: Argument `currentCommunicationPoint` contains a value of type `Real` or type `Nothing`. If no argument is passed the default value `nothing` is used. `currentCommunicationPoint` defines the current communication point of the master. -- `noSetFMUStatePriorToCurrentPoint::Bool = true`: Argument `noSetFMUStatePriorToCurrentPoint` contains a value of type `Boolean`. If no argument is passed the default value `true` is used. `noSetFMUStatePriorToCurrentPoint` indicates whether `fmi2SetFMUState` is no longer called for times before the `currentCommunicationPoint` in this simulation run Simulation run. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.104]: 4.2.2 Computation +export fmi2SimulateCS - -""" -function fmiDoStep(str::fmi2Struct, args...; kwargs...) - fmi2DoStep(str, args...; kwargs...) +function fmiSimulateCS(args...; kwargs...) + warnDeprecated("fmiSimulateCS", "simulateCS") + simulateCS(args...; kwargs...) end -export fmiDoStep - -""" -DEPRECATED - fmiSetTime(c::fmi2Struct, c::FMU2Component, time::fmi2Real) - - fmiSetTime(c::fmi2Struct, c::FMU2Component, t::Real) - -Set a new time instant and re-initialize caching of variables that depend on time. - -# Arguments -- `c::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `c::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `c::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `time::fmi2Real`: Argument `time` contains a value of type `fmi2Real` which is a alias type for `Real` data type. `time` sets the independent variable time t. -- `t::Real`: Argument `t` contains a value of type `Real`. `t` sets the independent variable time t. +export fmiSimulateCS -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.1 Providing Independent Variables and Re-initialization of Caching - -""" -function fmiSetTime(c::fmi2Struct, args...; kwargs...) - fmi2SetTime(c, args...; kwargs...) +function fmiLoad(args...; kwargs...) + warnDeprecated("fmiLoad", "loadFMU") + loadFMU(args...; kwargs...) end -export fmiSetTime - -""" -DEPRECATED - fmiSetContinuousStates(str::fmi2Struct, c::FMU2Component, - x::AbstractArray{fmi2Real}, - nx::Csize_t) - - fmiSetContinuousStates(str::fmi2Struct, c::FMU2Component, - x::Union{AbstractArray{Float32},AbstractArray{Float64}}) - -Set a new (continuous) state vector +export fmiLoad -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `x::AbstractArray{fmi2Real}`: Argument `x` contains values of type `fmi2Real` which is a alias type for `Real` data type.`x` is the `AbstractArray` of the vector values of `Real` input variables of function h that changes its value in the actual Mode. -- `x::Union{AbstractArray{Float32},AbstractArray{Float64}}`: -- `nx::Csize_t`: Argument `nx` defines the length of vector `x` and is provided for checking purposes - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.1 Providing Independent Variables and Re-initialization of Caching - -""" -function fmiSetContinuousStates(str::fmi2Struct, args...; kwargs...) - fmi2SetContinuousStates(str, args...; kwargs...) +function fmi2Load(args...; kwargs...) + warnDeprecated("fmi2Load", "loadFMU", "FMI version is determined automatically.") + loadFMU(args...; kwargs...) end -export fmiSetContinuousStates - -""" -DEPRECATED - fmi2EnterEventMode(str::fmi2Struct) - -The model enters Event Mode from the Continuous-Time Mode and discrete-time equations may become active (and relations are not β€œfrozen”). - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously +export fmi2Load -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations - -""" -function fmi2EnterEventMode(str::fmi2Struct) - fmi2EnterEventMode(str) +function fmi3Load(args...; kwargs...) + warnDeprecated("fmi3Load", "loadFMU", "FMI version is determined automatically.") + loadFMU(args...; kwargs...) end -export fmi2EnterEventMode - -""" -DEPRECATED - fmiNewDiscreteStates(str::fmi2Struct) - -Returns the next discrete states - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- `eventInfo::fmi2EventInfo*`: Strut with `fmi2Boolean` Variables -More detailed: - - `newDiscreteStatesNeeded::fmi2Boolean`: If `newDiscreteStatesNeeded = fmi2True` the FMU should stay in Event Mode, and the FMU requires to set new inputs to the FMU to compute and get the outputs and to call -fmi2NewDiscreteStates again. If all FMUs return `newDiscreteStatesNeeded = fmi2False` call fmi2EnterContinuousTimeMode. - - `terminateSimulation::fmi2Boolean`: If `terminateSimulation = fmi2True` call `fmi2Terminate` - - `nominalsOfContinuousStatesChanged::fmi2Boolean`: If `nominalsOfContinuousStatesChanged = fmi2True` then the nominal values of the states have changed due to the function call and can be inquired with `fmi2GetNominalsOfContinuousStates`. - - `valuesOfContinuousStatesChanged::fmi2Boolean`: If `valuesOfContinuousStatesChanged = fmi2True`, then at least one element of the continuous state vector has changed its value due to the function call. The new values of the states can be retrieved with `fmi2GetContinuousStates`. If no element of the continuous state vector has changed its value, `valuesOfContinuousStatesChanged` must return fmi2False. - - `nextEventTimeDefined::fmi2Boolean`: If `nextEventTimeDefined = fmi2True`, then the simulation shall integrate at most until `time = nextEventTime`, and shall call `fmi2EnterEventMode` at this time instant. If integration is stopped before nextEventTime, the definition of `nextEventTime` becomes obsolete. - - `nextEventTime::fmi2Real`: next event if `nextEventTimeDefined=fmi2True` -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations +export fmi3Load -""" -function fmiNewDiscreteStates(str::fmi2Struct) - fmi2NewDiscreteStates(str) +function fmiUnload(args...; kwargs...) + warnDeprecated("fmiUnload", "unloadFMU") + unloadFMU(args...; kwargs...) end -export fmiNewDiscreteStates +export fmiUnload -""" -DEPRECATED - fmiEnterContinuousTimeMode(str::fmi2Struct) - -The model enters Continuous-Time Mode and all discrete-time equations become inactive and all relations are β€œfrozen”. -This function has to be called when changing from Event Mode into Continuous-Time Mode. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously - -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations - -""" -function fmiEnterContinuousTimeMode(str::fmi2Struct) - fmi2EnterContinuousTimeMode(str) +function fmi2Unload(args...; kwargs...) + warnDeprecated("fmi2Unload", "unloadFMU", "FMI version is determined automatically.") + unloadFMU(args...; kwargs...) end -export fmiEnterContinuousTimeMode +export fmi2Unload -""" -DEPRECATED - fmiCompletedIntegratorStep(str::fmi2Struct, c::FMU2Component, noSetFMUStatePriorToCurrentPoint::fmi2Boolean) - -This function must be called by the environment after every completed step - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -- `noSetFMUStatePriorToCurrentPoint::fmi2Boolean`: Argument `noSetFMUStatePriorToCurrentPoint = fmi2True` if `fmi2SetFMUState` will no longer be called for time instants prior to current time in this simulation run. - -# Returns -- `status::fmi2Status`: Return `status` is an enumeration of type `fmi2Status` and indicates the success of the function call. -More detailed: - - `fmi2OK`: all well - - `fmi2Warning`: things are not quite right, but the computation can continue - - `fmi2Discard`: if the slave computed successfully only a subinterval of the communication step - - `fmi2Error`: the communication step could not be carried out at all - - `fmi2Fatal`: if an error occurred which corrupted the FMU irreparably - - `fmi2Pending`: this status is returned if the slave executes the function asynchronously -- `enterEventMode::Array{fmi2Boolean, 1}`: Returns `enterEventMode[1]` to signal to the environment if the FMU shall call `fmi2EnterEventMode` -- `terminateSimulation::Array{fmi2Boolean, 1}`: Returns `terminateSimulation[1]` to signal if the simulation shall be terminated. -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations - -""" -function fmiCompletedIntegratorStep(str::fmi2Struct, args...; kwargs...) - fmi2CompletedIntegratorStep(str, args...; kwargs...) +function fmi3Unload(args...; kwargs...) + warnDeprecated("fmi3Unload", "unloadFMU", "FMI version is determined automatically.") + unloadFMU(args...; kwargs...) end -export fmiCompletedIntegratorStep - -""" -DEPRECATED - fmiGetDerivatives(str::fmi2Struct) +export fmi3Unload -Compute state derivatives at the current time instant and for the current states. - -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- `derivatives::Array{fmi2Real}`: Returns an array of `fmi2Real` values representing the `derivatives` for the current states. The ordering of the elements of the derivatives vector is identical to the ordering of the state -vector. -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations - -""" -DEPRECATED -function fmiGetDerivatives(str::fmi2Struct) - fmi2GetDerivatives(str) -end -export fmiGetDerivatives - -""" -DEPRECATED - fmiGetEventIndicators(str::fmi2Struct) - -Returns the event indicators of the FMU -# Arguments -- `str::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `str::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `str::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. - -# Returns -- `eventIndicators::Array{fmi2Real}`:The event indicators are returned as a vector represented by an array of "fmi2Real" values. -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations - -""" -function fmiGetEventIndicators(str::fmi2Struct) - fmi2GetEventIndicators(str) -end -export fmiGetEventIndicators - -""" -DEPRECATED - fmiGetContinuousStates(s::fmi2Struct) - -Return the new (continuous) state vector x -# Arguments -- `s::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `s::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `s::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -# Returns -- `x::Array{fmi2Real}`: Returns an array of `fmi2Real` values representing the new continuous state vector `x`. -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations - - -""" -function fmiGetContinuousStates(s::fmi2Struct) - fmi2GetContinuousStates(s) -end -export fmiGetContinuousStates - -""" -DEPRECATED - fmiGetNominalsOfContinuousStates(s::fmi2Struct) - -Return the new (continuous) state vector x - -# Arguments -- `s::fmi2Struct`: Representative for an FMU in the FMI 2.0.2 Standard. -More detailed: `fmi2Struct = Union{FMU2, FMU2Component}` - - `s::FMU2`: Mutable struct representing a FMU and all it instantiated instances in the FMI 2.0.2 Standard. - - `s::FMU2Component`: Mutable struct represents an instantiated instance of an FMU in the FMI 2.0.2 Standard. -# Returns -- `x::Array{fmi2Real}`: Returns an array of `fmi2Real` values representing the new continuous state vector `x`. -# Source -- FMISpec2.0.2 Link: [https://fmi-standard.org/](https://fmi-standard.org/) -- FMISpec2.0.2[p.16]: 2.1.2 Platform Dependent Definitions (fmi2TypesPlatform.h) -- FMISpec2.0.2[p.16]: 2.1.3 Status Returned by Functions -- FMISpec2.0.2[p.83]: 3.2.2 Evaluation of Model Equations - -""" -function fmiGetNominalsOfContinuousStates(s::fmi2Struct) - fmi2GetNominalsOfContinuousStates(s) -end -export fmiGetNominalsOfContinuousStates - -##### function setters - -function fmiSetFctGetTypesPlatform(fmu::FMU2, fun) - fmi2SetFctGetTypesPlatform(fmu, fun) +function fmiInfo(args...; kwargs...) + warnDeprecated("fmiInfo", "info") + info(args...; kwargs...) end +export fmiInfo -function fmiSetFctGetVersion(fmu::FMU2, fun) - fmi2SetFctGetVersion(fmu, fun) +function fmi2Info(args...; kwargs...) + warnDeprecated("fmi2Info", "info", "FMI version is determined automatically.") + info(args...; kwargs...) end +export fmi2Info -function fmiSetFctInstantiate(fmu::FMU2, fun) - fmi2SetFctInstantiate(fmu, fun) +function fmi3Info(args...; kwargs...) + warnDeprecated("fmi3Info", "info", "FMI version is determined automatically.") + info(args...; kwargs...) end - -function fmiSetFctFreeInstance(fmu::FMU2, fun) - fmi2SetFctFreeInstance(fmu, fun) -end - -function fmiSetFctSetDebugLogging(fmu::FMU2, fun) - fmi2SetFctSetDebugLogging(fmu, fun) -end - -function fmiSetFctSetupExperiment(fmu::FMU2, fun) - fmi2SetFctSetupExperiment(fmu, fun) -end - -function fmiSetEnterInitializationMode(fmu::FMU2, fun) - fmi2SetEnterInitializationMode(fmu, fun) -end - -function fmiSetFctExitInitializationMode(fmu::FMU2, fun) - fmi2SetFctExitInitializationMode(fmu, fun) -end - -function fmiSetFctTerminate(fmu::FMU2, fun) - fmi2SetFctTerminate(fmu, fun) -end - -function fmiSetFctReset(fmu::FMU2, fun) - fmi2SetFctReset(fmu, fun) -end - -function fmiSetFctGetReal(fmu::FMU2, fun) - fmi2SetFctGetReal(fmu, fun) -end - -function fmiSetFctGetInteger(fmu::FMU2, fun) - fmi2SetFctGetInteger(fmu, fun) -end - -function fmiSetFctGetBoolean(fmu::FMU2, fun) - fmi2SetFctGetBoolean(fmu, fun) -end - -function fmiSetFctGetString(fmu::FMU2, fun) - fmi2SetFctGetString(fmu, fun) -end - -function fmiSetFctSetReal(fmu::FMU2, fun) - fmi2SetFctSetReal(fmu, fun) -end - -function fmiSetFctSetInteger(fmu::FMU2, fun) - fmi2SetFctSetInteger(fmu, fun) -end - -function fmiSetFctSetBoolean(fmu::FMU2, fun) - fmi2SetFctSetBoolean(fmu, fun) -end - -function fmiSetFctSetString(fmu::FMU2, fun) - fmi2SetFctSetString(fmu, fun) -end - -function fmiSetFctSetTime(fmu::FMU2, fun) - fmi2SetFctSetTime(fmu, fun) -end - -function fmiSetFctSetContinuousStates(fmu::FMU2, fun) - fmi2SetFctSetContinuousStates(fmu, fun) -end - -function fmiSetFctEnterEventMode(fmu::FMU2, fun) - fmi2SetFctEnterEventMode(fmu, fun) -end - -function fmiSetFctNewDiscreteStates(fmu::FMU2, fun) - fmi2SetFctNewDiscreteStates(fmu, fun) -end - -function fmiSetFctEnterContinuousTimeMode(fmu::FMU2, fun) - fmi2SetFctEnterContinuousTimeMode(fmu, fun) -end - -function fmiSetFctCompletedIntegratorStep(fmu::FMU2, fun) - fmi2SetFctCompletedIntegratorStep(fmu, fun) -end - -function fmiSetFctGetDerivatives(fmu::FMU2, fun) - fmi2SetFctGetDerivatives(fmu, fun) -end - -function fmiSetFctGetEventIndicators(fmu::FMU2, fun) - fmi2SetFctGetEventIndicators(fmu, fun) -end - -function fmiSetFctGetContinuousStates(fmu::FMU2, fun) - fmi2SetFctGetContinuousStates(fmu, fun) -end - -function fmiSetFctGetNominalsOfContinuousStates(fmu::FMU2, fun) - fmi2SetFctGetNominalsOfContinuousStates(fmu, fun) -end - -function fmiGetSolutionTime(solution::FMU2Solution, args...; kwargs...) - fmi2GetSolutionTime(solution, args...; kwargs...) -end - -function fmiGetSolutionState(solution::FMU2Solution, args...; kwargs...) - fmi2GetSolutionState(solution, args...; kwargs...) -end - -function fmiGetSolutionDerivative(solution::FMU2Solution, args...; kwargs...) - fmi2GetSolutionDerivative(solution, args...; kwargs...) -end - -function fmiGetSolutionValue(solution::FMU2Solution, args...; kwargs...) - fmi2GetSolutionValue(solution, args...; kwargs...) -end - -# renames - -function fmiSampleDirectionalDerivative(args...; kwargs...) - fmi2SampleJacobian(args...; kwargs...) -end - -function fmiSampleDirectionalDerivative!(args...; kwargs...) - fmi2SampleJacobian!(args...; kwargs...) -end \ No newline at end of file +export fmi3Info diff --git a/src/extensions/CSV.jl b/src/extensions/CSV.jl deleted file mode 100644 index eed60aea..00000000 --- a/src/extensions/CSV.jl +++ /dev/null @@ -1,23 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMIImport: FMUSolution - -""" - fmiSaveSolutionCSV(solution::FMUSolution, filepath::AbstractString) - -Save a `solution` of an FMU simulation as csv file at `filepath`. -(requires Package CSV in Julia Environment) - -See also [`fmiSaveSolutionMAT`](@ref), [`fmiSaveSolutionJLD2`](@ref), [`fmiLoadSolutionJLD2`](@ref). -""" -function fmiSaveSolutionCSV(solution::FMUSolution, filepath::AbstractString) - df = DataFrames.DataFrame(time = solution.values.t) - for i in 1:length(solution.values.saveval[1]) - df[!, Symbol(fmi2ValueReferenceToString(solution.component.fmu, solution.valueReferences[i]))] = [val[i] for val in solution.values.saveval] - end - CSV.write(filepath, df) -end -export fmiSaveSolutionCSV diff --git a/src/extensions/JLD2.jl b/src/extensions/JLD2.jl deleted file mode 100644 index 660e0eba..00000000 --- a/src/extensions/JLD2.jl +++ /dev/null @@ -1,32 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMIImport: FMUSolution - -""" - fmiSaveSolutionJLD2(solution::FMUSolution, filepath::AbstractString; keyword="solution") - -Save a `solution` of an FMU simulation under `keyword` in a jld2 file at `filepath`. -(requires Package JLD2 in Julia Environment) - -See also [`fmiSaveSolutionCSV`](@ref), [`fmiSaveSolutionMAT`](@ref), [`fmiLoadSolutionJLD2`](@ref). -""" -function fmiSaveSolutionJLD2(solution::FMUSolution, filepath::AbstractString; keyword="solution") - return JLD2.save(filepath, Dict(keyword=>solution)) -end -export fmiSaveSolutionJLD2 - -""" - fmiLoadSolutionJLD2(filepath::AbstractString; keyword="solution") - -Load a [`FMUSolution`](@ref) from jld2 file at `filepath` using `keyword` as jld2 keyword. -(requires Package JLD2 in Julia Environment) - -See also [`fmiSaveSolutionCSV`](@ref), [`fmiSaveSolutionMAT`](@ref), [`fmiSaveSolutionJLD2`](@ref). -""" -function fmiLoadSolutionJLD2(filepath::AbstractString; keyword="solution") - return JLD2.load(filepath, keyword) -end -export fmiLoadSolutionJLD2 \ No newline at end of file diff --git a/src/extensions/MAT.jl b/src/extensions/MAT.jl deleted file mode 100644 index ca79ce86..00000000 --- a/src/extensions/MAT.jl +++ /dev/null @@ -1,30 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMIImport: FMUSolution - -""" - fmiSaveSolutionMAT(solution::FMUSolution, filepath::AbstractString) - - -Save a `solution` of an FMU simulation as mat file at `filepath`. -(requires Package MAT in Julia Environment) - -See also [`fmiSaveSolutionCSV`](@ref), [`fmiSaveSolutionJLD2`](@ref), [`fmiLoadSolutionJLD2`](@ref). -""" -function fmiSaveSolutionMAT(solution::FMUSolution, filepath::AbstractString) - file = MAT.matopen(filepath, "w") - x = collect.(solution.values.saveval) - v = [tup[k] for tup in x, k in 1:length(x[1])] - v = hcat(solution.values.t, v) - MAT.write(file, "time", v[:,1]) - for i in 2:length(v[1,:]) - MAT.write(file, replace(fmi2ValueReferenceToString(solution.component.fmu, solution.valueReferences[i-1])[1], "." => "_"), v[:,i]) - # df[!, Symbol(fmi2ValueReferenceToString(solution.component.fmu, solution.valueReferences[i]))] = [val[i] for val in solution.values.saveval] - end - - MAT.close(file) -end -export fmiSaveSolutionMAT \ No newline at end of file diff --git a/src/extensions/Plots.jl b/src/extensions/Plots.jl deleted file mode 100644 index 32aafb13..00000000 --- a/src/extensions/Plots.jl +++ /dev/null @@ -1,228 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMIImport: FMUSolution -import FMIImport.FMICore: unsense - -""" - fmiPlot(solution::FMUSolution; kwargs...) - -Create a figure and [`fmiPlot!`](@ref)'s the `solution` of a FMU simulation with the `kwargs` into it and returns the figure. -(requires Package Plots in Julia Environment) - -See also [`fmiPlot!`](@ref) -""" -function fmiPlot(solution::FMUSolution; kwargs...) - fig = Plots.plot(; xlabel="t [s]") - fmiPlot!(fig, solution; kwargs...) - return fig -end -export fmiPlot - -""" - fmiPlot!(fig::Plots.Plot, solution::FMUSolution; - [states::Union{Bool, Nothing}=nothing, - values::Union{Bool, Nothing}=nothing, - stateEvents::Union{Bool, Nothing}=nothing, - timeEvents::Union{Bool, Nothing}=nothing, - stateIndices=nothing, - valueIndices=nothing, - maxLabelLength=64, - plotkwargs...]) - -Plot the `solution` of a FMU simulation into `fig` and return the figure. - -# Arguments -- `fig::Plots.Plot`: Figure to plot into -- `solution::FMUSolution`: Struct containing information about the solutions values, success, states and events of a specific FMU simulation. -- `states::Union{Bool, Nothing}=nothing`: controls if states should be plotted (default = nothing: plot states from `solution`, as long as they exist) -- `values::Union{Bool, Nothing}=nothing`: controls if values should be plotted (default = nothing: plot values from `solution`, as long as they exist) -- `stateEvents::Union{Bool, Nothing}=nothing`: controls if stateEvents should be plotted (default = nothing: plot stateEvents from `solution`, if at least one and at most 100 exist) -- `timeEvents::Union{Bool, Nothing}=nothing`: controls if timeEvents should be plotted (default = nothing: plot timeEvents from `solution`, if at least one and at most 100 exist) -- `stateIndices=nothing`: controls which states will be plotted by index in state vector (default = nothing: plot all states) -- `valueIndices=nothing`: controls which values will be plotted by index (default = nothing: plot all values) -- `maxLabelLength=64`: controls the maximum length for legend labels (too long labels are cut from front) -- `plotkwargs...`: Arguments, that are passed on to Plots.plot! - -See also [`fmiPlot`](@ref) -""" -function fmiPlot!(fig::Plots.Plot, solution::FMUSolution; - states::Union{Bool, Nothing}=nothing, - values::Union{Bool, Nothing}=nothing, - stateEvents::Union{Bool, Nothing}=nothing, - timeEvents::Union{Bool, Nothing}=nothing, - stateIndices=nothing, - valueIndices=nothing, - maxLabelLength=64, - plotkwargs...) - - component = nothing - if isa(solution, FMU2Solution) - component = solution.component - elseif isa(solution, FMU3Solution) - component = solution.fmu.instances[end] # ToDo: This is very poor! - else - @assert false "Invalid solution type." - end - - numStateEvents = 0 - numTimeEvents = 0 - for e in solution.events - if e.indicator > 0 - numStateEvents += 1 - else - numTimeEvents += 1 - end - end - - if isnothing(states) - states = (solution.states !== nothing) - end - - if values === nothing - values = (solution.values !== nothing) - end - - if stateEvents === nothing - stateEvents = false - for e in solution.events - if e.indicator > 0 - stateEvents = true - break - end - end - - if numStateEvents > 100 - @info "fmiPlot(...): Number of state events ($(numStateEvents)) exceeding 100, disabling automatic plotting of state events (can be forced with keyword `stateEvents=true`)." - stateEvents = false - end - end - - if timeEvents === nothing - timeEvents = false - for e in solution.events - if e.indicator == 0 - timeEvents = true - break - end - end - - if numTimeEvents > 100 - @info "fmiPlot(...): Number of time events ($(numTimeEvents)) exceeding 100, disabling automatic plotting of time events (can be forced with keyword `timeEvents=true`)." - timeEvents = false - end - end - - if stateIndices === nothing - stateIndices = 1:length(component.fmu.modelDescription.stateValueReferences) - end - - if valueIndices === nothing - if solution.values !== nothing - valueIndices = 1:length(solution.values.saveval[1]) - end - end - - plot_min = Inf - plot_max = -Inf - - # plot states - if states - t = collect(unsense(e) for e in solution.states.t) - numValues = length(solution.states.u[1]) - - for v in 1:numValues - if v ∈ stateIndices - vr = component.fmu.modelDescription.stateValueReferences[v] - vrNames = fmi2ValueReferenceToString(component.fmu, vr) - vrName = length(vrNames) > 0 ? vrNames[1] : "?" - - vals = collect(unsense(data[v]) for data in solution.states.u) - - plot_min = min(plot_min, vals...) - plot_max = max(plot_max, vals...) - - # prevent legend labels from getting too long - label = "$vrName ($vr)" - labelLength = length(label) - if labelLength > maxLabelLength - label = "..." * label[labelLength-maxLabelLength:end] - end - - Plots.plot!(fig, t, vals; label=label, plotkwargs...) - end - end - end - - # plot recorded values - if values - t = collect(unsense(e) for e in solution.values.t) - numValues = length(solution.values.saveval[1]) - - for v in 1:numValues - if v ∈ valueIndices - vr = "[unknown]" - vrName = "[unknown]" - if solution.valueReferences != nothing && v <= length(solution.valueReferences) - vr = solution.valueReferences[v] - vrNames = fmi2ValueReferenceToString(component.fmu, vr) - vrName = length(vrNames) > 0 ? vrNames[1] : "?" - end - - vals = collect(unsense(data[v]) for data in solution.values.saveval) - - plot_min = min(plot_min, vals...) - plot_max = max(plot_max, vals...) - - # prevent legend labels from getting too long - label = "$vrName ($vr)" - labelLength = length(label) - if labelLength > maxLabelLength - label = "..." * label[labelLength-maxLabelLength:end] - end - - Plots.plot!(fig, t, vals; label=label, plotkwargs...) - end - end - end - - if stateEvents - first = true - for e in solution.events - if e.indicator > 0 - Plots.plot!(fig, [e.t, e.t], [plot_min, plot_max]; label=(first ? "State event(s)" : nothing), style=:dash, color=:blue) - first = false - end - end - end - - if timeEvents - first = true - for e in solution.events - if e.indicator == 0 - Plots.plot!(fig, [e.t, e.t], [plot_min, plot_max]; label=(first ? "Time event(s)" : nothing), style=:dash, color=:red) - first = false - end - end - end - - return fig -end -export fmiPlot! - -""" - Plots.plot(solution::FMUSolution; kwargs...) - Plots.plot!(fig::Plots.Plot, solution::FMUSolution; kwargs...) - -Plot FMUs using the original plot-command from Plots. - -See also [`fmiPlot`](@ref), [`fmiPlot!`](@ref). -""" Plots.plot, Plots.plot! -function Plots.plot(solution::FMUSolution; kwargs...) - fmiPlot(solution; kwargs...) -end -function Plots.plot!(fig::Plots.Plot, solution::FMUSolution; kwargs...) - fmiPlot!(fig, solution; kwargs...) -end diff --git a/src/sim.jl b/src/sim.jl new file mode 100644 index 00000000..a558cb59 --- /dev/null +++ b/src/sim.jl @@ -0,0 +1,557 @@ +# +# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher +# Licensed under the MIT license. See LICENSE file in the project root for details. +# + +using FMIImport.FMIBase.SciMLBase: solve, RightRootFind, ReturnCode +using FMIImport.FMIBase.DiffEqCallbacks: CallbackSet, SavedValues, copyat_or_push! + +import LinearAlgebra: eigvals +import FMIImport.FMIBase.ProgressMeter + +import FMIImport: prepareSolveFMU, finishSolveFMU +import FMIImport.FMIBase: setupODEProblem, setupCallbacks, setupSolver!, eval! +import FMIImport.FMIBase: getEmptyReal, getEmptyValueReference, isTrue, isStatusOK +import FMIImport.FMIBase: doStep + +""" + simulate(fmu, instance=nothing, tspan=nothing; kwargs...) + simulate(fmu, tspan; kwargs...) + simulate(instance, tspan; kwargs...) + +Starts a simulation of the `FMU2` for the instantiated type: CS, ME or SE (this is selected automatically or during loading of the FMU). +You can force a specific simulation mode by calling [`simulateCS`](@ref), [`simulateME`](@ref) or [`simulateSE`](@ref) directly. + +# Arguments +- `fmu::FMU`: The FMU to be simulated. +- `c::Union{FMUInstance, Nothing}=nothing`: The instance (FMI3) or component (FMI2) of the FMU, `nothing` if not available. +- `tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing`: Simulation-time-span as tuple (default = nothing: use default value from FMU's model description or (0.0, 1.0) if not specified) + +# Keyword arguments +- `recordValues::fmi2ValueReferenceFormat` = nothing: Array of variables (Strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` +- `saveat = nothing`: Time points to save (interpolated) values at (default = nothing: save at each solver timestep) +- `setup::Bool`: call fmi2SetupExperiment, fmi2EnterInitializationMode and fmi2ExitInitializationMode before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `reset::Bool`: call fmi2Reset before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `instantiate::Bool`: call fmi2Instantiate! before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `freeInstance::Bool`: call fmi2FreeInstance after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `terminate::Bool`: call fmi2Terminate after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `inputValueReferences::fmi2ValueReferenceFormat = nothing`: Input variables (Strings or variableIdentifiers) to set at each simulation step +- `inputFunction = nothing`: Function to get values for the input variables at each simulation step. +- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dict of parameter variables (strings or variableIdentifiers) and values (Real, Integer, Boolean, String) to set parameters during initialization +- `showProgress::Bool = true`: print simulation progressmeter in REPL + +## Input function pattern +[`c`: current component, `u`: current state ,`t`: current time, returning array of values to be passed to `fmi2SetReal(..., inputValueReferences, inputFunction(...))` or `fmi3SetFloat64`]: +- `inputFunction(t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, x::AbstractVector{<:Real}, u::AbstractVector{<:Real})` +- `inputFunction(x::AbstractVector{<:Real}, t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, x::AbstractVector{<:Real}, t::Real, u::AbstractVector{<:Real})` + +# Returns: +- A [`FMUSolution`](@ref) struct. + +See also [`simulate`](@ref), [`simulateME`](@ref), [`simulateCS`](@ref), [`simulateSE`](@ref). +""" +function simulate( + fmu::FMU2, + c::Union{FMU2Component,Nothing} = nothing, + tspan::Union{Tuple{Float64,Float64},Nothing} = nothing; + kwargs..., +) + + if fmu.type == fmi2TypeCoSimulation + return simulateCS(fmu, c, tspan; kwargs...) + elseif fmu.type == fmi2TypeModelExchange + return simulateME(fmu, c, tspan; kwargs...) + else + error(unknownFMUType) + end +end +function simulate( + fmu::FMU3, + c::Union{FMU3Instance,Nothing} = nothing, + tspan::Union{Tuple{Float64,Float64},Nothing} = nothing; + kwargs..., +) + + if fmu.type == fmi3TypeCoSimulation + return simulateCS(fmu, c, tspan; kwargs...) + elseif fmu.type == fmi3TypeModelExchange + return simulateME(fmu, c, tspan; kwargs...) + elseif fmu.type == fmi3TypeScheduledExecution + return simulateSE(fmu, c, tspan; kwargs...) + else + error(unknownFMUType) + end +end +simulate(c::FMUInstance, tspan::Tuple{Float64,Float64}; kwargs...) = + simulate(c.fmu, c, tspan; kwargs...) +simulate(fmu::FMU, tspan::Tuple{Float64,Float64}; kwargs...) = + simulate(fmu, nothing, tspan; kwargs...) +export simulate + +""" + simulateME(fmu, instance=nothing, tspan=nothing; kwargs...) + simulateME(fmu, tspan; kwargs...) + simulateME(instance, tspan; kwargs...) + +Simulate ME-FMU for the given simulation time interval. +State- and Time-Events are handled correctly. + +# Arguments +- `fmu::FMU`: The FMU to be simulated. +- `c::Union{FMUInstance, Nothing}=nothing`: The instance (FMI3) or component (FMI2) of the FMU, `nothing` if not available. +- `tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing`: Simulation-time-span as tuple (default = nothing: use default value from FMU's model description or (0.0, 1.0) if not specified) + +# Keyword arguments +- `solver = nothing`: Any Julia-supported ODE-solver (default = nothing: use DifferentialEquations.jl default solver) +- `recordValues::fmi2ValueReferenceFormat` = nothing: Array of variables (Strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` +- `recordEventIndicators::Union{AbstractArray{<:Integer, 1}, UnitRange{<:Integer}, Nothing} = nothing`: Array or Range of event indicators to record +- `recordEigenvalues::Bool=false`: compute and record eigenvalues +- `saveat = nothing`: Time points to save (interpolated) values at (default = nothing: save at each solver timestep) +- `x0::Union{AbstractArray{<:Real}, Nothing} = nothing`: inital fmu State (default = nothing: use current or default-inital fmu state) +- `setup::Bool`: call fmi2SetupExperiment, fmi2EnterInitializationMode and fmi2ExitInitializationMode before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `reset::Bool`: call fmi2Reset before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `instantiate::Bool`: call fmi2Instantiate! before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `freeInstance::Bool`: call fmi2FreeInstance after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `terminate::Bool`: call fmi2Terminate after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `inputValueReferences::fmi2ValueReferenceFormat = nothing`: Input variables (Strings or variableIdentifiers) to set at each simulation step +- `inputFunction = nothing`: Function to get values for the input variables at each simulation step. +- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dict of parameter variables (strings or variableIdentifiers) and values (Real, Integer, Boolean, String) to set parameters during initialization +- `callbacksBefore = []`: callbacks to call *before* the internal callbacks for state- and time-events are called +- `callbacksAfter = []`: callbacks to call *after* the internal callbacks for state- and time-events are called +- `showProgress::Bool = true`: print simulation progressmeter in REPL +- `solveKwargs...`: keyword arguments that get passed onto the solvers solve call + +## Input function pattern +[`c`: current component, `u`: current state ,`t`: current time, returning array of values to be passed to `fmi2SetReal(..., inputValueReferences, inputFunction(...))` or `fmi3SetFloat64`]: +- `inputFunction(t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, x::AbstractVector{<:Real}, u::AbstractVector{<:Real})` +- `inputFunction(x::AbstractVector{<:Real}, t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, x::AbstractVector{<:Real}, t::Real, u::AbstractVector{<:Real})` + +# Returns: +- A [`FMUSolution`](@ref) struct. + +See also [`simulate`](@ref), [`simulateCS`](@ref), [`simulateSE`](@ref). +""" +function simulateME( + fmu::FMU, + c::Union{FMUInstance,Nothing}, + tspan::Union{Tuple{Float64,Float64},Nothing} = nothing; + solver = nothing, # [ToDo] type + recordValues::fmi2ValueReferenceFormat = nothing, + recordEventIndicators::Union{AbstractArray{<:Integer,1},UnitRange{<:Integer},Nothing} = nothing, + recordEigenvalues::Bool = false, + saveat = nothing, # [ToDo] type + x0::Union{AbstractArray{<:Real},Nothing} = nothing, + setup::Bool = fmu.executionConfig.setup, + reset::Bool = fmu.executionConfig.reset, + instantiate::Bool = fmu.executionConfig.instantiate, + freeInstance::Bool = fmu.executionConfig.freeInstance, + terminate::Bool = fmu.executionConfig.terminate, + inputValueReferences::fmi2ValueReferenceFormat = nothing, + inputFunction = nothing, + parameters::Union{Dict{<:Any,<:Any},Nothing} = nothing, + callbacksBefore::AbstractVector = [], # [ToDo] type + callbacksAfter::AbstractVector = [], # [ToDo] type + showProgress::Bool = true, + solveKwargs..., +) + + @assert isModelExchange(fmu) "simulateME(...): This function supports Model Excahnge FMUs only." + + recordValues = prepareValueReference(fmu, recordValues) + inputValueReferences = prepareValueReference(fmu, inputValueReferences) + hasInputs = length(inputValueReferences) > 0 + + solveKwargs = Dict{Symbol,Any}(solveKwargs...) + tspan = setupSolver!(fmu, tspan, solveKwargs) + t_start, t_stop = tspan + + if !isnothing(saveat) + solveKwargs[:saveat] = saveat + end + + progressMeter = nothing + if showProgress + progressMeter = ProgressMeter.Progress( + 1000; + desc = "Simulating ME-FMU ...", + color = :blue, + dt = 1.0, + ) #, barglyphs=ProgressMeter.BarGlyphs("[=> ]")) + ProgressMeter.update!(progressMeter, 0) # show it! + end + + # input function handling + _inputFunction = nothing + if !isnothing(inputFunction) + _inputFunction = FMUInputFunction(inputFunction, inputValueReferences) + end + + inputs = nothing + if hasInputs + inputValues = eval!(_inputFunction, nothing, nothing, t_start) + inputs = Dict(inputValueReferences .=> inputValues) + end + c, x0 = prepareSolveFMU( + fmu, + c, + :ME; + parameters = parameters, + t_start = t_start, + t_stop = t_stop, + x0 = x0, + inputs = inputs, + ) + + # Zero state FMU: add dummy state + if c.fmu.isZeroState + x0 = [0.0] + end + + @assert !isnothing(x0) "x0 is nothing after prepare!" + + c.problem = setupODEProblem(c, x0, tspan; inputFunction = _inputFunction) + cbs = setupCallbacks( + c, + recordValues, + recordEventIndicators, + recordEigenvalues, + _inputFunction, + inputValueReferences, + progressMeter, + t_start, + t_stop, + saveat, + ) + + #solveKwargs = Dict(solveKwargs...) + #setupSolver(fmu, solveKwargs) + + for cb in callbacksBefore + insertAt!(cbs, cb, 1) + end + + for cb in callbacksAfter + push!(cbs, cb) + end + + # from here on, we are in event mode, if `setup=false` this is the job of the user + #@assert c.state == fmi2ComponentStateEventMode "FMU needs to be in event mode after setup." + + # if x0 === nothing + # x0 = fmi2GetContinuousStates(c) + # x0_nom = fmi2GetNominalsOfContinuousStates(c) + # end + + # initial event handling + #handleEvents(c) + #fmi2EnterContinuousTimeMode(c) + + # callback functions + + if isnothing(solver) + c.solution.states = solve(c.problem; callback = CallbackSet(cbs...), solveKwargs...) + else + c.solution.states = + solve(c.problem, solver; callback = CallbackSet(cbs...), solveKwargs...) + end + + c.solution.success = (c.solution.states.retcode == ReturnCode.Success) + + if !c.solution.success + logWarning( + fmu, + "FMU simulation failed with solver return code `$(c.solution.states.retcode)`, please check log for hints.", + ) + end + + # ZeroStateFMU: remove dummy state + if c.fmu.isZeroState + c.solution.states = nothing + end + + # cleanup progress meter + if showProgress + ProgressMeter.finish!(progressMeter) + end + + finishSolveFMU(fmu, c; freeInstance = freeInstance, terminate = terminate) + + return c.solution +end +simulateME(c::FMUInstance, tspan::Tuple{Float64,Float64}; kwargs...) = + simulateME(c.fmu, c, tspan; kwargs...) +simulateME(fmu::FMU, tspan::Tuple{Float64,Float64}; kwargs...) = + simulateME(fmu, nothing, tspan; kwargs...) +export simulateME + +############ Co-Simulation ############ + +""" + simulateCS(fmu, instance=nothing, tspan=nothing; kwargs...) + simulateCS(fmu, tspan; kwargs...) + simulateCS(instance, tspan; kwargs...) + +Simulate CS-FMU for the given simulation time interval. +State- and Time-Events are handled internally by the FMU. + +# Arguments +- `fmu::FMU`: The FMU to be simulated. +- `c::Union{FMUInstance, Nothing}=nothing`: The instance (FMI3) or component (FMI2) of the FMU, `nothing` if not available. +- `tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing`: Simulation-time-span as tuple (default = nothing: use default value from FMU's model description or (0.0, 1.0) if not specified) + +# Keyword arguments +- `tolerance::Union{Real, Nothing} = nothing`: The tolerance for the internal FMU solver. +- `recordValues::fmi2ValueReferenceFormat` = nothing: Array of variables (Strings or variableIdentifiers) to record. Results are returned as `DiffEqCallbacks.SavedValues` +- `saveat = nothing`: Time points to save (interpolated) values at (default = nothing: save at each solver timestep) +- `setup::Bool`: call fmi2SetupExperiment, fmi2EnterInitializationMode and fmi2ExitInitializationMode before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `reset::Bool`: call fmi2Reset before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `instantiate::Bool`: call fmi2Instantiate! before each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `freeInstance::Bool`: call fmi2FreeInstance after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `terminate::Bool`: call fmi2Terminate after each step (default = nothing: use value from `fmu`'s `FMU2ExecutionConfiguration`) +- `inputValueReferences::fmi2ValueReferenceFormat = nothing`: Input variables (Strings or variableIdentifiers) to set at each simulation step +- `inputFunction = nothing`: Function to get values for the input variables at each simulation step. +- `parameters::Union{Dict{<:Any, <:Any}, Nothing} = nothing`: Dict of parameter variables (strings or variableIdentifiers) and values (Real, Integer, Boolean, String) to set parameters during initialization +- `showProgress::Bool = true`: print simulation progressmeter in REPL + +## Input function pattern +[`c`: current component, `u`: current state ,`t`: current time, returning array of values to be passed to `fmi2SetReal(..., inputValueReferences, inputFunction(...))` or `fmi3SetFloat64`]: +- `inputFunction(t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, x::AbstractVector{<:Real}, u::AbstractVector{<:Real})` +- `inputFunction(x::AbstractVector{<:Real}, t::Real, u::AbstractVector{<:Real})` +- `inputFunction(c::Union{FMUInstance, Nothing}, x::AbstractVector{<:Real}, t::Real, u::AbstractVector{<:Real})` + +# Returns: +- A [`FMUSolution`](@ref) struct. + +See also [`simulate`](@ref), [`simulateME`](@ref), [`simulateSE`](@ref). +""" +function simulateCS( + fmu::FMU, + c::Union{FMUInstance,Nothing}, + tspan::Union{Tuple{Float64,Float64},Nothing} = nothing; + tolerance::Union{Real,Nothing} = nothing, + dt::Union{Real,Nothing} = nothing, + recordValues::fmi2ValueReferenceFormat = nothing, + saveat = [], + setup::Bool = fmu.executionConfig.setup, + reset::Bool = fmu.executionConfig.reset, + instantiate::Bool = fmu.executionConfig.instantiate, + freeInstance::Bool = fmu.executionConfig.freeInstance, + terminate::Bool = fmu.executionConfig.terminate, + inputValueReferences::fmiValueReferenceFormat = nothing, + inputFunction = nothing, + showProgress::Bool = true, + parameters::Union{Dict{<:Any,<:Any},Nothing} = nothing, +) + + @assert isCoSimulation(fmu) "simulateCS(...): This function supports Co-Simulation FMUs only." + + # input function handling + @debug "Simulating CS-FMU: Preparing input function ..." + inputValueReferences = prepareValueReference(fmu, inputValueReferences) + hasInputs = (length(inputValueReferences) > 0) + + _inputFunction = nothing + u = getEmptyReal(fmu) + u_refs = getEmptyValueReference(fmu) + if hasInputs + _inputFunction = FMUInputFunction(inputFunction, inputValueReferences) + u_refs = _inputFunction.vrs + end + + # outputs + @debug "Simulating CS-FMU: Preparing outputs ..." + y_refs = getEmptyValueReference(fmu) + y = getEmptyReal(fmu) + if !isnothing(recordValues) + y_refs = prepareValueReference(fmu, recordValues) + y = zeros(fmi2Real, length(y_refs)) + end + + t_start, t_stop = (tspan == nothing ? (nothing, nothing) : tspan) + + # pull default values from the model description - if not given by user + @debug "Simulating CS-FMU: Pulling default values ..." + variableSteps = + isCoSimulation(fmu) && + isTrue(fmu.modelDescription.coSimulation.canHandleVariableCommunicationStepSize) + + t_start = t_start === nothing ? getDefaultStartTime(fmu.modelDescription) : t_start + t_start = t_start === nothing ? 0.0 : t_start + + t_stop = t_stop === nothing ? getDefaultStopTime(fmu.modelDescription) : t_stop + t_stop = t_stop === nothing ? 1.0 : t_stop + + tolerance = + tolerance === nothing ? getDefaultTolerance(fmu.modelDescription) : tolerance + tolerance = tolerance === nothing ? 0.0 : tolerance + + dt = dt === nothing ? getDefaultStepSize(fmu.modelDescription) : dt + dt = dt === nothing ? 1e-3 : dt + + @debug "Simulating CS-FMU: Preparing inputs ..." + inputs = nothing + if hasInputs + inputValues = eval!(_inputFunction, nothing, nothing, t_start) + inputs = Dict(inputValueReferences .=> inputValues) + end + + @debug "Simulating CS-FMU: Preparing solve ..." + c, _ = prepareSolveFMU( + fmu, + c, + :CS; + instantiate = instantiate, + freeInstance = freeInstance, + terminate = terminate, + reset = reset, + setup = setup, + parameters = parameters, + t_start = t_start, + t_stop = t_stop, + tolerance = tolerance, + inputs = inputs, + ) + fmusol = c.solution + + # default setup + if length(saveat) == 0 + saveat = t_start:dt:t_stop + end + + # setup if no variable steps + if variableSteps == false + if length(saveat) >= 2 + dt = saveat[2] - saveat[1] + end + end + + t = t_start + + progressMeter = nothing + if showProgress + progressMeter = + ProgressMeter.Progress(1000; desc = "Sim. CS-FMU ...", color = :blue, dt = 1.0) + ProgressMeter.update!(progressMeter, 0) # show it! + end + + first_step = true + + fmusol.values = + SavedValues(Float64, Tuple{collect(Float64 for i = 1:length(y_refs))...}) + fmusol.valueReferences = copy(y_refs) + + i = 1 + + fmusol.success = true + + @debug "Starting simulation from $(t_start) to $(t_stop), variable steps: $(variableSteps)" + + while t < t_stop + + if variableSteps + if length(saveat) > (i + 1) + dt = saveat[i+1] - saveat[i] + else + dt = t_stop - t + end + end + + if !first_step + ret = doStep(c, dt; currentCommunicationPoint = t) + + if !isStatusOK(fmu, ret) + fmusol.success = false + end + + t = t + dt + i += 1 + else + first_step = false + end + + if hasInputs + u = eval!(_inputFunction, c, nothing, t) + end + + c(u = u, u_refs = u_refs, y = y, y_refs = y_refs) + + svalues = (y...,) + copyat_or_push!(fmusol.values.t, i, t) + copyat_or_push!(fmusol.values.saveval, i, svalues, Val{false}) + + if !isnothing(progressMeter) + ProgressMeter.update!( + progressMeter, + floor(Integer, 1000.0 * (t - t_start) / (t_stop - t_start)), + ) + end + + end + + if !fmusol.success + logWarning(fmu, "FMU simulation failed, please check log for hints.") + end + + if !isnothing(progressMeter) + ProgressMeter.finish!(progressMeter) + end + + finishSolveFMU(fmu, c; freeInstance = freeInstance, terminate = terminate) + + return fmusol +end +simulateCS(c::FMUInstance, tspan::Tuple{Float64,Float64}; kwargs...) = + simulateCS(c.fmu, c, tspan; kwargs...) +simulateCS(fmu::FMU, tspan::Tuple{Float64,Float64}; kwargs...) = + simulateCS(fmu, nothing, tspan; kwargs...) +export simulateCS + +# [TODO] simulate ScheduledExecution +""" + simulateSE(fmu, instance=nothing, tspan=nothing; kwargs...) + simulateSE(fmu, tspan; kwargs...) + simulateSE(instance, tspan; kwargs...) + +To be implemented ... + +# Arguments +- `fmu::FMU3`: The FMU to be simulated. Note: SE is only available in FMI3. +- `c::Union{FMU3Instance, Nothing}=nothing`: The instance (FMI3) of the FMU, `nothing` if not available. +- `tspan::Union{Tuple{Float64, Float64}, Nothing}=nothing`: Simulation-time-span as tuple (default = nothing: use default value from FMU's model description or (0.0, 1.0) if not specified) + +# Keyword arguments +- To be implemented ... + +# Returns: +- A [`FMUSolution`](@ref) struct. + +See also [`simulate`](@ref), [`simulateME`](@ref), [`simulateCS`](@ref). +""" +function simulateSE( + fmu::FMU2, + c::Union{FMU2Component,Nothing}, + tspan::Union{Tuple{Float64,Float64},Nothing} = nothing, +) + @assert false "This is a FMI2-FMU, scheduled execution is not supported in FMI2." +end +function simulateSE( + fmu::FMU3, + c::Union{FMU3Instance,Nothing}, + tspan::Union{Tuple{Float64,Float64},Nothing} = nothing, +) + # [ToDo] + @assert false "Not implemented yet. Please open an issue if this is needed." +end +simulateSE(c::FMUInstance, tspan::Tuple{Float64,Float64}; kwargs...) = + simulateSE(c.fmu, c, tspan; kwargs...) +simulateSE(fmu::FMU, tspan::Tuple{Float64,Float64}; kwargs...) = + simulateSE(fmu, nothing, tspan; kwargs...) +export simulateSE diff --git a/test/FMI2/cs_me.jl b/test/FMI2/cs_me.jl deleted file mode 100644 index 2e0de3cd..00000000 --- a/test/FMI2/cs_me.jl +++ /dev/null @@ -1,33 +0,0 @@ -############### -# Prepare FMU # -############### - -t_start = 0.0 -t_stop = 1.0 - -### - -fmuStruct, myFMU = getFMUStruct("SpringPendulum1D") - -sol = fmiSimulateCS(fmuStruct, (t_start, t_stop)) -@test sol.success -sol = fmiSimulateME(fmuStruct, (t_start, t_stop); solver=FBDF(autodiff=false)) -@test sol.success - -fmiUnload(myFMU) - -### - -fmuStruct, myFMU = getFMUStruct("SpringPendulum1D"; type=:ME) - -sol = fmiSimulate(fmuStruct, (t_start, t_stop); solver=FBDF(autodiff=false)) -@test sol.success -fmiUnload(myFMU) - -### - -fmuStruct, myFMU = getFMUStruct("SpringPendulum1D"; type=:CS) - -sol = fmiSimulate(fmuStruct, (t_start, t_stop)) -@test sol.success -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI2/exec_config.jl b/test/FMI2/exec_config.jl deleted file mode 100644 index 47921a2b..00000000 --- a/test/FMI2/exec_config.jl +++ /dev/null @@ -1,71 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMI.FMIImport - -t_start = 0.0 -t_stop = 1.0 - -fmuStruct = Dict{Symbol, Union{FMU2, FMU2Component}}() -myFMU = Dict{Symbol, FMU2}() - -fmuStruct[:ME], myFMU[:ME] = getFMUStruct("SpringPendulum1D"; type=:ME) -fmuStruct[:CS], myFMU[:CS] = getFMUStruct("SpringPendulum1D"; type=:CS) - -for execConf in (FMU2_EXECUTION_CONFIGURATION_NO_FREEING, FMU2_EXECUTION_CONFIGURATION_RESET, FMU2_EXECUTION_CONFIGURATION_NO_RESET) # ToDo: Add `FMU2_EXECUTION_CONFIGURATION_NOTHING` - for mode in (:CS, :ME) - global fmuStruct, myFMU - - @info "\t$(mode) | $(execConf)" - - myFMU[mode].executionConfig = execConf - - # sim test - numInst = length(myFMU[mode].components) - - if mode == :CS - fmiSimulateCS(fmuStruct[mode], (t_start, t_stop)) - elseif mode == :ME - fmiSimulateME(fmuStruct[mode], (t_start, t_stop)) - else - @assert false "Unknown mode `$(mode)`." - end - - if execConf.instantiate - numInst += 1 - end - if execConf.freeInstance - numInst -= 1 - end - - @test length(myFMU[mode].components) == numInst - - othermode = (mode == :CS ? :ME : :CS) - - # prepare next run start - if isa(fmuStruct[mode], FMU2) - if !execConf.freeInstance - fmi2FreeInstance!(myFMU[mode]) - end - - fmi2Instantiate!(myFMU[othermode]; type=(othermode==:ME ? fmi2TypeModelExchange : fmi2TypeCoSimulation)) - - elseif isa(fmuStruct[mode], FMU2Component) - if !execConf.freeInstance - fmi2FreeInstance!(fmuStruct[mode]) - end - fmuStruct[othermode] = fmi2Instantiate!(myFMU[othermode]; type=(othermode==:ME ? fmi2TypeModelExchange : fmi2TypeCoSimulation)) - - else - @assert false "Unknown fmuStruct type `$(typeof(fmuStruct[mode]))`" - end - - # prepare next run end - - end -end - -fmiUnload(myFMU[:ME]) -fmiUnload(myFMU[:CS]) \ No newline at end of file diff --git a/test/FMI2/getter_setter.jl b/test/FMI2/getter_setter.jl deleted file mode 100644 index a5a08bd1..00000000 --- a/test/FMI2/getter_setter.jl +++ /dev/null @@ -1,85 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -############### -# Prepare FMU # -############### - -fmuStruct, myFMU = getFMUStruct("IO"; type=:CS) - -if isa(fmuStruct, FMU2) - # [Note] no instance allocated at this point - fmi2Instantiate!(fmuStruct) -end - -@test fmiSetupExperiment(fmuStruct, 0.0) == 0 - -@test fmiEnterInitializationMode(fmuStruct) == 0 - -realValueReferences = ["p_real", "u_real"] -integerValueReferences = ["p_integer", "u_integer"] -booleanValueReferences = ["p_boolean", "u_boolean"] -stringValueReferences = ["p_string", "p_string"] - -######################### -# Testing Single Values # -######################### - -rndReal = 100 * rand() -rndInteger = round(Integer, 100 * rand()) -rndBoolean = rand() > 0.5 -rndString = Random.randstring(12) - -cacheReal = 0.0 -cacheInteger = 0 -cacheBoolean = false -cacheString = "" - -fmiSet(fmuStruct, - [realValueReferences[1], integerValueReferences[1], booleanValueReferences[1], stringValueReferences[1]], - [rndReal, rndInteger, rndBoolean, rndString]) -@test fmiGet(fmuStruct, - [realValueReferences[1], integerValueReferences[1], booleanValueReferences[1], stringValueReferences[1]]) == - [rndReal, rndInteger, rndBoolean, rndString] - -#@test fmiGetStartValue(fmuStruct, "p_enumeration") == "myEnumeration1" -@test fmiGetStartValue(fmuStruct, "p_string") == "Hello World!" -@test fmiGetStartValue(fmuStruct, "p_real") == 0.0 - -################## -# Testing Arrays # -################## - -rndReal = [100 * rand(), 100 * rand()] -rndInteger = [round(Integer, 100 * rand()), round(Integer, 100 * rand())] -rndBoolean = [(rand() > 0.5), (rand() > 0.5)] -tmp = Random.randstring(8) -rndString = [tmp, tmp] - -cacheReal = [0.0, 0.0] -cacheInteger = [FMI.fmi2Integer(0), FMI.fmi2Integer(0)] -cacheBoolean = [FMI.fmi2Boolean(false), FMI.fmi2Boolean(false)] -cacheString = [pointer(""), pointer("")] - -#@test fmiGetStartValue(fmuStruct, ["p_enumeration", "p_string", "p_real"]) == ["myEnumeration1", "Hello World!", 0.0] -@test fmiGetStartValue(fmuStruct, ["p_string", "p_real"]) == ["Hello World!", 0.0] - -#################################### -# Testing input/output derivatives # -#################################### - -@test fmiSetRealInputDerivatives(fmuStruct, ["u_real"], ones(FMI.fmi2Integer, 1), zeros(1)) == 0 - -@test fmiExitInitializationMode(fmuStruct) == 0 -@test fmiDoStep(fmuStruct, 0.1) == 0 - -dirs = fmiGetRealOutputDerivatives(fmuStruct, ["y_real"], ones(FMI.fmi2Integer, 1)) -@test dirs == 0.0 # ToDo: Force a `dirs != 0.0` - -############ -# Clean up # -############ - -fmiUnload(myFMU) diff --git a/test/FMI2/load_save.jl b/test/FMI2/load_save.jl deleted file mode 100644 index 5c15b332..00000000 --- a/test/FMI2/load_save.jl +++ /dev/null @@ -1,91 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using JLD2 -using CSV -using DataFrames -using MAT - -# our simulation setup -t_start = 0.0 -t_stop = 8.0 - -# load the FMU container -fmuStruct, myFMU = getFMUStruct("SpringFrictionPendulum1D") - -recordValues = ["mass.s", "mass.v"] -solutionME = fmiSimulateME(myFMU, (t_start, t_stop); recordValues=recordValues, solver=FBDF(autodiff=false)) -solutionCS = fmiSimulateCS(myFMU, (t_start, t_stop); recordValues=recordValues) - -# ME - -fmiSaveSolution(solutionME, "solutionME.jld2") - -#@warn "Loading solution tests are disabled for now." -#anotherSolutionME = solutionME -anotherSolutionME = fmiLoadSolution("solutionME.jld2") - -@test solutionME.success == true -@test solutionME.success == anotherSolutionME.success -@test solutionME.states.u == anotherSolutionME.states.u -@test solutionME.states.t == anotherSolutionME.states.t -@test solutionME.values.saveval == anotherSolutionME.values.saveval -@test solutionME.values.t == anotherSolutionME.values.t - -# ME-BONUS: events -@test solutionME.events == anotherSolutionME.events - -# test csv -x = collect.(solutionME.values.saveval) -v = [tup[k] for tup in x, k in 1:length(x[1])] -fmiSaveSolutionCSV(solutionME, "solutionME.csv") -csv_df = CSV.read("solutionME.csv", DataFrame) - -@test v[:,1] == csv_df[!, 2] -@test solutionME.values.t == csv_df[!, 1] - -# test mat -fmiSaveSolutionMAT(solutionME, "solutionME.mat") -vars = matread("solutionME.mat") -@test vars["time"] == solutionME.values.t -for i in 1:length(solutionME.valueReferences) - key = replace(fmi2ValueReferenceToString(solutionME.component.fmu, solutionME.valueReferences[i])[1], "." => "_") - @test vars[key] == v[:,i] -end - -# CS - -fmiSaveSolution(solutionCS, "solutionCS.jld2") - -#@warn "Loading solution tests are disabled for now." -#anotherSolutionCS = solutionCS -anotherSolutionCS = fmiLoadSolution("solutionCS.jld2") - -@test solutionCS.success == true -@test solutionCS.success == anotherSolutionCS.success -@test solutionCS.values.saveval == anotherSolutionCS.values.saveval -@test solutionCS.values.t == anotherSolutionCS.values.t - -# test csv -x = collect.(solutionCS.values.saveval) -v = [tup[k] for tup in x, k in 1:length(x[1])] -fmiSaveSolutionCSV(solutionCS, "solutionCS.csv") -csv_df = CSV.read("solutionCS.csv", DataFrame) - -@test v[:,1] == csv_df[!, 2] -@test solutionCS.values.t == csv_df[!, 1] - - -# test mat -fmiSaveSolutionMAT(solutionCS, "solutionME.mat") -vars = matread("solutionME.mat") -@test vars["time"] == solutionCS.values.t -for i in 1:length(solutionCS.valueReferences) - key = replace(fmi2ValueReferenceToString(solutionCS.component.fmu, solutionCS.valueReferences[i])[1], "." => "_") - @test vars[key] == v[:,i] -end - -# unload the FMU, remove unpacked data on disc ("clean up") -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI2/performance.jl b/test/FMI2/performance.jl deleted file mode 100644 index 66fb138e..00000000 --- a/test/FMI2/performance.jl +++ /dev/null @@ -1,228 +0,0 @@ -# -# Copyright (c) 2023 Tobias Thummerer, Lars Mikelsons -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# this is temporary until it's implemented in native Julia, see: -# https://discourse.julialang.org/t/debug-has-massive-performance-impact/103974/19 -using Logging -if Sys.iswindows() - Logging.disable_logging(Logging.Debug) -end - -using FMI, FMI.FMIImport, FMI.FMIImport.FMICore, FMIZoo -using BenchmarkTools, Test - -fmuStruct, myFMU = getFMUStruct("BouncingBall1D", "Dymola", "2022x"; type=:ME) - -c = fmi2Instantiate!(fmu) - -evalBenchmark = function(b) - res = run(b) - min_time = min(res.times...) - memory = res.memory - allocs = res.allocs - return min_time, memory, allocs -end - -########## enter / exit initialization mode ########## - -function enterExitInitializationModeReset(c) - fmi2Reset(c) - fmi2EnterInitializationMode(c) - fmi2ExitInitializationMode(c) - return nothing -end - -b = @benchmarkable enterExitInitializationModeReset($c) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 0 -@test memory <= 0 - -########## string-value-reference conversion ########## - -buffer = zeros(fmi2Real, 2) -vrs_str = ["mass_radius", "der(mass_v)"] -vrs = prepareValueReference(fmu, vrs_str) - -function stringToValueReference(md, name) - fmi2StringToValueReference(md, name) - return nothing -end - -b = @benchmarkable stringToValueReference($fmu.modelDescription, $vrs_str[1]) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 0 -@test memory <= 0 - -b = @benchmarkable stringToValueReference($fmu.modelDescription, $vrs_str) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 1 # allocation of one tuple, containing the model description -@test memory <= 64 - -########## get real ########## - -vrs = prepareValueReference(fmu, vrs_str) - -function getReal!(c, vrs, buffer) - fmi2GetReal!(c, vrs, buffer) - return nothing -end -function getReal(c, vrs) - fmi2GetReal(c, vrs) - return nothing -end - -b = @benchmarkable getReal!($c, $vrs, $buffer) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 0 -@test memory <= 0 - -b = @benchmarkable getReal!($c, $vrs_str, $buffer) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 1 # allocation for on-the-fly string conversion -@test memory <= 64 - -b = @benchmarkable getReal($c, $vrs_str) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 2 # allocation for on-the-fly string conversion AND allocating an array for the results -@test memory <= 144 - -########## get derivatives ########## - -buffer = zeros(fmi2Real, 2) -nx = Csize_t(length(buffer)) - -function getDerivatives!(c, buffer, nx) - fmi2GetDerivatives!(c, buffer, nx) - return nothing -end - -function getDerivatives!(c, buffer) - fmi2GetDerivatives!(c, buffer) - return nothing -end - -function getDerivatives(c) - fmi2GetDerivatives(c) - return nothing -end - -b = @benchmarkable getDerivatives!($c, $buffer, $nx) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 0 -@test memory <= 0 - -b = @benchmarkable getDerivatives!($c, $buffer) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 0 -@test memory <= 0 - -b = @benchmarkable getDerivatives($c) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 1 # this is the allocation for the 1 result array -@test memory <= 80 # this is memory for 2 array elements and the array pointer (+1) - -########## f(x) evaluation / right-hand side ########## - -c.solution = FMU2Solution(c) -fmi2Reset(c) -fmi2EnterInitializationMode(c) -fmi2ExitInitializationMode(c) - -import FMI.FMIImport.FMICore: eval! - -cRef = UInt64(pointer_from_objref(c)) -dx = zeros(fmi2Real, 2) -dx_refs = c.fmu.modelDescription.derivativeValueReferences -y = zeros(fmi2Real, 0) -y_refs = zeros(fmi2ValueReference, 0) -x = zeros(fmi2Real, 2) -u = zeros(fmi2Real, 0) -u_refs = zeros(fmi2ValueReference, 0) -p = zeros(fmi2Real, 0) -p_refs = zeros(fmi2ValueReference, 0) -ec = zeros(fmi2Real, 0) -ec_idcs = zeros(fmi2ValueReference, 0) -t = -1.0 -b = @benchmarkable eval!($cRef, $dx, $dx_refs, $y, $y_refs, $x, $u, $u_refs, $p, $p_refs, $ec, $ec_idcs, $t) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 0 -@test memory <= 0 - -b = @benchmarkable $c(dx=$dx, y=$y, y_refs=$y_refs, x=$x, u=$u, u_refs=$u_refs, p=$p, p_refs=$p_refs, ec=$ec, ec_idcs=$ec_idcs, t=$t) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 9 # [ToDo] 3 `ignore_derivatives` causes an extra 3 allocations (48 bytes) -@test memory <= 224 # [ToDo] reduce again 48 - -_p = () -b = @benchmarkable FMI.fx($c, $dx, $x, $_p, $t, nothing) -min_time, memory, allocs = evalBenchmark(b) -# ToDo: This is too much, but currently necessary to be compatible with all AD-frameworks, as well as ForwardDiffChainRules -@test allocs <= 9 # [ToDo]3 -@test memory <= 224 # [ToDo] reduce again 48 - -# AD - -using FMISensitivity -import FMISensitivity.ChainRulesCore -import FMISensitivity.ChainRulesCore: ZeroTangent, NoTangent -import FMISensitivity.ForwardDiff -import FMISensitivity.ReverseDiff - -# frule -Ξ”x = similar(x) -Ξ”tuple = (NoTangent(), NoTangent(), NoTangent(), NoTangent(), NoTangent(), NoTangent(), Ξ”x, NoTangent(), NoTangent(), NoTangent(), NoTangent(), NoTangent(), NoTangent(), NoTangent()) -fun = function(_x) - Ξ©, βˆ‚Ξ© = ChainRulesCore.frule(Ξ”tuple, eval!, cRef, dx, dx_refs, y, y_refs, _x, u, u_refs, p, p_refs, ec, ec_idcs, t) -end - -b = @benchmarkable fun($x) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 4 -@test memory <= 144 - -# rrule -fun = function (_x) - Ξ©, pullback = ChainRulesCore.rrule(eval!, cRef, dx, dx_refs, y, y_refs, _x, u, u_refs, p, p_refs, ec, ec_idcs, t) -end - -b = @benchmarkable fun($x) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 9 -@test memory <= 400 - -# rrule pullback -Ξ©, pullback = ChainRulesCore.rrule(eval!, cRef, dx, dx_refs, y, y_refs, x, u, u_refs, p, p_refs, ec, ec_idcs, t) -rΜ„ = copy(dx) -fun = function(_rΜ„, _pullback) - _pullback(_rΜ„) -end - -b = @benchmarkable fun($rΜ„, $pullback) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 5 -@test memory <= 144 - -# eval! -fun = function(_x) - eval!(cRef, dx, dx_refs, y, y_refs, _x, u, u_refs, p, p_refs, ec, ec_idcs, t) -end - -b = @benchmarkable fun($x) -min_time, memory, allocs = evalBenchmark(b) -@test allocs <= 0 -@test memory <= 0 - -config = ForwardDiff.JacobianConfig(fun, x, ForwardDiff.Chunk{length(x)}()) -b = @benchmarkable ForwardDiff.jacobian($fun, $x, $config) -min_time, memory, allocs = evalBenchmark(b) -# ToDo: This is way too much! -@test allocs <= 240 -@test memory <= 13000 - -b = @benchmarkable ReverseDiff.jacobian($fun, $x) -min_time, memory, allocs = evalBenchmark(b) -# ToDo: This is way too much! -@test allocs <= 240 -@test memory <= 12000 \ No newline at end of file diff --git a/test/FMI2/plots.jl b/test/FMI2/plots.jl deleted file mode 100644 index 5f26625b..00000000 --- a/test/FMI2/plots.jl +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using Plots - -# our simulation setup -t_start = 0.0 -t_stop = 8.0 - -# load the FMU container -fmuStruct, myFMU = getFMUStruct("SpringPendulum1D") - -# print some useful FMU-information into the REPL -fmiInfo(myFMU) - -# make an instance from the FMU -fmiInstantiate!(myFMU) - -recordValues = ["mass.s", "mass.v"] -solutionME = fmiSimulateME(myFMU, (t_start, t_stop); recordValues=recordValues, solver=FBDF(autodiff=false)) -solutionCS = fmiSimulateCS(myFMU, (t_start, t_stop); recordValues=recordValues) - -# plot the results -fig = fmiPlot(solutionME) - -fig = Plots.plot() -fmiPlot!(fig, solutionME) - -fig = fmiPlot(solutionCS) - -fig = Plots.plot() -fmiPlot!(fig, solutionCS) - -# unload the FMU, remove unpacked data on disc ("clean up") -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI2/sim_CS.jl b/test/FMI2/sim_CS.jl deleted file mode 100644 index 6d85c515..00000000 --- a/test/FMI2/sim_CS.jl +++ /dev/null @@ -1,68 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# case 1: CS-FMU Simulation - -fmuStruct, myFMU = getFMUStruct("SpringPendulum1D") - -t_start = 0.0 -t_stop = 8.0 - -# test without recording values (but why?) -solution = fmiSimulateCS(fmuStruct, (t_start, t_stop); dt=1e-2) -@test solution.success - -# test with recording values -solution = fmiSimulateCS(fmuStruct, (t_start, t_stop); dt=1e-2, recordValues=["mass.s", "mass.v"]) -@test solution.success -@test length(solution.values.saveval) == t_start:1e-2:t_stop |> length -@test length(solution.values.saveval[1]) == 2 - -t = solution.values.t -s = collect(d[1] for d in solution.values.saveval) -v = collect(d[2] for d in solution.values.saveval) -@test t[1] == t_start -@test t[end] == t_stop - -# reference values from Simulation in Dymola2020x (Dassl) -@test s[1] == 0.5 -@test v[1] == 0.0 - -if ENV["EXPORTINGTOOL"] == "Dymola/2020x" # ToDo: Linux FMU was corrupted - @test s[end] β‰ˆ 0.509219 atol=1e-1 - @test v[end] β‰ˆ 0.314074 atol=1e-1 -end - -fmiUnload(myFMU) - -# case 2: CS-FMU with input signal - -extForce_t = function (t::Real, u::AbstractArray{<:Real}) - u[1] = sin(t) -end - -extForce_ct = function (c::Union{FMU2Component, Nothing}, t::Real, u::AbstractArray{<:Real}) - u[1] = sin(t) -end - -fmuStruct, myFMU = getFMUStruct("SpringPendulumExtForce1D") - -for inpfct in [extForce_ct, extForce_t] - global solution - - solution = fmiSimulateCS(fmuStruct, (t_start, t_stop); dt=1e-2, recordValues=["mass.s", "mass.v"], inputValueReferences=["extForce"], inputFunction=inpfct) - @test solution.success - @test length(solution.values.saveval) > 0 - @test length(solution.values.t) > 0 - - @test t[1] == t_start - @test t[end] == t_stop -end - -# reference values from Simulation in Dymola2020x (Dassl) -@test [solution.values.saveval[1]...] == [0.5, 0.0] -@test sum(abs.([solution.values.saveval[end]...] - [0.613371, 0.188633])) < 0.2 -fmiUnload(myFMU) - diff --git a/test/FMI2/sim_ME.jl b/test/FMI2/sim_ME.jl deleted file mode 100644 index 2c2a1be9..00000000 --- a/test/FMI2/sim_ME.jl +++ /dev/null @@ -1,193 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using DifferentialEquations -using Sundials - -# to use autodiff! -using FMISensitivity -using FMI.FMIImport.FMICore: sense_setindex! - -t_start = 0.0 -t_stop = 8.0 -dtmax_inputs = 1e-3 -rand_x0 = rand(2) - -kwargs = Dict(:dtmin => 1e-64, :abstol => 1e-8, :reltol => 1e-6, :dt => 1e-32) -solvers = [Tsit5(), Rodas5(autodiff=false)] # [Tsit5(), FBDF(autodiff=false), FBDF(autodiff=true), Rodas5(autodiff=false), Rodas5(autodiff=true)] - -extForce_t = function(t::Real, u::AbstractArray{<:Real}) - sense_setindex!(u, sin(t), 1) -end - -extForce_cxt = function(c::Union{FMU2Component, Nothing}, x::Union{AbstractArray{<:Real}, Nothing}, t::Real, u::AbstractArray{<:Real}) - x1 = 0.0 - if x != nothing - x1 = x[1] - end - sense_setindex!(u, sin(t) * x1, 1) -end - -for solver in solvers - - global fmuStruct, fmu, solution - - @info "Testing solver: $(solver)" - - # case 1: ME-FMU with state events - - fmuStruct, fmu = getFMUStruct("SpringFrictionPendulum1D") - - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); solver=solver, kwargs...) - @test length(solution.states.u) > 0 - @test length(solution.states.t) > 0 - - @test solution.states.t[1] == t_start - @test solution.states.t[end] == t_stop - - # reference values from Simulation in Dymola2020x (Dassl) - @test solution.states.u[1] == [0.5, 0.0] - @test sum(abs.(solution.states.u[end] - [1.06736, -1.03552e-10])) < 0.1 - fmiUnload(fmu) - - # case 2: ME-FMU with state and time events - - fmuStruct, fmu = getFMUStruct("SpringTimeFrictionPendulum1D") - - ### test without recording values - - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); solver=solver, kwargs...) - @test length(solution.states.u) > 0 - @test length(solution.states.t) > 0 - - @test solution.states.t[1] == t_start - @test solution.states.t[end] == t_stop - - # reference values from Simulation in Dymola2020x (Dassl) - @test solution.states.u[1] == [0.5, 0.0] - @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 - - ### test with recording values (variable step record values) - - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); recordValues="mass.f", solver=solver, kwargs...) - dataLength = length(solution.states.u) - @test dataLength > 0 - @test length(solution.states.t) == dataLength - @test length(solution.values.saveval) == dataLength - @test length(solution.values.t) == dataLength - - @test solution.states.t[1] == t_start - @test solution.states.t[end] == t_stop - @test solution.values.t[1] == t_start - @test solution.values.t[end] == t_stop - - # value/state getters - @test solution.states.t == fmi2GetSolutionTime(solution) - @test collect(s[1] for s in solution.values.saveval) == fmi2GetSolutionValue(solution, 1; isIndex=true) - @test collect(u[1] for u in solution.states.u ) == fmi2GetSolutionState(solution, 1; isIndex=true) - @test isapprox(fmi2GetSolutionState(solution, 2; isIndex=true), fmi2GetSolutionDerivative(solution, 1; isIndex=true); atol=1e-1) # tolerance is large, because Rosenbrock23 solution derivative is not that accurate (other solvers reach 1e-4 for this example) - @info "Max error of solver polynomial derivative: $(max(abs.(fmi2GetSolutionState(solution, 2; isIndex=true) .- fmi2GetSolutionDerivative(solution, 1; isIndex=true))...))" - - # reference values from Simulation in Dymola2020x (Dassl) - @test sum(abs.(solution.states.u[1] - [0.5, 0.0])) < 1e-4 - @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 - @test abs(solution.values.saveval[1][1] - 0.75) < 1e-4 - @test sum(abs.(solution.values.saveval[end][1] - -0.54435 )) < 0.015 - - ### test with recording values (fixed step record values) - - tData = t_start:0.1:t_stop - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); recordValues="mass.f", saveat=tData, solver=solver, kwargs...) - @test length(solution.states.u) == length(tData) - @test length(solution.states.t) == length(tData) - @test length(solution.values.saveval) == length(tData) - @test length(solution.values.t) == length(tData) - - @test solution.states.t[1] == t_start - @test solution.states.t[end] == t_stop - @test solution.values.t[1] == t_start - @test solution.values.t[end] == t_stop - - # reference values from Simulation in Dymola2020x (Dassl) - @test sum(abs.(solution.states.u[1] - [0.5, 0.0])) < 1e-4 - @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 - @test abs(solution.values.saveval[1][1] - 0.75) < 1e-4 - @test sum(abs.(solution.values.saveval[end][1] - -0.54435 )) < 0.015 - - fmiUnload(fmu) - - # case 3a: ME-FMU without events, but with input signal - - fmuStruct, fmu = getFMUStruct("SpringPendulumExtForce1D") - - for inpfct in [extForce_cxt, extForce_t] - - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); inputValueReferences=["extForce"], inputFunction=inpfct, solver=solver, dtmax=dtmax_inputs, kwargs...) # dtmax to force resolution - @test length(solution.states.u) > 0 - @test length(solution.states.t) > 0 - - @test solution.states.t[1] == t_start - @test solution.states.t[end] == t_stop - end - - # reference values `extForce_t` from Simulation in Dymola2020x (Dassl) - @test solution.states.u[1] == [0.5, 0.0] - @test sum(abs.(solution.states.u[end] - [0.613371, 0.188633])) < 0.012 - fmiUnload(fmu) - - # case 3b: ME-FMU without events, but with input signal (autodiff) - - fmuStruct, fmu = getFMUStruct("SpringPendulumExtForce1D") - - # there are issues with AD in Julia < 1.7.0 - # ToDo: Fix Linux FMU - if VERSION >= v"1.7.0" && !Sys.islinux() - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); solver=solver, dtmax=dtmax_inputs, kwargs...) # dtmax to force resolution - - @test length(solution.states.u) > 0 - @test length(solution.states.t) > 0 - - @test solution.states.t[1] == t_start - @test solution.states.t[end] == t_stop - - # reference values (no force) from Simulation in Dymola2020x (Dassl) - @test solution.states.u[1] == [0.5, 0.0] - @test sum(abs.(solution.states.u[end] - [0.509219, 0.314074])) < 0.01 - end - - fmiUnload(fmu) - - # case 4: ME-FMU without events, but saving value interpolation - - fmuStruct, fmu = getFMUStruct("SpringPendulumExtForce1D") - - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); saveat=tData, recordValues=:states, solver=solver, kwargs...) - @test length(solution.states.u) == length(tData) - @test length(solution.states.t) == length(tData) - @test length(solution.values.saveval) == length(tData) - @test length(solution.values.t) == length(tData) - - for i in 1:length(tData) - @test sum(abs(solution.states.t[i] - solution.states.t[i])) < 1e-6 - @test sum(abs(solution.states.u[i][1] - solution.values.saveval[i][1])) < 1e-6 - @test sum(abs(solution.states.u[i][2] - solution.values.saveval[i][2])) < 1e-6 - end - - fmiUnload(fmu) - - # case 5: ME-FMU with different (random) start state - - fmuStruct, fmu = getFMUStruct("SpringFrictionPendulum1D") - - solution = fmiSimulateME(fmuStruct, (t_start, t_stop); x0=rand_x0, solver=solver, kwargs...) - @test length(solution.states.u) > 0 - @test length(solution.states.t) > 0 - - @test solution.states.t[1] == t_start - @test solution.states.t[end] == t_stop - - @test solution.states.u[1] == rand_x0 - fmiUnload(fmu) -end \ No newline at end of file diff --git a/test/FMI2/sim_auto.jl b/test/FMI2/sim_auto.jl deleted file mode 100644 index 62dba71f..00000000 --- a/test/FMI2/sim_auto.jl +++ /dev/null @@ -1,49 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -pathToFMU = get_model_filename("SpringPendulum1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# load FMU in temporary directory -fmuStruct, myFMU = getFMUStruct(pathToFMU) -@test isfile(myFMU.zipPath) == true -@test isdir(splitext(myFMU.zipPath)[1]) == true -fmiUnload(myFMU) - -# load FMU in source directory -fmuDir = joinpath(splitpath(pathToFMU)[1:end-1]...) -fmuStruct, myFMU = getFMUStruct(pathToFMU; unpackPath=fmuDir) -@test isfile(splitext(pathToFMU)[1] * ".zip") == true -@test isdir(splitext(pathToFMU)[1]) == true - -t_start = 0.0 -t_stop = 8.0 -dt = 1e-2 - -# test without recording values (but why?) -sol = fmiSimulate(fmuStruct, (t_start, t_stop); dt=dt) -@test sol.success - -# test with recording values -solution = fmiSimulate(fmuStruct, (t_start, t_stop); dt=dt, recordValues=["mass.s", "mass.v"], setup=true) -@test solution.success -@test length(solution.values.saveval) == length(t_start:dt:t_stop) -@test length(solution.values.saveval[1]) == 2 - -t = solution.values.t -s = collect(d[1] for d in solution.values.saveval) -v = collect(d[2] for d in solution.values.saveval) -@test t[1] == t_start -@test t[end] == t_stop - -# reference values from Simulation in Dymola2020x (Dassl) -@test s[1] == 0.5 -@test v[1] == 0.0 - -if ENV["EXPORTINGTOOL"] == "Dymola/2020x" # ToDo: Linux FMU was corrupted - @test s[end] β‰ˆ 0.509219 atol=1e-1 - @test v[end] β‰ˆ 0.314074 atol=1e-1 -end - -fmiUnload(myFMU) diff --git a/test/FMI2/sim_zero_state.jl b/test/FMI2/sim_zero_state.jl deleted file mode 100644 index 9e135fb3..00000000 --- a/test/FMI2/sim_zero_state.jl +++ /dev/null @@ -1,44 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using DifferentialEquations: Tsit5 - -t_start = 0.0 -t_stop = 8.0 -solver=FBDF(autodiff=false) -dtmax = 0.01 - -extForce_t! = function(t, u) - u[1] = sin(t) -end - -fmuStruct, myFMU = getFMUStruct("SpringPendulumExtForce1D") - -# make a dummy zero-state FMU by overwriting the state field (ToDo: Use an actual zero state FMU from FMIZoo.jl) -myFMU.modelDescription.stateValueReferences = [] -myFMU.modelDescription.derivativeValueReferences = [] -myFMU.modelDescription.numberOfEventIndicators = 0 -myFMU.isZeroState = true - -comp = fmiInstantiate!(myFMU; loggingOn=false) -@test comp != 0 - -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = comp -end -@assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -solution = fmiSimulateME(fmuStruct, (t_start, t_stop); solver=solver, dtmax=dtmax, recordValues=["a"], inputValueReferences=myFMU.modelDescription.inputValueReferences, inputFunction=extForce_t!) -@test isnothing(solution.states) - -@test solution.values.t[1] == t_start -@test solution.values.t[end] == t_stop - -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI2/state.jl b/test/FMI2/state.jl deleted file mode 100644 index 4638f331..00000000 --- a/test/FMI2/state.jl +++ /dev/null @@ -1,55 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMI.FMIImport - -############### -# Prepare FMU # -############### - -fmuStruct, myFMU = getFMUStruct("SpringPendulum1D") - -comp = fmi2Instantiate!(myFMU; loggingOn=true) -@test comp != 0 - -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = comp -end -@assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -@test fmi2SetupExperiment(fmuStruct, 0.0) == fmi2StatusOK -@test fmi2EnterInitializationMode(fmuStruct) == fmi2StatusOK -@test fmi2ExitInitializationMode(fmuStruct) == fmi2StatusOK - -########################### -# Testing state functions # -########################### - -if fmiCanGetSetState(myFMU) - @test fmiGet(fmuStruct, "mass.s") == 0.5 - - FMUstate = fmiGetState(fmuStruct) - - fmiSet(fmuStruct, "mass.s", 10.0) - @test fmiGet(fmuStruct, "mass.s") == 10.0 - - fmiSetState(fmuStruct, FMUstate) - @test fmiGet(fmuStruct, "mass.s") == 0.5 - - fmiFreeState!(fmuStruct, FMUstate) -else - @info "The FMU provided from the tool `$(ENV["EXPORTINGTOOL"])` does not support state get and set. Skipping related tests." -end - -############ -# Clean up # -############ - -fmiUnload(myFMU) diff --git a/test/FMI3/cs_me.jl b/test/FMI3/cs_me.jl deleted file mode 100644 index 98bb0aa7..00000000 --- a/test/FMI3/cs_me.jl +++ /dev/null @@ -1,54 +0,0 @@ -############### -# Prepare FMU # -############### - -t_start = 0.0 -t_stop = 1.0 - -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") -@test fmiIsCoSimulation(myFMU) -@test fmiIsModelExchange(myFMU) -# inst = fmiInstantiate!(myFMU; loggingOn=false) -# @test inst != 0 - -# # choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = inst -end -sol = fmiSimulateCS(fmuStruct, t_start, t_stop) -@test sol.success -sol = fmiSimulateME(fmuStruct, t_start, t_stop) -@test sol.success -fmiUnload(myFMU) - -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") -inst = fmi3InstantiateModelExchange!(myFMU; loggingOn=false) -@test inst.type == FMI.fmi3TypeModelExchange -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = inst -end -sol = fmiSimulate(fmuStruct, t_start, t_stop) -@test sol.success -fmiUnload(myFMU) - -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") -inst = fmi3InstantiateCoSimulation!(myFMU; loggingOn=false) -@test inst.type == FMI.fmi3TypeCoSimulation -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = inst -end -sol = fmiSimulate(fmuStruct, t_start, t_stop) -@test sol.success -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI3/exec_config.jl b/test/FMI3/exec_config.jl deleted file mode 100644 index 59286bf0..00000000 --- a/test/FMI3/exec_config.jl +++ /dev/null @@ -1,80 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMI.FMIImport - -t_start = 0.0 -t_stop = 1.0 - -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") - -comp = fmi3InstantiateCoSimulation!(myFMU; loggingOn=false) -@test comp != 0 -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = comp -end -@assert fmuStruct !== nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -for execConf in (FMU3_EXECUTION_CONFIGURATION_NO_FREEING, FMU3_EXECUTION_CONFIGURATION_RESET, FMU3_EXECUTION_CONFIGURATION_NO_RESET) # ToDo: Add `FMU3_EXECUTION_CONFIGURATION_NOTHING` - for mode in ([:CS]) - global fmuStruct - @info "\t$(mode) | $(execConf)" - - myFMU.executionConfig = execConf - - # sim test - numInst = length(myFMU.instances) - - if mode == :CS - fmiSimulateCS(fmuStruct, t_start, t_stop) - elseif mode == :ME - fmiSimulateME(fmuStruct, t_start, t_stop) - else - @assert false "Unknown mode `$(mode)`." - end - - if execConf.instantiate - numInst += 1 - end - if execConf.freeInstance - numInst -= 1 - end - - @test length(myFMU.instances) == numInst - - # prepare next run start - if envFMUSTRUCT == "FMU" - if execConf.freeInstance - fmi3FreeInstance!(myFMU) - end - - if mode == :CS - fmi3InstantiateCoSimulation!(myFMU) - elseif mode == :ME - fmi3InstantiateModelExchange!(myFMU) - end - - elseif envFMUSTRUCT == "FMUCOMPONENT" - if execConf.freeInstance - fmi3FreeInstance!(fmuStruct) - end - if mode == :CS - fmi3InstantiateCoSimulation!(myFMU) - elseif mode == :ME - fmi3InstantiateModelExchange!(myFMU) - end - - end - # prepare next run end - - end -end - -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI3/getter_setter.jl b/test/FMI3/getter_setter.jl deleted file mode 100644 index 45c65d62..00000000 --- a/test/FMI3/getter_setter.jl +++ /dev/null @@ -1,82 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -import FMI.FMIImport.FMICore - -############### -# Prepare FMU # -############### - -myFMU = fmiLoad("Feedthrough", "ModelicaReferenceFMUs", "0.0.20", "3.0") -inst = fmi3InstantiateCoSimulation!(myFMU; loggingOn=true) -@test inst != 0 - -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = inst -end -@assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -@test fmi3EnterInitializationMode(fmuStruct) == 0 -@test fmi3ExitInitializationMode(fmuStruct) == 0 - -realValueReferences = ["Float32_continuous_input", "Float64_continuous_input"] -integerValueReferences = ["Int32_input", "Int64_input"] -booleanValueReferences = ["Boolean_input", "Boolean_output"] -stringValueReferences = ["String_parameter", "String_parameter"] - -######################### -# Testing Single Values # -######################### - -rndReal = 100 * rand() -rndInteger = round(Integer, 100 * rand()) -rndBoolean = rand() > 0.5 -rndString = Random.randstring(12) - -cacheReal = 0.0 -cacheInteger = 0 -cacheBoolean = false -cacheString = "" - -fmiSet(fmuStruct, - [realValueReferences[1], integerValueReferences[1], booleanValueReferences[1], stringValueReferences[1]], - [Float32(rndReal), rndInteger, rndBoolean, rndString]) -@test fmiGet(fmuStruct, - [realValueReferences[1], integerValueReferences[1], booleanValueReferences[1], stringValueReferences[1]]) == - [Float32(rndReal), rndInteger, FMICore.fmi3Boolean(rndBoolean), rndString] - -#@test fmiGetStartValue(fmuStruct, "p_enumeration") == "myEnumeration1" -# println(fmi3ModelVariablesForValueReference(inst.fmu.modelDescription, UInt32(29))) -@test fmiGetStartValue(fmuStruct, "String_parameter") == "Set me!" -@test fmiGetStartValue(fmuStruct, "Float32_continuous_input") == 0.0 - -################## -# Testing Arrays # -################## - -rndReal = [100 * rand(), 100 * rand()] -rndInteger = [round(Integer, 100 * rand()), round(Integer, 100 * rand())] -rndBoolean = [(rand() > 0.5), (rand() > 0.5)] -tmp = Random.randstring(8) -rndString = [tmp, tmp] - -cacheReal = [0.0, 0.0] -cacheInteger = [FMI.fmi3Int32(0), FMI.fmi3Int32(0)] -cacheBoolean = [FMI.fmi3Boolean(false), FMI.fmi3Boolean(false)] -cacheString = [pointer(""), pointer("")] - -#@test fmiGetStartValue(fmuStruct, ["p_enumeration", "p_string", "p_real"]) == ["myEnumeration1", "Hello World!", 0.0] -@test fmiGetStartValue(fmuStruct, ["String_parameter", "Float32_continuous_input"]) == ["Set me!", 0.0] - -############ -# Clean up # -############ - -fmiUnload(myFMU) diff --git a/test/FMI3/load_save.jl b/test/FMI3/load_save.jl deleted file mode 100644 index e202d922..00000000 --- a/test/FMI3/load_save.jl +++ /dev/null @@ -1,51 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using JLD2 - -# our simulation setup -t_start = 0.0 -t_stop = 8.0 - -# load the FMU container -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") - -recordValues = ["h", "v"] -solutionME = fmiSimulateME(myFMU, t_start, t_stop; recordValues=recordValues) -solutionCS = fmiSimulateCS(myFMU, t_start, t_stop; recordValues=recordValues) - -# ME - -fmiSaveSolution(solutionME, "solutionME.jld2") - -#@warn "Loading solution tests are disabled for now." -#anotherSolutionME = solutionME -anotherSolutionME = fmiLoadSolution("solutionME.jld2") - -@test solutionME.success == true -@test solutionME.success == anotherSolutionME.success -@test solutionME.states.u == anotherSolutionME.states.u -@test solutionME.states.t == anotherSolutionME.states.t -@test solutionME.values.saveval == anotherSolutionME.values.saveval -@test solutionME.values.t == anotherSolutionME.values.t - -# ME-BONUS: events -@test solutionME.events == anotherSolutionME.events - -# CS - -fmiSaveSolution(solutionCS, "solutionCS.jld2") - -#@warn "Loading solution tests are disabled for now." -#anotherSolutionCS = solutionCS -anotherSolutionCS = fmiLoadSolution("solutionCS.jld2") - -@test solutionCS.success == true -@test solutionCS.success == anotherSolutionCS.success -@test solutionCS.values.saveval == anotherSolutionCS.values.saveval -@test solutionCS.values.t == anotherSolutionCS.values.t - -# unload the FMU, remove unpacked data on disc ("clean up") -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI3/plots.jl b/test/FMI3/plots.jl deleted file mode 100644 index 53b6ebbd..00000000 --- a/test/FMI3/plots.jl +++ /dev/null @@ -1,37 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using Plots - -# our simulation setup -t_start = 0.0 -t_stop = 8.0 - -# load the FMU container -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") - -# print some useful FMU-information into the REPL -fmiInfo(myFMU) - -# make an instance from the FMU -fmi3InstantiateCoSimulation!(myFMU) - -recordValues = ["h", "v"] -# solutionME = fmiSimulateME(myFMU, t_start, t_stop; recordValues=recordValues) -solutionCS = fmiSimulateCS(myFMU, t_start, t_stop; recordValues=recordValues) - -# plot the results -# fig = fmiPlot(solutionME) - -# fig = Plots.plot() -# fmiPlot!(fig, solutionME) - -fig = fmiPlot(solutionCS) - -fig = Plots.plot() -fmiPlot!(fig, solutionCS) - -# unload the FMU, remove unpacked data on disc ("clean up") -fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI3/sim_CS.jl b/test/FMI3/sim_CS.jl deleted file mode 100644 index 9c7236a1..00000000 --- a/test/FMI3/sim_CS.jl +++ /dev/null @@ -1,87 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -# case 1: CS-FMU Simulation - -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") - -comp = fmi3InstantiateCoSimulation!(myFMU; loggingOn=false) -@test comp != 0 - -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = comp -end -@assert fmuStruct !== nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -t_start = 0.0 -t_stop = 3.0 - -# test without recording values (but why?) -# solution = fmiSimulateCS(fmuStruct, t_start, t_stop) -# @test solution.success - -# test with recording values -solution = fmiSimulateCS(fmuStruct, t_start, t_stop; dt=1e-2, recordValues=["h", "v"]) -@test solution.success -@test length(solution.values.saveval) == t_start:1e-2:t_stop |> length -@test length(solution.values.saveval[1]) == 2 - -t = solution.values.t -s = collect(d[1] for d in solution.values.saveval) -v = collect(d[2] for d in solution.values.saveval) -@test t[1] == t_start -@test t[end] == t_stop - - -# reference values from Simulation in Dymola2020x (Dassl) -@test s[1] == 1.0 -@test v[1] == 0.0 - -if ENV["EXPORTINGTOOL"] == "ModelicaReferenceFMUs" # ToDo: Linux FMU was corrupted - @test s[end] β‰ˆ 0.0 atol=1e-1 - @test v[end] β‰ˆ 0.0 atol=1e-1 -end - -fmiUnload(myFMU) - -# case 2: CS-FMU with input signal not supported with BouncingBall FMU - -# function extForce(t) -# [sin(t)] -# end - -# myFMU = fmiLoad("SpringPendulumExtForce1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# comp = fmiInstantiate!(myFMU; loggingOn=false) -# @test comp != 0 - -# # choose FMU or FMUComponent -# fmuStruct = nothing -# envFMUSTRUCT = ENV["FMUSTRUCT"] -# if envFMUSTRUCT == "FMU" -# fmuStruct = myFMU -# elseif envFMUSTRUCT == "FMUCOMPONENT" -# fmuStruct = comp -# end -# @assert fmuStruct !== nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -# solution = fmiSimulateCS(fmuStruct, t_start, t_stop; dt=1e-2, recordValues=["mass.s", "mass.v"], inputValueReferences=["extForce"], inputFunction=extForce) -# @test solution.success -# @test length(solution.values.saveval) > 0 -# @test length(solution.values.t) > 0 - -# @test t[1] == t_start -# @test t[end] == t_stop - -# # reference values from Simulation in Dymola2020x (Dassl) -# @test [solution.values.saveval[1]...] == [0.5, 0.0] -# @test sum(abs.([solution.values.saveval[end]...] - [0.613371, 0.188633])) < 0.2 -# fmiUnload(myFMU) - diff --git a/test/FMI3/sim_ME.jl b/test/FMI3/sim_ME.jl deleted file mode 100644 index 8f8918bc..00000000 --- a/test/FMI3/sim_ME.jl +++ /dev/null @@ -1,261 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using DifferentialEquations: Tsit5, Rosenbrock23 - -t_start = 0.0 -t_stop = 3.0 - -# case 1: ME-FMU with state events - -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") - -comp = fmi3InstantiateModelExchange!(myFMU; loggingOn=false) -@test comp != 0 - -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = comp -end -@assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -solution = fmiSimulateME(fmuStruct, t_start, t_stop) -@test length(solution.states.u) > 0 -@test length(solution.states.t) > 0 - -@test solution.states.t[1] == t_start -@test solution.states.t[end] == t_stop - -# reference values from Simulation in Dymola2020x (Dassl) -@test solution.states.u[1] == [1.0, 0.0] -@test sum(abs.(solution.states.u[end] - [1.0, 0.0])) < 0.1 -fmiUnload(myFMU) - -# case 2: ME-FMU with state and time events - -# myFMU = fmiLoad("SpringTimeFrictionPendulum1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# comp = fmiInstantiate!(myFMU; loggingOn=false) -# @test comp != 0 - -# # choose FMU or FMUComponent -# fmuStruct = nothing -# envFMUSTRUCT = ENV["FMUSTRUCT"] -# if envFMUSTRUCT == "FMU" -# fmuStruct = myFMU -# elseif envFMUSTRUCT == "FMUCOMPONENT" -# fmuStruct = comp -# end -# @assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -# ### test without recording values - -# solution = fmiSimulateME(fmuStruct, t_start, t_stop; dtmax=0.001) # dtmax to force resolution -# @test length(solution.states.u) > 0 -# @test length(solution.states.t) > 0 - -# @test solution.states.t[1] == t_start -# @test solution.states.t[end] == t_stop - -# # reference values from Simulation in Dymola2020x (Dassl) -# @test solution.states.u[1] == [0.5, 0.0] -# @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 - -# ### test with recording values (variable step record values) - -# solution= fmiSimulateME(fmuStruct, t_start, t_stop; recordValues="mass.f", dtmax=0.001) # dtmax to force resolution -# dataLength = length(solution.states.u) -# @test dataLength > 0 -# @test length(solution.states.t) == dataLength -# @test length(solution.values.saveval) == dataLength -# @test length(solution.values.t) == dataLength - -# @test solution.states.t[1] == t_start -# @test solution.states.t[end] == t_stop -# @test solution.values.t[1] == t_start -# @test solution.values.t[end] == t_stop - -# # reference values from Simulation in Dymola2020x (Dassl) -# @test sum(abs.(solution.states.u[1] - [0.5, 0.0])) < 1e-4 -# @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 -# @test abs(solution.values.saveval[1][1] - 0.75) < 1e-4 -# @test sum(abs.(solution.values.saveval[end][1] - -0.54435 )) < 0.015 - -# ### test with recording values (fixed step record values) - -# tData = t_start:0.1:t_stop -# solution = fmiSimulateME(fmuStruct, t_start, t_stop; recordValues="mass.f", saveat=tData, dtmax=0.001) # dtmax to force resolution -# @test length(solution.states.u) == length(tData) -# @test length(solution.states.t) == length(tData) -# @test length(solution.values.saveval) == length(tData) -# @test length(solution.values.t) == length(tData) - -# @test solution.states.t[1] == t_start -# @test solution.states.t[end] == t_stop -# @test solution.values.t[1] == t_start -# @test solution.values.t[end] == t_stop - -# # reference values from Simulation in Dymola2020x (Dassl) -# @test sum(abs.(solution.states.u[1] - [0.5, 0.0])) < 1e-4 -# @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 -# @test abs(solution.values.saveval[1][1] - 0.75) < 1e-4 -# @test sum(abs.(solution.values.saveval[end][1] - -0.54435 )) < 0.015 - -# fmiUnload(myFMU) - -# # case 3a: ME-FMU without events, but with input signal (explicit solver: Tsit5) - -# function extForce(t) -# [sin(t)] -# end - -# myFMU = fmiLoad("SpringPendulumExtForce1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# comp = fmiInstantiate!(myFMU; loggingOn=false) -# @test comp != 0 - -# # choose FMU or FMUComponent -# fmuStruct = nothing -# envFMUSTRUCT = ENV["FMUSTRUCT"] -# if envFMUSTRUCT == "FMU" -# fmuStruct = myFMU -# elseif envFMUSTRUCT == "FMUCOMPONENT" -# fmuStruct = comp -# end -# @assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -# solution = fmiSimulateME(fmuStruct, t_start, t_stop; inputValueReferences=["extForce"], inputFunction=extForce, solver=Tsit5(), dtmax=0.001) # dtmax to force resolution -# @test length(solution.states.u) > 0 -# @test length(solution.states.t) > 0 - -# @test solution.states.t[1] == t_start -# @test solution.states.t[end] == t_stop - -# # reference values from Simulation in Dymola2020x (Dassl) -# @test solution.states.u[1] == [0.5, 0.0] -# @test sum(abs.(solution.states.u[end] - [0.613371, 0.188633])) < 0.012 -# fmiUnload(myFMU) - -# # case 3b: ME-FMU without events, but with input signal (implicit solver: Rosenbrock23, autodiff) - -# myFMU = fmiLoad("SpringPendulumExtForce1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# comp = fmiInstantiate!(myFMU; loggingOn=false) -# @test comp != 0 - -# # choose FMU or FMUComponent -# fmuStruct = nothing -# envFMUSTRUCT = ENV["FMUSTRUCT"] -# if envFMUSTRUCT == "FMU" -# fmuStruct = myFMU -# elseif envFMUSTRUCT == "FMUCOMPONENT" -# fmuStruct = comp -# end -# @assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -# # ToDo: autodiff=true not working currently! -# # solution = fmiSimulateME(fmuStruct, t_start, t_stop; inputValueReferences=["extForce"], inputFunction=extForce, solver=Rosenbrock23(autodiff=true), dtmax=0.001) # dtmax to force resolution -# # @test length(solution.states.u) > 0 -# # @test length(solution.states.t) > 0 - -# # @test solution.states.t[1] == t_start -# # @test solution.states.t[end] == t_stop - -# # # reference values from Simulation in Dymola2020x (Dassl) -# # @test solution.states.u[1] == [0.5, 0.0] -# # @test sum(abs.(solution.states.u[end] - [0.613371, 0.188633])) < 0.01 -# fmiUnload(myFMU) - -# # case 3c: ME-FMU without events, but with input signal (implicit solver: Rosenbrock23, no autodiff) - -# myFMU = fmiLoad("SpringPendulumExtForce1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# comp = fmiInstantiate!(myFMU; loggingOn=false) -# @test comp != 0 - -# # choose FMU or FMUComponent -# fmuStruct = nothing -# envFMUSTRUCT = ENV["FMUSTRUCT"] -# if envFMUSTRUCT == "FMU" -# fmuStruct = myFMU -# elseif envFMUSTRUCT == "FMUCOMPONENT" -# fmuStruct = comp -# end -# @assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -# solution = fmiSimulateME(fmuStruct, t_start, t_stop; inputValueReferences=["extForce"], inputFunction=extForce, solver=Rosenbrock23(autodiff=false), dtmax=0.001) # dtmax to force resolution -# @test length(solution.states.u) > 0 -# @test length(solution.states.t) > 0 - -# @test solution.states.t[1] == t_start -# @test solution.states.t[end] == t_stop - -# # reference values from Simulation in Dymola2020x (Dassl) -# @test solution.states.u[1] == [0.5, 0.0] -# @test sum(abs.(solution.states.u[end] - [0.613371, 0.188633])) < 0.01 -# fmiUnload(myFMU) - -# # case 4: ME-FMU without events, but saving value interpolation - -# myFMU = fmiLoad("SpringPendulumExtForce1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# comp = fmiInstantiate!(myFMU; loggingOn=false) -# @test comp != 0 - -# # choose FMU or FMUComponent -# fmuStruct = nothing -# envFMUSTRUCT = ENV["FMUSTRUCT"] -# if envFMUSTRUCT == "FMU" -# fmuStruct = myFMU -# elseif envFMUSTRUCT == "FMUCOMPONENT" -# fmuStruct = comp -# end -# @assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -# solution = fmiSimulateME(fmuStruct, t_start, t_stop; saveat=tData, recordValues=myFMU.modelDescription.stateValueReferences) -# @test length(solution.states.u) == length(tData) -# @test length(solution.states.t) == length(tData) -# @test length(solution.values.saveval) == length(tData) -# @test length(solution.values.t) == length(tData) - -# for i in 1:length(tData) -# @test sum(abs(solution.states.t[i] - solution.states.t[i])) < 1e-6 -# @test sum(abs(solution.states.u[i][1] - solution.values.saveval[i][1])) < 1e-6 -# @test sum(abs(solution.states.u[i][2] - solution.values.saveval[i][2])) < 1e-6 -# end - -# fmiUnload(myFMU) - -# # case 5: ME-FMU with different (random) start state - -# myFMU = fmiLoad("SpringFrictionPendulum1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) - -# comp = fmiInstantiate!(myFMU; loggingOn=false) -# @test comp != 0 - -# # choose FMU or FMUComponent -# fmuStruct = nothing -# envFMUSTRUCT = ENV["FMUSTRUCT"] -# if envFMUSTRUCT == "FMU" -# fmuStruct = myFMU -# elseif envFMUSTRUCT == "FMUCOMPONENT" -# fmuStruct = comp -# end -# @assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -# rand_x0 = rand(2) -# solution = fmiSimulateME(fmuStruct, t_start, t_stop; x0=rand_x0) -# @test length(solution.states.u) > 0 -# @test length(solution.states.t) > 0 - -# @test solution.states.t[1] == t_start -# @test solution.states.t[end] == t_stop - -# @test solution.states.u[1] == rand_x0 -# fmiUnload(myFMU) \ No newline at end of file diff --git a/test/FMI3/sim_auto.jl b/test/FMI3/sim_auto.jl deleted file mode 100644 index 193cfadc..00000000 --- a/test/FMI3/sim_auto.jl +++ /dev/null @@ -1,61 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -pathToFMU = get_model_filename("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") - -# load FMU in temporary directory -myFMU = fmiLoad(pathToFMU) -@test isfile(myFMU.zipPath) == true -@test isdir(splitext(myFMU.zipPath)[1]) == true -fmiUnload(myFMU) - -# load FMU in source directory -fmuDir = joinpath(splitpath(pathToFMU)[1:end-1]...) -myFMU = fmiLoad(pathToFMU; unpackPath=fmuDir) -@test isfile(splitext(pathToFMU)[1] * ".zip") == true -@test isdir(splitext(pathToFMU)[1]) == true - -comp = fmiInstantiate!(myFMU; loggingOn=false) -@test comp != 0 - -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = comp -end -@assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -t_start = 0.0 -t_stop = 8.0 - -# test without recording values (but why?) -sol = fmiSimulate(fmuStruct, t_start, t_stop; dt=1e-2) -@test sol.success - -# test with recording values -solution = fmiSimulate(fmuStruct, t_start, t_stop; dt=1e-2, recordValues=["mass.s", "mass.v"], setup=true) -@test solution.success -@test length(solution.values.saveval) == t_start:1e-2:t_stop |> length -@test length(solution.values.saveval[1]) == 2 - -t = solution.values.t -s = collect(d[1] for d in solution.values.saveval) -v = collect(d[2] for d in solution.values.saveval) -@test t[1] == t_start -@test t[end] == t_stop - -# reference values from Simulation in Dymola2020x (Dassl) -@test s[1] == 0.5 -@test v[1] == 0.0 - -if ENV["EXPORTINGTOOL"] == "Dymola/2020x" # ToDo: Linux FMU was corrupted - @test s[end] β‰ˆ 0.509219 atol=1e-1 - @test v[end] β‰ˆ 0.314074 atol=1e-1 -end - -fmiUnload(myFMU) diff --git a/test/FMI3/state.jl b/test/FMI3/state.jl deleted file mode 100644 index ec4ebcb7..00000000 --- a/test/FMI3/state.jl +++ /dev/null @@ -1,54 +0,0 @@ -# -# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher -# Licensed under the MIT license. See LICENSE file in the project root for details. -# - -using FMI.FMIImport - -############### -# Prepare FMU # -############### - -myFMU = fmiLoad("BouncingBall", "ModelicaReferenceFMUs", "0.0.20", "3.0") - -inst = fmi3InstantiateCoSimulation!(myFMU; loggingOn=true) -@test inst != 0 - -# choose FMU or FMUComponent -fmuStruct = nothing -envFMUSTRUCT = ENV["FMUSTRUCT"] -if envFMUSTRUCT == "FMU" - fmuStruct = myFMU -elseif envFMUSTRUCT == "FMUCOMPONENT" - fmuStruct = inst -end -@assert fmuStruct != nothing "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" - -@test fmi3EnterInitializationMode(fmuStruct) == 0 -@test fmi3ExitInitializationMode(fmuStruct) == 0 - -########################### -# Testing state functions # -########################### - -if fmiCanGetSetState(myFMU) - @test fmiGet(fmuStruct, "h") == 1 - - FMUstate = fmiGetState(fmuStruct) - - fmiSet(fmuStruct, "h", 10.0) - @test fmiGet(fmuStruct, "h") == 10.0 - - fmiSetState(fmuStruct, FMUstate) - @test fmiGet(fmuStruct, "h") == 1 - - fmiFreeState!(fmuStruct, FMUstate) -else - @info "The FMU provided from the tool `$(ENV["EXPORTINGTOOL"])` does not support state get, set, serialization and deserialization. Skipping related tests." -end - -############ -# Clean up # -############ - -fmiUnload(myFMU) diff --git a/test/Project.toml b/test/Project.toml index 4179e004..4ffc202f 100644 --- a/test/Project.toml +++ b/test/Project.toml @@ -18,7 +18,6 @@ Zygote = "e88e6eb3-aa80-5325-afca-941959d7151f" [compat] Aqua = "0.8" -FMIZoo = "0.3.3" julia = "1.6" [extras] diff --git a/test/FMI2/eval.jl b/test/eval.jl similarity index 64% rename from test/FMI2/eval.jl rename to test/eval.jl index fdd73692..b6b0db7a 100644 --- a/test/FMI2/eval.jl +++ b/test/eval.jl @@ -1,18 +1,18 @@ -using PkgEval -using FMI -using Test - -config = Configuration(; julia="1.8", time_limit=120*60); - -package = Package(; name="FMI"); - -@info "PkgEval" -result = evaluate([config], [package]) - -@info "Result" -println(result) - -@info "Log" -println(result[1, :log]) - -@test result[1, :status] == :ok +using PkgEval +using FMI +using Test + +config = Configuration(; julia = "1.10", time_limit = 120 * 60); + +package = Package(; name = "FMI"); + +@info "PkgEval" +result = evaluate([config], [package]) + +@info "Result" +println(result) + +@info "Log" +println(result[1, :log]) + +@test result[1, :status] == :ok diff --git a/test/runtests.jl b/test/runtests.jl index 2de20adc..748ab0e2 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -9,186 +9,120 @@ using Test using Aqua import Random -import FMI.FMIImport.FMICore: fmi2StatusOK, fmi3StatusOK, fmi2ComponentStateTerminated, fmi2ComponentStateInstantiated, fmi3Boolean -import FMI.FMIImport.FMICore: FMU2_EXECUTION_CONFIGURATION_NO_FREEING, FMU2_EXECUTION_CONFIGURATION_NO_RESET, FMU2_EXECUTION_CONFIGURATION_RESET, FMU2_EXECUTION_CONFIGURATION_NOTHING +using FMI.FMIImport +using FMI.FMIImport.FMIBase +using FMI.FMIImport.FMIBase.FMICore + +import FMI.FMIImport.FMIBase: FMU_EXECUTION_CONFIGURATIONS + using FMI.FMIImport using DifferentialEquations: FBDF -exportingToolsWindows = [("Dymola", "2022x")] -exportingToolsLinux = [("Dymola", "2022x")] -fmuStructs = ["FMU", "FMUCOMPONENT"] +fmuStructs = ("FMU", "FMUCOMPONENT") # enable assertions for warnings/errors for all default execution configurations -for exec in [FMU2_EXECUTION_CONFIGURATION_NO_FREEING, FMU2_EXECUTION_CONFIGURATION_NO_RESET, FMU2_EXECUTION_CONFIGURATION_RESET, FMU2_EXECUTION_CONFIGURATION_NOTHING, FMU3_EXECUTION_CONFIGURATION_NO_FREEING, FMU3_EXECUTION_CONFIGURATION_NO_RESET, FMU3_EXECUTION_CONFIGURATION_RESET] +for exec in FMU_EXECUTION_CONFIGURATIONS exec.assertOnError = true exec.assertOnWarning = true end -function getFMUStruct(modelname, tool=ENV["EXPORTINGTOOL"], version=ENV["EXPORTINGVERSION"]; kwargs...) - +function getFMUStruct( + modelname, + mode, + tool = ENV["EXPORTINGTOOL"], + version = ENV["EXPORTINGVERSION"], + fmiversion = ENV["FMIVERSION"], + fmustruct = ENV["FMUSTRUCT"]; + kwargs..., +) + # choose FMU or FMUComponent if endswith(modelname, ".fmu") - fmu = fmiLoad(modelname; kwargs...) + fmu = loadFMU(modelname; kwargs...) else - fmu = fmiLoad(modelname, tool, version; kwargs...) + fmu = loadFMU(modelname, tool, version, fmiversion; kwargs...) end - envFMUSTRUCT = ENV["FMUSTRUCT"] - - if envFMUSTRUCT == "FMU" + if fmustruct == "FMU" return fmu, fmu - elseif envFMUSTRUCT == "FMUCOMPONENT" - comp = fmiInstantiate!(fmu; loggingOn=false) - @test comp != 0 - return comp, fmu + elseif fmustruct == "FMUCOMPONENT" + inst, _ = FMI.prepareSolveFMU(fmu, nothing, mode; loggingOn = true) + @test !isnothing(inst) + return inst, fmu else - @assert false "Unknown fmuStruct, environment variable `FMUSTRUCT` = `$envFMUSTRUCT`" + @assert false "Unknown fmuStruct, variable `FMUSTRUCT` = `$(fmustruct)`" end end -function runtestsFMI2(exportingTool) - ENV["EXPORTINGTOOL"] = exportingTool[1] - ENV["EXPORTINGVERSION"] = exportingTool[2] +@testset "FMI.jl" begin + if Sys.iswindows() || Sys.islinux() + @info "Automated testing is supported on Windows/Linux." - @testset "Testing FMUs exported from $exportingTool" begin + ENV["EXPORTINGTOOL"] = "Dymola" + ENV["EXPORTINGVERSION"] = "2023x" - for str in fmuStructs - @testset "Functions for $str" begin - ENV["FMUSTRUCT"] = str + for fmiversion in (2.0, 3.0) + ENV["FMIVERSION"] = fmiversion - @info "Variable Getters / Setters (getter_setter.jl)" - @testset "Variable Getters / Setters" begin - include("FMI2/getter_setter.jl") - end + @testset "Testing FMI $(ENV["FMIVERSION"]) FMUs exported from $(ENV["EXPORTINGTOOL"]) $(ENV["EXPORTINGVERSION"])" begin - @info "Execution Configurations (exec_config.jl)" - @testset "Execution Configurations" begin - include("FMI2/exec_config.jl") - end - - @info "State Manipulation (state.jl)" - @testset "State Manipulation" begin - include("FMI2/state.jl") - end + for fmustruct in fmuStructs + ENV["FMUSTRUCT"] = fmustruct - @info "Automatic Simulation (sim_auto.jl)" - @testset "Automatic Simulation (CS or ME)" begin - include("FMI2/sim_auto.jl") - end + @testset "Functions for $(ENV["FMUSTRUCT"])" begin - @info "CS Simulation (sim_CS.jl)" - @testset "CS Simulation" begin - include("FMI2/sim_CS.jl") - end + @info "CS Simulation (sim_CS.jl)" + @testset "CS Simulation" begin + include("sim_CS.jl") + end - @info "ME Simulation (sim_ME.jl)" - @testset "ME Simulation" begin - include("FMI2/sim_ME.jl") - end + @info "ME Simulation (sim_ME.jl)" + @testset "ME Simulation" begin + include("sim_ME.jl") + end - @info "Support CS and ME simultaneously (cs_me.jl)" - @testset "Support CS and ME simultaneously" begin - include("FMI2/cs_me.jl") - end + @info "SE Simulation (sim_SE.jl)" + @testset "SE Simulation" begin + include("sim_SE.jl") + end - @info "Simulation FMU without states (sim_zero_state.jl)" - @testset "Simulation FMU without states" begin - include("FMI2/sim_zero_state.jl") - end + @info "Simulation FMU without states (sim_zero_state.jl)" + @testset "Simulation FMU without states" begin + include("sim_zero_state.jl") + end + end - @info "Loading/Saving simulation results (load_save.jl)" - @testset "Loading/Saving simulation results" begin - include("FMI2/load_save.jl") + # if VERSION >= v"1.9.0" + # @info "Performance (performance.jl)" + # @testset "Performance" begin + # include("FMI2/performance.jl") + # end + # else + @info "Julia Version $(VERSION), skipping performance tests ..." + #end end end end - # if VERSION >= v"1.9.0" - # @info "Performance (performance.jl)" - # @testset "Performance" begin - # include("FMI2/performance.jl") - # end - # else - @info "Julia Version $(VERSION), skipping performance tests ..." - #end - - @info "Plotting (plots.jl)" - @testset "Plotting" begin - include("FMI2/plots.jl") - end - end -end - -function runtestsFMI3(exportingTool) - ENV["EXPORTINGTOOL"] = exportingTool[1] - ENV["EXPORTINGVERSION"] = exportingTool[2] - - @testset "Testing FMUs exported from $exportingTool" begin - - for str in fmuStructs - @testset "Functions for $str" begin - ENV["FMUSTRUCT"] = str - @testset "Variable Getters / Setters (getter_setter.jl)" begin - include("FMI3/getter_setter.jl") - end - - @info "Execution Configurations (exec_config.jl)" - @testset "Execution Configurations" begin - include("FMI3/exec_config.jl") - end + @testset "Aqua.jl" begin + @info "Aqua: Method ambiguity" + @testset "Method ambiguities" begin + Aqua.test_ambiguities([FMI]) + end - @testset "State Manipulation (state.jl)" begin - include("FMI3/state.jl") - end - - @testset "CS Simulation (sim_CS.jl)" begin - include("FMI3/sim_CS.jl") - end - @testset "ME Simulation (sim_ME.jl)" begin - include("FMI3/sim_ME.jl") - end - @testset "Support CS and ME simultaneously (cs_me.jl)" begin - include("FMI3/cs_me.jl") - end - @testset "Loading/Saving simulation results (load_save.jl)" begin - include("FMI3/load_save.jl") - end + @info "Aqua: Piracies" + @testset "Piracies" begin + Aqua.test_piracies(FMI) # ; broken = true) end - end - @testset "Plotting (plots.jl)" begin - include("FMI3/plots.jl") + @info "Aqua: Testing all (method ambiguities and piracies are tested separately)" + Aqua.test_all(FMI; ambiguities = false, piracies = false) end - end -end -@testset "FMI.jl" begin - if Sys.iswindows() - @info "Automated testing is supported on Windows." - for exportingTool in exportingToolsWindows - runtestsFMI2(exportingTool) - #runtestsFMI3(exportingTool) - end - elseif Sys.islinux() - @info "Automated testing is supported on Linux." - for exportingTool in exportingToolsLinux - runtestsFMI2(exportingTool) - #runtestsFMI3(exportingTool) - end elseif Sys.isapple() @warn "Test-sets are currently using Windows- and Linux-FMUs, automated testing for macOS is currently not supported." end - @testset "Aqua.jl" begin - # Ambiguities in external packages - @testset "Method ambiguity" begin - Aqua.test_ambiguities([FMI]) - end - @testset "Piracy" begin - Aqua.test_piracies(FMI; broken = true) - end - Aqua.test_all(FMI; ambiguities = false, piracies = false) - end end diff --git a/test/sim_CS.jl b/test/sim_CS.jl new file mode 100644 index 00000000..66d93213 --- /dev/null +++ b/test/sim_CS.jl @@ -0,0 +1,75 @@ +# +# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher +# Licensed under the MIT license. See LICENSE file in the project root for details. +# + +# testing different modes for CS (co simulation) mode + +# case 1: CS-FMU Simulation + +fmuStruct, fmu = getFMUStruct("SpringPendulum1D", :CS) + +t_start = 0.0 +t_stop = 8.0 + +# test without recording values (just for completeness) +solution = simulateCS(fmuStruct, (t_start, t_stop); dt = 1e-2) +@test solution.success + +# test with recording values +solution = + simulateCS(fmuStruct, (t_start, t_stop); dt = 1e-2, recordValues = ["mass.s", "mass.v"]) +@test solution.success +@test length(solution.values.saveval) == t_start:1e-2:t_stop |> length +@test length(solution.values.saveval[1]) == 2 + +t = solution.values.t +s = collect(d[1] for d in solution.values.saveval) +v = collect(d[2] for d in solution.values.saveval) +@test t[1] == t_start +@test t[end] == t_stop + +# reference values from Simulation in Dymola2020x (Dassl, default settings) +@test s[1] == 0.5 +@test v[1] == 0.0 + +@test isapprox(s[end], 0.509219; atol = 1e-1) +@test isapprox(v[end], 0.314074; atol = 1e-1) + +unloadFMU(fmu) + +# case 2: CS-FMU with input signal + +extForce_t! = function (t::Real, u::AbstractArray{<:Real}) + u[1] = sin(t) +end + +extForce_ct! = function (c::Union{FMUInstance,Nothing}, t::Real, u::AbstractArray{<:Real}) + u[1] = sin(t) +end + +fmustruct, fmu = getFMUStruct("SpringPendulumExtForce1D", :CS) + +for inpfct! in [extForce_ct!, extForce_t!] + global solution + + solution = simulateCS( + fmustruct, + (t_start, t_stop); + dt = 1e-2, + recordValues = ["mass.s", "mass.v"], + inputValueReferences = ["extForce"], + inputFunction = inpfct!, + ) + @test solution.success + @test length(solution.values.saveval) > 0 + @test length(solution.values.t) > 0 + + @test t[1] == t_start + @test t[end] == t_stop +end + +# reference values from Simulation in Dymola2020x (Dassl, default settings) +@test [solution.values.saveval[1]...] == [0.5, 0.0] +@test sum(abs.([solution.values.saveval[end]...] - [0.613371, 0.188633])) < 0.2 +unloadFMU(fmu) \ No newline at end of file diff --git a/test/sim_ME.jl b/test/sim_ME.jl new file mode 100644 index 00000000..8d67e485 --- /dev/null +++ b/test/sim_ME.jl @@ -0,0 +1,246 @@ +# +# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher +# Licensed under the MIT license. See LICENSE file in the project root for details. +# + +# testing different modes for ME (model exchange) mode + +using DifferentialEquations +using Sundials + +# to use autodiff! +using FMISensitivity +using FMI.FMIImport.FMIBase: sense_setindex! + +t_start = 0.0 +t_stop = 8.0 +dtmax_inputs = 1e-3 +rand_x0 = rand(2) + +kwargs = Dict(:dtmin => 1e-64, :abstol => 1e-8, :reltol => 1e-6, :dt => 1e-32) +solvers = [Tsit5(), Rodas5(autodiff = false)] # [Tsit5(), FBDF(autodiff=false), FBDF(autodiff=true), Rodas5(autodiff=false), Rodas5(autodiff=true)] + +extForce_t! = function (t::Real, u::AbstractArray{<:Real}) + sense_setindex!(u, sin(t), 1) +end + +extForce_cxt! = function ( + c::Union{FMUInstance,Nothing}, + x::Union{AbstractArray{<:Real},Nothing}, + t::Real, + u::AbstractArray{<:Real}, +) + x1 = 0.0 + if x != nothing + x1 = x[1] + end + sense_setindex!(u, sin(t) * x1, 1) +end + +for solver in solvers + + global fmuStruct, fmu, solution + + @info "Testing solver: $(solver)" + + # case 1: ME-FMU with state events + + fmuStruct, fmu = getFMUStruct("SpringFrictionPendulum1D", :ME) + + solution = simulateME(fmuStruct, (t_start, t_stop); solver = solver, kwargs...) + @test length(solution.states.u) > 0 + @test length(solution.states.t) > 0 + + @test solution.states.t[1] == t_start + @test solution.states.t[end] == t_stop + + # reference values from Simulation in Dymola2020x (Dassl) + @test solution.states.u[1] == [0.5, 0.0] + @test sum(abs.(solution.states.u[end] - [1.06736, -1.03552e-10])) < 0.1 + unloadFMU(fmu) + + # case 2: ME-FMU with state and time events + + fmuStruct, fmu = getFMUStruct("SpringTimeFrictionPendulum1D", :ME) + + ### test without recording values + + solution = simulateME(fmuStruct, (t_start, t_stop); solver = solver, kwargs...) + @test length(solution.states.u) > 0 + @test length(solution.states.t) > 0 + + @test solution.states.t[1] == t_start + @test solution.states.t[end] == t_stop + + # reference values from Simulation in Dymola2020x (Dassl) + @test solution.states.u[1] == [0.5, 0.0] + @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 + + ### test with recording values (variable step record values) + + solution = simulateME( + fmuStruct, + (t_start, t_stop); + recordValues = "mass.f", + solver = solver, + kwargs..., + ) + dataLength = length(solution.states.u) + @test dataLength > 0 + @test length(solution.states.t) == dataLength + @test length(solution.values.saveval) == dataLength + @test length(solution.values.t) == dataLength + + @test solution.states.t[1] == t_start + @test solution.states.t[end] == t_stop + @test solution.values.t[1] == t_start + @test solution.values.t[end] == t_stop + + # value/state getters + @test solution.states.t == getTime(solution) + @test collect(s[1] for s in solution.values.saveval) == + getValue(solution, 1; isIndex = true) + @test collect(u[1] for u in solution.states.u) == getState(solution, 1; isIndex = true) + @test isapprox( + getState(solution, 2; isIndex = true), + getStateDerivative(solution, 1; isIndex = true); + atol = 1e-1, + ) # tolerance is large, because Rosenbrock23 solution derivative is not that accurate (other solvers reach 1e-4 for this example) + @info "Max error of solver polynominal derivative: $(max(abs.(getState(solution, 2; isIndex=true) .- getStateDerivative(solution, 1; isIndex=true))...))" + + # reference values from Simulation in Dymola2020x (Dassl) + @test sum(abs.(solution.states.u[1] - [0.5, 0.0])) < 1e-4 + @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 + @test abs(solution.values.saveval[1][1] - 0.75) < 1e-4 + @test sum(abs.(solution.values.saveval[end][1] - -0.54435)) < 0.015 + + ### test with recording values (fixed step record values) + + tData = t_start:0.1:t_stop + solution = simulateME( + fmuStruct, + (t_start, t_stop); + recordValues = "mass.f", + saveat = tData, + solver = solver, + kwargs..., + ) + @test length(solution.states.u) == length(tData) + @test length(solution.states.t) == length(tData) + @test length(solution.values.saveval) == length(tData) + @test length(solution.values.t) == length(tData) + + @test solution.states.t[1] == t_start + @test solution.states.t[end] == t_stop + @test solution.values.t[1] == t_start + @test solution.values.t[end] == t_stop + + # reference values from Simulation in Dymola2020x (Dassl) + @test sum(abs.(solution.states.u[1] - [0.5, 0.0])) < 1e-4 + @test sum(abs.(solution.states.u[end] - [1.05444, 1e-10])) < 0.01 + @test abs(solution.values.saveval[1][1] - 0.75) < 1e-4 + @test sum(abs.(solution.values.saveval[end][1] - -0.54435)) < 0.015 + + unloadFMU(fmu) + + # case 3a: ME-FMU without events, but with input signal + + fmuStruct, fmu = getFMUStruct("SpringPendulumExtForce1D", :ME) + + for inpfct! in [extForce_cxt!, extForce_t!] + + solution = simulateME( + fmuStruct, + (t_start, t_stop); + inputValueReferences = ["extForce"], + inputFunction = inpfct!, + solver = solver, + dtmax = dtmax_inputs, + kwargs..., + ) # dtmax to force resolution + @test length(solution.states.u) > 0 + @test length(solution.states.t) > 0 + + @test solution.states.t[1] == t_start + @test solution.states.t[end] == t_stop + end + + # reference values `extForce_t` from Simulation in Dymola2020x (Dassl) + @test solution.states.u[1] == [0.5, 0.0] + @test sum(abs.(solution.states.u[end] - [0.613371, 0.188633])) < 0.012 + unloadFMU(fmu) + + # case 3b: ME-FMU without events, but with input signal (autodiff) + + fmuStruct, fmu = getFMUStruct("SpringPendulumExtForce1D", :ME) + + # there are issues with AD in Julia < 1.7.0 + # ToDo: Fix Linux FMU + if VERSION >= v"1.7.0" && !Sys.islinux() + solution = simulateME( + fmuStruct, + (t_start, t_stop); + solver = solver, + dtmax = dtmax_inputs, + kwargs..., + ) # dtmax to force resolution + + @test length(solution.states.u) > 0 + @test length(solution.states.t) > 0 + + @test solution.states.t[1] == t_start + @test solution.states.t[end] == t_stop + + # reference values (no force) from Simulation in Dymola2020x (Dassl) + @test solution.states.u[1] == [0.5, 0.0] + @test sum(abs.(solution.states.u[end] - [0.509219, 0.314074])) < 0.01 + end + + unloadFMU(fmu) + + # case 4: ME-FMU without events, but saving value interpolation + + fmuStruct, fmu = getFMUStruct("SpringPendulumExtForce1D", :ME) + + solution = simulateME( + fmuStruct, + (t_start, t_stop); + saveat = tData, + recordValues = :states, + solver = solver, + kwargs..., + ) + @test length(solution.states.u) == length(tData) + @test length(solution.states.t) == length(tData) + @test length(solution.values.saveval) == length(tData) + @test length(solution.values.t) == length(tData) + + @test isapprox(solution.states.t, solution.states.t; atol = 1e-6) + @test isapprox( + collect(u[1] for u in solution.states.u), + collect(u[1] for u in solution.values.saveval); + atol = 1e-6, + ) + @test isapprox( + collect(u[2] for u in solution.states.u), + collect(u[2] for u in solution.values.saveval); + atol = 1e-6, + ) + + unloadFMU(fmu) + + # case 5: ME-FMU with different (random) start state + + fmuStruct, fmu = getFMUStruct("SpringFrictionPendulum1D", :ME) + + solution = + simulateME(fmuStruct, (t_start, t_stop); x0 = rand_x0, solver = solver, kwargs...) + @test length(solution.states.u) > 0 + @test length(solution.states.t) > 0 + + @test solution.states.t[1] == t_start + @test solution.states.t[end] == t_stop + + @test solution.states.u[1] == rand_x0 + unloadFMU(fmu) +end diff --git a/test/sim_SE.jl b/test/sim_SE.jl new file mode 100644 index 00000000..b41bb349 --- /dev/null +++ b/test/sim_SE.jl @@ -0,0 +1,8 @@ +# +# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher +# Licensed under the MIT license. See LICENSE file in the project root for details. +# + +# testing different modes for SE (scheduled execution) mode + +# [ToDo] coming soon diff --git a/test/sim_zero_state.jl b/test/sim_zero_state.jl new file mode 100644 index 00000000..8328873a --- /dev/null +++ b/test/sim_zero_state.jl @@ -0,0 +1,38 @@ +# +# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher +# Licensed under the MIT license. See LICENSE file in the project root for details. +# + +using DifferentialEquations + +t_start = 0.0 +t_stop = 8.0 +solver = Tsit5() + +inputFct! = function (t, u) + u[1] = sin(t) + return nothing +end + +fmuStruct, fmu = getFMUStruct("IO", :ME) +@test fmu.isZeroState # check if zero state is identified + +solution = simulateME( + fmuStruct, + (t_start, t_stop); + solver = solver, + recordValues = ["y_real"], # , "y_boolean", "y_integer"], # [ToDo] different types to record + inputValueReferences = ["u_real"], # [ToDo] different types to set + inputFunction = inputFct!, +) + +@test isnothing(solution.states) +@test solution.values.t[1] == t_start +@test solution.values.t[end] == t_stop +@test isapprox( + collect(u[1] for u in solution.values.saveval), + sin.(solution.values.t); + atol = 1e-6, +) + +unloadFMU(fmu) diff --git a/test/unpack.jl b/test/unpack.jl new file mode 100644 index 00000000..b8a08a94 --- /dev/null +++ b/test/unpack.jl @@ -0,0 +1,21 @@ +# +# Copyright (c) 2021 Tobias Thummerer, Lars Mikelsons, Josef Kircher +# Licensed under the MIT license. See LICENSE file in the project root for details. +# + +# test different unpacking path options for FMUs + +pathToFMU = + get_model_filename("SpringPendulum1D", ENV["EXPORTINGTOOL"], ENV["EXPORTINGVERSION"]) + +# load FMU in temporary directory +fmuStruct, myFMU = getFMUStruct(pathToFMU) +@test isfile(myFMU.zipPath) == true +@test isdir(splitext(myFMU.zipPath)[1]) == true +fmiUnload(myFMU) + +# load FMU in source directory +fmuDir = joinpath(splitpath(pathToFMU)[1:end-1]...) +fmuStruct, myFMU = getFMUStruct(pathToFMU; unpackPath = fmuDir) +@test isfile(splitext(pathToFMU)[1] * ".zip") == true +@test isdir(splitext(pathToFMU)[1]) == true