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