├── test ├── .gitignore ├── Project.toml ├── runtests.jl ├── testFMIExport.jl ├── modelicaSystemTest.jl ├── parserTest.jl ├── omcTest.jl └── apiTest.jl ├── regression-tests ├── .gitignore ├── Project.toml ├── runSingleTest.jl └── regressionTests.jl ├── docs ├── .gitignore ├── Project.toml ├── src │ ├── sendExpression.md │ ├── api.md │ ├── index.md │ ├── quickstart.md │ ├── modelicaSystem.md │ └── assets │ │ ├── logo.svg │ │ └── logo-large-dark.svg ├── README.md ├── make.jl ├── testmodels │ ├── BouncingBall.mo │ └── ModSeborgCSTRorg.mo └── Manifest.toml ├── .gitignore ├── .github ├── dependabot.yml └── workflows │ ├── TagBot.yml │ ├── Test.yml │ ├── documentation.yml │ └── regressionTests.yml ├── Project.toml ├── LICENSE.md ├── bin └── generate_lexer.jl ├── src ├── error.jl ├── OMJulia.jl ├── memory.jl ├── sendExpression.jl ├── parser.jl ├── omcSession.jl ├── api.jl └── lexer.jl └── README.md /test/.gitignore: -------------------------------------------------------------------------------- 1 | /test-*/ 2 | -------------------------------------------------------------------------------- /regression-tests/.gitignore: -------------------------------------------------------------------------------- 1 | temp/ 2 | -------------------------------------------------------------------------------- /docs/.gitignore: -------------------------------------------------------------------------------- 1 | /build/ 2 | /omc-temp/ 3 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .vscode/ 2 | *.cov 3 | /BouncingBall* 4 | Manifest.toml 5 | -------------------------------------------------------------------------------- /.github/dependabot.yml: -------------------------------------------------------------------------------- 1 | version: 2 2 | updates: 3 | - package-ecosystem: github-actions 4 | directory: / 5 | schedule: 6 | interval: daily 7 | -------------------------------------------------------------------------------- /regression-tests/Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" 3 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 4 | FMI = "14a09403-18e3-468f-ad8a-74f8dda2d9ac" 5 | OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" 6 | Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 7 | -------------------------------------------------------------------------------- /test/Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" 3 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 4 | OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" 5 | SafeTestsets = "1bc83da4-3b8d-516f-aca4-4fe02f6d838f" 6 | Test = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 7 | -------------------------------------------------------------------------------- /docs/Project.toml: -------------------------------------------------------------------------------- 1 | [deps] 2 | CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" 3 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 4 | Documenter = "e30172f5-a6a5-5a46-863b-614d45cd2de4" 5 | OMJulia = "0f4fe800-344e-11e9-2949-fb537ad918e1" 6 | PlotlyDocumenter = "9b90f1cd-2639-4507-8b17-2fbe371ceceb" 7 | PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" 8 | 9 | [compat] 10 | Documenter = "^0.27" 11 | OMJulia = "^0.3.0" 12 | PlotlyJS = "^0.18.13" 13 | -------------------------------------------------------------------------------- /docs/src/sendExpression.md: -------------------------------------------------------------------------------- 1 | # sendExpression 2 | 3 | Start a new `OMCSession` and send 4 | [scripting API](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html) 5 | expressions to the omc session with `sendExpression()`. 6 | 7 | ```@docs 8 | sendExpression 9 | ``` 10 | 11 | ## Examples 12 | 13 | ```@repl 14 | using OMJulia # hide 15 | omc = OMJulia.OMCSession() # hide 16 | version = OMJulia.sendExpression(omc, "getVersion()") 17 | OMJulia.quit(omc) 18 | ``` 19 | -------------------------------------------------------------------------------- /docs/README.md: -------------------------------------------------------------------------------- 1 | # Documentation 2 | 3 | We use Documenter.jl to build the OMJulia documentation that is linked from the 4 | OpenModelica User's Guide. 5 | 6 | ## Build and host locally 7 | 8 | Make sure you developed OMJulia.jl, so that Documenter.jl is using the correct version to 9 | build. 10 | To run Documenter.jl along with LiveServer to render the docs and track any modifications 11 | run: 12 | 13 | ```julia 14 | using Pkg; Pkg.activate("docs/"); Pkg.resolve() 15 | using OMJulia, LiveServer 16 | servedocs() 17 | ``` 18 | -------------------------------------------------------------------------------- /docs/make.jl: -------------------------------------------------------------------------------- 1 | using Documenter, OMJulia 2 | 3 | ENV["JULIA_DEBUG"]="Documenter" 4 | 5 | @info "Make the docs" 6 | makedocs( 7 | sitename = "OMJulia.jl", 8 | format = Documenter.HTML(edit_link = "master"), 9 | workdir = joinpath(@__DIR__,".."), 10 | pages = [ 11 | "Home" => "index.md", 12 | "Quickstart" => "quickstart.md", 13 | "ModelicaSystem" => "modelicaSystem.md", 14 | "OMJulia.API" => "api.md", 15 | "sendExpression" => "sendExpression.md" 16 | ], 17 | modules = [OMJulia], 18 | ) 19 | 20 | @info "Deploy the docs" 21 | deploydocs( 22 | repo = "github.com/OpenModelica/OMJulia.jl.git", 23 | devbranch = "master" 24 | ) 25 | -------------------------------------------------------------------------------- /Project.toml: -------------------------------------------------------------------------------- 1 | name = "OMJulia" 2 | uuid = "0f4fe800-344e-11e9-2949-fb537ad918e1" 3 | authors = ["Martin Sjölund ", "Arunkumar Palanisamy "] 4 | version = "0.3.2" 5 | 6 | [deps] 7 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 8 | DataStructures = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 9 | LightXML = "9c8b4983-aa76-5018-a973-4c85ecc9e179" 10 | Random = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 11 | ZMQ = "c2297ded-f4af-51ae-bb23-16f91089e4e1" 12 | 13 | [compat] 14 | DataFrames = "0.19.4, 0.20, 0.21, 0.22, 1" 15 | DataStructures = "0.9, 0.10, 0.11, 0.12, 0.13, 0.14, 0.15, 0.16.1, 0.17, 0.18" 16 | LightXML = "0.8, 0.9" 17 | ZMQ = "1" 18 | julia = "1.2" 19 | -------------------------------------------------------------------------------- /docs/testmodels/BouncingBall.mo: -------------------------------------------------------------------------------- 1 | model BouncingBall 2 | parameter Real e=0.7 "coefficient of restitution"; 3 | parameter Real g=9.81 "gravity acceleration"; 4 | Real h(fixed=true, start=1) "height of ball"; 5 | Real v(fixed=true) "velocity of ball"; 6 | Boolean flying(fixed=true, start=true) "true, if ball is flying"; 7 | Boolean impact; 8 | Real v_new(fixed=true); 9 | Integer foo; 10 | 11 | equation 12 | impact = h <= 0.0; 13 | foo = if impact then 1 else 2; 14 | der(v) = if flying then -g else 0; 15 | der(h) = v; 16 | 17 | when {h <= 0.0 and v <= 0.0,impact} then 18 | v_new = if edge(impact) then -e*pre(v) else 0; 19 | flying = v_new > 0; 20 | reinit(v, v_new); 21 | end when; 22 | 23 | end BouncingBall; 24 | -------------------------------------------------------------------------------- /.github/workflows/TagBot.yml: -------------------------------------------------------------------------------- 1 | name: TagBot 2 | on: 3 | issue_comment: 4 | types: 5 | - created 6 | workflow_dispatch: 7 | inputs: 8 | lookback: 9 | default: 3 10 | permissions: 11 | actions: read 12 | checks: read 13 | contents: write 14 | deployments: read 15 | issues: read 16 | discussions: read 17 | packages: read 18 | pages: read 19 | pull-requests: read 20 | repository-projects: read 21 | security-events: read 22 | statuses: read 23 | jobs: 24 | TagBot: 25 | if: github.event_name == 'workflow_dispatch' || github.actor == 'JuliaTagBot' 26 | runs-on: ubuntu-latest 27 | steps: 28 | - uses: JuliaRegistries/TagBot@v1 29 | with: 30 | token: ${{ secrets.GITHUB_TOKEN }} 31 | ssh: ${{ secrets.DOCUMENTER_KEY }} 32 | -------------------------------------------------------------------------------- /docs/src/api.md: -------------------------------------------------------------------------------- 1 | # OMJulia.API 2 | 3 | Module `OMJulia.API` aims to provide a Julia interface to the OpenModelica scripting API. 4 | In contrast to sending the scripting api calls directly via [`sendExpression`](@ref) 5 | this API has a Julia-like interface and some level of error handling implemented. 6 | This means errors will throw Julia Exception [`OMJulia.API.ScriptingError`](@ref) instead 7 | of only printing to stdout. 8 | 9 | !!! warn 10 | Not all `OMJulia.API` functions are tested and some functions could have slightly 11 | different default values compared to the OpenModelica scripting API. 12 | 13 | 14 | Instead of escaping strings yourself the API interface handles this for you: 15 | 16 | ```julia 17 | sendExpression(omc, "loadFile(\"$(bouncingBallFile)\")") 18 | ``` 19 | 20 | becomes 21 | 22 | ```julia 23 | API.loadFile(omc, bouncingBallFile) 24 | ``` 25 | 26 | ## Functions 27 | 28 | ```@autodocs 29 | Modules = [OMJulia.API] 30 | Order = [:function, :type] 31 | Filter = t -> t != OMJulia.API.modelicaString 32 | ``` 33 | -------------------------------------------------------------------------------- /.github/workflows/Test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | 3 | on: 4 | push: 5 | branches: ['master', 'maintenance/*'] 6 | pull_request: 7 | workflow_dispatch: 8 | 9 | jobs: 10 | test: 11 | runs-on: ${{ matrix.os }} 12 | timeout-minutes: 30 13 | strategy: 14 | fail-fast: false 15 | matrix: 16 | julia-version: ['1.6', '1.10'] 17 | julia-arch: ['x64'] 18 | os: ['ubuntu-latest', 'windows-latest'] 19 | omc-version: ['stable'] 20 | 21 | steps: 22 | - uses: actions/checkout@v4 23 | 24 | - name: "Set up OpenModelica Compiler" 25 | uses: OpenModelica/setup-openmodelica@v1.0 26 | with: 27 | version: ${{ matrix.omc-version }} 28 | packages: | 29 | omc 30 | libraries: | 31 | 'Modelica 4.0.0' 32 | 33 | - run: "omc --version" 34 | 35 | - name: "Set up Julia" 36 | uses: julia-actions/setup-julia@v2 37 | with: 38 | version: ${{ matrix.julia-version }} 39 | arch: ${{ matrix.julia-arch }} 40 | 41 | - name: Cache Julia 42 | uses: julia-actions/cache@v2 43 | 44 | - name: "Build OMJulia" 45 | uses: julia-actions/julia-buildpkg@v1 46 | 47 | - name: "Test OMJulia" 48 | uses: julia-actions/julia-runtest@v1 49 | with: 50 | coverage: false 51 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Documentation 2 | 3 | on: 4 | push: 5 | branches: 6 | - master 7 | tags: '*' 8 | pull_request: 9 | 10 | jobs: 11 | documentation: 12 | permissions: 13 | contents: write 14 | runs-on: ubuntu-latest 15 | strategy: 16 | matrix: 17 | julia-version: ['1.10'] 18 | julia-arch: [x64] 19 | os: [ubuntu-latest] 20 | timeout-minutes: 60 21 | 22 | steps: 23 | - uses: actions/checkout@v4 24 | 25 | - name: Setup OpenModelica 26 | uses: OpenModelica/setup-openmodelica@v1.0 27 | with: 28 | version: 'nightly' 29 | packages: | 30 | 'omc' 31 | libraries: | 32 | 'Modelica 4.0.0' 33 | 34 | - name: Setup Julia 35 | uses: julia-actions/setup-julia@v2 36 | with: 37 | version: ${{ matrix.julia-version }} 38 | arch: ${{ matrix.julia-arch }} 39 | 40 | - name: Cache Julia 41 | uses: julia-actions/cache@v2 42 | 43 | - name: Install dependencies 44 | run: julia --project=docs/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' 45 | 46 | - name: Build and deploy 47 | env: 48 | GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} # If authenticating with GitHub Actions token 49 | DOCUMENTER_KEY: ${{ secrets.DOCUMENTER_KEY }} 50 | run: julia --project=docs/ docs/make.jl 51 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | Redistribution and use in source and binary forms, with or without modification, 2 | are permitted provided that the following conditions are met: 3 | 4 | 1. Redistributions of source code must retain the above copyright notice, 5 | this list of conditions and the following disclaimer. 6 | 7 | 2. Redistributions in binary form must reproduce the above copyright notice, 8 | this list of conditions and the following disclaimer 9 | in the documentation and/or other materials provided with the distribution. 10 | 11 | 3. Neither the name of the copyright holder nor the names of its contributors 12 | may be used to endorse or promote products derived from this software 13 | without specific prior written permission. 14 | 15 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 16 | ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 17 | WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 18 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 19 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 20 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 21 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 22 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 23 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 24 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -------------------------------------------------------------------------------- /test/runtests.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | using SafeTestsets 30 | using Test 31 | 32 | @testset "OMJulia" begin 33 | @safetestset "Parsing" begin include("parserTest.jl") end 34 | @safetestset "OMCSession" begin include("omcTest.jl") end 35 | @safetestset "ModelicaSystem" begin include("modelicaSystemTest.jl") end 36 | @safetestset "API" begin include("apiTest.jl") end 37 | end 38 | -------------------------------------------------------------------------------- /docs/testmodels/ModSeborgCSTRorg.mo: -------------------------------------------------------------------------------- 1 | model ModSeborgCSTRorg 2 | // Model of ORiGinal Seborg CSTR in ode form 3 | // author: Bernt Lie 4 | // University of Southeast Norway 5 | // November 7, 2017 6 | // 7 | // Parameters 8 | parameter Real V = 100 "Reactor volume, L"; 9 | parameter Real rho = 1e3 "Liquid density, g/L"; 10 | parameter Real a = 1 "Stoichiometric constant, -"; 11 | parameter Real EdR = 8750 "Activation temperature, K"; 12 | parameter Real k0 = exp(EdR/350) "Pre-exponential factor, 1/min"; 13 | parameter Real cph = 0.239 "Specific heat capacity of mixture, J.g-1.K-1"; 14 | parameter Real DrHt = -5e4 "Molar enthalpy of reaction, J/mol"; 15 | parameter Real UA = 5e4 "Heat transfer parameter, J/(min.K)"; 16 | 17 | // Initial state parameters 18 | parameter Real cA0 = 0.5 "Initial concentration of A, mol/L"; 19 | parameter Real T0 = 350 "Initial temperature, K"; 20 | // Declaring variables 21 | // -- states 22 | Real cA(start = cA0, fixed = true) "Initializing concentration of A in reactor, mol/L"; 23 | Real T(start = T0, fixed = true) "Initializing temperature in reactor, K"; 24 | // -- auxiliary variables 25 | Real r "Rate of reaction, mol/(L.s)"; 26 | Real k "Reaction 'constant', ..."; 27 | Real Qd "Heat flow rate, J/min"; 28 | // -- input variables 29 | input Real Vdi "Volumetric flow rate through reactor, L/min"; 30 | input Real cAi "Influent molar concentration of A, mol/L"; 31 | input Real Ti "Influent temperature, K"; 32 | input Real Tc "Cooling temperature', K"; 33 | // -- output variables 34 | output Real y_T "Reactor temperature, K"; 35 | // Equations constituting the model 36 | equation 37 | // Differential equations 38 | der(cA) = Vdi*(cAi-cA)/V- a*r; 39 | der(T) = Vdi*(Ti-T)/V + (-DrHt)*r/(rho*cph) + Qd/(rho*V*cph); 40 | // Algebraic equations 41 | r = k*cA^a; 42 | k = k0*exp(-EdR/T); 43 | Qd = UA*(Tc-T); 44 | // Outputs 45 | y_T = T; 46 | end ModSeborgCSTRorg; -------------------------------------------------------------------------------- /.github/workflows/regressionTests.yml: -------------------------------------------------------------------------------- 1 | name: Regression Tests 2 | 3 | on: 4 | push: 5 | branches: ['master', 'maintenance/*'] 6 | schedule: 7 | - cron: "25 4 * * 3" # Every Wednesday at 04:25 8 | workflow_dispatch: 9 | 10 | jobs: 11 | regression-test: 12 | if: github.repository == 'OpenModelica/OMJulia.jl' # Run only on OpenModelica/OMJulia.jl to prevent spamming forks 13 | runs-on: ${{ matrix.os }} 14 | timeout-minutes: 60 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | julia-version: ['1.6', '1.10'] 19 | julia-arch: ['x64'] 20 | os: ['ubuntu-latest', 'windows-latest'] 21 | omc-version: ['stable', 'nightly', '1.21'] 22 | 23 | steps: 24 | - uses: actions/checkout@v4 25 | 26 | - name: "Set up OpenModelica Compiler" 27 | uses: OpenModelica/setup-openmodelica@v1.0 28 | with: 29 | version: ${{ matrix.omc-version }} 30 | packages: | 31 | omc 32 | libraries: | 33 | 'Modelica 4.0.0' 34 | 35 | - run: "omc --version" 36 | 37 | - name: "Set up Julia" 38 | uses: julia-actions/setup-julia@v2 39 | with: 40 | version: ${{ matrix.julia-version }} 41 | arch: ${{ matrix.julia-arch }} 42 | 43 | - name: Cache Julia 44 | uses: julia-actions/cache@v2 45 | 46 | - name: "Build OMJulia" 47 | uses: julia-actions/julia-buildpkg@v1 48 | 49 | - name: Install dependencies 50 | run: julia --project=regression-tests/ -e 'using Pkg; Pkg.develop(PackageSpec(path=pwd())); Pkg.instantiate()' 51 | 52 | - name: "Run regression test" 53 | shell: bash 54 | run: julia --project=regression-tests/. -e 'include("regression-tests/regressionTests.jl"); runTests(libraries, models)' 55 | 56 | - name: Archive FMUs 57 | uses: actions/upload-artifact@v3 58 | with: 59 | name: fmu-export 60 | path: regression-tests/temp/**/*.fmu 61 | -------------------------------------------------------------------------------- /docs/src/index.md: -------------------------------------------------------------------------------- 1 | # OMJulia.jl 2 | 3 | **Julia scripting OpenModelica interface.** 4 | 5 | ## Overview 6 | 7 | OMJulia - the OpenModelica Julia API is a free, open source, highly portable Julia based 8 | interactive session handler for Julia scripting of OpenModelica API functionality. 9 | It provides the modeler with components for creating a complete Julia-Modelica modeling, 10 | compilation and simulation environment based on the latest OpenModelica implementation and 11 | Modelica library standard available. 12 | 13 | OMJulia is structured to combine both the solving strategy and model building. 14 | Thus, domain experts (people writing the models) and computational engineers (people 15 | writing the solver code) can work on one unified tool that is industrially viable for 16 | optimization of Modelica models, while offering a flexible platform for algorithm 17 | development and research. 18 | OMJulia is not a standalone package, it depends upon the OpenModelica installation. 19 | 20 | OMJulia is implemented in Julia and depends on ZeroMQ - high performance asynchronous 21 | messaging library and it supports the Modelica Standard Library version 4.0 that is 22 | included with OpenModelica. 23 | 24 | ## Installation 25 | 26 | Make sure [OpenModelica](https://openmodelica.org/) is installed. 27 | 28 | Install OMJulia.jl with: 29 | 30 | ```julia 31 | julia> import Pkg; Pkg.add("OMJulia") 32 | ``` 33 | 34 | ## Features of OMJulia 35 | 36 | The OMJulia package contains the following features: 37 | 38 | - Interactive session handling, parsing, interpretation of commands and Modelica 39 | expressions for evaluation, simulation, plotting, etc. 40 | - Connect with the OpenModelica compiler through zmq sockets 41 | - Able to interact with the OpenModelica compiler through the available API 42 | - Easy access to the Modelica Standard library. 43 | - All the API calls are communicated with the help of the sendExpression method 44 | implemented in a Julia module 45 | - The results are returned as strings 46 | -------------------------------------------------------------------------------- /test/testFMIExport.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | using Test 30 | import OMJulia 31 | 32 | @testset "testFMIExport" begin 33 | workdir = abspath(joinpath(@__DIR__, "test_fmi_export")) 34 | rm(workdir, recursive=true, force=true) 35 | mkpath(workdir) 36 | 37 | mod = OMJulia.OMCSession() 38 | OMJulia.ModelicaSystem(mod, modelName="Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", library="Modelica") 39 | fmu1 = OMJulia.convertMo2FMU(mod) 40 | @test isfile(fmu1) 41 | 42 | OMJulia.ModelicaSystem(mod, modelName="Modelica.Fluid.Examples.DrumBoiler.DrumBoiler", library="Modelica") 43 | fmu2 = OMJulia.convertMo2FMU(mod) 44 | @test isfile(fmu2) 45 | 46 | OMJulia.quit(mod) 47 | end 48 | -------------------------------------------------------------------------------- /test/modelicaSystemTest.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | using Test 30 | import OMJulia 31 | 32 | @testset "ModelicaSystem" begin 33 | workdir = abspath(joinpath(@__DIR__, "test-modelicasystem")) 34 | rm(workdir, recursive=true, force=true) 35 | mkpath(workdir) 36 | 37 | resultfile = joinpath(workdir, "ModSeborgCSTRorg_res.mat") 38 | 39 | mod = OMJulia.OMCSession() 40 | OMJulia.ModelicaSystem(mod, 41 | joinpath(@__DIR__, "..", "docs", "testmodels", "ModSeborgCSTRorg.mo"), 42 | "ModSeborgCSTRorg") 43 | OMJulia.simulate(mod, 44 | resultfile = resultfile) 45 | @test isfile(resultfile) 46 | fmu = OMJulia.convertMo2FMU(mod) 47 | @test isfile(fmu) 48 | OMJulia.quit(mod) 49 | end 50 | -------------------------------------------------------------------------------- /bin/generate_lexer.jl: -------------------------------------------------------------------------------- 1 | # Generate a Lexer for OpenModelica output (Values.Value) 2 | # ===================================================================== 3 | 4 | import Automa 5 | import Automa.RegExp: @re_str 6 | import MacroTools 7 | const re = Automa.RegExp 8 | 9 | # Describe patterns in regular expression. 10 | t = re"[tT][rR][uU][eE]" 11 | f = re"[fF][aA][lL][sS][eE]" 12 | string = re"\"([^\"\\x5c]|(\\x5c.))*\"" 13 | ident = re"[_A-Za-z][_A-Za-z0-9]*|'([^'\\x5c]|(\\x5c.))+'" 14 | int = re"[-+]?[0-9]+" 15 | prefloat = re"[-+]?([0-9]+\.[0-9]*|[0-9]*\.[0-9]+)" 16 | float = prefloat | re.cat(prefloat | re"[-+]?[0-9]+", re"[eE][-+]?[0-9]+") 17 | operator = re"[={}(),;]|end" 18 | number = int | float 19 | ws = re"[ ]+" 20 | omtoken = number | string | ident | operator 21 | omtokens = re.opt(ws) * re.rep(omtoken * re.opt(ws)) 22 | 23 | # Compile a finite-state machine. 24 | tokenizer = Automa.compile( 25 | t => :(emit(true)), 26 | f => :(emit(false)), 27 | operator => :(emit(Symbol(data[ts:te]))), 28 | re"record" => :(emit(Record())), 29 | string => :(emit(unescape_string(data[ts+1:te-1]))), 30 | ident => :(emit(Identifier(unescape_string(data[ts:te])))), # Should this be a symbol instead? 31 | int => :(emit(parse(Int, data[ts:te]))), 32 | float => :(emit(parse(Float64, data[ts:te]))), 33 | re"[\n\t ]" => :(), 34 | re"." => :(failed = true) 35 | ) 36 | 37 | # Generate a tokenizing function from the machine. 38 | ctx = Automa.CodeGenContext() 39 | init_code = MacroTools.prettify(Automa.generate_init_code(ctx, tokenizer)) 40 | exec_code = MacroTools.prettify(Automa.generate_exec_code(ctx, tokenizer)) 41 | 42 | write(open("src/lexer.jl","w"), """# Generated Lexer for OpenModelica Values.Value output 43 | 44 | function tokenize(data::String) 45 | $(init_code) 46 | p_end = p_eof = sizeof(data) 47 | failed = false 48 | tokens = Any[] 49 | emit(tok) = push!(tokens, tok) 50 | while p ≤ p_eof && cs > 0 51 | $(exec_code) 52 | end 53 | if cs < 0 || failed 54 | throw(LexerError("Error while lexing")) 55 | end 56 | if p < p_eof 57 | throw(LexerError("Did not scan until end of file. Remaining: \$(data[p:p_eof])")) 58 | end 59 | return tokens 60 | end 61 | """) 62 | -------------------------------------------------------------------------------- /src/error.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | """ 30 | omc process error 31 | """ 32 | struct OMCError <: Exception 33 | cmd::Cmd 34 | stdout_file::Union{String, Missing} 35 | stderr_file::Union{String, Missing} 36 | 37 | function OMCError(cmd, stdout_file=missing, stderr_file=missing) 38 | new(cmd, stdout_file, stderr_file) 39 | end 40 | end 41 | """ 42 | Show error from log files 43 | """ 44 | function Base.showerror(io::IO, e::OMCError) 45 | println(io, "OMCError ") 46 | println(io, "Command $(e.cmd) failed") 47 | if !ismissing(e.stdout_file) 48 | println(io, read(e.stdout_file, String)) 49 | end 50 | if !ismissing(e.stdout_file) 51 | print(io, read(e.stderr_file, String)) 52 | end 53 | end 54 | 55 | """ 56 | Timeout error 57 | """ 58 | struct TimeoutError <: Exception 59 | msg::String 60 | end 61 | function Base.showerror(io::IO, e::TimeoutError) 62 | println(io, "TimeoutError") 63 | print(e.msg) 64 | end 65 | -------------------------------------------------------------------------------- /src/OMJulia.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | module OMJulia 30 | global IS_FILE_OMJULIA = false 31 | 32 | using DataFrames 33 | using DataStructures 34 | using LightXML 35 | using Random 36 | using ZMQ 37 | 38 | export sendExpression, ModelicaSystem 39 | # getMethods 40 | export getParameters, getQuantities, showQuantities, getInputs, getOutputs, getSimulationOptions, getSolutions, getContinuous, getWorkDirectory 41 | # setMethods 42 | export setInputs, setParameters, setSimulationOptions 43 | # simulation 44 | export simulate, buildModel 45 | # Linearizion 46 | export linearize, getLinearInputs, getLinearOutputs, getLinearStates, getLinearizationOptions, setLinearizationOptions 47 | # sensitivity analysis 48 | export sensitivity 49 | # package manager 50 | export installPackage, updatePackageIndex, getAvailablePackageVersions, upgradeInstalledPackages 51 | 52 | include("error.jl") 53 | include("parser.jl") 54 | include("omcSession.jl") 55 | include("sendExpression.jl") 56 | include("modelicaSystem.jl") 57 | include("api.jl") 58 | end 59 | -------------------------------------------------------------------------------- /test/parserTest.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | using OMJulia 30 | 31 | function check(string, expected_value, expected_type) 32 | value = OMJulia.Parser.parseOM(string) 33 | return expected_value == value && expected_type == typeof(value) 34 | end 35 | 36 | @testset "Parser" begin 37 | @test check("123.0", 123.0, Float64) 38 | @test check("123", 123, Int) 39 | @test check("1.", 1.0, Float64) 40 | @test check(".2", 0.2, Float64) 41 | @test check("1e3", 1e3, Float64) 42 | @test check("1e+2", 1e+2, Float64) 43 | @test check("tRuE", true, Bool) 44 | @test check("false", false, Bool) 45 | @test check("\"ab\\nc\"", "ab\nc", String) 46 | @test check("{\"abc\"}", ["abc"], Array{String,1}) 47 | @test check("{1}", [1], Array{Int,1}) 48 | @test check("{1,2,3}", [1,2,3], Array{Int,1}) 49 | @test check("(1,2,3)", (1,2,3), Tuple{Int,Int,Int}) 50 | @test check("NONE()", nothing, Nothing) 51 | @test check("SOME(1)", 1, Int) 52 | @test check("abc_2", :abc_2, Symbol) 53 | @test check("record ABC end ABC;", Dict(), Dict{String,Any}) 54 | @test check("record ABC a = 1, 'b' = 2,\n c = 3\nend ABC;", Dict("a" => 1, "'b'" => 2, "c" => 3), Dict{String,Int}) 55 | @test check("", nothing, Nothing) 56 | end 57 | -------------------------------------------------------------------------------- /src/memory.jl: -------------------------------------------------------------------------------- 1 | # SizedMemory 2 | # =========== 3 | # The Automa.jl package is licensed under the MIT "Expat" License: 4 | 5 | # Copyright (c) 2016: BioJulia. 6 | # 7 | # Permission is hereby granted, free of charge, to any person obtaining a copy 8 | # of this software and associated documentation files (the "Software"), to deal 9 | # in the Software without restriction, including without limitation the rights 10 | # to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 11 | # copies of the Software, and to permit persons to whom the Software is 12 | # furnished to do so, subject to the following conditions: 13 | # 14 | # The above copyright notice and this permission notice shall be included in all 15 | # copies or substantial portions of the Software. 16 | # 17 | # THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 18 | # IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 19 | # FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 20 | # AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 21 | # LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | # OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 23 | # SOFTWARE. 24 | 25 | 26 | struct SizedMemory 27 | ptr::Ptr{UInt8} 28 | len::UInt 29 | end 30 | 31 | """ 32 | SizedMemory(data) 33 | 34 | Create a `SizedMemory` object from `data`. 35 | 36 | `data` must implement `Automa.pointerstart` and `Automa.pointerend` methods. 37 | These are used to get the range of the contiguous data memory of `data`. These 38 | have default methods which uses `Base.pointer` and `Base.sizeof` methods. For 39 | example, `String` and `Vector{UInt8}` support these `Base` methods. 40 | 41 | Note that it is user's responsibility to keep the `data` object alive during 42 | `SizedMemory`'s lifetime because it does not have a reference to the object. 43 | """ 44 | function SizedMemory(data, len::Integer=(pointerend(data) + 1) - pointerstart(data)) 45 | return SizedMemory(pointerstart(data), len) 46 | end 47 | 48 | """ 49 | pointerstart(data)::Ptr{UInt8} 50 | 51 | Return the start position of `data`. 52 | 53 | The default implementation is `convert(Ptr{UInt8}, pointer(data))`. 54 | """ 55 | function pointerstart(data)::Ptr{UInt8} 56 | return convert(Ptr{UInt8}, pointer(data)) 57 | end 58 | 59 | """ 60 | pointerend(data)::Ptr{UInt8} 61 | 62 | Return the end position of `data`. 63 | 64 | The default implementation is `Automa.pointerstart(data) + sizeof(data) - 1`. 65 | """ 66 | function pointerend(data)::Ptr{UInt8} 67 | return pointerstart(data) + sizeof(data) - 1 68 | end 69 | 70 | function Base.checkbounds(mem::SizedMemory, i::Integer) 71 | if 1 ≤ i ≤ mem.len 72 | return 73 | end 74 | throw(BoundsError(i)) 75 | end 76 | 77 | function Base.getindex(mem::SizedMemory, i::Integer) 78 | @boundscheck checkbounds(mem, i) 79 | return unsafe_load(mem.ptr, i) 80 | end 81 | 82 | function Base.lastindex(mem::SizedMemory) 83 | return Int(mem.len) 84 | end 85 | 86 | function Base.length(mem::SizedMemory) 87 | return Int(mem.len) 88 | end 89 | -------------------------------------------------------------------------------- /src/sendExpression.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | """ 30 | sendExpression(omc, expr; parsed=true) 31 | 32 | Send API call to OpenModelica ZMQ server. 33 | See [OpenModelica User's Guide Scripting API](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html) 34 | for a complete list of all functions. 35 | 36 | !!! note 37 | Some characters in argument `expr` need to be escaped. 38 | E.g. `"` becomes `\\"`. 39 | For example scripting API call 40 | 41 | ```modelica 42 | loadFile("/path/to/M.mo") 43 | ``` 44 | 45 | will translate to 46 | 47 | ```julia 48 | sendExpression(omc, "loadFile(\\"/path/to/M.mo\\")") 49 | ``` 50 | 51 | !!! warn 52 | On Windows path separation symbol `\\` needs to be escaped `\\\\` 53 | or replaced to Unix style path `/` to prevent warnings. 54 | 55 | ```modelica 56 | loadFile("C:\\\\path\\\\to\\\\M.mo") 57 | ``` 58 | 59 | translate to 60 | 61 | ```julia 62 | sendExpression(omc, "loadFile(\\"C:\\\\\\\\path\\\\\\\\to\\\\\\\\M.mo\\")") # Windows 63 | sendExpression(omc, "loadFile(\\"/c/path/to/M.mo\\")") # Windows 64 | ``` 65 | 66 | ## Example 67 | 68 | ```julia 69 | using OMJulia 70 | omc = OMJulia.OMCSession() 71 | OMJulia.sendExpression(omc, "getVersion()") 72 | ``` 73 | """ 74 | function sendExpression(omc::OMCSession, expr::String; parsed=true) 75 | if !process_running(omc.zmqSession.omcprocess) 76 | return error("Process Exited, No connection with OMC. Create a new instance of OMCSession") 77 | end 78 | 79 | @debug "sending expression: $(expr)" 80 | ZMQ.Sockets.send(omc.zmqSession.socket, expr) 81 | @debug "Receiving message from ZMQ socket" 82 | message = ZMQ.Sockets.recv(omc.zmqSession.socket) 83 | @debug "Recieved message" 84 | if parsed 85 | return Parser.parseOM(unsafe_string(message)) 86 | else 87 | return unsafe_string(message) 88 | end 89 | end 90 | -------------------------------------------------------------------------------- /src/parser.jl: -------------------------------------------------------------------------------- 1 | module Parser 2 | 3 | # Proposed for Julia 1.5.x 4 | #if isdefined(Base, :Experimental) && isdefined(Base.Experimental, Symbol("@optlevel")) 5 | # @eval Base.Experimental.@optlevel 1 6 | #end 7 | 8 | struct Identifier 9 | id::String 10 | end 11 | 12 | struct Record 13 | end 14 | 15 | struct ParseError <: Exception 16 | errmsg::AbstractString 17 | end 18 | 19 | struct LexerError <: Exception 20 | errmsg::AbstractString 21 | end 22 | 23 | include("memory.jl") 24 | include("lexer.jl") 25 | 26 | show(io::IO, exc::ParseError) = print(io, string("Parse error: ",exc.errmsg)) 27 | 28 | function parseOM(t::Union{Int,Float64,String,Bool}, tokens) 29 | return t 30 | end 31 | 32 | function checkToken(sym::Symbol, tok) 33 | if tok != sym 34 | throw(ParseError("Expected token of type $sym, got $(tok)")) 35 | end 36 | tok 37 | end 38 | 39 | function checkToken(t, tok) 40 | if typeof(tok) != t 41 | throw(ParseError("Expected token of type $t, got $(typeof(tok))")) 42 | end 43 | tok 44 | end 45 | 46 | function parseSequence(tokens, last) 47 | res = [] 48 | tok = popfirst!(tokens) 49 | if tok == last 50 | return res 51 | end 52 | push!(res, parseOM(tok, tokens)) 53 | tok = popfirst!(tokens) 54 | while tok == Symbol(",") 55 | push!(res, parseOM(popfirst!(tokens), tokens)) 56 | tok = popfirst!(tokens) 57 | end 58 | checkToken(last, tok) 59 | return collect(tuple(res...)) 60 | end 61 | 62 | function parseOM(t::Symbol, tokens) 63 | if t == Symbol("(") 64 | res = tuple(parseSequence(tokens, Symbol(")"))...) 65 | elseif t == Symbol("{") 66 | res = parseSequence(tokens, Symbol("}")) 67 | end 68 | end 69 | 70 | function parseOM(t::Identifier, tokens) 71 | if t.id == "NONE" 72 | checkToken(Symbol("("), popfirst!(tokens)) 73 | checkToken(Symbol(")"), popfirst!(tokens)) 74 | return nothing 75 | elseif t.id == "SOME" 76 | checkToken(Symbol("("), popfirst!(tokens)) 77 | res = parseOM(popfirst!(tokens), tokens) 78 | checkToken(Symbol(")"), popfirst!(tokens)) 79 | return res 80 | else 81 | return Symbol(t.id) 82 | end 83 | end 84 | 85 | function parseOM(t::Record, tokens) 86 | res = Tuple{String,Any}[] 87 | 88 | checkToken(Identifier, popfirst!(tokens)) 89 | tok = popfirst!(tokens) 90 | if tok != :end 91 | id = checkToken(Identifier, tok) 92 | checkToken(Symbol("="), popfirst!(tokens)) 93 | val = parseOM(popfirst!(tokens), tokens) 94 | push!(res, (id.id, val)) 95 | tok = popfirst!(tokens) 96 | while tok == Symbol(",") 97 | id = checkToken(Identifier, popfirst!(tokens)) 98 | checkToken(Symbol("="), popfirst!(tokens)) 99 | val = parseOM(popfirst!(tokens), tokens) 100 | push!(res, (id.id, val)) 101 | tok = popfirst!(tokens) 102 | end 103 | end 104 | checkToken(:end, tok) 105 | checkToken(Identifier, popfirst!(tokens)) 106 | checkToken(Symbol(";"), popfirst!(tokens)) 107 | # Fixes the type of the dictionary 108 | if isempty(res) 109 | return Dict(res) 110 | end 111 | return Dict(collect(Base.tuple(res...))) 112 | end 113 | 114 | function parseOM(tokens::AbstractArray{Any,1}) 115 | if length(tokens)==0 116 | return nothing 117 | end 118 | t = popfirst!(tokens) 119 | res = parseOM(t, tokens) 120 | if !isempty(tokens) 121 | throw(ParseError("Expected EOF, got output $tokens")) 122 | end 123 | res 124 | end 125 | 126 | function parseOM(str::String) 127 | parseOM(tokenize(str)) 128 | end 129 | 130 | end 131 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # OMJulia.jl 2 | 3 | *Julia scripting [OpenModelica](https://openmodelica.org/) interface.* 4 | 5 | [![][docs-dev-img]][docs-dev-url] [![][GHA-test-img]][GHA-test-url] [![][GHA-regressions-img]][GHA-regressions-url] 6 | 7 | ## Requirements 8 | 9 | - [OpenModelica](https://www.openmodelica.org/) 10 | - [Julia](https://julialang.org/) 11 | 12 | ## Installing OMJulia 13 | 14 | Make sure [OpenModelica](https://openmodelica.org/) is installed. 15 | 16 | Install OMJulia.jl with: 17 | 18 | ```julia 19 | julia> import Pkg; Pkg.add("OMJulia") 20 | ``` 21 | 22 | ## Usage 23 | 24 | ```julia 25 | julia> using OMJulia 26 | julia> omc = OMJulia.OMCSession() 27 | julia> sendExpression(omc, "getVersion()") 28 | "OpenModelica v1.21.0-dev-185-g9d983b8e35 (64-bit)" 29 | julia> sendExpression(omc, "model a end a;") 30 | 1-element Array{Symbol,1}: 31 | :a 32 | julia> sendExpression(omc, "getClassNames()") 33 | 1-element Array{Symbol,1}: 34 | :a 35 | julia> sendExpression(omc, "loadModel(Modelica)") 36 | true 37 | julia> sendExpression(omc, "simulate(Modelica.Electrical.Analog.Examples.CauerLowPassAnalog)") 38 | Dict{String,Any} with 10 entries: 39 | "timeCompile" => 9.97018 40 | "simulationOptions" => "startTime = 0.0, stopTime = 60.0, numberOfIntervals = 500, tolerance = 1e-006, method = 'dassl', fileNamePrefix = 'Modelica.Electrical.Analog.Examples.CauerLowPassAnalog', options = '', outputFormat = 'mat', variableFilter = '.*', cflags = '', simflags = ''" 41 | "messages" => "LOG_SUCCESS | info | The initialization finished successfully without homotopy method.\nLOG_SUCCESS | info | The simulation finished successfully.\n" 42 | "timeFrontend" => 0.45081 43 | "timeTotal" => 11.04 44 | "timeTemplates" => 0.104619 45 | "timeSimulation" => 0.29745 46 | "resultFile" => "PATH/TO/Modelica.Electrical.Analog.Examples.CauerLowPassAnalog_res.mat" 47 | "timeSimCode" => 0.0409317 48 | "timeBackend" => 0.140713 49 | julia> OMJulia.quit(omc) 50 | "quit requested, shutting server down\n" 51 | ``` 52 | 53 | ## Bug Reports 54 | 55 | - Submit OMJulia.jl bugs in this repositories [Issues](../../issues) section. 56 | - Submit OpenModelica related bugs through the [OpenModelica GitHub issues](https://github.com/OpenModelica/OpenModelica/issues/new). 57 | - [Pull requests](../../pulls) are welcome ❤️ 58 | 59 | ## License 60 | 61 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 62 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 63 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 64 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 65 | ACCORDING TO RECIPIENTS CHOICE. 66 | 67 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 68 | Public License (OSMC-PL) are obtained from OSMC, either from the above 69 | address, from the URLs: http://www.openmodelica.org or 70 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 71 | distribution. GNU version 3 is obtained from: 72 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 73 | http://www.opensource.org/licenses/BSD-3-Clause. 74 | 75 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 76 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 77 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 78 | CONDITIONS OF OSMC-PL. 79 | 80 | [docs-dev-img]: https://img.shields.io/badge/docs-dev-blue.svg 81 | [docs-dev-url]: https://OpenModelica.github.io/OMJulia.jl/dev/ 82 | 83 | [GHA-test-img]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/Test.yml/badge.svg?branch=master 84 | [GHA-test-url]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/Test.yml 85 | 86 | [GHA-regressions-img]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/regressionTests.yml/badge.svg?branch=master 87 | [GHA-regressions-url]: https://github.com/OpenModelica/OMJulia.jl/actions/workflows/regressionTests.yml 88 | -------------------------------------------------------------------------------- /test/omcTest.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | using Test 30 | import OMJulia 31 | 32 | @testset "OpenModelica" begin 33 | @testset "OMCSession" begin 34 | workdir = abspath(joinpath(@__DIR__, "test-session")) 35 | rm(workdir, recursive=true, force=true) 36 | mkpath(workdir) 37 | 38 | if Sys.iswindows() 39 | workdir = replace(workdir, "\\" => "\\\\") 40 | end 41 | 42 | oldwd = pwd() 43 | try 44 | omc = OMJulia.OMCSession() 45 | OMJulia.sendExpression(omc, "cd(\"$workdir\")") 46 | version = OMJulia.sendExpression(omc, "getVersion()") 47 | @test (startswith(version, "v1.") || startswith(version, "OpenModelica v1.") || startswith(version, "OpenModelica 1.")) 48 | a = OMJulia.sendExpression(omc, "model a end a;") 49 | @test a == [:a] 50 | 51 | classNames = OMJulia.sendExpression(omc, "getClassNames()") 52 | @test classNames == [:a] 53 | @test true == OMJulia.sendExpression(omc, "loadModel(Modelica)") 54 | res = OMJulia.sendExpression(omc, "simulate(Modelica.Electrical.Analog.Examples.CauerLowPassAnalog)") 55 | @test isfile(res["resultFile"]) 56 | @test occursin("The simulation finished successfully.", res["messages"]) 57 | 58 | @test 3 == OMJulia.sendExpression(omc, "1+2") 59 | OMJulia.quit(omc) 60 | finally 61 | cd(oldwd) 62 | end 63 | end 64 | 65 | @testset "Multiple sessions" begin 66 | workdir1 = abspath(joinpath(@__DIR__, "test-omc1")) 67 | workdir2 = abspath(joinpath(@__DIR__, "test-omc2")) 68 | rm(workdir1, recursive=true, force=true) 69 | rm(workdir2, recursive=true, force=true) 70 | mkpath(workdir1) 71 | mkpath(workdir2) 72 | 73 | if Sys.iswindows() 74 | workdir1 = replace(workdir1, "\\" => "\\\\") 75 | workdir2 = replace(workdir2, "\\" => "\\\\") 76 | end 77 | 78 | oldwd = pwd() 79 | try 80 | omc1 = OMJulia.OMCSession() 81 | omc2 = OMJulia.OMCSession() 82 | 83 | OMJulia.sendExpression(omc1, "cd(\"$workdir1\")") 84 | @test true == OMJulia.sendExpression(omc1, "loadModel(Modelica)") 85 | res = OMJulia.sendExpression(omc1, "simulate(Modelica.Blocks.Examples.PID_Controller)") 86 | @test isfile(joinpath(@__DIR__, "test-omc1", "Modelica.Blocks.Examples.PID_Controller_res.mat")) 87 | 88 | OMJulia.sendExpression(omc2, "cd(\"$workdir2\")") 89 | @test true == OMJulia.sendExpression(omc2, "loadModel(Modelica)") 90 | res = OMJulia.sendExpression(omc2, "simulate(Modelica.Blocks.Examples.PID_Controller)") 91 | @test isfile(joinpath(@__DIR__, "test-omc2", "Modelica.Blocks.Examples.PID_Controller_res.mat")) 92 | 93 | OMJulia.quit(omc1) 94 | OMJulia.quit(omc2) 95 | finally 96 | cd(oldwd) 97 | end 98 | end 99 | end 100 | -------------------------------------------------------------------------------- /test/apiTest.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | using Test 30 | using CSV 31 | using DataFrames 32 | import OMJulia 33 | 34 | @testset "API" begin 35 | workdir = abspath(joinpath(@__DIR__, "test-API")) 36 | rm(workdir, recursive=true, force=true) 37 | mkpath(workdir) 38 | if Sys.iswindows() 39 | workdir = replace(workdir, "\\" => "/") 40 | end 41 | 42 | omc = OMJulia.OMCSession() 43 | # Install packages 44 | @test OMJulia.API.updatePackageIndex(omc) 45 | versions = OMJulia.API.getAvailablePackageVersions(omc, "Modelica", version="3.0.0+maint.om") 46 | @test "3.0.0+maint.om" in versions 47 | @test OMJulia.API.upgradeInstalledPackages(omc) 48 | @test OMJulia.API.installPackage(omc, "Modelica", version = "") 49 | 50 | # Load file 51 | @test OMJulia.API.loadFile(omc, joinpath(@__DIR__, "../docs/testmodels/BouncingBall.mo")) 52 | 53 | # Enter non-existing directory 54 | @test_throws OMJulia.API.ScriptingError throw(OMJulia.API.ScriptingError(msg = "Test error message.")) 55 | @test_throws OMJulia.API.ScriptingError throw(OMJulia.API.ScriptingError(omc, msg = "Test error message.")) 56 | @test_throws OMJulia.API.ScriptingError OMJulia.API.cd(omc, "this/is/not/a/valid/directory/I/hope/otherwise/our/test/does/some/wild/stuff") 57 | 58 | dir = OMJulia.API.cd(omc, workdir) 59 | result = OMJulia.API.buildModel(omc, "BouncingBall") 60 | @test result[2] == "BouncingBall_init.xml" 61 | resultfile = joinpath(workdir, "BouncingBall_res.mat") 62 | 63 | # Remove simulation artifacts from previous buildModel 64 | if VERSION > v"1.4" 65 | foreach(rm, readdir(workdir, join=true)) 66 | else 67 | foreach(rm, joinpath.(workdir, readdir(workdir))) 68 | end 69 | OMJulia.API.simulate(omc, "BouncingBall") 70 | @test isfile(resultfile) 71 | 72 | vars = OMJulia.API.readSimulationResultVars(omc, resultfile) 73 | @test var = "h" in vars 74 | 75 | simres = OMJulia.API.readSimulationResult(omc, resultfile, ["time", "h", "v"]) 76 | @test simres[2][1] == 1.0 77 | 78 | df = DataFrame(:time => simres[1], :h => simres[2], :v => simres[3]) 79 | expectedFile = joinpath(workdir, "BouncingBall_ref.csv") 80 | wrongExpectedFile = joinpath(workdir, "BouncingBall_wrong.csv") 81 | CSV.write(expectedFile, df) 82 | df2 = copy(df) 83 | df2[:,2] .= df2[:,2] .* 0.01 84 | CSV.write(wrongExpectedFile, df2) 85 | 86 | @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, resultfile, expectedFile, "diff"; vars=String[]) 87 | @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, resultfile, expectedFile, "diff"; vars=["h", "v"]) 88 | @test (false, ["h"]) == OMJulia.API.diffSimulationResults(omc, resultfile, wrongExpectedFile, "diff"; vars=["h", "v"]) 89 | 90 | fmu = joinpath(workdir, "BouncingBall.fmu") 91 | OMJulia.API.buildModelFMU(omc, "BouncingBall") 92 | @test isfile(fmu) 93 | 94 | @test OMJulia.API.setCommandLineOptions(omc, "--generateSymbolicLinearization") 95 | 96 | @test OMJulia.API.loadFile(omc, joinpath(@__DIR__, "../docs/testmodels/ModSeborgCSTRorg.mo")) 97 | 98 | @test [:BouncingBall, :ModSeborgCSTRorg] == sort(OMJulia.API.getClassNames(omc)) 99 | 100 | flatModelicaCode = OMJulia.API.instantiateModel(omc, "BouncingBall") 101 | @test occursin("class BouncingBall", flatModelicaCode) 102 | 103 | OMJulia.quit(omc) 104 | end 105 | -------------------------------------------------------------------------------- /regression-tests/runSingleTest.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | import Pkg; Pkg.activate(@__DIR__) 30 | import OMJulia 31 | import FMI 32 | 33 | using Test 34 | using DataFrames 35 | using CSV 36 | 37 | """ 38 | Simulate single model to generate a result file. 39 | """ 40 | function testSimulation(omc::OMJulia.OMCSession, className::String) 41 | @info "\tSimulation" 42 | @testset "Simulation" begin 43 | res = OMJulia.API.simulate(omc, className; outputFormat="csv") 44 | resultFile = res["resultFile"] 45 | 46 | @test isfile(resultFile) 47 | return resultFile 48 | end 49 | end 50 | 51 | """ 52 | Build a FMU for a single model, import the generated FMU, simulate it and compare to given reference results. 53 | """ 54 | function testFmuExport(omc::OMJulia.OMCSession, className::String, referenceResult, recordValues; workdir::String) 55 | fmuPath = "" 56 | fmuImportSuccess = false 57 | @info "\tFMU Export" 58 | @testset "Export" begin 59 | fmuPath = OMJulia.API.buildModelFMU(omc, className) 60 | @test isfile(fmuPath) 61 | @test splitext(splitpath(fmuPath)[end]) == (className, ".fmu") 62 | end 63 | 64 | @info "\tFMU Import" 65 | @testset "Import" begin 66 | if isfile(fmuPath) 67 | fmu = FMI.fmiLoad(fmuPath) 68 | solution = FMI.fmiSimulate(fmu; recordValues = recordValues, showProgress=false) 69 | 70 | # Own implementation of CSV export, workaround for https://github.com/ThummeTo/FMI.jl/issues/198 71 | df = DataFrames.DataFrame(time = solution.values.t) 72 | for i in 1:length(solution.values.saveval[1]) 73 | for var in FMI.fmi2ValueReferenceToString(fmu, solution.valueReferences[i]) 74 | if in(var, recordValues) 75 | df[!, Symbol(var)] = [val[i] for val in solution.values.saveval] 76 | end 77 | end 78 | end 79 | fmiResult = joinpath(workdir, "FMI_results.csv") 80 | CSV.write(fmiResult, df) 81 | 82 | #FMI.fmiSaveSolution(solution, "FMI_results.csv") 83 | fmuImportSuccess = true 84 | end 85 | @test fmuImportSuccess 86 | end 87 | 88 | @info "\tCheck Results" 89 | @testset "Verification" begin 90 | if fmuImportSuccess 91 | @test (true, String[]) == OMJulia.API.diffSimulationResults(omc, "FMI_results.csv", referenceResult, "diff") 92 | else 93 | @test false 94 | end 95 | end 96 | end 97 | 98 | """ 99 | Run Simulation and FMU export/import test for all models. 100 | """ 101 | function runSingleTest(library, version, model, modeldir) 102 | local resultFile 103 | 104 | @info "Testing library: $library, model $model" 105 | mkpath(modeldir) 106 | omc = OMJulia.OMCSession() 107 | 108 | try 109 | @testset "$model" verbose=true begin 110 | @testset "Simulation" begin 111 | OMJulia.API.cd(omc, modeldir) 112 | 113 | @test OMJulia.API.loadModel(omc, library; priorityVersion = [version], requireExactVersion = true) 114 | resultFile = testSimulation(omc, model) 115 | end 116 | 117 | @testset "FMI" begin 118 | if isfile(resultFile) 119 | recordValues = names(CSV.read(resultFile, DataFrame))[2:end] 120 | filter!(val -> !startswith(val, "\$"), recordValues) # Filter internal variables 121 | testFmuExport(omc, model, resultFile, recordValues; workdir=modeldir) 122 | else 123 | @test false 124 | end 125 | end 126 | end 127 | finally 128 | OMJulia.quit(omc) 129 | end 130 | end 131 | 132 | # Comand-line interface 133 | if !isempty(PROGRAM_FILE) 134 | if length(ARGS) == 4 135 | library = ARGS[1] 136 | version = ARGS[2] 137 | model = ARGS[3] 138 | modeldir = ARGS[4] 139 | runSingleTest(library, version, model, modeldir) 140 | else 141 | @error "Wrong number of arguments" 142 | for a in ARGS; println(a); end 143 | return -1 144 | end 145 | end 146 | -------------------------------------------------------------------------------- /regression-tests/regressionTests.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | using Test 30 | 31 | """ 32 | Run single test process. 33 | 34 | Start a new Julia process. 35 | Kill process and throw an error when timeout is reached. 36 | Catch InterruptException, kill process and rethorw InterruptException. 37 | 38 | # Arguments 39 | - `library`: Modelica library name. 40 | - `version`: Library version. 41 | - `model`: Modelica model from library to test. 42 | - `testdir`: Test working directory. 43 | 44 | # Keywords 45 | - `timeout=10*60::Integer`: Timeout in seconds. Defaults to 10 minutes. 46 | """ 47 | function singleTest(library, version, model, testdir; 48 | timeout=10*60::Integer) 49 | 50 | mkpath(testdir) 51 | logFile = joinpath(testdir, "runSingleTest.log") 52 | rm(logFile, force=true) 53 | 54 | @info "Testing $model" 55 | 56 | cmd = Cmd(`$(joinpath(Sys.BINDIR, "julia")) runSingleTest.jl $(library) $(version) $(model) $(testdir)`, dir=@__DIR__) 57 | @info cmd 58 | plp = pipeline(cmd, stdout=logFile, stderr=logFile) 59 | process = run(plp, wait=false) 60 | 61 | try 62 | timer = Timer(0; interval=1) 63 | for _ in 1:timeout 64 | wait(timer) 65 | if !process_running(process) 66 | close(timer) 67 | break 68 | end 69 | end 70 | if process_running(process) 71 | @error "Killing $(process)" 72 | kill(process) 73 | end 74 | catch e 75 | if isa(e, InterruptException) && process_running(p) 76 | @error "Killing process $(cmd)." 77 | kill(p) 78 | end 79 | rethrow(e) 80 | end 81 | 82 | println(read(logFile, String)) 83 | 84 | status = (process.exitcode == 0) && 85 | isfile(joinpath(testdir, "$(model).fmu")) && 86 | isfile(joinpath(testdir, "FMI_results.csv")) 87 | 88 | return status 89 | end 90 | 91 | """ 92 | Run all tests. 93 | 94 | # Arguments 95 | - `libraries::Vector{Tuple{S,S}}`: Vector of tuples with library and version to test. 96 | - `models::Vector{Vector{S}}`: Vector of vectors with models to test for each library. 97 | 98 | # Keywords 99 | - `workdir`: Root working directory. 100 | """ 101 | function runTests(libraries::Vector{Tuple{S,S}}, 102 | models::Vector{Vector{S}}; 103 | workdir=abspath(joinpath(@__DIR__, "temp"))) where S<:AbstractString 104 | 105 | rm(workdir, recursive=true, force=true) # This can break on Windows when some program or file is still open 106 | mkpath(workdir) 107 | 108 | @testset "OpenModelica" begin 109 | for (i, (library, version)) in enumerate(libraries) 110 | @testset verbose=true "$library" begin 111 | libdir = joinpath(workdir, library) 112 | mkpath(libdir) 113 | 114 | for model in models[i] 115 | modeldir = joinpath(libdir, model) 116 | @testset "$model" begin 117 | @test singleTest(library, version, model, modeldir) 118 | end 119 | end 120 | end 121 | end 122 | end 123 | 124 | return 125 | end 126 | 127 | libraries = [ 128 | ("Modelica", "4.0.0") 129 | ] 130 | 131 | models = [ 132 | [ 133 | "Modelica.Blocks.Examples.Filter", 134 | "Modelica.Electrical.Analog.Examples.CauerLowPassAnalog", 135 | "Modelica.Blocks.Examples.RealNetwork1", 136 | "Modelica.Electrical.Digital.Examples.FlipFlop", 137 | "Modelica.Mechanics.Rotational.Examples.FirstGrounded", 138 | "Modelica.Mechanics.Rotational.Examples.CoupledClutches", 139 | "Modelica.Mechanics.MultiBody.Examples.Elementary.DoublePendulum", 140 | "Modelica.Mechanics.MultiBody.Examples.Elementary.FreeBody", 141 | "Modelica.Fluid.Examples.TraceSubstances.RoomCO2WithControls", 142 | "Modelica.Clocked.Examples.SimpleControlledDrive.ClockedWithDiscreteTextbookController", 143 | "Modelica.Fluid.Examples.PumpingSystem" 144 | ] 145 | ] 146 | -------------------------------------------------------------------------------- /docs/src/quickstart.md: -------------------------------------------------------------------------------- 1 | # Quickstart 2 | 3 | There are three ways to interact with OpenModelica: 4 | 5 | - [`ModelicaSystem`](@ref modelicasystem): A Julia style scripting API that handles low level 6 | API calls. 7 | - [`OMJulia.API`](@ref omjulia-api): A Julia style scripting API that handles low level 8 | [`sendExpression`](@ref) calls and has some degree of error handling. 9 | - [Scripting API with sendExpression](@ref scripting-api-with-sendExpression): 10 | Send expressions to the low level OpenModelica scripting API. 11 | 12 | The following examples demonstrate how to simulate Modelica model `BouncingBall` in both 13 | ways. 14 | 15 | ```modelica 16 | model BouncingBall 17 | parameter Real e=0.7 "coefficient of restitution"; 18 | parameter Real g=9.81 "gravity acceleration"; 19 | Real h(fixed=true, start=1) "height of ball"; 20 | Real v(fixed=true) "velocity of ball"; 21 | Boolean flying(fixed=true, start=true) "true, if ball is flying"; 22 | Boolean impact; 23 | Real v_new(fixed=true); 24 | Integer foo; 25 | equation 26 | impact = h <= 0.0; 27 | foo = if impact then 1 else 2; 28 | der(v) = if flying then -g else 0; 29 | der(h) = v; 30 | 31 | when {h <= 0.0 and v <= 0.0,impact} then 32 | v_new = if edge(impact) then -e*pre(v) else 0; 33 | flying = v_new > 0; 34 | reinit(v, v_new); 35 | end when; 36 | end BouncingBall; 37 | ``` 38 | 39 | !!! info 40 | The BouncingBall.mo file can be found in your OpenModelica installation directory in 41 | `/share/doc/omc/testmodels/BouncingBall.mo`. 42 | 43 | ## [ModelicaSystem](@id modelicasystem) 44 | 45 | Start a new [`OMJulia.OMCSession`](@ref) and create a new [`ModelicaSystem`](@ref) to 46 | build and simulate the `BouncingBall` model. 47 | Afterwards the result can be plotted in Julia. 48 | 49 | ```@repl ModelicaSystem-example 50 | using OMJulia 51 | using CSV, DataFrames, PlotlyJS 52 | using PlotlyDocumenter # hide 53 | 54 | mod = OMJulia.OMCSession(); 55 | 56 | installDir = sendExpression(mod, "getInstallationDirectoryPath()") 57 | bouncingBallFile = joinpath(installDir, "share", "doc", "omc", "testmodels", "BouncingBall.mo") 58 | 59 | ModelicaSystem(mod, 60 | bouncingBallFile, 61 | "BouncingBall") 62 | simulate(mod, 63 | resultfile = "BouncingBall_ref.csv", 64 | simflags = "-override=outputFormat=csv,stopTime=3") 65 | 66 | resultfile = joinpath(getWorkDirectory(mod), "BouncingBall_ref.csv") 67 | df = DataFrame(CSV.File(resultfile)); 68 | 69 | plt = plot(df, 70 | x=:time, y=:h, 71 | mode="lines", 72 | Layout(title="Bouncing Ball", height = 700)) 73 | 74 | OMJulia.quit(mod) 75 | ``` 76 | 77 | ```@example ModelicaSystem-example 78 | PlotlyDocumenter.to_documenter(plt) # hide 79 | ``` 80 | 81 | ## [OMJulia.API](@id omjulia-api) 82 | 83 | ## Example 84 | 85 | Start a new [`OMJulia.OMCSession`](@ref) and call 86 | [scripting API](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html) 87 | directly using the [`OMJulia.API`](@ref) module. 88 | 89 | ```@repl API-example 90 | using OMJulia 91 | using OMJulia.API: API 92 | 93 | using CSV, DataFrames, PlotlyJS 94 | using PlotlyDocumenter # hide 95 | 96 | omc = OMJulia.OMCSession(); 97 | omcWorkDir = mkpath(joinpath("docs", "omc-temp")) # hide 98 | mkpath(omcWorkDir) # hide 99 | API.cd(omcWorkDir) # hide 100 | installDir = API.getInstallationDirectoryPath(omc) 101 | bouncingBallFile = joinpath(installDir, "share", "doc", "omc", "testmodels", "BouncingBall.mo") 102 | bouncingBallFile = abspath(bouncingBallFile) # hide 103 | API.loadFile(omc, bouncingBallFile) 104 | res = API.simulate(omc, "BouncingBall"; stopTime=3.0, outputFormat = "csv") 105 | resultfile = res["resultFile"] 106 | df = DataFrame(CSV.File(resultfile)); 107 | 108 | plt = plot(df, 109 | x=:time, y=:h, 110 | mode="lines", 111 | Layout(title="Bouncing Ball", height = 700)) 112 | 113 | OMJulia.quit(omc) 114 | ``` 115 | 116 | ```@example API-example 117 | PlotlyDocumenter.to_documenter(plt) # hide 118 | ``` 119 | 120 | ## [Scripting API with sendExpression](@id scripting-api-with-sendExpression) 121 | 122 | Start a new [`OMJulia.OMCSession`](@ref) and send 123 | [scripting API](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html) 124 | expressions to the omc session with [`sendExpression()`](@ref). 125 | 126 | !!! warn 127 | All special characters inside a string argument for an API function need to be escaped 128 | when passing to `sendExpression`. 129 | 130 | E.g. MOS command 131 | ```modelica 132 | loadFile("/some/path/to/BouncingBall.mo"); 133 | ``` 134 | becomes Julia code 135 | ```julia 136 | sendExpression(omc, "loadFile(\"/some/path/to/BouncingBall.mo\")") 137 | ``` 138 | 139 | !!! info 140 | On Windows path separation symbol `\` needs to be escaped `\\` 141 | or replaced to Unix style path `/` to prevent warnings. 142 | 143 | 144 | ```@repl ModelicaSystem-example 145 | using OMJulia 146 | 147 | omc = OMJulia.OMCSession(); 148 | omcWorkDir = mkpath(joinpath("docs", "omc-temp")) # hide 149 | mkpath(omcWorkDir) # hide 150 | sendExpression(omc, "cd(\"$(omcWorkDir)\")") # hide 151 | installDir = sendExpression(omc, "getInstallationDirectoryPath()") 152 | bouncingBallFile = joinpath(installDir, "share", "doc", "omc", "testmodels", "BouncingBall.mo") 153 | bouncingBallFile = abspath(bouncingBallFile) # hide 154 | if Sys.iswindows() 155 | bouncingBallFile = replace(bouncingBallFile, "\\" => "/") 156 | end 157 | sendExpression(omc, "loadFile(\"$(bouncingBallFile)\")") 158 | sendExpression(omc, "simulate(BouncingBall)") 159 | OMJulia.quit(omc) 160 | ``` 161 | -------------------------------------------------------------------------------- /docs/src/modelicaSystem.md: -------------------------------------------------------------------------------- 1 | # Advanced API 2 | 3 | A Julia style scripting API that handles low level API calls. 4 | ## ModelicaSystem 5 | 6 | ```@docs 7 | ModelicaSystem 8 | ``` 9 | 10 | ```@docs 11 | OMJulia.OMCSession 12 | OMJulia.quit 13 | ``` 14 | 15 | ### Example 16 | Let us see the usage of [`ModelicaSystem`](@ref) with the help of Modelica model 17 | `ModSeborgCSTRorg` 18 | 19 | ```modelica 20 | model ModSeborgCSTRorg 21 | // Model of original Seborg CSTR in ode form 22 | // author: Bernt Lie, University of Southeast Norway,November 7, 2017 23 | 24 | // Parameters 25 | parameter Real V = 100 "Reactor volume, L"; 26 | parameter Real rho = 1e3 "Liquid density, g/L"; 27 | parameter Real a = 1 "Stoichiometric constant, -"; 28 | parameter Real EdR = 8750 "Activation temperature, K"; 29 | parameter Real k0 = exp(EdR/350) "Pre-exponential factor, 1/min"; 30 | parameter Real cph = 0.239 "Specific heat capacity of mixture, J.g-1.K-1"; 31 | parameter Real DrHt = -5e4 "Molar enthalpy of reaction, J/mol"; 32 | parameter Real UA = 5e4 "Heat transfer parameter, J/(min.K)"; 33 | 34 | // Initial state parameters 35 | parameter Real cA0 = 0.5 "Initial concentration of A, mol/L"; 36 | parameter Real T0 = 350 "Initial temperature, K"; 37 | // Declaring variables 38 | // -- states 39 | Real cA(start = cA0, fixed = true) "Initializing concentration of A in reactor, mol/L"; 40 | Real T(start = T0, fixed = true) "Initializing temperature in reactor, K"; 41 | // -- auxiliary variables 42 | Real r "Rate of reaction, mol/(L.s)"; 43 | Real k "Reaction 'constant', ..."; 44 | Real Qd "Heat flow rate, J/min"; 45 | // -- input variables 46 | input Real Vdi "Volumetric flow rate through reactor, L/min"; 47 | input Real cAi "Influent molar concentration of A, mol/L"; 48 | input Real Ti "Influent temperature, K"; 49 | input Real Tc "Cooling temperature', K"; 50 | // -- output variables 51 | output Real y_T "Reactor temperature, K"; 52 | // Equations constituting the model 53 | equation 54 | // Differential equations 55 | der(cA) = Vdi*(cAi-cA)/V- a*r; 56 | der(T) = Vdi*(Ti-T)/V + (-DrHt)*r/(rho*cph) + Qd/(rho*V*cph); 57 | // Algebraic equations 58 | r = k*cA^a; 59 | k = k0*exp(-EdR/T); 60 | Qd = UA*(Tc-T); 61 | // Outputs 62 | y_T = T; 63 | end ModSeborgCSTRorg 64 | ``` 65 | 66 | ```@repl ModSeborgCSTRorg-example 67 | using OMJulia 68 | mod = OMJulia.OMCSession() 69 | omcWorkDir = mkpath(joinpath("docs", "omc-temp")) # hide 70 | mkpath(omcWorkDir) # hide 71 | sendExpression(mod, "cd(\"$(omcWorkDir)\")") # hide 72 | ModelicaSystem(mod, 73 | joinpath("docs", "testmodels", "ModSeborgCSTRorg.mo"), 74 | "ModSeborgCSTRorg") 75 | ``` 76 | 77 | ## WorkDirectory 78 | 79 | For each [`OMJulia.OMCSession`](@ref) session a temporary work directory is created and 80 | the results are published in that working directory. 81 | In order to get the work directory use [`getWorkDirectory`](@ref). 82 | 83 | ```@docs 84 | getWorkDirectory 85 | ``` 86 | 87 | ```@repl ModSeborgCSTRorg-example 88 | getWorkDirectory(mod) 89 | ``` 90 | 91 | ## Build Model 92 | 93 | ```@docs 94 | buildModel 95 | ``` 96 | 97 | In case the Modelica model needs to be updated or additional simulation flags needs to be 98 | set using [`sendExpression`](@ref) The [`buildModel`](@ref) API can be used after 99 | [`ModelicaSystem`](@ref). 100 | 101 | ``` 102 | buildModel(omc) 103 | buildModel(omc, variableFilter="a|T") 104 | ``` 105 | 106 | ## Get Methods 107 | 108 | ```@docs 109 | getQuantities 110 | showQuantities 111 | getContinuous 112 | getInputs 113 | getOutputs 114 | getParameters 115 | getSimulationOptions 116 | getSolutions 117 | ``` 118 | 119 | ### Examples 120 | 121 | ```@repl ModSeborgCSTRorg-example 122 | getQuantities(mod) 123 | getQuantities(mod, "T") 124 | getQuantities(mod, ["T","cA"]) 125 | showQuantities(mod) 126 | ``` 127 | 128 | ```@repl ModSeborgCSTRorg-example 129 | getContinuous(mod) 130 | getContinuous(mod, ["Qd","Tc"]) 131 | ``` 132 | 133 | ```@repl ModSeborgCSTRorg-example 134 | getInputs(mod) 135 | getOutputs(mod) 136 | ``` 137 | 138 | ```@repl ModSeborgCSTRorg-example 139 | getParameters(mod) 140 | getParameters(mod, ["a","V"]) 141 | ``` 142 | 143 | ```@repl ModSeborgCSTRorg-example 144 | getSimulationOptions(mod) 145 | getSimulationOptions(mod, ["stepSize","tolerance"]) 146 | ``` 147 | ### Reading Simulation Results 148 | 149 | To read the simulation results, we need to simulate the model first and use the getSolution() API to read the results 150 | 151 | ```@repl ModSeborgCSTRorg-example 152 | simulate(mod) 153 | ``` 154 | 155 | The getSolution method can be used in two different ways. 156 | 1. using default result filename 157 | 2. use the result filenames provided by user 158 | 159 | This provides a way to compare simulation results and perform regression testing 160 | 161 | ```@repl ModSeborgCSTRorg-example 162 | getSolutions(mod) 163 | getSolutions(mod, ["time","a"]) 164 | ``` 165 | ### Examples of using resultFile provided by user location 166 | 167 | ``` 168 | getSolutions(mod, resultfile="C:/BouncingBal/tmpbouncingBall.mat") //returns list of simulation variables for which results are available , the resulfile location is provided by user 169 | getSolutions(mod, ["time","h"], resultfile="C:/BouncingBal/tmpbouncingBall.mat") // return list of array 170 | ``` 171 | ## Set Methods 172 | 173 | ```@docs 174 | setInputs 175 | setParameters 176 | setSimulationOptions 177 | ``` 178 | 179 | ### Examples 180 | 181 | ```@repl ModSeborgCSTRorg-example 182 | setInputs(mod, "cAi=100") 183 | setInputs(mod, ["cAi=100","Ti=200","Vdi=300","Tc=250"]) 184 | ``` 185 | 186 | ```@repl ModSeborgCSTRorg-example 187 | setParameters(mod, "a=3") 188 | setParameters(mod, ["a=4","V=200"]) 189 | ``` 190 | 191 | ```@repl ModSeborgCSTRorg-example 192 | setSimulationOptions(mod, ["stopTime=2.0", "tolerance=1e-08"]) 193 | ``` 194 | 195 | ## Advanced Simulation 196 | 197 | ```@docs 198 | simulate 199 | ``` 200 | 201 | An example of how to do advanced simulation to set parameter values using set methods and finally simulate the "ModSeborgCSTRorg.mo" model is given below . 202 | 203 | ```@repl ModSeborgCSTRorg-example 204 | getParameters(mod) 205 | setParameters(mod, "a=3.0") 206 | ``` 207 | 208 | To check whether new values are updated to model , we can again query the getParameters(). 209 | 210 | ```@repl ModSeborgCSTRorg-example 211 | getParameters(mod) 212 | ``` 213 | 214 | Similary we can also use setInputs() to set a value for the inputs during various time interval can also be done using the following. 215 | 216 | ```@repl ModSeborgCSTRorg-example 217 | setInputs(mod, "cAi=100") 218 | ``` 219 | And finally we simulate the model 220 | 221 | ```@repl ModSeborgCSTRorg-example 222 | simulate(mod) 223 | ``` 224 | 225 | ## Linearization 226 | 227 | ```@docs 228 | linearize 229 | getLinearizationOptions 230 | setLinearizationOptions 231 | getLinearInputs 232 | getLinearOutputs 233 | getLinearStates 234 | ``` 235 | 236 | ### Examples 237 | 238 | ```@repl ModSeborgCSTRorg-example 239 | getLinearizationOptions(mod) 240 | getLinearizationOptions(mod, ["startTime","stopTime"]) 241 | ``` 242 | 243 | ```@repl ModSeborgCSTRorg-example 244 | setLinearizationOptions(mod,["stopTime=2.0","tolerance=1e-06"]) 245 | ``` 246 | 247 | ```@repl ModSeborgCSTRorg-example 248 | res = linearize(mod) 249 | ``` 250 | 251 | ```@repl ModSeborgCSTRorg-example 252 | getLinearInputs(mod) 253 | getLinearOutputs(mod) 254 | getLinearStates(mod) 255 | ``` 256 | 257 | ## Sensitivity Analysis 258 | 259 | ```@docs 260 | sensitivity 261 | ``` 262 | 263 | ### Examples 264 | 265 | ```@repl ModSeborgCSTRorg-example 266 | (Sn, Sa) = sensitivity(mod, ["UA","EdR"], ["T","cA"], [1e-2,1e-4]) 267 | OMJulia.quit(mod) # hide 268 | ``` 269 | -------------------------------------------------------------------------------- /src/omcSession.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | """ 30 | Linearization <: Any 31 | 32 | Collection of linearization settings and variables. 33 | 34 | See also [``] 35 | """ 36 | mutable struct Linearization 37 | "Name of linear model in Julia function `linearfile`" 38 | linearmodelname::AbstractString 39 | "Julia file linearized_model.jl containing linearization matrices A, B, C and D." 40 | linearfile::AbstractString 41 | "Experiment settings for linearization" 42 | linearOptions::Dict{AbstractString, AbstractString} 43 | linearFlag::Bool 44 | 45 | "Input variables" 46 | linearinputs::Union{Missing, Any} 47 | "Output variables" 48 | linearoutputs::Union{Missing, Any} 49 | "State variables" 50 | linearstates::Union{Missing, Any} 51 | 52 | function Linearization() 53 | linearmodelname = "" 54 | linearfile = "" 55 | linearOptions = Dict("startTime" => "0.0", "stopTime" => "1.0", "stepSize" => "0.002", "tolerance" => "1e-6") 56 | linearFlag = false 57 | 58 | new(linearmodelname, linearfile, linearOptions, linearFlag, missing, missing, missing) 59 | end 60 | end 61 | 62 | """ 63 | ZMQSession <: Any 64 | 65 | ZeroMQ session running interactive omc process. 66 | 67 | ----------------------------------------- 68 | 69 | ZMQSession(omc::Union{String, Nothing}=nothing)::ZMQSession 70 | 71 | Start new interactive OpenModelica session using ZeroMQ. 72 | 73 | ## Arguments 74 | 75 | - `omc::Union{String, Nothing}`: Path to OpenModelica compiler. 76 | Use omc from `PATH` if nothing is provided. 77 | """ 78 | mutable struct ZMQSession 79 | context::ZMQ.Context 80 | socket::ZMQ.Socket 81 | omcprocess::Base.Process 82 | 83 | function ZMQSession(omc::Union{String, Nothing}=nothing)::ZMQSession 84 | args1 = "--interactive=zmq" 85 | randPortSuffix = Random.randstring(10) 86 | args2 = "-z=julia.$(randPortSuffix)" 87 | 88 | stdoutfile = "stdout-$(randPortSuffix).log" 89 | stderrfile = "stderr-$(randPortSuffix).log" 90 | 91 | local omcprocess 92 | if Sys.iswindows() 93 | if !isnothing(omc ) 94 | ompath = replace(omc, r"[/\\]+" => "/") 95 | dirpath = dirname(dirname(omc)) 96 | ## create a omc process with OPENMODELICAHOME set to custom directory 97 | @info("Setting environment variable OPENMODELICAHOME=\"$dirpath\" for this session.") 98 | withenv("OPENMODELICAHOME" => dirpath) do 99 | omcprocess = open(pipeline(`$omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile)) 100 | end 101 | else 102 | omhome = "" 103 | try 104 | omhome = ENV["OPENMODELICAHOME"] 105 | catch Exception 106 | println(Exception, "is not set, Please set the environment Variable") 107 | return 108 | end 109 | ompath = replace(joinpath(omhome, "bin", "omc.exe"), r"[/\\]+" => "/") 110 | # ompath=joinpath(omhome,"bin") 111 | ## create a omc process with default OPENMODELICAHOME set in environment variable 112 | withenv("OPENMODELICAHOME" => omhome) do 113 | omcprocess = open(pipeline(`$ompath $args1 $args2`)) 114 | end 115 | end 116 | portfile = join(["openmodelica.port.julia.", randPortSuffix]) 117 | else 118 | if Sys.isapple() 119 | # add omc to path if not exist 120 | ENV["PATH"] = ENV["PATH"] * "/opt/openmodelica/bin" 121 | if !isnothing(omc ) 122 | omcprocess = open(pipeline(`$omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile)) 123 | else 124 | omcprocess = open(pipeline(`omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile)) 125 | end 126 | else 127 | if !isnothing(omc ) 128 | omcprocess = open(pipeline(`$omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile)) 129 | else 130 | omcprocess = open(pipeline(`omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile)) 131 | end 132 | end 133 | portfile = join(["openmodelica.", ENV["USER"], ".port.julia.", randPortSuffix]) 134 | end 135 | fullpath = joinpath(tempdir(), portfile) 136 | @info("Path to zmq file=\"$fullpath\"") 137 | ## Try to find better approach if possible, as sleep does not work properly across different platform 138 | tries = 0 139 | while tries < 100 && !isfile(fullpath) 140 | sleep(0.02) 141 | tries += 1 142 | end 143 | # Catch omc error 144 | if process_exited(omcprocess) && omcprocess.exitcode != 0 145 | throw(OMCError(omcprocess.cmd, stdoutfile, stderrfile)) 146 | end 147 | rm.([stdoutfile, stderrfile], force=true) 148 | if tries >= 100 149 | throw(TimeoutError("ZMQ server port file \"$fullpath\" not created yet.")) 150 | end 151 | filedata = read(fullpath, String) 152 | context = ZMQ.Context() 153 | socket = ZMQ.Socket(context, REQ) 154 | ZMQ.connect(socket, filedata) 155 | 156 | zmqSession = new(context, socket, omcprocess) 157 | 158 | # Register finalizer to stop omc process when this OMCsession is no longer reachable 159 | f(zmqSession) = kill(zmqSession.omcprocess) 160 | finalizer(f, zmqSession) 161 | 162 | return zmqSession 163 | end 164 | end 165 | 166 | """ 167 | OMCSession <: Any 168 | 169 | OMC session struct. 170 | 171 | -------------- 172 | 173 | OMCSession(omc=nothing) 174 | 175 | Create new OpenModelica session. 176 | 177 | ## Arguments 178 | 179 | - `omc::Union{String, Nothing}`: Path to OpenModelica compiler. 180 | Use omc from `PATH` if nothing is provided. 181 | 182 | See also [`ModelicaSystem`](@ref), [`OMJulia.quit`](@ref). 183 | """ 184 | mutable struct OMCSession 185 | simulationFlag::Bool 186 | inputFlag::Bool 187 | simulateOptions::Dict 188 | overridevariables::Dict 189 | simoptoverride::Dict 190 | tempdir::AbstractString 191 | "Current directory" 192 | currentdir::AbstractString 193 | resultfile::AbstractString 194 | filepath::AbstractString 195 | modelname::AbstractString 196 | xmlfile::AbstractString 197 | csvfile::AbstractString 198 | "Filter for simulation result passed to buildModel" 199 | variableFilter::Union{AbstractString, Nothing} 200 | quantitieslist::Array{Any, 1} 201 | parameterlist::Dict 202 | inputlist::Dict 203 | outputlist::Dict 204 | "List of continuous model variables" 205 | continuouslist::Dict 206 | 207 | zmqSession::ZMQSession 208 | linearization::Linearization 209 | 210 | function OMCSession(omc::Union{String, Nothing}=nothing)::OMCSession 211 | this = new() 212 | this.overridevariables = Dict() 213 | this.simoptoverride = Dict() 214 | this.quantitieslist = Any[] 215 | this.parameterlist = Dict() 216 | this.simulateOptions = Dict() 217 | this.inputlist = Dict() 218 | this.outputlist = Dict() 219 | this.continuouslist = Dict() 220 | this.currentdir = pwd() 221 | this.filepath = "" 222 | this.modelname = "" 223 | this.xmlfile = "" 224 | this.resultfile = "" 225 | this.simulationFlag = false 226 | this.inputFlag = false 227 | this.csvfile = "" 228 | this.variableFilter = nothing 229 | this.tempdir = "" 230 | this.linearization = Linearization() 231 | this.zmqSession = ZMQSession(omc) 232 | 233 | return this 234 | end 235 | end 236 | 237 | """ 238 | quit(omc::OMCSession; timeout=4::Integer) 239 | 240 | Quit OMCSession. 241 | 242 | # Arguments 243 | - `omc::OMCSession`: OMC session. 244 | 245 | # Keywords 246 | - `timeout=4::Integer`: Timeout in seconds. 247 | 248 | See also [`OMJulia.OMCSession`](@ref). 249 | """ 250 | function quit(omc::OMCSession; timeout=4::Integer) 251 | 252 | tsk = @task sendExpression(omc, "quit()", parsed=false) 253 | schedule(tsk) 254 | Timer(timeout) do timer 255 | istaskdone(tsk) || Base.throwto(tsk, InterruptException()) 256 | end 257 | try 258 | fetch(tsk) 259 | catch _; 260 | if !process_exited(omc.zmqSession.omcprocess) 261 | @warn "omc process did not respond to send expression \"quit()\". Killing the process" 262 | kill(omc.zmqSession.omcprocess) 263 | end 264 | end 265 | 266 | # Wait one second for process to exit, kill otherwise 267 | if !process_exited(omc.zmqSession.omcprocess) 268 | Timer(1) do timer 269 | if !process_exited(omc.zmqSession.omcprocess) 270 | @warn "omc process didn't stop after evaluating expression \"quit()\". Killing the process" 271 | kill(omc.zmqSession.omcprocess) 272 | end 273 | end 274 | end 275 | 276 | return 277 | end 278 | -------------------------------------------------------------------------------- /docs/src/assets/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 46 | 48 | 49 | 51 | image/svg+xml 52 | 54 | 55 | 56 | 57 | 58 | 63 | 66 | 70 | 74 | 78 | 82 | 86 | 90 | 94 | 98 | 102 | 106 | 110 | 114 | 115 | 116 | 117 | -------------------------------------------------------------------------------- /docs/src/assets/logo-large-dark.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 21 | 23 | 49 | 51 | 52 | 54 | image/svg+xml 55 | 57 | 58 | 59 | 60 | 65 | 72 | 79 | 80 | 83 | 87 | 91 | 95 | 99 | 103 | 107 | 111 | 115 | 119 | 123 | 127 | 131 | 132 | 133 | 134 | -------------------------------------------------------------------------------- /docs/Manifest.toml: -------------------------------------------------------------------------------- 1 | # This file is machine-generated - editing it directly is not advised 2 | 3 | julia_version = "1.10.3" 4 | manifest_format = "2.0" 5 | project_hash = "604eeaface908c15652302f68480b22b5caadfdc" 6 | 7 | [[deps.ANSIColoredPrinters]] 8 | git-tree-sha1 = "574baf8110975760d391c710b6341da1afa48d8c" 9 | uuid = "a4c015fc-c6ff-483c-b24f-f7ea428134e9" 10 | version = "0.0.1" 11 | 12 | [[deps.ArgTools]] 13 | uuid = "0dad84c5-d112-42e6-8d28-ef12dabb789f" 14 | version = "1.1.1" 15 | 16 | [[deps.Artifacts]] 17 | uuid = "56f22d72-fd6d-98f1-02f0-08ddc0907c33" 18 | 19 | [[deps.AssetRegistry]] 20 | deps = ["Distributed", "JSON", "Pidfile", "SHA", "Test"] 21 | git-tree-sha1 = "b25e88db7944f98789130d7b503276bc34bc098e" 22 | uuid = "bf4720bc-e11a-5d0c-854e-bdca1663c893" 23 | version = "0.1.0" 24 | 25 | [[deps.Base64]] 26 | uuid = "2a0f44e3-6c83-55bd-87e4-b1978d98bd5f" 27 | 28 | [[deps.BitFlags]] 29 | git-tree-sha1 = "2dc09997850d68179b69dafb58ae806167a32b1b" 30 | uuid = "d1d4a3ce-64b1-5f1a-9ba4-7e7e69966f35" 31 | version = "0.1.8" 32 | 33 | [[deps.Blink]] 34 | deps = ["Base64", "Distributed", "HTTP", "JSExpr", "JSON", "Lazy", "Logging", "MacroTools", "Mustache", "Mux", "Pkg", "Reexport", "Sockets", "WebIO"] 35 | git-tree-sha1 = "bc93511973d1f949d45b0ea17878e6cb0ad484a1" 36 | uuid = "ad839575-38b3-5650-b840-f874b8c74a25" 37 | version = "0.12.9" 38 | 39 | [[deps.CSV]] 40 | deps = ["CodecZlib", "Dates", "FilePathsBase", "InlineStrings", "Mmap", "Parsers", "PooledArrays", "PrecompileTools", "SentinelArrays", "Tables", "Unicode", "WeakRefStrings", "WorkerUtilities"] 41 | git-tree-sha1 = "6c834533dc1fabd820c1db03c839bf97e45a3fab" 42 | uuid = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" 43 | version = "0.10.14" 44 | 45 | [[deps.CodecZlib]] 46 | deps = ["TranscodingStreams", "Zlib_jll"] 47 | git-tree-sha1 = "59939d8a997469ee05c4b4944560a820f9ba0d73" 48 | uuid = "944b1d66-785c-5afd-91f1-9de20f533193" 49 | version = "0.7.4" 50 | 51 | [[deps.ColorSchemes]] 52 | deps = ["ColorTypes", "ColorVectorSpace", "Colors", "FixedPointNumbers", "PrecompileTools", "Random"] 53 | git-tree-sha1 = "4b270d6465eb21ae89b732182c20dc165f8bf9f2" 54 | uuid = "35d6a980-a343-548e-a6ea-1d62b119f2f4" 55 | version = "3.25.0" 56 | 57 | [[deps.ColorTypes]] 58 | deps = ["FixedPointNumbers", "Random"] 59 | git-tree-sha1 = "b10d0b65641d57b8b4d5e234446582de5047050d" 60 | uuid = "3da002f7-5984-5a60-b8a6-cbb66c0b333f" 61 | version = "0.11.5" 62 | 63 | [[deps.ColorVectorSpace]] 64 | deps = ["ColorTypes", "FixedPointNumbers", "LinearAlgebra", "Requires", "Statistics", "TensorCore"] 65 | git-tree-sha1 = "a1f44953f2382ebb937d60dafbe2deea4bd23249" 66 | uuid = "c3611d14-8923-5661-9e6a-0046d554d3a4" 67 | version = "0.10.0" 68 | 69 | [deps.ColorVectorSpace.extensions] 70 | SpecialFunctionsExt = "SpecialFunctions" 71 | 72 | [deps.ColorVectorSpace.weakdeps] 73 | SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b" 74 | 75 | [[deps.Colors]] 76 | deps = ["ColorTypes", "FixedPointNumbers", "Reexport"] 77 | git-tree-sha1 = "362a287c3aa50601b0bc359053d5c2468f0e7ce0" 78 | uuid = "5ae59095-9a9b-59fe-a467-6f913c188581" 79 | version = "0.12.11" 80 | 81 | [[deps.Compat]] 82 | deps = ["TOML", "UUIDs"] 83 | git-tree-sha1 = "b1c55339b7c6c350ee89f2c1604299660525b248" 84 | uuid = "34da2185-b29b-5c13-b0c7-acf172513d20" 85 | version = "4.15.0" 86 | weakdeps = ["Dates", "LinearAlgebra"] 87 | 88 | [deps.Compat.extensions] 89 | CompatLinearAlgebraExt = "LinearAlgebra" 90 | 91 | [[deps.CompilerSupportLibraries_jll]] 92 | deps = ["Artifacts", "Libdl"] 93 | uuid = "e66e0078-7015-5450-92f7-15fbd957f2ae" 94 | version = "1.1.1+0" 95 | 96 | [[deps.ConcurrentUtilities]] 97 | deps = ["Serialization", "Sockets"] 98 | git-tree-sha1 = "6cbbd4d241d7e6579ab354737f4dd95ca43946e1" 99 | uuid = "f0e56b4a-5159-44fe-b623-3e5288b988bb" 100 | version = "2.4.1" 101 | 102 | [[deps.Crayons]] 103 | git-tree-sha1 = "249fe38abf76d48563e2f4556bebd215aa317e15" 104 | uuid = "a8cc5b0e-0ffa-5ad4-8c14-923d3ee1735f" 105 | version = "4.1.1" 106 | 107 | [[deps.DataAPI]] 108 | git-tree-sha1 = "abe83f3a2f1b857aac70ef8b269080af17764bbe" 109 | uuid = "9a962f9c-6df0-11e9-0e5d-c546b8b5ee8a" 110 | version = "1.16.0" 111 | 112 | [[deps.DataFrames]] 113 | deps = ["Compat", "DataAPI", "DataStructures", "Future", "InlineStrings", "InvertedIndices", "IteratorInterfaceExtensions", "LinearAlgebra", "Markdown", "Missings", "PooledArrays", "PrecompileTools", "PrettyTables", "Printf", "REPL", "Random", "Reexport", "SentinelArrays", "SortingAlgorithms", "Statistics", "TableTraits", "Tables", "Unicode"] 114 | git-tree-sha1 = "04c738083f29f86e62c8afc341f0967d8717bdb8" 115 | uuid = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 116 | version = "1.6.1" 117 | 118 | [[deps.DataStructures]] 119 | deps = ["Compat", "InteractiveUtils", "OrderedCollections"] 120 | git-tree-sha1 = "1d0a14036acb104d9e89698bd408f63ab58cdc82" 121 | uuid = "864edb3b-99cc-5e75-8d2d-829cb0a9cfe8" 122 | version = "0.18.20" 123 | 124 | [[deps.DataValueInterfaces]] 125 | git-tree-sha1 = "bfc1187b79289637fa0ef6d4436ebdfe6905cbd6" 126 | uuid = "e2d170a0-9d28-54be-80f0-106bbe20a464" 127 | version = "1.0.0" 128 | 129 | [[deps.Dates]] 130 | deps = ["Printf"] 131 | uuid = "ade2ca70-3891-5945-98fb-dc099432e06a" 132 | 133 | [[deps.DelimitedFiles]] 134 | deps = ["Mmap"] 135 | git-tree-sha1 = "9e2f36d3c96a820c678f2f1f1782582fcf685bae" 136 | uuid = "8bb1440f-4735-579b-a4ab-409b98df4dab" 137 | version = "1.9.1" 138 | 139 | [[deps.Distributed]] 140 | deps = ["Random", "Serialization", "Sockets"] 141 | uuid = "8ba89e20-285c-5b6f-9357-94700520ee1b" 142 | 143 | [[deps.DocStringExtensions]] 144 | deps = ["LibGit2"] 145 | git-tree-sha1 = "2fb1e02f2b635d0845df5d7c167fec4dd739b00d" 146 | uuid = "ffbed154-4ef7-542d-bbb7-c09d3a79fcae" 147 | version = "0.9.3" 148 | 149 | [[deps.Documenter]] 150 | deps = ["ANSIColoredPrinters", "Base64", "Dates", "DocStringExtensions", "IOCapture", "InteractiveUtils", "JSON", "LibGit2", "Logging", "Markdown", "REPL", "Test", "Unicode"] 151 | git-tree-sha1 = "39fd748a73dce4c05a9655475e437170d8fb1b67" 152 | uuid = "e30172f5-a6a5-5a46-863b-614d45cd2de4" 153 | version = "0.27.25" 154 | 155 | [[deps.Downloads]] 156 | deps = ["ArgTools", "FileWatching", "LibCURL", "NetworkOptions"] 157 | uuid = "f43a241f-c20a-4ad4-852c-f6b1247861c6" 158 | version = "1.6.0" 159 | 160 | [[deps.ExceptionUnwrapping]] 161 | deps = ["Test"] 162 | git-tree-sha1 = "dcb08a0d93ec0b1cdc4af184b26b591e9695423a" 163 | uuid = "460bff9d-24e4-43bc-9d9f-a8973cb893f4" 164 | version = "0.1.10" 165 | 166 | [[deps.FilePathsBase]] 167 | deps = ["Compat", "Dates", "Mmap", "Printf", "Test", "UUIDs"] 168 | git-tree-sha1 = "9f00e42f8d99fdde64d40c8ea5d14269a2e2c1aa" 169 | uuid = "48062228-2e41-5def-b9a4-89aafe57970f" 170 | version = "0.9.21" 171 | 172 | [[deps.FileWatching]] 173 | uuid = "7b1f6079-737a-58dc-b8bc-7a2ca5c1b5ee" 174 | 175 | [[deps.FixedPointNumbers]] 176 | deps = ["Statistics"] 177 | git-tree-sha1 = "05882d6995ae5c12bb5f36dd2ed3f61c98cbb172" 178 | uuid = "53c48c17-4a7d-5ca2-90c5-79b7896eea93" 179 | version = "0.8.5" 180 | 181 | [[deps.FunctionalCollections]] 182 | deps = ["Test"] 183 | git-tree-sha1 = "04cb9cfaa6ba5311973994fe3496ddec19b6292a" 184 | uuid = "de31a74c-ac4f-5751-b3fd-e18cd04993ca" 185 | version = "0.5.0" 186 | 187 | [[deps.Future]] 188 | deps = ["Random"] 189 | uuid = "9fa8497b-333b-5362-9e8d-4d0656e87820" 190 | 191 | [[deps.HTTP]] 192 | deps = ["Base64", "CodecZlib", "ConcurrentUtilities", "Dates", "ExceptionUnwrapping", "Logging", "LoggingExtras", "MbedTLS", "NetworkOptions", "OpenSSL", "Random", "SimpleBufferStream", "Sockets", "URIs", "UUIDs"] 193 | git-tree-sha1 = "d1d712be3164d61d1fb98e7ce9bcbc6cc06b45ed" 194 | uuid = "cd3eb016-35fb-5094-929b-558a96fad6f3" 195 | version = "1.10.8" 196 | 197 | [[deps.Hiccup]] 198 | deps = ["MacroTools", "Test"] 199 | git-tree-sha1 = "6187bb2d5fcbb2007c39e7ac53308b0d371124bd" 200 | uuid = "9fb69e20-1954-56bb-a84f-559cc56a8ff7" 201 | version = "0.2.2" 202 | 203 | [[deps.HypertextLiteral]] 204 | deps = ["Tricks"] 205 | git-tree-sha1 = "7134810b1afce04bbc1045ca1985fbe81ce17653" 206 | uuid = "ac1192a8-f4b3-4bfe-ba22-af5b92cd3ab2" 207 | version = "0.9.5" 208 | 209 | [[deps.IOCapture]] 210 | deps = ["Logging", "Random"] 211 | git-tree-sha1 = "8b72179abc660bfab5e28472e019392b97d0985c" 212 | uuid = "b5f81e59-6552-4d32-b1f0-c071b021bf89" 213 | version = "0.2.4" 214 | 215 | [[deps.InlineStrings]] 216 | deps = ["Parsers"] 217 | git-tree-sha1 = "9cc2baf75c6d09f9da536ddf58eb2f29dedaf461" 218 | uuid = "842dd82b-1e85-43dc-bf29-5d0ee9dffc48" 219 | version = "1.4.0" 220 | 221 | [[deps.InteractiveUtils]] 222 | deps = ["Markdown"] 223 | uuid = "b77e0a4c-d291-57a0-90e8-8db25a27a240" 224 | 225 | [[deps.InvertedIndices]] 226 | git-tree-sha1 = "0dc7b50b8d436461be01300fd8cd45aa0274b038" 227 | uuid = "41ab1584-1d38-5bbf-9106-f11c6c58b48f" 228 | version = "1.3.0" 229 | 230 | [[deps.IteratorInterfaceExtensions]] 231 | git-tree-sha1 = "a3f24677c21f5bbe9d2a714f95dcd58337fb2856" 232 | uuid = "82899510-4779-5014-852e-03e436cf321d" 233 | version = "1.0.0" 234 | 235 | [[deps.JLLWrappers]] 236 | deps = ["Artifacts", "Preferences"] 237 | git-tree-sha1 = "7e5d6779a1e09a36db2a7b6cff50942a0a7d0fca" 238 | uuid = "692b3bcd-3c85-4b1f-b108-f13ce0eb3210" 239 | version = "1.5.0" 240 | 241 | [[deps.JSExpr]] 242 | deps = ["JSON", "MacroTools", "Observables", "WebIO"] 243 | git-tree-sha1 = "b413a73785b98474d8af24fd4c8a975e31df3658" 244 | uuid = "97c1335a-c9c5-57fe-bc5d-ec35cebe8660" 245 | version = "0.5.4" 246 | 247 | [[deps.JSON]] 248 | deps = ["Dates", "Mmap", "Parsers", "Unicode"] 249 | git-tree-sha1 = "31e996f0a15c7b280ba9f76636b3ff9e2ae58c9a" 250 | uuid = "682c06a0-de6a-54ab-a142-c8b1cf79cde6" 251 | version = "0.21.4" 252 | 253 | [[deps.Kaleido_jll]] 254 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 255 | git-tree-sha1 = "43032da5832754f58d14a91ffbe86d5f176acda9" 256 | uuid = "f7e6163d-2fa5-5f23-b69c-1db539e41963" 257 | version = "0.2.1+0" 258 | 259 | [[deps.LaTeXStrings]] 260 | git-tree-sha1 = "50901ebc375ed41dbf8058da26f9de442febbbec" 261 | uuid = "b964fa9f-0449-5b57-a5c2-d3ea65f4040f" 262 | version = "1.3.1" 263 | 264 | [[deps.Lazy]] 265 | deps = ["MacroTools"] 266 | git-tree-sha1 = "1370f8202dac30758f3c345f9909b97f53d87d3f" 267 | uuid = "50d2b5c4-7a5e-59d5-8109-a42b560f39c0" 268 | version = "0.15.1" 269 | 270 | [[deps.LibCURL]] 271 | deps = ["LibCURL_jll", "MozillaCACerts_jll"] 272 | uuid = "b27032c2-a3e7-50c8-80cd-2d36dbcbfd21" 273 | version = "0.6.4" 274 | 275 | [[deps.LibCURL_jll]] 276 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll", "Zlib_jll", "nghttp2_jll"] 277 | uuid = "deac9b47-8bc7-5906-a0fe-35ac56dc84c0" 278 | version = "8.4.0+0" 279 | 280 | [[deps.LibGit2]] 281 | deps = ["Base64", "LibGit2_jll", "NetworkOptions", "Printf", "SHA"] 282 | uuid = "76f85450-5226-5b5a-8eaa-529ad045b433" 283 | 284 | [[deps.LibGit2_jll]] 285 | deps = ["Artifacts", "LibSSH2_jll", "Libdl", "MbedTLS_jll"] 286 | uuid = "e37daf67-58a4-590a-8e99-b0245dd2ffc5" 287 | version = "1.6.4+0" 288 | 289 | [[deps.LibSSH2_jll]] 290 | deps = ["Artifacts", "Libdl", "MbedTLS_jll"] 291 | uuid = "29816b5a-b9ab-546f-933c-edad1886dfa8" 292 | version = "1.11.0+1" 293 | 294 | [[deps.Libdl]] 295 | uuid = "8f399da3-3557-5675-b5ff-fb832c97cbdb" 296 | 297 | [[deps.Libiconv_jll]] 298 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 299 | git-tree-sha1 = "f9557a255370125b405568f9767d6d195822a175" 300 | uuid = "94ce4f54-9a6c-5748-9c1c-f9c7231a4531" 301 | version = "1.17.0+0" 302 | 303 | [[deps.LightXML]] 304 | deps = ["Libdl", "XML2_jll"] 305 | git-tree-sha1 = "3a994404d3f6709610701c7dabfc03fed87a81f8" 306 | uuid = "9c8b4983-aa76-5018-a973-4c85ecc9e179" 307 | version = "0.9.1" 308 | 309 | [[deps.LinearAlgebra]] 310 | deps = ["Libdl", "OpenBLAS_jll", "libblastrampoline_jll"] 311 | uuid = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e" 312 | 313 | [[deps.Logging]] 314 | uuid = "56ddb016-857b-54e1-b83d-db4d58db5568" 315 | 316 | [[deps.LoggingExtras]] 317 | deps = ["Dates", "Logging"] 318 | git-tree-sha1 = "c1dd6d7978c12545b4179fb6153b9250c96b0075" 319 | uuid = "e6f89c97-d47a-5376-807f-9c37f3926c36" 320 | version = "1.0.3" 321 | 322 | [[deps.MacroTools]] 323 | deps = ["Markdown", "Random"] 324 | git-tree-sha1 = "2fa9ee3e63fd3a4f7a9a4f4744a52f4856de82df" 325 | uuid = "1914dd2f-81c6-5fcd-8719-6d5c9610ff09" 326 | version = "0.5.13" 327 | 328 | [[deps.Markdown]] 329 | deps = ["Base64"] 330 | uuid = "d6f4376e-aef5-505a-96c1-9c027394607a" 331 | 332 | [[deps.MbedTLS]] 333 | deps = ["Dates", "MbedTLS_jll", "MozillaCACerts_jll", "NetworkOptions", "Random", "Sockets"] 334 | git-tree-sha1 = "c067a280ddc25f196b5e7df3877c6b226d390aaf" 335 | uuid = "739be429-bea8-5141-9913-cc70e7f3736d" 336 | version = "1.1.9" 337 | 338 | [[deps.MbedTLS_jll]] 339 | deps = ["Artifacts", "Libdl"] 340 | uuid = "c8ffd9c3-330d-5841-b78e-0817d7145fa1" 341 | version = "2.28.2+1" 342 | 343 | [[deps.Missings]] 344 | deps = ["DataAPI"] 345 | git-tree-sha1 = "ec4f7fbeab05d7747bdf98eb74d130a2a2ed298d" 346 | uuid = "e1d29d7a-bbdc-5cf2-9ac0-f12de2c33e28" 347 | version = "1.2.0" 348 | 349 | [[deps.Mmap]] 350 | uuid = "a63ad114-7e13-5084-954f-fe012c677804" 351 | 352 | [[deps.MozillaCACerts_jll]] 353 | uuid = "14a3606d-f60d-562e-9121-12d972cd8159" 354 | version = "2023.1.10" 355 | 356 | [[deps.Mustache]] 357 | deps = ["Printf", "Tables"] 358 | git-tree-sha1 = "a7cefa21a2ff993bff0456bf7521f46fc077ddf1" 359 | uuid = "ffc61752-8dc7-55ee-8c37-f3e9cdd09e70" 360 | version = "1.0.19" 361 | 362 | [[deps.Mux]] 363 | deps = ["AssetRegistry", "Base64", "HTTP", "Hiccup", "MbedTLS", "Pkg", "Sockets"] 364 | git-tree-sha1 = "7295d849103ac4fcbe3b2e439f229c5cc77b9b69" 365 | uuid = "a975b10e-0019-58db-a62f-e48ff68538c9" 366 | version = "1.0.2" 367 | 368 | [[deps.NetworkOptions]] 369 | uuid = "ca575930-c2e3-43a9-ace4-1e988b2c1908" 370 | version = "1.2.0" 371 | 372 | [[deps.OMJulia]] 373 | deps = ["DataFrames", "DataStructures", "LightXML", "Random", "ZMQ"] 374 | path = "/home/aheuermann/workspace/julia/OMJulia.jl" 375 | uuid = "0f4fe800-344e-11e9-2949-fb537ad918e1" 376 | version = "0.3.1" 377 | 378 | [[deps.Observables]] 379 | git-tree-sha1 = "7438a59546cf62428fc9d1bc94729146d37a7225" 380 | uuid = "510215fc-4207-5dde-b226-833fc4488ee2" 381 | version = "0.5.5" 382 | 383 | [[deps.OpenBLAS_jll]] 384 | deps = ["Artifacts", "CompilerSupportLibraries_jll", "Libdl"] 385 | uuid = "4536629a-c528-5b80-bd46-f80d51c5b363" 386 | version = "0.3.23+4" 387 | 388 | [[deps.OpenSSL]] 389 | deps = ["BitFlags", "Dates", "MozillaCACerts_jll", "OpenSSL_jll", "Sockets"] 390 | git-tree-sha1 = "38cb508d080d21dc1128f7fb04f20387ed4c0af4" 391 | uuid = "4d8831e6-92b7-49fb-bdf8-b643e874388c" 392 | version = "1.4.3" 393 | 394 | [[deps.OpenSSL_jll]] 395 | deps = ["Artifacts", "JLLWrappers", "Libdl"] 396 | git-tree-sha1 = "3da7367955dcc5c54c1ba4d402ccdc09a1a3e046" 397 | uuid = "458c3c95-2e84-50aa-8efc-19380b2a3a95" 398 | version = "3.0.13+1" 399 | 400 | [[deps.OrderedCollections]] 401 | git-tree-sha1 = "dfdf5519f235516220579f949664f1bf44e741c5" 402 | uuid = "bac558e1-5e72-5ebc-8fee-abe8a469f55d" 403 | version = "1.6.3" 404 | 405 | [[deps.PackageExtensionCompat]] 406 | git-tree-sha1 = "fb28e33b8a95c4cee25ce296c817d89cc2e53518" 407 | uuid = "65ce6f38-6b18-4e1d-a461-8949797d7930" 408 | version = "1.0.2" 409 | weakdeps = ["Requires", "TOML"] 410 | 411 | [[deps.Parameters]] 412 | deps = ["OrderedCollections", "UnPack"] 413 | git-tree-sha1 = "34c0e9ad262e5f7fc75b10a9952ca7692cfc5fbe" 414 | uuid = "d96e819e-fc66-5662-9728-84c9c7592b0a" 415 | version = "0.12.3" 416 | 417 | [[deps.Parsers]] 418 | deps = ["Dates", "PrecompileTools", "UUIDs"] 419 | git-tree-sha1 = "8489905bcdbcfac64d1daa51ca07c0d8f0283821" 420 | uuid = "69de0a69-1ddd-5017-9359-2bf0b02dc9f0" 421 | version = "2.8.1" 422 | 423 | [[deps.Pidfile]] 424 | deps = ["FileWatching", "Test"] 425 | git-tree-sha1 = "2d8aaf8ee10df53d0dfb9b8ee44ae7c04ced2b03" 426 | uuid = "fa939f87-e72e-5be4-a000-7fc836dbe307" 427 | version = "1.3.0" 428 | 429 | [[deps.Pkg]] 430 | deps = ["Artifacts", "Dates", "Downloads", "FileWatching", "LibGit2", "Libdl", "Logging", "Markdown", "Printf", "REPL", "Random", "SHA", "Serialization", "TOML", "Tar", "UUIDs", "p7zip_jll"] 431 | uuid = "44cfe95a-1eb2-52ea-b672-e2afdf69b78f" 432 | version = "1.10.0" 433 | 434 | [[deps.PlotlyBase]] 435 | deps = ["ColorSchemes", "Dates", "DelimitedFiles", "DocStringExtensions", "JSON", "LaTeXStrings", "Logging", "Parameters", "Pkg", "REPL", "Requires", "Statistics", "UUIDs"] 436 | git-tree-sha1 = "56baf69781fc5e61607c3e46227ab17f7040ffa2" 437 | uuid = "a03496cd-edff-5a9b-9e67-9cda94a718b5" 438 | version = "0.8.19" 439 | 440 | [[deps.PlotlyDocumenter]] 441 | deps = ["Downloads", "HypertextLiteral", "PackageExtensionCompat", "Random"] 442 | git-tree-sha1 = "e21d99c9987d32251cff85204119ac0c07ef399c" 443 | uuid = "9b90f1cd-2639-4507-8b17-2fbe371ceceb" 444 | version = "0.1.3" 445 | 446 | [deps.PlotlyDocumenter.extensions] 447 | PlotlyBaseExt = "PlotlyBase" 448 | PlotlyJSExt = "PlotlyJS" 449 | PlotlyLightExt = "PlotlyLight" 450 | 451 | [deps.PlotlyDocumenter.weakdeps] 452 | PlotlyBase = "a03496cd-edff-5a9b-9e67-9cda94a718b5" 453 | PlotlyJS = "f0f68f2c-4968-5e81-91da-67840de0976a" 454 | PlotlyLight = "ca7969ec-10b3-423e-8d99-40f33abb42bf" 455 | 456 | [[deps.PlotlyJS]] 457 | deps = ["Base64", "Blink", "DelimitedFiles", "JSExpr", "JSON", "Kaleido_jll", "Markdown", "Pkg", "PlotlyBase", "PlotlyKaleido", "REPL", "Reexport", "Requires", "WebIO"] 458 | git-tree-sha1 = "e62d886d33b81c371c9d4e2f70663c0637f19459" 459 | uuid = "f0f68f2c-4968-5e81-91da-67840de0976a" 460 | version = "0.18.13" 461 | 462 | [deps.PlotlyJS.extensions] 463 | CSVExt = "CSV" 464 | DataFramesExt = ["DataFrames", "CSV"] 465 | IJuliaExt = "IJulia" 466 | JSON3Ext = "JSON3" 467 | 468 | [deps.PlotlyJS.weakdeps] 469 | CSV = "336ed68f-0bac-5ca0-87d4-7b16caf5d00b" 470 | DataFrames = "a93c6f00-e57d-5684-b7b6-d8193f3e46c0" 471 | IJulia = "7073ff75-c697-5162-941a-fcdaad2a7d2a" 472 | JSON3 = "0f8b85d8-7281-11e9-16c2-39a750bddbf1" 473 | 474 | [[deps.PlotlyKaleido]] 475 | deps = ["Base64", "JSON", "Kaleido_jll"] 476 | git-tree-sha1 = "2650cd8fb83f73394996d507b3411a7316f6f184" 477 | uuid = "f2990250-8cf9-495f-b13a-cce12b45703c" 478 | version = "2.2.4" 479 | 480 | [[deps.PooledArrays]] 481 | deps = ["DataAPI", "Future"] 482 | git-tree-sha1 = "36d8b4b899628fb92c2749eb488d884a926614d3" 483 | uuid = "2dfb63ee-cc39-5dd5-95bd-886bf059d720" 484 | version = "1.4.3" 485 | 486 | [[deps.PrecompileTools]] 487 | deps = ["Preferences"] 488 | git-tree-sha1 = "5aa36f7049a63a1528fe8f7c3f2113413ffd4e1f" 489 | uuid = "aea7be01-6a6a-4083-8856-8a6e6704d82a" 490 | version = "1.2.1" 491 | 492 | [[deps.Preferences]] 493 | deps = ["TOML"] 494 | git-tree-sha1 = "9306f6085165d270f7e3db02af26a400d580f5c6" 495 | uuid = "21216c6a-2e73-6563-6e65-726566657250" 496 | version = "1.4.3" 497 | 498 | [[deps.PrettyTables]] 499 | deps = ["Crayons", "LaTeXStrings", "Markdown", "PrecompileTools", "Printf", "Reexport", "StringManipulation", "Tables"] 500 | git-tree-sha1 = "66b20dd35966a748321d3b2537c4584cf40387c7" 501 | uuid = "08abe8d2-0d0c-5749-adfa-8a2ac140af0d" 502 | version = "2.3.2" 503 | 504 | [[deps.Printf]] 505 | deps = ["Unicode"] 506 | uuid = "de0858da-6303-5e67-8744-51eddeeeb8d7" 507 | 508 | [[deps.REPL]] 509 | deps = ["InteractiveUtils", "Markdown", "Sockets", "Unicode"] 510 | uuid = "3fa0cd96-eef1-5676-8a61-b3b8758bbffb" 511 | 512 | [[deps.Random]] 513 | deps = ["SHA"] 514 | uuid = "9a3f8284-a2c9-5f02-9a11-845980a1fd5c" 515 | 516 | [[deps.Reexport]] 517 | git-tree-sha1 = "45e428421666073eab6f2da5c9d310d99bb12f9b" 518 | uuid = "189a3867-3050-52da-a836-e630ba90ab69" 519 | version = "1.2.2" 520 | 521 | [[deps.Requires]] 522 | deps = ["UUIDs"] 523 | git-tree-sha1 = "838a3a4188e2ded87a4f9f184b4b0d78a1e91cb7" 524 | uuid = "ae029012-a4dd-5104-9daa-d747884805df" 525 | version = "1.3.0" 526 | 527 | [[deps.SHA]] 528 | uuid = "ea8e919c-243c-51af-8825-aaa63cd721ce" 529 | version = "0.7.0" 530 | 531 | [[deps.SentinelArrays]] 532 | deps = ["Dates", "Random"] 533 | git-tree-sha1 = "90b4f68892337554d31cdcdbe19e48989f26c7e6" 534 | uuid = "91c51154-3ec4-41a3-a24f-3f23e20d615c" 535 | version = "1.4.3" 536 | 537 | [[deps.Serialization]] 538 | uuid = "9e88b42a-f829-5b0c-bbe9-9e923198166b" 539 | 540 | [[deps.SimpleBufferStream]] 541 | git-tree-sha1 = "874e8867b33a00e784c8a7e4b60afe9e037b74e1" 542 | uuid = "777ac1f9-54b0-4bf8-805c-2214025038e7" 543 | version = "1.1.0" 544 | 545 | [[deps.Sockets]] 546 | uuid = "6462fe0b-24de-5631-8697-dd941f90decc" 547 | 548 | [[deps.SortingAlgorithms]] 549 | deps = ["DataStructures"] 550 | git-tree-sha1 = "66e0a8e672a0bdfca2c3f5937efb8538b9ddc085" 551 | uuid = "a2af1166-a08f-5f64-846c-94a0d3cef48c" 552 | version = "1.2.1" 553 | 554 | [[deps.SparseArrays]] 555 | deps = ["Libdl", "LinearAlgebra", "Random", "Serialization", "SuiteSparse_jll"] 556 | uuid = "2f01184e-e22b-5df5-ae63-d93ebab69eaf" 557 | version = "1.10.0" 558 | 559 | [[deps.Statistics]] 560 | deps = ["LinearAlgebra", "SparseArrays"] 561 | uuid = "10745b16-79ce-11e8-11f9-7d13ad32a3b2" 562 | version = "1.10.0" 563 | 564 | [[deps.StringManipulation]] 565 | deps = ["PrecompileTools"] 566 | git-tree-sha1 = "a04cabe79c5f01f4d723cc6704070ada0b9d46d5" 567 | uuid = "892a3eda-7b42-436c-8928-eab12a02cf0e" 568 | version = "0.3.4" 569 | 570 | [[deps.SuiteSparse_jll]] 571 | deps = ["Artifacts", "Libdl", "libblastrampoline_jll"] 572 | uuid = "bea87d4a-7f5b-5778-9afe-8cc45184846c" 573 | version = "7.2.1+1" 574 | 575 | [[deps.TOML]] 576 | deps = ["Dates"] 577 | uuid = "fa267f1f-6049-4f14-aa54-33bafae1ed76" 578 | version = "1.0.3" 579 | 580 | [[deps.TableTraits]] 581 | deps = ["IteratorInterfaceExtensions"] 582 | git-tree-sha1 = "c06b2f539df1c6efa794486abfb6ed2022561a39" 583 | uuid = "3783bdb8-4a98-5b6b-af9a-565f29a5fe9c" 584 | version = "1.0.1" 585 | 586 | [[deps.Tables]] 587 | deps = ["DataAPI", "DataValueInterfaces", "IteratorInterfaceExtensions", "LinearAlgebra", "OrderedCollections", "TableTraits"] 588 | git-tree-sha1 = "cb76cf677714c095e535e3501ac7954732aeea2d" 589 | uuid = "bd369af6-aec1-5ad0-b16a-f7cc5008161c" 590 | version = "1.11.1" 591 | 592 | [[deps.Tar]] 593 | deps = ["ArgTools", "SHA"] 594 | uuid = "a4e569a6-e804-4fa4-b0f3-eef7a1d5b13e" 595 | version = "1.10.0" 596 | 597 | [[deps.TensorCore]] 598 | deps = ["LinearAlgebra"] 599 | git-tree-sha1 = "1feb45f88d133a655e001435632f019a9a1bcdb6" 600 | uuid = "62fd8b95-f654-4bbd-a8a5-9c27f68ccd50" 601 | version = "0.1.1" 602 | 603 | [[deps.Test]] 604 | deps = ["InteractiveUtils", "Logging", "Random", "Serialization"] 605 | uuid = "8dfed614-e22c-5e08-85e1-65c5234f0b40" 606 | 607 | [[deps.TranscodingStreams]] 608 | git-tree-sha1 = "5d54d076465da49d6746c647022f3b3674e64156" 609 | uuid = "3bb67fe8-82b1-5028-8e26-92a6c54297fa" 610 | version = "0.10.8" 611 | weakdeps = ["Random", "Test"] 612 | 613 | [deps.TranscodingStreams.extensions] 614 | TestExt = ["Test", "Random"] 615 | 616 | [[deps.Tricks]] 617 | git-tree-sha1 = "eae1bb484cd63b36999ee58be2de6c178105112f" 618 | uuid = "410a4b4d-49e4-4fbc-ab6d-cb71b17b3775" 619 | version = "0.1.8" 620 | 621 | [[deps.URIs]] 622 | git-tree-sha1 = "67db6cc7b3821e19ebe75791a9dd19c9b1188f2b" 623 | uuid = "5c2747f8-b7ea-4ff2-ba2e-563bfd36b1d4" 624 | version = "1.5.1" 625 | 626 | [[deps.UUIDs]] 627 | deps = ["Random", "SHA"] 628 | uuid = "cf7118a7-6976-5b1a-9a39-7adc72f591a4" 629 | 630 | [[deps.UnPack]] 631 | git-tree-sha1 = "387c1f73762231e86e0c9c5443ce3b4a0a9a0c2b" 632 | uuid = "3a884ed6-31ef-47d7-9d2a-63182c4928ed" 633 | version = "1.0.2" 634 | 635 | [[deps.Unicode]] 636 | uuid = "4ec0a83e-493e-50e2-b9ac-8f72acf5a8f5" 637 | 638 | [[deps.WeakRefStrings]] 639 | deps = ["DataAPI", "InlineStrings", "Parsers"] 640 | git-tree-sha1 = "b1be2855ed9ed8eac54e5caff2afcdb442d52c23" 641 | uuid = "ea10d353-3f73-51f8-a26c-33c1cb351aa5" 642 | version = "1.4.2" 643 | 644 | [[deps.WebIO]] 645 | deps = ["AssetRegistry", "Base64", "Distributed", "FunctionalCollections", "JSON", "Logging", "Observables", "Pkg", "Random", "Requires", "Sockets", "UUIDs", "WebSockets", "Widgets"] 646 | git-tree-sha1 = "0eef0765186f7452e52236fa42ca8c9b3c11c6e3" 647 | uuid = "0f1e0344-ec1d-5b48-a673-e5cf874b6c29" 648 | version = "0.8.21" 649 | 650 | [[deps.WebSockets]] 651 | deps = ["Base64", "Dates", "HTTP", "Logging", "Sockets"] 652 | git-tree-sha1 = "4162e95e05e79922e44b9952ccbc262832e4ad07" 653 | uuid = "104b5d7c-a370-577a-8038-80a2059c5097" 654 | version = "1.6.0" 655 | 656 | [[deps.Widgets]] 657 | deps = ["Colors", "Dates", "Observables", "OrderedCollections"] 658 | git-tree-sha1 = "fcdae142c1cfc7d89de2d11e08721d0f2f86c98a" 659 | uuid = "cc8bc4a8-27d6-5769-a93b-9d913e69aa62" 660 | version = "0.6.6" 661 | 662 | [[deps.WorkerUtilities]] 663 | git-tree-sha1 = "cd1659ba0d57b71a464a29e64dbc67cfe83d54e7" 664 | uuid = "76eceee3-57b5-4d4a-8e66-0e911cebbf60" 665 | version = "1.6.1" 666 | 667 | [[deps.XML2_jll]] 668 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Libiconv_jll", "Zlib_jll"] 669 | git-tree-sha1 = "52ff2af32e591541550bd753c0da8b9bc92bb9d9" 670 | uuid = "02c8fc9c-b97f-50b9-bbe4-9be30ff0a78a" 671 | version = "2.12.7+0" 672 | 673 | [[deps.ZMQ]] 674 | deps = ["FileWatching", "PrecompileTools", "Sockets", "ZeroMQ_jll"] 675 | git-tree-sha1 = "91530c108063680ac33b8b0cb8abba601e78a094" 676 | uuid = "c2297ded-f4af-51ae-bb23-16f91089e4e1" 677 | version = "1.2.4" 678 | 679 | [[deps.ZeroMQ_jll]] 680 | deps = ["Artifacts", "JLLWrappers", "Libdl", "libsodium_jll"] 681 | git-tree-sha1 = "42f97fb27394378591666ab0e9cee369e6d0e1f9" 682 | uuid = "8f1865be-045e-5c20-9c9f-bfbfb0764568" 683 | version = "4.3.5+0" 684 | 685 | [[deps.Zlib_jll]] 686 | deps = ["Libdl"] 687 | uuid = "83775a58-1f1d-513f-b197-d71354ab007a" 688 | version = "1.2.13+1" 689 | 690 | [[deps.libblastrampoline_jll]] 691 | deps = ["Artifacts", "Libdl"] 692 | uuid = "8e850b90-86db-534c-a0d3-1478176c7d93" 693 | version = "5.8.0+1" 694 | 695 | [[deps.libsodium_jll]] 696 | deps = ["Artifacts", "JLLWrappers", "Libdl", "Pkg"] 697 | git-tree-sha1 = "848ab3d00fe39d6fbc2a8641048f8f272af1c51e" 698 | uuid = "a9144af2-ca23-56d9-984f-0d03f7b5ccf8" 699 | version = "1.0.20+0" 700 | 701 | [[deps.nghttp2_jll]] 702 | deps = ["Artifacts", "Libdl"] 703 | uuid = "8e850ede-7688-5339-a07c-302acd2aaf8d" 704 | version = "1.52.0+1" 705 | 706 | [[deps.p7zip_jll]] 707 | deps = ["Artifacts", "Libdl"] 708 | uuid = "3f19e933-33d8-53b3-aaab-bd5110c3b7a0" 709 | version = "17.4.0+2" 710 | -------------------------------------------------------------------------------- /src/api.jl: -------------------------------------------------------------------------------- 1 | #= 2 | This file is part of OpenModelica. 3 | Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC), 4 | c/o Linköpings universitet, Department of Computer and Information Science, 5 | SE-58183 Linköping, Sweden. 6 | 7 | All rights reserved. 8 | 9 | THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE 10 | GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2. 11 | ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES 12 | RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3, 13 | ACCORDING TO RECIPIENTS CHOICE. 14 | 15 | The OpenModelica software and the OSMC (Open Source Modelica Consortium) 16 | Public License (OSMC-PL) are obtained from OSMC, either from the above 17 | address, from the URLs: http://www.openmodelica.org or 18 | http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica 19 | distribution. GNU version 3 is obtained from: 20 | http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from: 21 | http://www.opensource.org/licenses/BSD-3-Clause. 22 | 23 | This program is distributed WITHOUT ANY WARRANTY; without even the implied 24 | warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS 25 | EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE 26 | CONDITIONS OF OSMC-PL. 27 | =# 28 | 29 | # The functions below are generated using the autoGenerate.jl located 30 | # in scripts folder, the generated code is 95 % accurate, and we need to 31 | # do some fixes manually for certain API's, but in future this could be improved 32 | # and completely use the autoGenerate.jl to get 100% correct generated codes 33 | 34 | """ 35 | 36 | """ 37 | module API 38 | 39 | import ..OMJulia 40 | 41 | """ 42 | ScriptingError <: Exception 43 | 44 | OpenModelica scripting error with message `msg` and 45 | additional `error string` from `getErrroString`. 46 | """ 47 | struct ScriptingError <: Exception 48 | "Error message" 49 | msg::String 50 | "Error string from getErrorString()" 51 | errorString::String 52 | 53 | """ 54 | ScriptingError(omc=nothing; msg = "", errorString=nothing) 55 | 56 | Construct error message from `msg` and `errorString`. 57 | If OMCSession `omc` is available and `errorString=nothing` call `API.getErrorString()`. 58 | """ 59 | function ScriptingError(omc::Union{OMJulia.OMCSession, Nothing} = nothing; 60 | msg::String = "", 61 | errorString::Union{String, Nothing} = nothing) 62 | 63 | if isnothing(errorString) && !isnothing(omc) 64 | errorString = strip(OMJulia.sendExpression(omc, "getErrorString()")) 65 | elseif isnothing(errorString) 66 | errorString = "" 67 | end 68 | return new(msg, errorString) 69 | end 70 | 71 | function Base.showerror(io::IO, e::ScriptingError) 72 | println(io, e.msg) 73 | println(io, e.errorString) 74 | end 75 | end 76 | 77 | """ 78 | modelicaString(name) 79 | 80 | Wrappes string in quotes and replaces Windows style path seperation `\\` with `/`. 81 | """ 82 | function modelicaString(name::String) 83 | formattedString = join(["\"", name, "\""]) 84 | return replace(formattedString, "\\" => "/") 85 | end 86 | 87 | """ 88 | modelicaString(vec) 89 | 90 | Wrappes array in brackets and for each elemetn add quotes and replaces Windows style path seperation `\\` with `/`. 91 | """ 92 | function modelicaString(vec::Vector{String}) 93 | return "{" .* join(modelicaString.(vec), ", ") .* "}" 94 | end 95 | 96 | """ 97 | makeVectorString(vec) 98 | 99 | Add quotes around each string element. 100 | """ 101 | function makeVectorString(vec::Vector{String}) 102 | if length(vec) == 0 103 | return "\"\"" 104 | end 105 | return join("\"" .* vec .* "\"", ", ") 106 | end 107 | 108 | """ 109 | loadFile(omc, fileName; 110 | encoding = "", 111 | uses = true, 112 | notify = true, 113 | requireExactVersion = false) 114 | 115 | Load file `fileName` (*.mo) and merge it with the loaded AST. 116 | See [OpenModelica scripting API `loadFile`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#loadfile). 117 | """ 118 | function loadFile(omc::OMJulia.OMCSession, 119 | fileName::String; 120 | encoding::String = "", 121 | uses::Bool = true, 122 | notify::Bool = true, 123 | requireExactVersion::Bool = false 124 | ) 125 | 126 | exp = join(["loadFile", "(", "fileName", "=", modelicaString(fileName), ",", "encoding", "=", modelicaString(encoding), ",", "uses", "=", uses,",", "notify", "=", notify,",", "requireExactVersion", "=", requireExactVersion,")"]) 127 | success = OMJulia.sendExpression(omc, exp) 128 | 129 | if !success 130 | throw(ScriptingError(omc, msg = "Failed to load file $(modelicaString(fileName)).")) 131 | end 132 | return success 133 | end 134 | 135 | """ 136 | loadModel(omc, className; 137 | priorityVersion = String[], 138 | notify = false, 139 | languageStandard = "", 140 | requireExactVersion = false) 141 | 142 | Loads a Modelica library. 143 | 144 | See [OpenModelica scripting API `loadModel`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#loadmodel). 145 | """ 146 | function loadModel(omc::OMJulia.OMCSession, 147 | className::String; 148 | priorityVersion::Vector{String} = String[], 149 | notify::Bool = false, 150 | languageStandard::String = "", 151 | requireExactVersion::Bool = false 152 | ) 153 | exp = join(["loadModel", "(", "className", "=", className, ",", "priorityVersion", "=", "{", makeVectorString(priorityVersion), "}", ",", "notify", "=", notify,",", "languageStandard", "=", modelicaString(languageStandard), ",", "requireExactVersion", "=", requireExactVersion,")"]) 154 | success = OMJulia.sendExpression(omc, exp) 155 | 156 | if !success 157 | throw(ScriptingError(omc, msg = "Failed to load model $(className).")) 158 | end 159 | return success 160 | end 161 | 162 | """ 163 | simulate(omc, className; 164 | startTime = 0.0, 165 | stopTime = nothing, 166 | numberOfIntervals = 500, 167 | tolerance = 1e-6, 168 | method = "", 169 | fileNamePrefix=className, 170 | options = "", 171 | outputFormat = "mat", 172 | variableFilter = ".*", 173 | cflags = "", 174 | simflags = "") 175 | 176 | Simulates a modelica model by generating C code, build it and run the simulation executable. 177 | 178 | See [OpenModelica scripting API `simulate`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#simulate). 179 | """ 180 | function simulate(omc::OMJulia.OMCSession, 181 | className::String; 182 | startTime::Union{Float64, Nothing} = nothing, 183 | stopTime::Union{Float64, Nothing} = nothing, 184 | numberOfIntervals::Union{Int64, Nothing} = nothing, 185 | tolerance::Union{Float64, Nothing} = nothing, 186 | method::String = "", 187 | fileNamePrefix::String = className, 188 | options::String = "", 189 | outputFormat::String = "mat", 190 | variableFilter::String = ".*", 191 | cflags::String = "", 192 | simflags::String = "" 193 | ) 194 | 195 | exp = join(["simulate", "(", className, ","]) 196 | 197 | # There is no default value for startTime, stopTime, numberOfIntervals, tolerance, 198 | # we can provide that behaves like not giving any value and using the values from the experiment annotation if exists, otherwise use default values 199 | if !isnothing(startTime) 200 | exp *= "startTime = $startTime," 201 | end 202 | if !isnothing(stopTime) 203 | exp *= "stopTime = $stopTime," 204 | end 205 | if !isnothing(numberOfIntervals) 206 | exp *= "numberOfIntervals = $numberOfIntervals," 207 | end 208 | if !isnothing(tolerance) 209 | exp *= "tolerance = $tolerance," 210 | end 211 | 212 | exp *= join(["method", "=", modelicaString(method), ",", 213 | "fileNamePrefix", "=", modelicaString(fileNamePrefix), ",", 214 | "options", "=", modelicaString(options), ",", 215 | "outputFormat", "=", modelicaString(outputFormat), ",", 216 | "variableFilter", "=", modelicaString(variableFilter), ",", 217 | "cflags", "=", modelicaString(cflags), ",", 218 | "simflags", "=", modelicaString(simflags), ")"]) 219 | simulationResults = OMJulia.sendExpression(omc, exp) 220 | 221 | if !haskey(simulationResults, "resultFile") || isempty(simulationResults["resultFile"]) 222 | if haskey(simulationResults, "messages") 223 | throw(ScriptingError(omc, msg = "Failed to simulate $(className).\n" * simulationResults["messages"] )) 224 | else 225 | throw(ScriptingError(omc, msg = "Failed to simulate $(className).")) 226 | end 227 | end 228 | return simulationResults 229 | end 230 | 231 | """ 232 | buildModel(omc, className; 233 | startTime = 0.0, 234 | stopTime = 1.0, 235 | numberOfIntervals = 500, 236 | tolerance = 1e-6, 237 | method = "", 238 | fileNamePrefix = className, 239 | options = "", 240 | outputFormat = "mat", 241 | variableFilter = ".*", 242 | cflags = "", 243 | simflags = "") 244 | 245 | Build Modelica model by generating C code and compiling it into an executable simulation. 246 | It does not run the simulation! 247 | 248 | See [OpenModelica scripting API `buildModel`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#buildmodel). 249 | """ 250 | function buildModel(omc::OMJulia.OMCSession, 251 | className::String; 252 | startTime::Union{Float64, Nothing} = nothing, 253 | stopTime::Union{Float64, Nothing} = nothing, 254 | numberOfIntervals::Union{Int64, Nothing} = nothing, 255 | tolerance::Union{Float64, Nothing} = nothing, 256 | method::String = "", 257 | fileNamePrefix::String = className, 258 | options::String = "", 259 | outputFormat::String = "mat", 260 | variableFilter::String = ".*", 261 | cflags::String = "", 262 | simflags::String = "" 263 | ) 264 | 265 | exp = join(["buildModel", "(", className, ","]) 266 | 267 | # There is no default value for startTime, stopTime, numberOfIntervals, tolerance, 268 | # we can provide that behaves like not giving any value and using the values from the experiment annotation if exists, otherwise use default values 269 | if !isnothing(startTime) 270 | exp *= "startTime = $startTime," 271 | end 272 | if !isnothing(stopTime) 273 | exp *= "stopTime = $stopTime," 274 | end 275 | if !isnothing(numberOfIntervals) 276 | exp *= "numberOfIntervals = $numberOfIntervals," 277 | end 278 | if !isnothing(tolerance) 279 | exp *= "tolerance = $tolerance," 280 | end 281 | 282 | exp *= join(["method", "=", modelicaString(method), ",", 283 | "fileNamePrefix", "=", modelicaString(fileNamePrefix), ",", 284 | "options", "=", modelicaString(options), ",", 285 | "outputFormat", "=", modelicaString(outputFormat), ",", 286 | "variableFilter", "=", modelicaString(variableFilter), ",", 287 | "cflags", "=", modelicaString(cflags), ",", 288 | "simflags", "=", modelicaString(simflags), ")"]) 289 | return OMJulia.sendExpression(omc, exp) 290 | end 291 | 292 | """ 293 | getClassNames(omc; 294 | class_ = "", 295 | recursive = false, 296 | qualified = false, 297 | sort = false, 298 | builtin = false, 299 | showProtected = false, 300 | includeConstants = false) 301 | 302 | Returns the list of class names defined in the class. 303 | 304 | See [OpenModelica scripting API `getClassNames`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#getclassnames). 305 | """ 306 | function getClassNames(omc::OMJulia.OMCSession; 307 | class_::String = "", 308 | recursive::Bool = false, 309 | qualified::Bool = false, 310 | sort::Bool = false, 311 | builtin::Bool = false, 312 | showProtected::Bool = false, 313 | includeConstants::Bool = false 314 | ) 315 | if (class_ == "") 316 | args = join(["recursive", "=", recursive, ", ", "qualified", "=", qualified, ", ", "sort", "=", sort, ", ", "builtin", "=", builtin, ", ", "showProtected", "=", showProtected, ", ", "includeConstants", "=", includeConstants]) 317 | else 318 | args = join(["class_", "=", class_, ", ", "recursive", "=", recursive, ", ", "qualified", "=", qualified, ", ", "sort", "=", sort, ", ", "builtin", "=", builtin, ", ", "showProtected", "=", showProtected, ", ", "includeConstants", "=", includeConstants]) 319 | end 320 | 321 | exp = "getClassNames($args)" 322 | 323 | return OMJulia.sendExpression(omc, exp) 324 | end 325 | 326 | """ 327 | readSimulationResult(omc, filename, 328 | variables = String[], 329 | size = 0) 330 | 331 | Reads a result file, returning a matrix corresponding to the variables and size given. 332 | 333 | See [OpenModelica scripting API `readSimulationResult`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#readsimulationresult). 334 | """ 335 | function readSimulationResult(omc::OMJulia.OMCSession, 336 | filename::String, 337 | variables::Vector{String} = String[], 338 | size::Int64 = 0 339 | ) 340 | 341 | exp = join(["readSimulationResult", "(", modelicaString(filename), ",", "{", join(variables, ", "), "}", ", ", size,")"]) 342 | return OMJulia.sendExpression(omc, exp) 343 | end 344 | 345 | """ 346 | readSimulationResultSize(omc, fileName) 347 | 348 | The number of intervals that are present in the output file. 349 | 350 | See [OpenModelica scripting API `readSimulationResultSize`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#readsimulationresultsize). 351 | """ 352 | function readSimulationResultSize(omc::OMJulia.OMCSession, 353 | fileName::String 354 | ) 355 | 356 | exp = join(["readSimulationResultSize", "(", "fileName", "=", modelicaString(fileName),")"]) 357 | return OMJulia.sendExpression(omc, exp) 358 | end 359 | 360 | """ 361 | readSimulationResultVars(omc, fileName; 362 | readParameters = true, 363 | openmodelicaStyle = false) 364 | 365 | Returns the variables in the simulation file; you can use val() and plot() commands using these names. 366 | 367 | See [OpenModelica scripting API `readSimulationResultVars`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#readsimulationresultvars). 368 | """ 369 | function readSimulationResultVars(omc::OMJulia.OMCSession, 370 | fileName::String; 371 | readParameters::Bool = true, 372 | openmodelicaStyle::Bool = false 373 | ) 374 | 375 | exp = join(["readSimulationResultVars", "(", "fileName", "=", modelicaString(fileName), ",", "readParameters", "=", readParameters,",", "openmodelicaStyle", "=", openmodelicaStyle,")"]) 376 | return OMJulia.sendExpression(omc, exp) 377 | end 378 | 379 | """ 380 | closeSimulationResultFile(omc) 381 | 382 | Closes the current simulation result file. 383 | Only needed by Windows. Windows cannot handle reading and writing to the same file from different processes. 384 | To allow OMEdit to make successful simulation again on the same file we must close the file after reading the Simulation Result Variables. 385 | Even OMEdit only use this API for Windows. 386 | 387 | See [OpenModelica scripting API `closeSimulationResultFile`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#closesimulationresultfile). 388 | """ 389 | function closeSimulationResultFile(omc::OMJulia.OMCSession) 390 | return OMJulia.sendExpression(omc, "closeSimulationResultFile()") 391 | end 392 | 393 | """ 394 | setCommandLineOptions(omc, option) 395 | 396 | The input is a regular command-line flag given to OMC, e.g. -d=failtrace or -g=MetaModelica. 397 | 398 | See [OpenModelica scripting API `setCommandLineOptions`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#setcommandlineoptions). 399 | """ 400 | function setCommandLineOptions(omc::OMJulia.OMCSession, 401 | option::String 402 | ) 403 | 404 | exp = join(["setCommandLineOptions", "(", "option", "=", modelicaString(option),")"]) 405 | success = OMJulia.sendExpression(omc, exp) 406 | if !success 407 | throw(ScriptingError(omc, msg = "Failed to set command line options $(modelicaString(option)).")) 408 | end 409 | return success 410 | end 411 | 412 | """ 413 | cd(omc, newWorkingDirectory="") 414 | 415 | Change directory to the given path `newWorkingDirectory` (which may be either relative or absolute). 416 | Returns the new working directory on success or a message on failure. 417 | If the given path is the empty string, the function simply returns the current working directory. 418 | 419 | See [OpenModelica scripting API `cd`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#cd). 420 | """ 421 | function cd(omc::OMJulia.OMCSession, 422 | newWorkingDirectory::String = ""; 423 | ) 424 | 425 | exp = join(["cd", "(", "newWorkingDirectory", "=", modelicaString(newWorkingDirectory),")"]) 426 | workingDirectory = OMJulia.sendExpression(omc, exp) 427 | 428 | if !ispath(workingDirectory) 429 | throw(ScriptingError(omc, msg = "Failed to change directory to $(modelicaString(newWorkingDirectory)).")) 430 | end 431 | return workingDirectory 432 | end 433 | 434 | """ 435 | Creates a model with symbolic linearization matrices. 436 | 437 | See [OpenModelica scripting API `linearize`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#linearize). 438 | """ 439 | function linearize(omc::OMJulia.OMCSession, 440 | className::String; 441 | startTime::Float64 = 0.0, 442 | stopTime::Float64 = 1.0, 443 | numberOfIntervals::Int64 = 500, 444 | stepSize::Float64 = 0.002, 445 | tolerance::Float64 = 1e-6, 446 | method::String = "", 447 | fileNamePrefix::String = className, 448 | options::String = "", 449 | outputFormat::String = "mat", 450 | variableFilter::String = ".*", 451 | cflags::String = "", 452 | simflags::String = "" 453 | ) 454 | 455 | exp = join(["linearize", "(", className, ",", "startTime", "=", startTime,",", "stopTime", "=", stopTime,",", "numberOfIntervals", "=", numberOfIntervals,",", "stepSize", "=", stepSize,",", "tolerance", "=", tolerance,",", "method", "=", modelicaString(method), ",", "fileNamePrefix", "=", modelicaString(fileNamePrefix), ",", "options", "=", modelicaString(options), ",", "outputFormat", "=", modelicaString(outputFormat), ",", "variableFilter", "=", modelicaString(variableFilter), ",", "cflags", "=", modelicaString(cflags), ",", "simflags", "=", modelicaString(simflags),")"]) 456 | return OMJulia.sendExpression(omc, exp) 457 | end 458 | 459 | """ 460 | buildModelFMU(omc, className; 461 | version = "2.0", 462 | fmuType = "me", 463 | fileNamePrefix=className, 464 | platforms=["static"], 465 | includeResources = false) 466 | 467 | Translates a modelica model into a Functional Mockup Unit. 468 | The only required argument is the className, while all others have some default values. 469 | 470 | See [OpenModelica scripting API `buildModelFMU`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#buildmodelfmu). 471 | """ 472 | function buildModelFMU(omc::OMJulia.OMCSession, 473 | className::String; 474 | version::String = "2.0", 475 | fmuType::String = "me", 476 | fileNamePrefix::String = className, 477 | platforms::Vector{String} = String["static"], 478 | includeResources::Bool = false 479 | ) 480 | 481 | exp = join(["buildModelFMU", "(", className, ",", "version", "=", modelicaString(version), ",", "fmuType", "=", modelicaString(fmuType), ",", "fileNamePrefix", "=", modelicaString(fileNamePrefix), ",", "platforms", "=", "{", makeVectorString(platforms), "}", ",", "includeResources", "=", includeResources,")"]) 482 | generatedFileName = OMJulia.sendExpression(omc, exp) 483 | 484 | if !isfile(generatedFileName) || !endswith(generatedFileName, ".fmu") 485 | throw(ScriptingError(omc, msg = "Failed to load file $(modelicaString(generatedFileName)).")) 486 | end 487 | return generatedFileName 488 | end 489 | 490 | """ 491 | getErrorString(omc, warningsAsErrors = false) 492 | 493 | Returns the current error message. 494 | 495 | See [OpenModelica scripting API `getErrorString`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#geterrorstring). 496 | """ 497 | function getErrorString(omc::OMJulia.OMCSession; 498 | warningsAsErrors::Bool = false 499 | ) 500 | 501 | exp = join(["getErrorString", "(", "warningsAsErrors", "=", warningsAsErrors,")"]) 502 | return OMJulia.sendExpression(omc, exp) 503 | end 504 | 505 | """ 506 | getVersion(omc) 507 | 508 | Returns the version of the Modelica compiler. 509 | 510 | See [OpenModelica scripting API `getVersion`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#getversion). 511 | """ 512 | function getVersion(omc::OMJulia.OMCSession) 513 | exp = join(["getVersion()"]) 514 | return OMJulia.sendExpression(omc, exp) 515 | end 516 | 517 | """ 518 | getInstallationDirectoryPath(omc) 519 | 520 | This returns `OPENMODELICAHOME` if it is set; on some platforms the default path is returned if it is not set. 521 | 522 | See [OpenModelica scripting API `getInstallationDirectoryPath`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#getinstallationdirectorypath). 523 | """ 524 | function getInstallationDirectoryPath(omc::OMJulia.OMCSession) 525 | exp = join(["getInstallationDirectoryPath()"]) 526 | return OMJulia.sendExpression(omc, exp) 527 | end 528 | 529 | """ 530 | diffSimulationResults(omc, actualFile, expectedFile, diffPrefix; 531 | relTol = 1e-3, 532 | relTolDiffMinMax = 1e-4, 533 | rangeDelta = 0.002, 534 | vars = String[], 535 | keepEqualResults = false) 536 | 537 | Compares simulation results. 538 | 539 | See [OpenModelica scripting API `diffSimulationResults`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#diffsimulationresults). 540 | """ 541 | function diffSimulationResults(omc::OMJulia.OMCSession, 542 | actualFile::String, 543 | expectedFile::String, 544 | diffPrefix::String; 545 | relTol::Float64 = 1e-3, 546 | relTolDiffMinMax::Float64 = 1e-4, 547 | rangeDelta::Float64 = 0.002, 548 | vars::Vector{String} = String[], 549 | keepEqualResults::Bool = false) 550 | 551 | exp = "diffSimulationResults($(modelicaString(actualFile)), 552 | $(modelicaString(expectedFile)), 553 | $(modelicaString(diffPrefix)), 554 | relTol=$relTol, 555 | relTolDiffMinMax=$relTolDiffMinMax, 556 | rangeDelta=$rangeDelta, 557 | vars=$(modelicaString(vars)), 558 | keepEqualResults=$keepEqualResults)" 559 | @debug "$exp" 560 | ret = OMJulia.sendExpression(omc, exp) 561 | 562 | if isnothing(ret) 563 | return (true, String[]) 564 | else 565 | return (ret[1], convert(Vector{String}, ret[2])) 566 | end 567 | end 568 | 569 | """ 570 | instantiateModel(omc, className) 571 | 572 | Instantiates the class and returns the flat Modelica code. 573 | 574 | See [OpenModelica scripting API `instantiateModel`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#instantiatemodel). 575 | """ 576 | function instantiateModel(omc::OMJulia.OMCSession, className::String) 577 | flatModelicaCode = OMJulia.sendExpression(omc, "instantiateModel($className)") 578 | if isempty(flatModelicaCode) 579 | throw(OMJulia.API.ScriptingError(omc, msg = "instantiateModel($className)")) 580 | end 581 | 582 | return flatModelicaCode 583 | end 584 | 585 | """ 586 | installPackage(omc, pkg; 587 | version="", 588 | exactMatch=false) 589 | 590 | Install package `pkg` with given `version`. If `version=""` try to install 591 | most recent version of package. If `exactMatch` is true install exact 592 | version, even if there are more recent backwards.compatible versions 593 | available. 594 | 595 | See [OpenModelica scripting API `installPackage`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#installpackage) 596 | or [Package Management](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/packagemanager.html#using-the-package-manager-from-the-interactive-environment). 597 | """ 598 | function installPackage(omc::OMJulia.OMCSession, pkg::String; version::String="", exactMatch::Bool=false) 599 | success = OMJulia.sendExpression(omc, "installPackage($pkg, version=\"$version\", exactMatch=$exactMatch)") 600 | if !success 601 | throw(OMJulia.API.ScriptingError(omc, msg = "installPackage($pkg, version=$version, exactMatch=$exactMatch)")) 602 | end 603 | return success 604 | end 605 | 606 | """ 607 | updatePackageIndex(omc) 608 | 609 | Update package index list. 610 | 611 | The package manager contacts OSMC sersers and updated the internally sotred 612 | list of available packages. 613 | 614 | See [OpenModelica scripting API `updatePackageIndex`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#updatepackageindex) 615 | or [Package Management](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/packagemanager.html#using-the-package-manager-from-the-interactive-environment). 616 | """ 617 | function updatePackageIndex(omc::OMJulia.OMCSession) 618 | success = OMJulia.sendExpression(omc, "updatePackageIndex()") 619 | if !success 620 | throw(OMJulia.API.ScriptingError(omc, msg = "updatePackageIndex()")) 621 | end 622 | return success 623 | end 624 | 625 | """ 626 | getAvailablePackageVersions(omc, pkg; version="") 627 | 628 | Get available package versions of `pkg`. 629 | Lists all available versions of the Buildings library on the OSMC server, 630 | starting from the most recent one, in descending order of priority. Note 631 | that pre-release versions have lower priority than all other versions. 632 | 633 | See [OpenModelica scripting API `getAvailablePackageVersions`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#getavailablepackageversions) 634 | or [Package 635 | Management](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/packagemanager.html#using-the-package-manager-from-the-interactive-environment). 636 | """ 637 | function getAvailablePackageVersions(omc::OMJulia.OMCSession, pkg::String; version::String="") 638 | versions = OMJulia.sendExpression(omc, "getAvailablePackageVersions($pkg, version=\"$version\")") 639 | if length(versions) == 0 640 | errorString = strip(OMJulia.sendExpression(omc, "getErrorString()")) 641 | if errorString != "" 642 | throw(OMJulia.API.ScriptingError(omc, msg = "getAvailablePackageVersions($pkg, version=$version)", errorString=errorString)) 643 | end 644 | end 645 | return versions 646 | end 647 | 648 | """ 649 | upgradeInstalledPackages(omc; installNewestVersions=true) 650 | 651 | Installs the latest available version of all installed packages. 652 | 653 | See [OpenModelica scripting API `upgradeInstalledPackages`](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html#upgradeinstalledpackages) 654 | or [Package 655 | Management](https://openmodelica.org/doc/OpenModelicaUsersGuide/latest/packagemanager.html#using-the-package-manager-from-the-interactive-environment). 656 | """ 657 | function upgradeInstalledPackages(omc::OMJulia.OMCSession; installNewestVersions::Bool=true) 658 | success = OMJulia.sendExpression(omc, "upgradeInstalledPackages($installNewestVersions)") 659 | if !success 660 | throw(OMJulia.API.ScriptingError(omc, msg = "upgradeInstalledPackages($installNewestVersions)")) 661 | end 662 | return success 663 | end 664 | end 665 | -------------------------------------------------------------------------------- /src/lexer.jl: -------------------------------------------------------------------------------- 1 | # Generated Lexer for OpenModelica Values.Value output 2 | 3 | const lexertable = [3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 1 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 6 0 6 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 7 0 0 0 0 0; 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 12 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 2 0 13 13 12 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 12 12 12 12 12; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 8 7 7 9 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 10 7 7 7 11 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 8 7 7 9 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 4 0 0 0 0 0 7 7 7 7 7 0 0 0 7 7 7 7 7 7 7 7 7 7 0 0 0 0 0 0 0; 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 5 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0; 3 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0 0] 4 | const csarr = [2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 12 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 2 14 2 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 6 -2 -3 -4 -5 -6 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 2 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 4 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 30 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 4 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 30 -29 -30 -31; 5 -2 27 31 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 3 -2 3 3 27 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 27 29 29 29 27; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 17 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 28 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 28 -28 -29 -30 -31; 9 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 18 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 15 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 19 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 10 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 16 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 25 -7 -8 -9 -10 -11 13 14 13 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 25 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 17 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 22 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 8 -2 28 -4 -5 26 21 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 28 -28 -29 -30 -31; 9 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 18 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 20 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 23 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 7 -2 -3 -4 -5 26 11 11 11 15 11 14 14 14 11 11 11 11 11 11 11 11 24 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 19 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 10 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 16 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 11 -2 -3 -4 -5 26 11 11 11 11 11 14 14 14 11 11 11 11 11 11 11 11 11 11 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31; 2 -2 -3 -4 -5 26 -7 -8 -9 -10 -11 14 14 14 -15 -16 -17 -18 -19 -20 -21 -22 -23 -24 26 26 -27 -28 -29 -30 -31] 5 | 6 | function tokenize(data::String) 7 | begin 8 | p::Int = 1 9 | p_end::Int = 0 10 | p_eof::Int = -1 11 | ts::Int = 0 12 | te::Int = 0 13 | cs::Int = 1 14 | end 15 | p_end = p_eof = sizeof(data) 16 | failed = false 17 | tokens = Any[] 18 | emit(tok) = push!(tokens, tok) 19 | while p ≤ p_eof && cs > 0 20 | begin 21 | kouprey = (SizedMemory)(data) 22 | t = 0 23 | ts = 0 24 | while p ≤ p_end && cs > 0 25 | seal = kouprey[p + 0] 26 | @inbounds duck = (lexertable)[(cs - 1) << 8 + seal + 1] 27 | cs = (csarr)[(cs - 1) << 8 + seal + 1] 28 | if duck == 1 29 | ts = p 30 | t = 10 31 | te = p 32 | t = 9 33 | te = p 34 | else 35 | if duck == 2 36 | ts = p 37 | t = 10 38 | te = p 39 | t = 7 40 | te = p 41 | else 42 | if duck == 3 43 | ts = p 44 | t = 10 45 | te = p 46 | else 47 | if duck == 4 48 | ts = p 49 | t = 10 50 | te = p 51 | t = 6 52 | te = p 53 | else 54 | if duck == 5 55 | ts = p 56 | t = 10 57 | te = p 58 | t = 3 59 | te = p 60 | else 61 | if duck == 6 62 | t = 5 63 | te = p 64 | else 65 | if duck == 7 66 | t = 6 67 | te = p 68 | else 69 | if duck == 8 70 | t = 6 71 | te = p 72 | t = 1 73 | te = p 74 | else 75 | if duck == 9 76 | t = 6 77 | te = p 78 | t = 2 79 | te = p 80 | else 81 | if duck == 10 82 | t = 6 83 | te = p 84 | t = 3 85 | te = p 86 | else 87 | if duck == 11 88 | t = 6 89 | te = p 90 | t = 4 91 | te = p 92 | else 93 | if duck == 12 94 | t = 8 95 | te = p 96 | else 97 | if duck == 13 98 | t = 7 99 | te = p 100 | else 101 | () 102 | end 103 | end 104 | end 105 | end 106 | end 107 | end 108 | end 109 | end 110 | end 111 | end 112 | end 113 | end 114 | end 115 | p += 1 116 | end 117 | if p > p_eof ≥ 0 && cs ∈ Set([12,11,10,15,16,9,17,18,19,8,20,7,21,22,23,24,6,5,27,29,4,3,2]) 118 | cs = 0 119 | elseif cs < 0 120 | p -= 1 121 | end 122 | if t > 0 && (cs ≤ 0 || p > p_end ≥ 0) 123 | if t == 10 124 | failed = true 125 | else 126 | if t == 9 127 | () 128 | else 129 | if t == 8 130 | emit(parse(Float64, data[ts:te])) 131 | else 132 | if t == 7 133 | emit(parse(Int, data[ts:te])) 134 | else 135 | if t == 6 136 | emit(Identifier(unescape_string(data[ts:te]))) 137 | else 138 | if t == 5 139 | emit(unescape_string(data[ts + 1:te - 1])) 140 | else 141 | if t == 4 142 | emit(Record()) 143 | else 144 | if t == 3 145 | emit(Symbol(data[ts:te])) 146 | else 147 | if t == 2 148 | emit(false) 149 | else 150 | if t == 1 151 | emit(true) 152 | else 153 | () 154 | end 155 | end 156 | end 157 | end 158 | end 159 | end 160 | end 161 | end 162 | end 163 | end 164 | p = te + 1 165 | if cs != 0 166 | cs = 1 167 | end 168 | end 169 | end 170 | end 171 | if cs < 0 || failed 172 | throw(LexerError("Error while lexing")) 173 | end 174 | if p < p_eof 175 | throw(LexerError("Did not scan until end of file. Remaining: $(data[p:p_eof])")) 176 | end 177 | return tokens 178 | end 179 | --------------------------------------------------------------------------------