]> gerrit.simantics Code Review - simantics/fmil.git/blob - org.simantics.fmil.core/native/FMUSimulator/src/fmu_control.cpp
Added getters and setters for all FMI data types.
[simantics/fmil.git] / org.simantics.fmil.core / native / FMUSimulator / src / fmu_control.cpp
1 /* ------------------------------------------------------------------------- 
2  * fmu_control.c
3  * Simulation controls for fmus
4  *
5  * Free libraries and tools used to implement this simulator:
6  *  - header files from the FMU specification
7  *  - eXpat 2.0.1 XML parser, see http://expat.sourceforge.net
8  *  - 7z.exe 4.57 zip and unzip tool, see http://www.7-zip.org <---------- Replace with zlib
9  * Author: Teemu Lempinen
10  * Copyright 2012 Semantum Oy
11  * -------------------------------------------------------------------------
12  */
13
14 #include <stdlib.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <map>
18 #include <string>
19 #include <vector>
20 #include <iostream>
21 #include <regex>
22 #include <atomic>
23
24 #include <org_simantics_fmil_FMILJNI.h>
25
26 extern "C" {
27         #include "fmi_me.h"
28         #include "sim_support.h"
29 }
30
31 #include "fmi1_cs.h"
32
33 #define PRINT(fmt,args) { FILE *fp = fopen("R:\\Simantics\\Sysdyn\\log.txt", "ab"); fprintf(fp, fmt, args); fclose(fp); }
34
35 using namespace std;
36
37 static std::atomic<int> instanceNameID;
38
39 int create_id() {
40     return instanceNameID++;
41 }
42
43 struct FMI1 {
44
45         void *fmu;
46
47         vector<string> variables;
48         vector<string> descriptions;
49         vector<string> declaredTypes;
50         vector<int> valueReferences;
51         vector<int> types;
52         vector<int> variabilities;
53         vector<int> causalities;
54
55         vector<string> declaredTypeNames;
56         vector<string> typeDescriptions;
57         vector<string> quantities;
58         vector<string> units;
59
60         vector<int> subscription;
61         double currentTime;
62         double timeStep;
63
64         int version;
65
66 };
67
68 struct FMUControlStruct {
69         double step;                                    // simulation step length
70         fmiReal currentTime;                    // current simulation time
71
72         fmiComponent c;                                 // instance of the fmu 
73         ScalarVariable** vars;                  // model variables
74
75         fmiEventInfo eventInfo;         // updated by calls to initialize and eventUpdate
76         const char* guid;               // global unique id of the fmu
77         fmiCallbackFunctions callbacks; // called by the model during simulation
78         fmiStatus fmiFlag;              // return code of the fmu functions
79
80         map<string,int> indexes;                // indexes for variable names in vars-table
81         map<string,int>::iterator it;
82
83         int nx;                                                 // number of state variables
84         double *x;                                              // continuous states
85         double *xdot;                                   // the crresponding derivatives in same order
86         int nz;                         // number of state event indicators
87         double *z;                                              // state event indicators
88         double *prez;                                   // previous values of state event indicators
89         
90         bool initialized;                               // has the fmu been initialized
91
92         vector<fmiValueReference> subscription;         // result subscriptions
93         vector<string> allVariables;    // all variables in an initialized model
94         vector<fmiValueReference> fmiValueReferences;           // all value references
95
96         string lastErrorMessage;
97
98         FMU fmu;
99 };
100
101 vector<FMI1> fmus;
102
103 //map<string,FMUControlStruct> fmus;            // indexes for variable names in vars-table
104
105 int throwFMILException(JNIEnv *env, string message) {
106         jclass newExcCls;
107     newExcCls = env->FindClass("org/simantics/fmil/core/FMILException");
108     if (newExcCls == NULL) {
109             newExcCls = env->FindClass("java/lang/Exception");
110     }
111     if (newExcCls == NULL) {
112         /* Unable to find the exception class, give up. */
113         return 1;
114     }
115         env->ThrowNew(newExcCls, message.c_str());
116         return 1;
117 }
118
119 int throwException(JNIEnv *env, string message) {
120         return throwFMILException(env, message);
121 }
122
123 bool isEmpty(const char *c) {
124         if (c == NULL) {
125                 return true;
126         }
127         if (c[0] == '\0') {
128                 return true;
129         }
130         return false;
131 }
132
133 /*
134 bool exists(string id) {
135         map<string,FMUControlStruct>::iterator it = fmus.find(id);
136         if(it != fmus.end()) {
137                 return true;
138         } else {
139                 return false;
140         }
141 }
142 */
143
144
145
146 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_loadFMUFile_1 
147         (JNIEnv *env, jobject obj, jstring path, jstring tempDir) {
148
149         FMI1 fmi1;
150         FMIL_Variable *vars;
151         FMIL_DeclaredType *types;
152
153         int returnValue;
154
155         int variableCount = 0;
156         int typeCount = 0;
157
158         int fmuVersion = 0;
159         const char *error = "";
160
161     const char *fmuPath = env->GetStringUTFChars(path, 0);
162         const char *fmuTempDir = env->GetStringUTFChars(tempDir, 0);
163
164         fmi1.currentTime = 0;
165         fmi1.timeStep = 0.1;
166         returnValue = FMI_CS_LOAD(fmuPath, fmuTempDir, &fmi1.fmu, &fmuVersion, &error);
167
168         if (returnValue != 0) {
169                 string message = "Could not load FMU: ";
170                 return throwFMILException(env, message += error);
171         }
172         if(!fmi1.fmu) {
173                 string message = "No FMU loaded: ";
174                 return throwFMILException(env, message += error);
175         }
176
177         fmi1.version = fmuVersion;
178         if (fmi1.version == 1) {
179                 vars = FMI1_CS_GET_VARIABLES(fmi1.fmu, &variableCount, &error);
180         } else if (fmi1.version == 2) {
181                 vars = FMI2_CS_GET_VARIABLES(fmi1.fmu, &variableCount, &error);
182         }
183         if (!isEmpty(error)) {
184                 string message = "Could not get variables ";
185                 return throwFMILException(env, message += error);
186         }
187
188    for(int i=0;i<variableCount;i++) {
189            fmi1.variables.push_back(string(vars[i].name));
190            if(vars[i].description)
191                         fmi1.descriptions.push_back(string(vars[i].description));
192            else
193                         fmi1.descriptions.push_back(string(""));
194            if(vars[i].declaredType)
195                         fmi1.declaredTypes.push_back(string(vars[i].declaredType));
196            else
197                         fmi1.declaredTypes.push_back(string(""));
198            fmi1.types.push_back(vars[i].type);
199            fmi1.causalities.push_back(vars[i].causality);
200            fmi1.variabilities.push_back(vars[i].variability);
201            fmi1.valueReferences.push_back(vars[i].vr);
202    }
203
204    if (fmi1.version == 1) {
205            types = FMI1_CS_GET_DECLARED_TYPES(fmi1.fmu, &typeCount, &error);
206    } else if (fmi1.version == 2) {
207            types = FMI2_CS_GET_DECLARED_TYPES(fmi1.fmu, &typeCount, &error);
208    }
209    if (!isEmpty(error)) {
210                 string message = "Could not get declared types ";
211                 return throwFMILException(env, message += error);
212         }
213
214    for(int i=0;i<typeCount;i++) {
215            fmi1.declaredTypeNames.push_back(string(types[i].name));
216            if(types[i].description)
217                         fmi1.typeDescriptions.push_back(string(types[i].description));
218            else
219                         fmi1.typeDescriptions.push_back(string(""));
220            if(types[i].quantity)
221                         fmi1.quantities.push_back(string(types[i].quantity));
222            else
223                         fmi1.quantities.push_back(string(""));
224            if(types[i].unit)
225                         fmi1.units.push_back(string(types[i].unit));
226            else
227                         fmi1.units.push_back(string(""));
228    }
229
230
231    fmus.push_back(fmi1);
232
233         env->ReleaseStringUTFChars(path, fmuPath);
234         env->ReleaseStringUTFChars(tempDir, fmuTempDir);
235
236         return (jint)fmus.size() - 1;
237
238 }
239
240 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setStepLength_1 
241         (JNIEnv *env, jobject obj, jint id, jdouble stepLength) {
242         fmus[id].timeStep = stepLength;
243         return 0;
244 }
245
246 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_subscribe_1
247   (JNIEnv *env, jobject obj, jint id, jintArray vrs) {
248
249         jboolean isCopy;
250         jint* elements = env -> GetIntArrayElements(vrs, &isCopy);
251         jsize n = env -> GetArrayLength(vrs);
252
253         int i;
254         for (i = 0; i < n; i++) {
255                 fmus[id].subscription.push_back(elements[i]);
256         } 
257           
258         if (isCopy == JNI_TRUE) {
259                 env -> ReleaseIntArrayElements(vrs, elements, 0);
260         }
261
262         return 0;
263
264 }
265
266 bool referenceExists(FMUControlStruct fmuStruct, string variable) {
267         map<string,int>::iterator it = fmuStruct.indexes.find(variable);
268         if(it != fmuStruct.indexes.end()) {
269                 return true;
270         } else {
271                 return false;
272         }
273 }
274
275 // Remember to check if reference exists
276 fmiValueReference getReference(FMUControlStruct fmuStruct, string variable) {
277         return fmuStruct.fmiValueReferences[fmuStruct.indexes[variable]];
278 }
279
280 // Get string representation of a scalar variable type
281 string getTypeString(ScalarVariable* sv) {
282         switch (sv->typeSpec->type){
283                 case elm_Integer:
284                         return "Integer";
285                 case elm_Enumeration:
286                         return "Enumeration";
287                 case elm_Real:
288                         return "Real";
289                 case elm_Boolean:
290                         return "Boolean";
291                 default:
292                         return "No type";
293         }
294 }
295
296 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setRealValue_1
297   (JNIEnv *env, jobject obj, jint id, jint vr, jdouble value) {
298
299         const char *error = "";
300         FMI1 &fmi = fmus[id];
301         if (fmi.version == 1) {
302                 FMI1_CS_SET_REAL(fmi.fmu, vr, value, &error);
303         }
304         else if (fmi.version == 2) {
305                 FMI2_CS_SET_REAL(fmi.fmu, vr, value, &error);
306         }
307         if (!isEmpty(error)) {
308                 string message = "Could not set real value: ";
309                 return throwFMILException(env, message += error);
310     }
311         return 0;
312 }
313
314 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setIntegerValue_1
315   (JNIEnv *env, jobject obj, jint id, jint vr, jint value) {
316         
317         const char *error = "";
318         FMI1 fmi = fmus[id];
319         if (fmi.version == 1) {
320                 FMI1_CS_SET_INTEGER(fmi.fmu, vr, value, &error);
321         }
322         else if (fmi.version == 2) {
323                 FMI2_CS_SET_INTEGER(fmi.fmu, vr, value, &error);
324         }
325         if (!isEmpty(error)) {
326                 string message = "Could not set integer value: ";
327                 return throwFMILException(env, message += error);
328         }
329         return 0;
330 }
331
332 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setBooleanValue_1
333   (JNIEnv *env, jobject obj, jint id, jint vr, jboolean value) {
334
335         const char *error = "";
336         FMI1 fmi = fmus[id];
337         if (fmi.version == 1) {
338                 FMI1_CS_SET_BOOLEAN(fmi.fmu, vr, value != 0, &error);
339         }
340         else if (fmi.version == 2) {
341                 FMI2_CS_SET_BOOLEAN(fmi.fmu, vr, value != 0, &error);
342         }
343         if (!isEmpty(error)) {
344                 string message = "Could not set boolean value: ";
345                 return throwFMILException(env, message += error);
346         }
347         return 0;
348 }
349
350 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setStringValue_1
351 (JNIEnv *env, jobject obj, jint id, jint vr, jstring value) {
352
353         const char *error = "";
354         const char *valueChars = env->GetStringUTFChars(value, 0);
355         FMI1 fmi = fmus[id];
356         if (fmi.version == 1) {
357                 FMI1_CS_SET_INTEGER(fmi.fmu, vr, value != 0, &error);
358         }
359         else if (fmi.version == 2) {
360                 FMI2_CS_SET_INTEGER(fmi.fmu, vr, value != 0, &error);
361         }
362         env->ReleaseStringUTFChars(value, valueChars);
363         if (!isEmpty(error)) {
364                 string message = "Could not set string value: ";
365                 return throwFMILException(env, message += error);
366         }
367         return 0;
368 }
369
370 JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_core_FMIL_isInitialized_1
371   (JNIEnv *env, jobject obj, jstring id) {
372           /*
373         const char *fmuId = env->GetStringUTFChars(id, 0);
374         if(exists(fmuId)) {
375                 FMUControlStruct& fmuStruct = fmus[fmuId];
376                 env->ReleaseStringUTFChars(id, fmuId);
377                 return fmuStruct.initialized;
378         } else {
379                 env->ReleaseStringUTFChars(id, fmuId);
380                 return false;
381         }
382         */
383           return 1;
384 }
385
386
387 JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_core_FMIL_getTime_1
388   (JNIEnv *env, jobject obj, jint id) {
389           return fmus[id].currentTime;
390 }
391
392 double getRealValue(FMUControlStruct fmuStruct, int index) {
393         ScalarVariable *sv = fmuStruct.vars[index];
394         fmiValueReference vr = fmuStruct.fmiValueReferences[index];
395         double real;
396         fmiInteger integer;
397         fmiBoolean fmibool;
398
399         switch (sv->typeSpec->type){
400         case elm_Real:
401                         fmuStruct.fmu.getReal(fmuStruct.c, &vr, 1, &real);
402             break;
403         case elm_Integer:
404         case elm_Enumeration:
405             fmuStruct.fmu.getInteger(fmuStruct.c, &vr, 1, &integer);
406                         real = (double)integer;
407             break;
408         case elm_Boolean:
409             fmuStruct.fmu.getBoolean(fmuStruct.c, &vr, 1, &fmibool);
410                         if(fmibool == fmiTrue)
411                                 real = 1.0;
412                         else
413                                 real = 0.0;
414             break;
415         }
416         return real;
417 }
418
419 JNIEXPORT jdoubleArray JNICALL Java_org_simantics_fmil_core_FMIL_getSubscribedResults_1
420   (JNIEnv *env, jobject obj, jint id, jdoubleArray result) {
421
422         jboolean isCopy;
423         jdouble* resultElements = env -> GetDoubleArrayElements(result, &isCopy);
424         jsize n = env -> GetArrayLength(result);
425         int *vrs;
426         const char *error = "";
427
428         FMI1 fmi = fmus[id];
429         if(n > 0) {
430                 vrs = &(fmus[id].subscription[0]);
431                 if (fmi.version == 1) {
432                         FMI1_CS_GET_REALS(fmi.fmu, vrs, resultElements, n, &error);
433                 } else if (fmi.version == 2) {
434                         FMI2_CS_GET_REALS(fmi.fmu, vrs, resultElements, n, &error);
435                 }
436         }
437         if (isCopy == JNI_TRUE) {
438                 env -> ReleaseDoubleArrayElements(result, resultElements, 0);
439         }
440
441         return result;
442         
443 }
444
445 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_instantiateSimulation_1
446   (JNIEnv *env, jobject obj, jint id) {
447
448           int uniqueId = create_id();
449           std::string instanceName = std::to_string(uniqueId);
450           int returnValue;
451           const char *error = "";
452
453           FMI1 &fmi = fmus[id];
454           if (fmi.version == 1) {
455                   returnValue = FMI1_CS_INSTANTIATE(fmi.fmu, instanceName.c_str(), &error);
456           } else if (fmi.version == 2) {
457                   returnValue = FMI2_CS_INSTANTIATE(fmi.fmu, instanceName.c_str(), &error);
458           }
459           if(returnValue != 0) {
460                 string message = "No FMU loaded: ";
461                 return throwFMILException(env, message += error);
462           }
463           return 0;
464 }
465
466 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_initializeSimulation_1
467   (JNIEnv *env, jobject obj, jint id) {
468         
469         const char *error = "";
470         int returnValue;
471         FMI1 fmi = fmus[id];
472         if (fmi.version == 1) {
473                 returnValue = FMI1_CS_INITIALIZE(fmi.fmu, &error);
474         } else if (fmi.version == 2) {
475                 returnValue = FMI2_CS_INITIALIZE(fmi.fmu, &error);
476         }
477         if(returnValue != 0) {
478                 string message = "Could not initialize simulation: ";
479                 return throwFMILException(env, message += error);
480         }
481
482         return 0;
483
484 }
485
486 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_setTime_1
487   (JNIEnv *env, jobject obj, jstring id, jdouble time) {
488           return 0;
489 }
490
491 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariables_1
492   (JNIEnv *env, jobject obj, jint id) {
493
494         jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].variables.size(),  
495                         env->FindClass("java/lang/String"),  
496                         env->NewStringUTF(""));  
497    
498         for(unsigned int i=0;i<fmus[id].variables.size();i++) {  
499                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].variables[i].c_str()));  
500         }  
501
502         return ret;  
503
504 }
505
506 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableDescriptions_1
507   (JNIEnv *env, jobject obj, jint id) {
508
509         jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].descriptions.size(),
510                         env->FindClass("java/lang/String"),  
511                         env->NewStringUTF(""));  
512    
513         for(unsigned int i=0;i<fmus[id].descriptions.size();i++) {  
514                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].descriptions[i].c_str()));  
515         }  
516
517         return ret;  
518
519 }
520
521 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableDeclaredTypes_1
522   (JNIEnv *env, jobject obj, jint id) {
523
524         jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].declaredTypes.size(),
525                         env->FindClass("java/lang/String"),  
526                         env->NewStringUTF(""));
527    
528         for(unsigned int i=0;i<fmus[id].declaredTypes.size();i++) {  
529                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypes[i].c_str()));  
530         }  
531
532         return ret;  
533
534 }
535
536 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableReferences_1
537   (JNIEnv *env, jobject obj, jint id, jintArray result) {
538
539         jboolean isCopy;
540         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
541         jsize n = env -> GetArrayLength(result);
542
543         int i;
544         for (i = 0; i < n; i++) {
545                 resultElements[i] = fmus[id].valueReferences[i];
546         } 
547           
548         if (isCopy == JNI_TRUE) {
549                 env -> ReleaseIntArrayElements(result, resultElements, 0);
550         }
551
552         return result;
553
554 }
555
556 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableTypes_1
557   (JNIEnv *env, jobject obj, jint id, jintArray result) {
558
559         jboolean isCopy;
560         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
561         jsize n = env -> GetArrayLength(result);
562
563         int i;
564         for (i = 0; i < n; i++) {
565                 resultElements[i] = fmus[id].types[i];
566         } 
567           
568         if (isCopy == JNI_TRUE) {
569                 env -> ReleaseIntArrayElements(result, resultElements, 0);
570         }
571
572         return result;
573
574 }
575
576 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableVariabilities_1
577   (JNIEnv *env, jobject obj, jint id, jintArray result) {
578
579         jboolean isCopy;
580         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
581         jsize n = env -> GetArrayLength(result);
582
583         for (jsize i = 0; i < n; i++) {
584                 resultElements[i] = fmus[id].variabilities[i];
585         } 
586           
587         if (isCopy == JNI_TRUE) {
588                 env -> ReleaseIntArrayElements(result, resultElements, 0);
589         }
590
591         return result;
592
593 }
594
595 JNIEXPORT jintArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllVariableCausalities_1
596   (JNIEnv *env, jobject obj, jint id, jintArray result) {
597
598         jboolean isCopy;
599         jint* resultElements = env -> GetIntArrayElements(result, &isCopy);
600         jsize n = env -> GetArrayLength(result);
601
602         for (jsize i = 0; i < n; i++) {
603                 resultElements[i] = fmus[id].causalities[i];
604         } 
605           
606         if (isCopy == JNI_TRUE) {
607                 env -> ReleaseIntArrayElements(result, resultElements, 0);
608         }
609
610         return result;
611
612 }
613
614 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypes_1
615   (JNIEnv *env, jobject obj, jint id) {
616
617         jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].declaredTypeNames.size(),
618                         env->FindClass("java/lang/String"),  
619                         env->NewStringUTF(""));
620    
621         for(unsigned int i=0;i<fmus[id].declaredTypeNames.size();i++) {  
622                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].declaredTypeNames[i].c_str()));  
623         }  
624
625         return ret;  
626
627 }
628
629 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeDescriptions_1
630   (JNIEnv *env, jobject obj, jint id) {
631
632         jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].typeDescriptions.size(),
633                         env->FindClass("java/lang/String"),  
634                         env->NewStringUTF(""));
635    
636         for(unsigned int i=0;i<fmus[id].typeDescriptions.size();i++) {  
637                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].typeDescriptions[i].c_str()));  
638         }  
639
640         return ret;  
641
642 }
643
644 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeQuantities_1
645   (JNIEnv *env, jobject obj, jint id) {
646
647         jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].quantities.size(),
648                         env->FindClass("java/lang/String"),  
649                         env->NewStringUTF(""));
650    
651         for(unsigned int i=0;i<fmus[id].quantities.size();i++) {  
652                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].quantities[i].c_str()));  
653         }  
654
655         return ret;  
656
657 }
658
659 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_getAllDeclaredTypeUnits_1
660   (JNIEnv *env, jobject obj, jint id) {
661
662         jobjectArray ret= (jobjectArray)env->NewObjectArray((jsize)fmus[id].units.size(),
663                         env->FindClass("java/lang/String"),  
664                         env->NewStringUTF(""));
665    
666         for(unsigned int i=0;i<fmus[id].units.size();i++) {  
667                 env->SetObjectArrayElement(ret,i,env->NewStringUTF(fmus[id].units[i].c_str()));  
668         }  
669
670         return ret;  
671
672 }
673
674 /*
675 JNIEXPORT jobjectArray JNICALL Java_org_simantics_fmil_core_FMIL_filterVariables_1
676   (JNIEnv *env, jobject obj, jstring id, jstring regexp) {
677          const char *rx = env->GetStringUTFChars(regexp, 0);
678          jobjectArray result = filterVariables(env, obj, id, rx);
679          env->ReleaseStringUTFChars(regexp, rx);
680          return result;
681 }
682 */
683
684 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_simulateStep_1
685   (JNIEnv *env, jobject obj, jint id) {
686
687           int returnValue;
688           const char *error = "";
689
690           FMI1 &fmi = fmus[id];
691           if (fmi.version == 1) {
692                   returnValue = FMI1_CS_STEP(fmi.fmu, fmi.currentTime, fmi.timeStep, &error);
693           } else if (fmi.version == 2) {
694                   returnValue = FMI2_CS_STEP(fmi.fmu, fmi.currentTime, fmi.timeStep, &error);
695           }
696           if(returnValue != 0) {
697                   string message = "Could not simulate step: ";
698                   return throwException(env,  message += error);
699           }
700
701           fmi.currentTime += fmi.timeStep;
702
703           return 0;
704
705           /*
706         const char *fmuId = env->GetStringUTFChars(id, 0);
707         if(exists(fmuId)) {
708                 FMUControlStruct& fmuStruct = fmus[fmuId];
709                 env->ReleaseStringUTFChars(id, fmuId);
710
711                 if(&fmuStruct.fmu == NULL || fmuStruct.fmu.modelDescription == NULL || &fmuStruct.vars == NULL) {
712                         return throwException(env, "Simulate step failed - fmu not loaded");
713                 }
714
715                 if(fmuStruct.x == NULL) {
716                         return throwException(env, "Simulate step failed - fmu not instantiated");
717                 }
718
719                 if(fmuStruct.initialized == false) {
720                         fmiBoolean toleranceControlled = fmiFalse;
721                         fmuStruct.fmiFlag =  fmuStruct.fmu.initialize(fmuStruct.c, toleranceControlled, fmuStruct.currentTime, &(fmuStruct.eventInfo));
722                         if (fmuStruct.fmiFlag > fmiWarning)  return throwException(env, "could not initialize model");
723                         fmuStruct.initialized = true;
724                 }
725
726                 FMU& fmu = fmuStruct.fmu;
727                 int debug = 0; // DEBUG ON = 1, OFF = 0
728
729                 int i;
730                 double dt, tPre, tEnd = fmuStruct.currentTime + fmuStruct.step;
731
732                 fmiBoolean timeEvent, stateEvent, stepEvent;
733                 fmiStatus fmiFlag;                      // return code of the fmu functions
734                 fmiValueReference vr;
735
736
737                 */
738                 /* Simulate the duration of one step. The simulation may be done in 
739                  * multiple parts if events occur
740                  */ /*
741                 while (fmuStruct.currentTime < tEnd) {
742                         // get current state and derivatives
743                         fmiFlag = fmu.getContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);
744                         if (fmiFlag > fmiWarning) 
745                                 return throwException(env, "could not retrieve states");
746
747                         fmiFlag = fmu.getDerivatives(fmuStruct.c, fmuStruct.xdot, fmuStruct.nx);
748                         if (fmiFlag > fmiWarning) 
749                                 return throwException(env, "could not retrieve derivatives");
750
751                          // advance time
752                         tPre = fmuStruct.currentTime;
753                         fmuStruct.currentTime = min(fmuStruct.currentTime+fmuStruct.step, tEnd);
754                         timeEvent = fmuStruct.eventInfo.upcomingTimeEvent && fmuStruct.eventInfo.nextEventTime < fmuStruct.currentTime;  
755                 
756                         if (timeEvent) fmuStruct.currentTime = fmuStruct.eventInfo.nextEventTime;
757                         dt = fmuStruct.currentTime - tPre; 
758                         fmiFlag = fmu.setTime(fmuStruct.c, fmuStruct.currentTime);
759                         if (fmiFlag > fmiWarning) throwException(env, "could not set time");
760
761                         if(referenceExists(fmuStruct, "time")) {
762                                 vr = getReference(fmuStruct, "time");
763                                 if(vr != NULL) {
764                                         fmu.setReal(fmuStruct.c, &vr, 1, &(fmuStruct.currentTime));
765                                 }
766                         }
767
768                         if(debug)
769                                 printf("Actual time: %lf\n", fmuStruct.currentTime);
770
771                         if (fmiFlag > fmiWarning) 
772                                 return throwException(env, "could not set time");
773
774                         // perform one step
775                         for (i=0; i<fmuStruct.nx; i++) 
776                                 fmuStruct.x[i] += dt*fmuStruct.xdot[i]; // forward Euler method
777
778                         fmiFlag = fmu.setContinuousStates(fmuStruct.c, fmuStruct.x, fmuStruct.nx);
779                         if (fmiFlag > fmiWarning) 
780                                 return throwException(env, "could not set states");
781
782                         // Check for step event, e.g. dynamic state selection
783                         fmiFlag = fmu.completedIntegratorStep(fmuStruct.c, &stepEvent);
784                         if (fmiFlag > fmiWarning) return throwException(env, "could not complete intgrator step");
785                         */
786 /*                      for (i=0; i<fmuStruct.nz; i++) fmuStruct.prez[i] = fmuStruct.z[i]; 
787                         fmiFlag = fmu.getEventIndicators(fmuStruct.c, fmuStruct.z, fmuStruct.nz);
788                         if (fmiFlag > fmiWarning) return throwException(env, "could not retrieve event indicators");
789                         stateEvent = FALSE;
790                         for (i=0; i<fmuStruct.nz; i++) 
791                                 stateEvent = stateEvent || (fmuStruct.prez[i] * fmuStruct.z[i] < 0);  
792      
793
794                         stepEvent = fmiTrue;
795                         // handle events
796                         if (timeEvent || stateEvent || stepEvent) {
797         
798                                 // event iteration in one step, ignoring intermediate results
799                                 fmiFlag = fmu.eventUpdate(fmuStruct.c, fmiFalse, &(fmuStruct.eventInfo));
800                                 if (fmiFlag > fmiWarning) return throwException(env, "could not perform event update");
801       
802                         } // if event
803                         */
804         
805 /*              }
806
807                 fflush(stdout);
808                 return 1;
809
810         } else {
811                 string message = fmuId;
812                 env->ReleaseStringUTFChars(id, fmuId);
813                 return throwException(env, "simulateStep: Model id " + message + " not found");
814         }*/
815         return 1;
816 }
817
818 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_unloadFMU_1
819   (JNIEnv *env, jobject obj, jint id) {
820
821           int returnValue;
822           const char *error = "";
823
824           FMI1 fmi = fmus[id];
825           if (fmi.version == 1) {
826                   returnValue = FMI1_CS_UNLOAD(fmi.fmu, &error);
827           } else if (fmi.version == 2) {
828                   returnValue = FMI2_CS_UNLOAD(fmi.fmu, &error);
829           }
830           if(returnValue != 0) {
831                 string message = "Could not unload FMU: ";
832                 return throwException(env, message += error);
833           }
834           return returnValue;
835 }
836
837 JNIEXPORT jdouble JNICALL Java_org_simantics_fmil_core_FMIL_getRealValue_1
838   (JNIEnv *env, jobject obj, jint id, jint vr) {
839
840           double value;
841           const char *error = "";
842
843           FMI1 fmi = fmus[id];
844           if (fmi.version == 1) {
845                   value = FMI1_CS_GET_REAL(fmi.fmu, vr, &error);
846           } else if (fmi.version == 2) {
847                   value = FMI2_CS_GET_REAL(fmi.fmu, vr, &error);
848           }
849           if (!isEmpty(error)) {
850                   string message = "Could not get real value: ";
851                   throwFMILException(env, message += error);
852                   return 0.0;
853           }
854           return value;
855 }
856
857 JNIEXPORT jint JNICALL Java_org_simantics_fmil_core_FMIL_getIntegerValue_1
858   (JNIEnv *env, jobject obj, jint id, jint vr) {
859
860         int value;
861         const char *error = "";
862
863         FMI1 fmi = fmus[id];
864         if (fmi.version == 1) {
865                 value = FMI1_CS_GET_INTEGER(fmi.fmu, vr, &error);
866         }
867         else if (fmi.version == 2) {
868                 value = FMI2_CS_GET_INTEGER(fmi.fmu, vr, &error);
869         }
870         if (!isEmpty(error)) {
871                 string message = "Could not get integer value: ";
872                 throwFMILException(env, message += error);
873                 return 0;
874         }
875         return value;
876 }
877
878 JNIEXPORT jboolean JNICALL Java_org_simantics_fmil_core_FMIL_getBooleanValue_1
879   (JNIEnv *env, jobject obj, jint id, jint vr) {
880
881         int value;
882         const char *error = "";
883
884         FMI1 fmi = fmus[id];
885         if (fmi.version == 1) {
886                 value = FMI1_CS_GET_BOOLEAN(fmi.fmu, vr, &error);
887         }
888         else if (fmi.version == 2) {
889                 value = FMI2_CS_GET_BOOLEAN(fmi.fmu, vr, &error);
890         }
891         if (!isEmpty(error)) {
892                 string message = "Could not get boolean value: ";
893                 throwFMILException(env, message += error);
894                 return 0;
895         }
896
897         return value != 0;
898 }
899
900 JNIEXPORT jstring JNICALL Java_org_simantics_fmil_core_FMIL_getStringValue_1
901   (JNIEnv *env, jobject obj, jint id, jint vr) {
902
903         const char *value;
904         const char *error = "";
905
906         FMI1 fmi = fmus[id];
907         if (fmi.version == 1) {
908                 value = FMI1_CS_GET_STRING(fmi.fmu, vr, &error);
909         }
910         else if (fmi.version == 2) {
911                 value = FMI2_CS_GET_STRING(fmi.fmu, vr, &error);
912         }
913         if (!isEmpty(error)) {
914                 string message = "Could not get string value: ";
915                 throwFMILException(env, message += error);
916                 return nullptr;
917         }
918
919         return env->NewStringUTF(value);
920 }