├── 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 | --------------------------------------------------------------------------------