-
Notifications
You must be signed in to change notification settings - Fork 13
/
omcSession.jl
277 lines (235 loc) · 9.1 KB
/
omcSession.jl
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
#=
This file is part of OpenModelica.
Copyright (c) 1998-2023, Open Source Modelica Consortium (OSMC),
c/o Linköpings universitet, Department of Computer and Information Science,
SE-58183 Linköping, Sweden.
All rights reserved.
THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3,
ACCORDING TO RECIPIENTS CHOICE.
The OpenModelica software and the OSMC (Open Source Modelica Consortium)
Public License (OSMC-PL) are obtained from OSMC, either from the above
address, from the URLs: http://www.openmodelica.org or
http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica
distribution. GNU version 3 is obtained from:
http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from:
http://www.opensource.org/licenses/BSD-3-Clause.
This program is distributed WITHOUT ANY WARRANTY; without even the implied
warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS
EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE
CONDITIONS OF OSMC-PL.
=#
"""
Linearization <: Any
Collection of linearization settings and variables.
See also [``]
"""
mutable struct Linearization
"Name of linear model in Julia function `linearfile`"
linearmodelname::AbstractString
"Julia file linearized_model.jl containing linearization matrices A, B, C and D."
linearfile::AbstractString
"Experiment settings for linearization"
linearOptions::Dict{AbstractString, AbstractString}
linearFlag::Bool
"Input variables"
linearinputs::Union{Missing, Any}
"Output variables"
linearoutputs::Union{Missing, Any}
"State variables"
linearstates::Union{Missing, Any}
function Linearization()
linearmodelname = ""
linearfile = ""
linearOptions = Dict("startTime" => "0.0", "stopTime" => "1.0", "stepSize" => "0.002", "tolerance" => "1e-6")
linearFlag = false
new(linearmodelname, linearfile, linearOptions, linearFlag, missing, missing, missing)
end
end
"""
ZMQSession <: Any
ZeroMQ session running interactive omc process.
-----------------------------------------
ZMQSession(omc::Union{String, Nothing}=nothing)::ZMQSession
Start new interactive OpenModelica session using ZeroMQ.
## Arguments
- `omc::Union{String, Nothing}`: Path to OpenModelica compiler.
Use omc from `PATH` if nothing is provided.
"""
mutable struct ZMQSession
context::ZMQ.Context
socket::ZMQ.Socket
omcprocess::Base.Process
function ZMQSession(omc::Union{String, Nothing}=nothing)::ZMQSession
args1 = "--interactive=zmq"
randPortSuffix = Random.randstring(10)
args2 = "-z=julia.$(randPortSuffix)"
stdoutfile = "stdout-$(randPortSuffix).log"
stderrfile = "stderr-$(randPortSuffix).log"
local omcprocess
if Sys.iswindows()
if !isnothing(omc )
ompath = replace(omc, r"[/\\]+" => "/")
dirpath = dirname(dirname(omc))
## create a omc process with OPENMODELICAHOME set to custom directory
@info("Setting environment variable OPENMODELICAHOME=\"$dirpath\" for this session.")
withenv("OPENMODELICAHOME" => dirpath) do
omcprocess = open(pipeline(`$omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile))
end
else
omhome = ""
try
omhome = ENV["OPENMODELICAHOME"]
catch Exception
println(Exception, "is not set, Please set the environment Variable")
return
end
ompath = replace(joinpath(omhome, "bin", "omc.exe"), r"[/\\]+" => "/")
# ompath=joinpath(omhome,"bin")
## create a omc process with default OPENMODELICAHOME set in environment variable
withenv("OPENMODELICAHOME" => omhome) do
omcprocess = open(pipeline(`$ompath $args1 $args2`))
end
end
portfile = join(["openmodelica.port.julia.", randPortSuffix])
else
if Sys.isapple()
# add omc to path if not exist
ENV["PATH"] = ENV["PATH"] * "/opt/openmodelica/bin"
if !isnothing(omc )
omcprocess = open(pipeline(`$omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile))
else
omcprocess = open(pipeline(`omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile))
end
else
if !isnothing(omc )
omcprocess = open(pipeline(`$omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile))
else
omcprocess = open(pipeline(`omc $args1 $args2`, stdout=stdoutfile, stderr=stderrfile))
end
end
portfile = join(["openmodelica.", ENV["USER"], ".port.julia.", randPortSuffix])
end
fullpath = joinpath(tempdir(), portfile)
@info("Path to zmq file=\"$fullpath\"")
## Try to find better approach if possible, as sleep does not work properly across different platform
tries = 0
while tries < 100 && !isfile(fullpath)
sleep(0.02)
tries += 1
end
# Catch omc error
if process_exited(omcprocess) && omcprocess.exitcode != 0
throw(OMCError(omcprocess.cmd, stdoutfile, stderrfile))
end
rm.([stdoutfile, stderrfile], force=true)
if tries >= 100
throw(TimeoutError("ZMQ server port file \"$fullpath\" not created yet."))
end
filedata = read(fullpath, String)
context = ZMQ.Context()
socket = ZMQ.Socket(context, REQ)
ZMQ.connect(socket, filedata)
zmqSession = new(context, socket, omcprocess)
# Register finalizer to stop omc process when this OMCsession is no longer reachable
f(zmqSession) = kill(zmqSession.omcprocess)
finalizer(f, zmqSession)
return zmqSession
end
end
"""
OMCSession <: Any
OMC session struct.
--------------
OMCSession(omc=nothing)
Create new OpenModelica session.
## Arguments
- `omc::Union{String, Nothing}`: Path to OpenModelica compiler.
Use omc from `PATH` if nothing is provided.
See also [`ModelicaSystem`](@ref), [`OMJulia.quit`](@ref).
"""
mutable struct OMCSession
simulationFlag::Bool
inputFlag::Bool
simulateOptions::Dict
overridevariables::Dict
simoptoverride::Dict
tempdir::AbstractString
"Current directory"
currentdir::AbstractString
resultfile::AbstractString
filepath::AbstractString
modelname::AbstractString
xmlfile::AbstractString
csvfile::AbstractString
"Filter for simulation result passed to buildModel"
variableFilter::Union{AbstractString, Nothing}
quantitieslist::Array{Any, 1}
parameterlist::Dict
inputlist::Dict
outputlist::Dict
"List of continuous model variables"
continuouslist::Dict
zmqSession::ZMQSession
linearization::Linearization
function OMCSession(omc::Union{String, Nothing}=nothing)::OMCSession
this = new()
this.overridevariables = Dict()
this.simoptoverride = Dict()
this.quantitieslist = Any[]
this.parameterlist = Dict()
this.simulateOptions = Dict()
this.inputlist = Dict()
this.outputlist = Dict()
this.continuouslist = Dict()
this.currentdir = pwd()
this.filepath = ""
this.modelname = ""
this.xmlfile = ""
this.resultfile = ""
this.simulationFlag = false
this.inputFlag = false
this.csvfile = ""
this.variableFilter = nothing
this.tempdir = ""
this.linearization = Linearization()
this.zmqSession = ZMQSession(omc)
return this
end
end
"""
quit(omc::OMCSession; timeout=4::Integer)
Quit OMCSession.
# Arguments
- `omc::OMCSession`: OMC session.
# Keywords
- `timeout=4::Integer`: Timeout in seconds.
See also [`OMJulia.OMCSession`](@ref).
"""
function quit(omc::OMCSession; timeout=4::Integer)
tsk = @task sendExpression(omc, "quit()", parsed=false)
schedule(tsk)
Timer(timeout) do timer
istaskdone(tsk) || Base.throwto(tsk, InterruptException())
end
try
fetch(tsk)
catch _;
if !process_exited(omc.zmqSession.omcprocess)
@warn "omc process did not respond to send expression \"quit()\". Killing the process"
kill(omc.zmqSession.omcprocess)
end
end
# Wait one second for process to exit, kill otherwise
if !process_exited(omc.zmqSession.omcprocess)
Timer(1) do timer
if !process_exited(omc.zmqSession.omcprocess)
@warn "omc process didn't stop after evaluating expression \"quit()\". Killing the process"
kill(omc.zmqSession.omcprocess)
end
end
end
return
end