├── jeromq-0.4.4-SNAPSHOT.jar
├── README.md
└── OMMatlab.m
/jeromq-0.4.4-SNAPSHOT.jar:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/OpenModelica/OMMatlab/HEAD/jeromq-0.4.4-SNAPSHOT.jar
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # OMMatlab
2 | Matlab scripting OpenModelica interface using ZEROMQ
3 |
4 | # Requirement:
5 | [Openmodelica](https://www.openmodelica.org/)
6 | [Matlab](https://se.mathworks.com/products/matlab.html)
7 | [zeromq/jeromq](https://github.com/zeromq/jeromq)
8 |
9 | The jeromq/zeromq library can be build by following the instructions in the repository, or the users can use the pre-build "jeromq-0.4.4-SNAPSHOT.jar" available in this repository and start using it straight away.
10 |
11 | # Installation
12 | Clone the repository and add the installation directory to Matlab PATH for future sessions. For Example
13 | ```
14 | from the matlab terminal, in windows
15 | >>> pathtool
16 | will open a window, add the directory to the list of entries and save. For example in windows
17 | "C:/OPENMODELICAGIT/OpenModelica/OMMatlab"
18 | ```
19 | ```
20 | Then we have to set the java classpath, so that the jeromq library can be used from Matlab. for that we need to create a file called javaclasspath.txt and add the jar file location to the file, To do that
21 | >>> prefdir
22 | will show the preferred directory path, For example in windows
23 | 'C:\Users\arupa54\AppData\Roaming\MathWorks\MATLAB\R2017b'
24 | create a file javaclasspath.txt in that location and add the jar file path to the file, for example in windows the entry would be
25 | C:/OPENMODELICAGIT/OpenModelica/OMMatlab/jeromq-0.4.4-SNAPSHOT.jar
26 | Note: The path should be added without any quotes either single or double
27 | ```
28 | You can also directly use the OMMatlab package directly from the directory where you have cloned, without need to perform the above steps. But the package cannot be used globally.
29 |
30 | # Usage
31 | ```
32 | >>> import OMMatlab.*;
33 | >>> omc=OMMatlab();
34 | >>> omc.sendExpression("getVersion()")
35 | "v1.13.0-dev-531-gde26b558a (64-bit)"
36 | >>> omc.sendExpression("model a end a;")
37 | "{a}"
38 | >>> omc.sendExpression('loadFile("C:\OMMatlab\BouncingBall.mo")')
39 | true
40 | >>> omc.sendExpression("getClassNames()")
41 | {a,BouncingBall}
42 | >>> omc.sendExpression("simulate(BouncingBall)")
43 | record SimulationResult
44 | resultFile = "C:/Users/arupa54/BouncingBall_res.mat",
45 | simulationOptions = "startTime = 0.0, stopTime = 1.0, numberOfIntervals = 500, tolerance = 1e-006, method = 'dassl', fileNamePrefix = 'BouncingBall', options = '', outputFormat = 'mat', variableFilter = '.*', cflags = '', simflags = ''",
46 | messages = "LOG_SUCCESS | info | The initialization finished successfully without homotopy method.
47 | LOG_SUCCESS | info | The simulation finished successfully.
48 | ",
49 | timeFrontend = 0.03334629789025638,
50 | timeBackend = 0.05818852816547053,
51 | timeSimCode = 0.02908068832276598,
52 | timeTemplates = 0.04130980342652182,
53 | timeCompile = 4.495768417986718,
54 | timeSimulation = 0.135430370984969,
55 | timeTotal = 4.795528603068404
56 | end SimulationResult;
57 | ```
58 | To see the list of available OpenModelicaScripting API see (https://www.openmodelica.org/doc/OpenModelicaUsersGuide/latest/scripting_api.html
59 |
--------------------------------------------------------------------------------
/OMMatlab.m:
--------------------------------------------------------------------------------
1 | % This file is part of OpenModelica.
2 | % Copyright (c) 1998-CurrentYear, Open Source Modelica Consortium (OSMC),
3 | % c/o Linköpings universitet, Department of Computer and Information Science,
4 | % SE-58183 Linköping, Sweden.
5 | %
6 | % All rights reserved.
7 | %
8 | % THIS PROGRAM IS PROVIDED UNDER THE TERMS OF THE BSD NEW LICENSE OR THE
9 | % GPL VERSION 3 LICENSE OR THE OSMC PUBLIC LICENSE (OSMC-PL) VERSION 1.2.
10 | % ANY USE, REPRODUCTION OR DISTRIBUTION OF THIS PROGRAM CONSTITUTES
11 | % RECIPIENT'S ACCEPTANCE OF THE OSMC PUBLIC LICENSE OR THE GPL VERSION 3,
12 | % ACCORDING TO RECIPIENTS CHOICE.
13 | %
14 | % The OpenModelica software and the OSMC (Open Source Modelica Consortium)
15 | % Public License (OSMC-PL) are obtained from OSMC, either from the above
16 | % address, from the URLs: http://www.openmodelica.org or
17 | % http://www.ida.liu.se/projects/OpenModelica, and in the OpenModelica
18 | % distribution. GNU version 3 is obtained from:
19 | % http://www.gnu.org/copyleft/gpl.html. The New BSD License is obtained from:
20 | % http://www.opensource.org/licenses/BSD-3-Clause.
21 | %
22 | % This program is distributed WITHOUT ANY WARRANTY; without even the implied
23 | % warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE, EXCEPT AS
24 | % EXPRESSLY SET FORTH IN THE BY RECIPIENT SELECTED SUBSIDIARY LICENSE
25 | % CONDITIONS OF OSMC-PL.
26 |
27 | classdef OMMatlab < handle
28 | properties (Access = private)
29 | process
30 | context
31 | requester
32 | portfile
33 | filename
34 | modelname
35 | xmlfile
36 | resultfile=''
37 | csvfile=''
38 | mattempdir=''
39 | simulationoptions=struct
40 | quantitieslist
41 | parameterlist=struct
42 | continuouslist=struct
43 | inputlist=struct
44 | outputlist=struct
45 | mappednames=struct
46 | overridevariables=struct
47 | simoptoverride=struct
48 | inputflag=false
49 | linearOptions=struct('startTime','0.0','stopTime','1.0','stepSize','0.002','tolerance','1e-6')
50 | linearfile
51 | linearFlag=false
52 | linearmodelname
53 | linearinputs
54 | linearoutputs
55 | linearstates
56 | linearStateIndex
57 | linearInputIndex
58 | linearOutputIndex
59 | linearquantitylist
60 | varFilter
61 | %fileid
62 | end
63 | methods
64 | function obj = OMMatlab(omcpath)
65 | %randomstring = char(97 + floor(26 .* rand(10,1)))';
66 | [~,randomstring]=fileparts(tempname);
67 | if ispc
68 | if ~exist('omcpath', 'var')
69 | omhome = getenv('OPENMODELICAHOME');
70 | omhomepath = replace(fullfile(omhome,'bin','omc.exe'),'\','/');
71 | %add omhome to path environment variabel
72 | %path1 = getenv('PATH');
73 | %path1 = [path1, ';', fullfile(omhome,'bin')];
74 | %disp(path1)
75 | %setenv('PATH', path1);
76 | %cmd ="START /b "+omhomepath +" --interactive=zmq +z=matlab."+randomstring;
77 | cmd = ['START /b',' ',omhomepath,' --interactive=zmq -z=matlab.',randomstring];
78 | else
79 | [dirname1,~]=fileparts(fileparts(omcpath));
80 | %disp(dirname1)
81 | cmd = ['START /b',' ',omcpath,' --interactive=zmq -z=matlab.',randomstring];
82 | end
83 | portfile = strcat('openmodelica.port.matlab.',randomstring);
84 | else
85 | if ismac && system("which omc") ~= 0
86 | %cmd =['/opt/openmodelica/bin/omc --interactive=zmq -z=matlab.',randomstring,' &'];
87 | if ~exist('omcpath', 'var')
88 | cmd =['/opt/openmodelica/bin/omc --interactive=zmq -z=matlab.',randomstring, ' >log.txt', ' &'];
89 | else
90 | cmd =[omcpath, ' --interactive=zmq -z=matlab.',randomstring, ' >log.txt', ' &'];
91 | end
92 | else
93 | %cmd =['omc --interactive=zmq -z=matlab.',randomstring,' &'];
94 | if ~exist('omcpath', 'var')
95 | cmd =['omc --interactive=zmq -z=matlab.',randomstring, ' >log.txt', ' &'];
96 | else
97 | cmd =[omcpath, ' --interactive=zmq -z=matlab.',randomstring, ' >log.txt', ' &'];
98 | end
99 | end
100 | portfile = strcat('openmodelica.',getenv('USER'),'.port.matlab.',randomstring);
101 | end
102 | %disp(cmd)
103 | system(cmd);
104 | %pause(0.2);
105 | obj.portfile = replace(fullfile(tempdir,portfile),'\','/');
106 | while true
107 | pause(0.01);
108 | if(isfile(obj.portfile))
109 | filedata=fileread(obj.portfile);
110 | break;
111 | end
112 | end
113 | import org.zeromq.*
114 | obj.context=ZMQ.context(1);
115 | obj.requester =obj.context.socket(ZMQ.REQ);
116 | %obj.portfile=replace(fullfile(tempdir,portfile),'\','/');
117 | %obj.fileid=fileread(obj.portfile);
118 | obj.requester.connect(filedata);
119 | end
120 |
121 |
122 | function reply = sendExpression(obj,expr)
123 | %%TODO check for omc process is running or not in a generic way
124 | %if(~obj.process.HasExited)
125 | obj.requester.send(expr,0);
126 | data=obj.requester.recvStr(0);
127 | % Parse java string object and return in appropriate matlab
128 | % structure if possible, otherwise return as normal strings
129 | reply=parseExpression(obj,string(data));
130 | %else
131 | %disp("Process Exited, No connection with OMC. Create a new instance of OMMatlab session");
132 | %return
133 | %end
134 | end
135 |
136 | function ModelicaSystem(obj,filename,modelname,libraries,commandLineOptions,variableFilter,customBuildDirectory)
137 | if (nargin < 2)
138 | error('Not enough arguments, filename and classname is required');
139 | end
140 |
141 | if ~exist(filename, 'file')
142 | msg=filename +" does not exist";
143 | error(msg);
144 | return;
145 | end
146 |
147 | % check for commandLineOptions
148 | if exist('commandLineOptions', 'var') && ~isempty(commandLineOptions)
149 | exp=join(["setCommandLineOptions(","""",commandLineOptions,"""",")"]);
150 | cmdExp=obj.sendExpression(exp);
151 | if(cmdExp == "false")
152 | disp(obj.sendExpression("getErrorString()"));
153 | return;
154 | end
155 | end
156 | % set default command Line Options for linearization as
157 | % linearize() will use the simulation executable and runtime
158 | % flag -l to perform linearization
159 | obj.sendExpression("setCommandLineOptions(""--linearizationDumpLanguage=matlab"")");
160 | obj.sendExpression("setCommandLineOptions(""--generateSymbolicLinearization"")")
161 | filepath = replace(filename,'\','/');
162 | %disp(filepath);
163 | loadfilemsg=obj.sendExpression("loadFile( """+ filepath +""")");
164 | if (loadfilemsg=="false")
165 | disp(obj.sendExpression("getErrorString()"));
166 | return;
167 | end
168 |
169 | % check for libraries
170 | if exist('libraries', 'var') && ~isempty(libraries)
171 | %disp("library given");
172 | if isa(libraries, 'struct')
173 | fields=fieldnames(libraries);
174 | for i=1:length(fieldnames(libraries))
175 | loadLibraryHelper(obj, fields(i), libraries.(fields{i}));
176 | end
177 | elseif isa(libraries, 'string')
178 | for n=1:length(libraries)
179 | loadLibraryHelper(obj, libraries{n});
180 | end
181 | elseif isa(libraries, 'cell')
182 | for n=1:length(libraries)
183 | if isa(libraries{n}, 'struct')
184 | fields=fieldnames(libraries{n});
185 | for i=1:length(fieldnames(libraries{n}))
186 | loadLibraryHelper(obj, fields(i), libraries{n}.(fields{i}));
187 | end
188 | elseif isa(libraries{n}, 'string')
189 | loadLibraryHelper(obj, libraries{n});
190 | end
191 | end
192 | else
193 | fprintf("| info | loadLibrary() failed, Unknown type detected:, The following patterns are supported \n1).""Modelica""\n2).[""Modelica"", ""PowerSystems""]\n3).struct(""Modelica"", ""3.2.3"")\n");
194 | return;
195 | end
196 | end
197 |
198 | obj.filename = filename;
199 | obj.modelname = modelname;
200 | %tmpdirname = char(97 + floor(26 .* rand(15,1)))';
201 |
202 | if exist('variableFilter', 'var') && ~isempty(variableFilter)
203 | obj.varFilter = join(["variableFilter=","""", variableFilter, """"]);
204 | else
205 | obj.varFilter = join(["variableFilter=","""",".*",""""]);
206 | end
207 |
208 |
209 | if exist('customBuildDirectory', 'var') && ~isempty(customBuildDirectory)
210 | if ~isfolder(customBuildDirectory)
211 | error(customBuildDirectory, " does not exist");
212 | return
213 | end
214 | obj.mattempdir = replace(char(customBuildDirectory),'\','/');
215 | else
216 | obj.mattempdir = replace(tempname,'\','/');
217 | mkdir(obj.mattempdir);
218 | end
219 | obj.sendExpression("cd("""+ obj.mattempdir +""")")
220 | buildModel(obj)
221 | end
222 |
223 | function loadLibraryHelper(obj, libname, version)
224 | if(isfile(libname))
225 | libmsg = obj.sendExpression("loadFile( """+ libname +""")");
226 | if (libmsg=="false")
227 | disp(obj.sendExpression("getErrorString()"));
228 | return;
229 | end
230 | else
231 | if exist('version', 'var')
232 | libname = strcat("loadModel(", libname, ", ", "{", """", version, """", "}", ")");
233 | else
234 | libname = strcat("loadModel(", libname, ")");
235 | end
236 | %disp(libname)
237 | libmsg = obj.sendExpression(libname);
238 | if (libmsg=="false")
239 | disp(obj.sendExpression("getErrorString()"));
240 | return;
241 | end
242 | end
243 | end
244 |
245 | function buildModel(obj)
246 | buildmodelexpr = join(["buildModel(",obj.modelname,", ", replace(obj.varFilter," ",""),")"]);
247 | %disp(buildmodelexpr);
248 | buildModelResult = obj.sendExpression(buildmodelexpr);
249 | %r2=split(erase(string(buildModelResult),["{","}",""""]),",");
250 | %disp(r2);
251 | if(isempty(char(buildModelResult(1))))
252 | disp(obj.sendExpression("getErrorString()"));
253 | return;
254 | end
255 | %xmlpath =strcat(obj.mattempdir,'\',r2{2});
256 | xmlpath=fullfile(obj.mattempdir,char(buildModelResult(2)));
257 | obj.xmlfile = replace(xmlpath,'\','/');
258 | xmlparse(obj);
259 | end
260 |
261 | function workdir = getWorkDirectory(obj)
262 | workdir = obj.mattempdir;
263 | return;
264 | end
265 |
266 | function xmlparse(obj)
267 | if isfile(obj.xmlfile)
268 | xDoc=xmlread(obj.xmlfile);
269 | % DefaultExperiment %
270 | allexperimentitems = xDoc.getElementsByTagName('DefaultExperiment');
271 | obj.simulationoptions.('startTime') = char(allexperimentitems.item(0).getAttribute('startTime'));
272 | obj.simulationoptions.('stopTime') = char(allexperimentitems.item(0).getAttribute('stopTime'));
273 | obj.simulationoptions.('stepSize') = char(allexperimentitems.item(0).getAttribute('stepSize'));
274 | obj.simulationoptions.('tolerance') = char(allexperimentitems.item(0).getAttribute('tolerance'));
275 | obj.simulationoptions.('solver') = char(allexperimentitems.item(0).getAttribute('solver'));
276 |
277 | % ScalarVariables %
278 | allvaritem = xDoc.getElementsByTagName('ScalarVariable');
279 | for k = 0:allvaritem.getLength-1
280 | scalar=struct;
281 | scalar.('name')=char(allvaritem.item(k).getAttribute('name'));
282 | scalar.('changeable')=char(allvaritem.item(k).getAttribute('isValueChangeable'));
283 | scalar.('description')=char(allvaritem.item(k).getAttribute('description'));
284 | scalar.('variability')=char(allvaritem.item(k).getAttribute('variability'));
285 | scalar.('causality') =char(allvaritem.item(k).getAttribute('causality'));
286 | scalar.('alias')=char(allvaritem.item(k).getAttribute('alias'));
287 | scalar.('aliasVariable')=char(allvaritem.item(k).getAttribute('aliasVariable'));
288 | scalar.('aliasVariableId')=char(allvaritem.item(k).getAttribute('aliasVariableId'));
289 |
290 | % iterate subchild to find start values of all types
291 | childNode = getFirstChild(allvaritem.item(k));
292 | while ~isempty(childNode)
293 | if childNode.getNodeType == childNode.ELEMENT_NODE
294 | if childNode.hasAttribute('start')
295 | %disp(name + "=" + char(childNode.getAttribute('start')) + "=" + attr)
296 | scalar.('start') = char(childNode.getAttribute('start'));
297 | else
298 | scalar.('start') = 'None';
299 | end
300 | if childNode.hasAttribute('min')
301 | scalar.('min') = char(childNode.getAttribute('min'));
302 | else
303 | scalar.('min') = 'None';
304 | end
305 | if childNode.hasAttribute('max')
306 | scalar.('max') = char(childNode.getAttribute('max'));
307 | else
308 | scalar.('max') = 'None';
309 | end
310 | %scalar.('value')=value;
311 | end
312 | childNode = getNextSibling(childNode);
313 | end
314 |
315 | % check for variability parameter and add to parameter list
316 | if(obj.linearFlag==false)
317 | name=scalar.('name');
318 | value=scalar.('start');
319 | if(strcmp(scalar.('variability'),'parameter'))
320 | try
321 | if isfield(obj.overridevariables, name)
322 | obj.parameterlist.(name) = obj.overridevariables.(name);
323 | else
324 | obj.parameterlist.(name) = value;
325 | end
326 | catch ME
327 | createvalidnames(obj,name,value,"parameter");
328 | end
329 | end
330 | % check for variability continuous and add to continuous list
331 | if(strcmp(scalar.('variability'),'continuous'))
332 | try
333 | obj.continuouslist.(name) = value;
334 | catch ME
335 | createvalidnames(obj,name,value,"continuous");
336 | end
337 | end
338 |
339 | % check for causality input and add to input list
340 | if(strcmp(scalar.('causality'),'input'))
341 | try
342 | obj.inputlist.(name) = value;
343 | catch ME
344 | createvalidnames(obj,name,value,"input");
345 | end
346 | end
347 | % check for causality output and add to output list
348 | if(strcmp(scalar.('causality'),'output'))
349 | try
350 | obj.outputlist.(name) = value;
351 | catch ME
352 | createvalidnames(obj,name,value,"output");
353 | end
354 | end
355 | end
356 | if(obj.linearFlag==true)
357 | if(scalar.('alias')=="alias")
358 | name=scalar.('name');
359 | if (name(2) == 'x')
360 | obj.linearstates=[obj.linearstates,name(4:end-1)];
361 | obj.linearStateIndex=[obj.linearStateIndex, str2double(char(scalar.('aliasVariableId')))];
362 | end
363 | if (name(2) == 'u')
364 | obj.linearinputs=[obj.linearinputs,name(4:end-1)];
365 | obj.linearInputIndex=[obj.linearInputIndex, str2double(char(scalar.('aliasVariableId')))];
366 | end
367 | if (name(2) == 'y')
368 | obj.linearoutputs=[obj.linearoutputs,name(4:end-1)];
369 | obj.linearOutputIndex=[obj.linearOutputIndex, str2double(char(scalar.('aliasVariableId')))];
370 | end
371 | end
372 | obj.linearquantitylist=[obj.linearquantitylist,scalar];
373 | else
374 | obj.quantitieslist=[obj.quantitieslist,scalar];
375 | end
376 | end
377 | else
378 | msg="xmlfile is not generated";
379 | error(msg);
380 | return;
381 | end
382 | end
383 |
384 | function result= getQuantities(obj,args)
385 | if isempty(obj.quantitieslist)
386 | result = [];
387 | return;
388 | end
389 | if exist('args', 'var')
390 | tmpresult=[];
391 | for n=1:length(args)
392 | for q=1:length(obj.quantitieslist)
393 | if(strcmp(obj.quantitieslist(q).name,args(n)))
394 | tmpresult=[tmpresult;obj.quantitieslist(q)];
395 | end
396 | end
397 | end
398 | result=struct2table(tmpresult,'AsArray',true);
399 | else
400 | result=struct2table(obj.quantitieslist,'AsArray',true);
401 | end
402 | return;
403 | end
404 |
405 | function result= getLinearQuantities(obj,args)
406 | if exist('args', 'var')
407 | tmpresult=[];
408 | for n=1:length(args)
409 | for q=1:length(obj.linearquantitylist)
410 | if(strcmp(obj.linearquantitylist(q).name,args(n)))
411 | tmpresult=[tmpresult;obj.linearquantitylist(q)];
412 | end
413 | end
414 | end
415 | result=struct2table(tmpresult,'AsArray',true);
416 | else
417 | result=struct2table(obj.linearquantitylist,'AsArray',true);
418 | end
419 | return;
420 | end
421 |
422 | function result = getParameters(obj,args)
423 | if exist('args', 'var')
424 | param=strings(1,length(args));
425 | for n=1:length(args)
426 | param(n) = obj.parameterlist.(args(n));
427 | end
428 | result = param;
429 | else
430 | result = obj.parameterlist;
431 | end
432 | return;
433 | end
434 |
435 | function result = getInputs(obj,args)
436 | if exist('args', 'var')
437 | inputs=strings(1,length(args));
438 | for n=1:length(args)
439 | inputs(n) = obj.inputlist.(args(n));
440 | end
441 | result = inputs;
442 | else
443 | result = obj.inputlist;
444 | end
445 | return;
446 | end
447 |
448 | function result = getOutputs(obj,args)
449 | if exist('args', 'var')
450 | outputs=strings(1,length(args));
451 | for n=1:length(args)
452 | outputs(n) = obj.outputlist.(args(n));
453 | end
454 | result = outputs;
455 | else
456 | result = obj.outputlist;
457 | end
458 | return;
459 | end
460 |
461 | function result = getContinuous(obj,args)
462 | if exist('args', 'var')
463 | continuous=strings(1,length(args));
464 | for n=1:length(args)
465 | continuous(n) = obj.continuouslist.(args(n));
466 | end
467 | result = continuous;
468 | else
469 | result = obj.continuouslist;
470 | end
471 | return;
472 | end
473 |
474 | function result = getSimulationOptions(obj,args)
475 | if exist('args', 'var')
476 | simoptions=strings(1,length(args));
477 | for n=1:length(args)
478 | simoptions(n) = obj.simulationoptions.(args(n));
479 | end
480 | result = simoptions;
481 | else
482 | result = obj.simulationoptions;
483 | end
484 | return;
485 | end
486 |
487 | function result = getLinearizationOptions(obj,args)
488 | if exist('args', 'var')
489 | linoptions=strings(1,length(args));
490 | for n=1:length(args)
491 | linoptions(n) = obj.linearOptions.(args(n));
492 | end
493 | result = linoptions;
494 | else
495 | result = obj.linearOptions;
496 | end
497 | return;
498 | end
499 |
500 | % Set Methods
501 | function setParameters(obj,args)
502 | if exist('args', 'var')
503 | for n=1:length(args)
504 | val=replace(args(n)," ","");
505 | value=split(val,"=");
506 | if(isfield(obj.parameterlist,char(value(1))))
507 | if isParameterChangeable(obj, value(1), value(2))
508 | obj.parameterlist.(value(1))= value(2);
509 | obj.overridevariables.(value(1))= value(2);
510 | end
511 | else
512 | disp(value(1) + " is not a parameter");
513 | return;
514 | end
515 | end
516 | end
517 | end
518 |
519 | % check for parameter modifiable or not
520 | function result = isParameterChangeable(obj, name, value)
521 | if (isfield(obj.mappednames, char(name)))
522 | tmpname = obj.mappednames.(name);
523 | else
524 | tmpname = name;
525 | end
526 | q = getQuantities(obj, string(tmpname));
527 | if q.changeable{1} == "false"
528 | disp("| info | setParameters() failed : It is not possible to set the following signal " + """" + name + """" + ", It seems to be structural, final, protected or evaluated or has a non-constant binding, use sendExpression(setParameterValue("+ obj.modelname + ", " + name + ", " + value + "), parsed=false)" + " and rebuild the model using buildModel() API")
529 | result = false;
530 | return;
531 | end
532 | result = true;
533 | return;
534 | end
535 |
536 | function setSimulationOptions(obj,args)
537 | if exist('args', 'var')
538 | for n=1:length(args)
539 | val=replace(args(n)," ","");
540 | value=split(val,"=");
541 | if(isfield(obj.simulationoptions,char(value(1))))
542 | obj.simulationoptions.(value(1))= value(2);
543 | obj.simoptoverride.(value(1)) = value(2);
544 | %obj.overridevariables.(value(1))= value(2);
545 | else
546 | disp(value(1) + " is not a Simulation Option");
547 | return;
548 | end
549 | end
550 | end
551 | end
552 |
553 | function setLinearizationOptions(obj,args)
554 | if exist('args', 'var')
555 | for n=1:length(args)
556 | val=replace(args(n)," ","");
557 | value=split(val,"=");
558 | if(isfield(obj.linearOptions,char(value(1))))
559 | obj.linearOptions.(value(1))= value(2);
560 | obj.linearOptions.(value(1))= value(2);
561 | else
562 | disp(value(1) + " is not a Linearization Option");
563 | return;
564 | end
565 | end
566 | end
567 | end
568 |
569 | function setInputs(obj,args)
570 | if exist('args', 'var')
571 | for n=1:length(args)
572 | val=replace(args(n)," ","");
573 | value=split(val,"=");
574 | if(isfield(obj.inputlist,char(value(1))))
575 | obj.inputlist.(value(1))= value(2);
576 | obj.inputflag=true;
577 | else
578 | disp(value(1) + " is not a Input");
579 | return;
580 | end
581 | end
582 | end
583 | end
584 |
585 | function createcsvData(obj, startTime, stopTime)
586 | obj.csvfile = replace(fullfile(obj.mattempdir,[char(obj.modelname),'.csv']),'\','/');
587 | fileID = fopen(obj.csvfile,"w");
588 | %disp(strjoin(fieldnames(obj.inputlist),","));
589 | fields=fieldnames(obj.inputlist);
590 | % check for mapped names incase of array vars
591 | fprintf(fileID, "time,");
592 | for i=1:length(fields)
593 | if (isfield(obj.mappednames, char(fields(i))))
594 | mappedNames = obj.mappednames.(fields{i});
595 | else
596 | mappedNames = char(fields(i));
597 | end
598 | fprintf(fileID, [mappedNames, ',']);
599 | end
600 | fprintf(fileID, "end\n");
601 | %csvdata = obj.inputlist;
602 | %time=strings(1,length(csvdata));
603 | time=[];
604 | count=1;
605 | tmpcsvdata=struct;
606 | for i=1:length(fieldnames(obj.inputlist))
607 | %disp(fields(i));
608 | %disp(obj.inputlist.(fields{i}));
609 | %disp("loop"+ num2str(i))
610 | %disp(fields{i})
611 | var = obj.inputlist.(fields{i});
612 | if(isempty(var))
613 | var="0";
614 | end
615 | s1 = eval(replace(replace(replace(replace(var,"[","{"),"]","}"),"(","{"),")","}"));
616 | tmpcsvdata.(char(fields(i))) = s1;
617 | %csvdata.()=s1;
618 | %disp(length(s1));
619 | if(length(s1)>1)
620 | for j=1:length(s1)
621 | t = s1(j);
622 | %disp(t{1}{1});
623 | %time(count)=t{1}{1};
624 | time=[time,t{1}{1}];
625 | count=count+1;
626 | end
627 | end
628 | end
629 | %disp(tmpcsvdata)
630 | %disp(length(time))
631 | if(isempty(time))
632 | time=[str2double(startTime),str2double(stopTime)];
633 | end
634 | t1=struct2cell(tmpcsvdata);
635 | %disp(length(t1))
636 | sortedtime=sort(time);
637 | previousvalue=struct;
638 | for t=1:length(sortedtime)
639 | fprintf(fileID,[num2str(sortedtime(t)),',']);
640 | %fprintf(fileID,[char(sortedtime(t)),',']);
641 | listcount=1;
642 | for i=1:length(t1)
643 | tmp1=t1{i};
644 | if(iscell(tmp1))
645 | %disp("length is :" + length(tmp1))
646 | found=false;
647 | for k=1:length(tmp1)
648 | if(sortedtime(t)==tmp1{k}{1})
649 | %disp(sortedtime(t)+ "=>" + tmp1{k}{1})
650 | data=tmp1{k}{2};
651 | %disp(sortedtime(t)+ "=>" + data)
652 | fprintf(fileID,[num2str(data),',']);
653 | %pfieldname=matlab.lang.makeValidName(string(listcount));
654 | pfieldname="x"+string(listcount);
655 | previousvalue.(pfieldname)=data;
656 | tmp1(k)=[];
657 | t1{i}=tmp1;
658 | found=true;
659 | break;
660 | end
661 | end
662 | if(found==false)
663 | %disp(previousvalue)
664 | %disp(string(listcount))
665 | tmpfieldname="x"+string(listcount);
666 | %disp("false loop" + previousvalue.(tmpfieldname))
667 | data=previousvalue.(tmpfieldname);
668 | fprintf(fileID,[num2str(data),',']);
669 | end
670 | else
671 | %disp("strings found" + t1{i})
672 | %disp(class(t1{i}))
673 | %fprintf(fileID,'%s',t1{i},',');
674 | fprintf(fileID,[num2str(t1{i}),',']);
675 | end
676 | listcount=listcount+1;
677 | end
678 | fprintf(fileID,[num2str(0),'\n']);
679 | %disp(sortedtime(t) + "****************************")
680 | end
681 | fclose(fileID);
682 | end
683 |
684 | function simulate(obj,resultfile,simflags)
685 | if exist('resultfile', 'var')
686 | %disp(resultfile);
687 | if ~isempty(resultfile)
688 | r=join([' -r=',char(resultfile)]);
689 | obj.resultfile=replace(fullfile(obj.mattempdir,char(resultfile)),'\','/');
690 | else
691 | r='';
692 | end
693 | else
694 | r='';
695 | obj.resultfile=replace(fullfile(obj.mattempdir,[char(obj.modelname),'_res.mat']),'\','/');
696 | end
697 | if exist('simflags', 'var')
698 | simflags=join([' ',char(simflags)]);
699 | else
700 | simflags='';
701 | end
702 | if(isfile(obj.xmlfile))
703 | if (ispc)
704 | getexefile = replace(fullfile(obj.mattempdir,[char(obj.modelname),'.exe']),'\','/');
705 | %disp(getexefile)
706 | else
707 | getexefile = replace(fullfile(obj.mattempdir,char(obj.modelname)),'\','/');
708 | end
709 | curdir=pwd;
710 | if(isfile(getexefile))
711 | cd(obj.mattempdir)
712 | if(~isempty(fieldnames(obj.overridevariables)) || ~isempty(fieldnames(obj.simoptoverride)))
713 | names = [fieldnames(obj.overridevariables); fieldnames(obj.simoptoverride)];
714 | tmpstruct = cell2struct([struct2cell(obj.overridevariables); struct2cell(obj.simoptoverride)], names, 1);
715 | fields=fieldnames(tmpstruct);
716 | tmpoverride1=strings(1,length(fields));
717 | overridefile = replace(fullfile(obj.mattempdir,[char(obj.modelname),'_override.txt']),'\','/');
718 | fileID = fopen(overridefile,"w");
719 | for i=1:length(fields)
720 | if (isfield(obj.mappednames,fields(i)))
721 | name=obj.mappednames.(fields{i});
722 | else
723 | name=fields(i);
724 | end
725 | tmpoverride1(i)=name+"="+tmpstruct.(fields{i});
726 | fprintf(fileID,tmpoverride1(i));
727 | fprintf(fileID,"\n");
728 | end
729 | fclose(fileID);
730 | %disp(overridefile)
731 | overridevar=join([' -overrideFile=',overridefile]);
732 | else
733 | overridevar='';
734 | end
735 |
736 | if(obj.inputflag==true)
737 | obj.createcsvData(obj.simulationoptions.('startTime'), obj.simulationoptions.('stopTime'))
738 | csvinput=join([' -csvInput=',obj.csvfile]);
739 | else
740 | csvinput='';
741 | end
742 |
743 | finalsimulationexe = [getexefile,overridevar,csvinput,r,simflags];
744 | %disp(finalsimulationexe);
745 | if ispc
746 | omhome = getenv('OPENMODELICAHOME');
747 | %set dll path needed for windows simulation
748 | dllpath = [replace(fullfile(omhome,'bin'),'\','/'),';',replace(fullfile(omhome,'lib/omc'),'\','/'),';',replace(fullfile(omhome,'lib/omc/cpp'),'\','/'),';',replace(fullfile(omhome,'lib/omc/omsicpp'),'\','/'),';',getenv('PATH')];
749 | %disp(dllpath);
750 | system(['set PATH=' dllpath ' && ' finalsimulationexe])
751 | else
752 | system(finalsimulationexe);
753 | end
754 | %obj.resultfile=replace(fullfile(obj.mattempdir,[char(obj.modelname),'_res.mat']),'\','/');
755 | else
756 | disp("Model cannot be Simulated: executable not found")
757 | end
758 | cd(curdir)
759 | %disp(pwd)
760 | else
761 | disp("Model cannot be Simulated: xmlfile not found")
762 | end
763 |
764 | end
765 |
766 | function result = linearize(obj, lintime, simflags)
767 | %linearize(SeborgCSTR.ModSeborgCSTRorg,startTime=0.0,stopTime=1.0,numberOfIntervals=500,stepSize=0.002,tolerance=1e-6,simflags="-csvInput=C:/Users/arupa54/AppData/Local/Temp/jl_59DA.tmp/SeborgCSTR.ModSeborgCSTRorg.csv -override=a=2.0")
768 | if exist('simflags', 'var')
769 | simflags=join([' ',char(simflags)]);
770 | else
771 | simflags='';
772 | end
773 | % check for override variables and their associated mapping
774 | names = [fieldnames(obj.overridevariables); fieldnames(obj.linearOptions)];
775 | tmpstruct = cell2struct([struct2cell(obj.overridevariables); struct2cell(obj.linearOptions)], names, 1);
776 | fields=fieldnames(tmpstruct);
777 | tmpoverride1=strings(1,length(fields));
778 | overridelinearfile = replace(fullfile(obj.mattempdir,[char(obj.modelname),'_override_linear.txt']),'\','/');
779 | fileID = fopen(overridelinearfile,"w");
780 | for i=1:length(fields)
781 | if (isfield(obj.mappednames,fields(i)))
782 | name=obj.mappednames.(fields{i});
783 | else
784 | name=fields(i);
785 | end
786 | tmpoverride1(i)=name+"="+tmpstruct.(fields{i});
787 | fprintf(fileID,tmpoverride1(i));
788 | fprintf(fileID,"\n");
789 | end
790 | fclose(fileID);
791 | if(~isempty(tmpoverride1))
792 | tmpoverride2=join([' -overrideFile=',overridelinearfile]);
793 | else
794 | tmpoverride2='';
795 | end
796 |
797 | if(obj.inputflag==true)
798 | obj.createcsvData(obj.linearOptions.('startTime'), obj.linearOptions.('stopTime'))
799 | csvinput=join([' -csvInput=',obj.csvfile]);
800 | else
801 | csvinput='';
802 | end
803 |
804 | if(isfile(obj.xmlfile))
805 | if (ispc)
806 | getexefile = replace(fullfile(obj.mattempdir,[char(obj.modelname),'.exe']),'\','/');
807 | %disp(getexefile)
808 | else
809 | getexefile = replace(fullfile(obj.mattempdir,char(obj.modelname)),'\','/');
810 | end
811 | else
812 | disp("Linearization cannot be performed as : " + obj.xmlfile + " not found, which means the model is not buid")
813 | end
814 | %linexpr=strcat('linearize(',obj.modelname,',',overridelinear,',','simflags=','"',csvinput,' ',tmpoverride2,'")');
815 | if exist('lintime', 'var')
816 | linruntime=join([getexefile, ' -l=', char(lintime)]);
817 | else
818 | linruntime=join([getexefile, ' -l=', char(obj.linearOptions.('stopTime'))]);
819 | end
820 | finallinearizationexe =[linruntime,tmpoverride2,csvinput,simflags];
821 | %disp(finallinearizationexe)
822 |
823 | curdir=pwd;
824 | cd(obj.mattempdir);
825 | if ispc
826 | omhome = getenv('OPENMODELICAHOME');
827 | %set dll path needed for windows simulation
828 | dllpath = [replace(fullfile(omhome,'bin'),'\','/'),';',replace(fullfile(omhome,'lib/omc'),'\','/'),';',replace(fullfile(omhome,'lib/omc/cpp'),'\','/'),';',replace(fullfile(omhome,'lib/omc/omsicpp'),'\','/'),';',getenv('PATH')];
829 | %disp(dllpath);
830 | system(['set PATH=' dllpath ' && ' finallinearizationexe])
831 | else
832 | system(finallinearizationexe);
833 | end
834 | %obj.resultfile=res.("resultFile");
835 |
836 | obj.linearmodelname=strcat('linearized_model');
837 | obj.linearfile=replace(fullfile(obj.mattempdir,[char(obj.linearmodelname),'.m']),'\','/');
838 |
839 | % support older openmodelica versions before OpenModelica v1.16.2
840 | % where linearize() generates "linear_modelname.mo" file
841 | if(~isfile(obj.linearfile))
842 | obj.linearmodelname=strcat('linear_',obj.modelname);
843 | obj.linearfile=replace(fullfile(obj.mattempdir,[char(obj.linearmodelname),'.m']),'\','/');
844 | end
845 |
846 | if(isfile(obj.linearfile))
847 | %addpath(obj.getWorkDirectory());
848 | % this function is called from the generated matlab code
849 | % linearized_model.m
850 | [A, B, C, D, stateVars, inputVars, outputVars] = linearized_model();
851 | result = {A, B, C, D};
852 | obj.linearstates = replace(stateVars,{'(',')'},{'[',']'});
853 | obj.linearinputs = replace(inputVars,{'(',')'},{'[',']'});
854 | obj.linearoutputs = replace(outputVars,{'(',')'},{'[',']'});
855 | obj.linearFlag = true;
856 | else
857 | disp("Linearization failed: " + obj.linearfile + " not found")
858 | disp(obj.sendExpression("getErrorString()"))
859 | return;
860 | end
861 | cd(curdir);
862 | end
863 |
864 | function result = getLinearMatrix(obj)
865 | matrix_A=struct;
866 | matrix_B=struct;
867 | matrix_C=struct;
868 | matrix_D=struct;
869 |
870 | for i=1:length(obj.linearquantitylist)
871 | name=obj.linearquantitylist(i).("name");
872 | value= obj.linearquantitylist(i).("value");
873 | if( obj.linearquantitylist(i).("variability")=="parameter")
874 | if(name(1)=='A')
875 | tmpname=matlab.lang.makeValidName(name);
876 | matrix_A.(tmpname)=value;
877 | end
878 | if(name(1)=='B')
879 | tmpname=matlab.lang.makeValidName(name);
880 | matrix_B.(tmpname)=value;
881 | end
882 | if(name(1)=='C')
883 | tmpname=matlab.lang.makeValidName(name);
884 | matrix_C.(tmpname)=value;
885 | end
886 | if(name(1)=='D')
887 | tmpname=matlab.lang.makeValidName(name);
888 | matrix_D.(tmpname)=value;
889 | end
890 | end
891 | end
892 | FullLinearMatrix={};
893 | tmpMatrix_A=getLinearMatrixValues(obj,matrix_A);
894 | tmpMatrix_B=getLinearMatrixValues(obj,matrix_B);
895 | tmpMatrix_C=getLinearMatrixValues(obj,matrix_C);
896 | tmpMatrix_D=getLinearMatrixValues(obj,matrix_D);
897 | FullLinearMatrix{1}=tmpMatrix_A;
898 | FullLinearMatrix{2}=tmpMatrix_B;
899 | FullLinearMatrix{3}=tmpMatrix_C;
900 | FullLinearMatrix{4}=tmpMatrix_D;
901 | result=FullLinearMatrix;
902 | return;
903 | end
904 |
905 | function result = getLinearMatrixValues(~,matrix_name)
906 | if(~isempty(fieldnames(matrix_name)))
907 | fields=fieldnames(matrix_name);
908 | t=fields{end};
909 |
910 | rows_char=extractBetween(t,string(t(1:2)),"_");
911 | rows=str2double(rows_char);
912 | columns_char=extractBetween(t,string(rows_char)+"_","_");
913 | columns=str2double(columns_char);
914 |
915 | tmpMatrix=zeros(rows,columns,'double');
916 | for i=1:length(fields)
917 | n=fields{i};
918 |
919 | r_char=extractBetween(n,string(n(1:2)),"_");
920 | r=str2double(r_char);
921 | c_char=extractBetween(n,string(r_char)+"_","_");
922 | c=str2double(c_char);
923 |
924 | val=str2double(matrix_name.(fields{i}));
925 | format shortG
926 | tmpMatrix(r,c)=val;
927 | end
928 | result=tmpMatrix;
929 | else
930 | result=zeros(0,0);
931 | end
932 | end
933 |
934 | function result = getLinearInputs(obj)
935 | if(obj.linearFlag==true)
936 | %[sortedinput, index] = sort(obj.linearInputIndex);
937 | result=obj.linearinputs();
938 | else
939 | disp("Model is not Linearized");
940 | end
941 | return;
942 | end
943 |
944 | function result = getLinearOutputs(obj)
945 | if(obj.linearFlag==true)
946 | %[sortedoutput, index] = sort(obj.linearOutputIndex);
947 | result=obj.linearoutputs();
948 | else
949 | disp("Model is not Linearized");
950 | end
951 | return;
952 | end
953 |
954 | function result = getLinearStates(obj)
955 | if(obj.linearFlag==true)
956 | %[sortedstates, index] = sort(obj.linearStateIndex);
957 | result=obj.linearstates();
958 | else
959 | disp("Model is not Linearized");
960 | end
961 | return;
962 | end
963 |
964 | function result = getSolutions(obj,args,resultfile)
965 | if exist('resultfile', 'var')
966 | resfile = char(resultfile);
967 | else
968 | resfile = obj.resultfile;
969 | end
970 | if(isfile(resfile))
971 | tmp1=obj.sendExpression("readSimulationResultVars(""" + resfile + """)");
972 | obj.sendExpression("closeSimulationResultFile()");
973 | if exist('args', 'var') && ~isempty(args)
974 | for i=1:length(args)
975 | if (~ismember(args(i), tmp1) && ~strcmp(args(i),"time"))
976 | disp(char(args(i))+ " does not exist in result file " + char(resfile));
977 | return;
978 | end
979 | end
980 | tmp1=strjoin(cellstr(args),',');
981 | tmp2=['{',tmp1,'}'];
982 | simresult=obj.sendExpression("readSimulationResult(""" + resfile + ""","+tmp2+")");
983 | obj.sendExpression("closeSimulationResultFile()");
984 | result=simresult;
985 | else
986 | result = tmp1;
987 | end
988 | return;
989 | else
990 | result= "Result File does not exist! " + char(resfile);
991 | disp(result);
992 | return;
993 | end
994 | end
995 |
996 | % function which creates valid field name as matlab
997 | % does not allow der(h) to be a valid name, also map
998 | % the changed names to mappednames struct, inorder to
999 | % keep track of the original names as it is needed to query
1000 | % simulation results
1001 | function createvalidnames(obj,name,value,structname)
1002 | tmpname=matlab.lang.makeValidName(name);
1003 | obj.mappednames.(tmpname)= name;
1004 | if(strcmp(structname,'continuous'))
1005 | obj.continuouslist.(tmpname)= value;
1006 | end
1007 | if(strcmp(structname,'parameter'))
1008 | obj.parameterlist.(tmpname)= value;
1009 | end
1010 | if(strcmp(structname,'input'))
1011 | obj.inputlist.(tmpname)= value;
1012 | end
1013 | if(strcmp(structname,'output'))
1014 | obj.outputlist.(tmpname)= value;
1015 | end
1016 | end
1017 |
1018 | function result = parseExpression(obj,args)
1019 | %final=regexp(args,'(?<=")[^"]+(?=")|[{}(),]|[a-zA-Z0-9.]+','match');
1020 | final=regexp(args,'"(.*?)"|[{}()=]|[-+a-zA-Z0-9_.]+','match');
1021 | %final=regexp(args,'"([^"]|\n)*"|[{}()=]|[a-zA-Z0-9.]+','match');
1022 | if(length(final)>1)
1023 | if(final(1)=="{" && final(2)~="{")
1024 | tmp3=strings(1,1);
1025 | count=1;
1026 | for i=1:length(final)
1027 | if(final(i)~="{" && final(i)~="}" && final(i)~="(" && final(i)~=")" && final(i)~=",")
1028 | value=replace(final{i},"""","");
1029 | tmp3(count)=value;
1030 | count=count+1;
1031 | end
1032 | end
1033 | result=tmp3;
1034 | elseif(final(1)=="{" && final(2)=="{")
1035 | %result=eval(args);
1036 | tmpresults={1};
1037 | tmpcount=1;
1038 | count=1;
1039 | for i=2:length(final)-1
1040 | if(final(i)=="{")
1041 | if(isnan(str2double(final(i+1))))
1042 | tmp=strings(1,1);
1043 | else
1044 | tmp=[];
1045 | end
1046 | elseif(final(i)=="}")
1047 | tmpresults{tmpcount}=tmp;
1048 | tmp=[];
1049 | count=1;
1050 | tmpcount=tmpcount+1;
1051 | else
1052 | tmp(count)=final(i);
1053 | count=count+1;
1054 | end
1055 | end
1056 | result=tmpresults;
1057 | elseif(final(1)=="record")
1058 | result=struct;
1059 | for i=3:length(final)-2
1060 | if(final(i)=="=")
1061 | value=replace(final(i+1),"""","");
1062 | result.(final(i-1))= value;
1063 | end
1064 | end
1065 | elseif(final(1)=="fail")
1066 | result=obj.sendExpression("getErrorString()");
1067 | else
1068 | %reply=final;
1069 | disp("returning unparsed string")
1070 | result=replace(args,"""","");
1071 | %result=args;
1072 | end
1073 | elseif(length(final)==1)
1074 | result=replace(final,"""","");
1075 | else
1076 | disp("returning unparsed string")
1077 | result=replace(args,"""","");
1078 | end
1079 | end
1080 |
1081 | function delete(obj)
1082 | %disp("inside delete")
1083 | obj.sendExpression("quit()")
1084 | obj.requester.close();
1085 | delete(obj);
1086 | end
1087 | end
1088 | end
1089 |
--------------------------------------------------------------------------------