--- /dev/null
+/*******************************************************************************\r
+ * Copyright (c) 2007, 2012, 2015 Association for Decentralized Information Management in\r
+ * Industry THTH ry.\r
+ * All rights reserved. This program and the accompanying materials\r
+ * are made available under the terms of the Eclipse Public License v1.0\r
+ * which accompanies this distribution, and is available at\r
+ * http://www.eclipse.org/legal/epl-v10.html\r
+ *\r
+ * Contributors:\r
+ * VTT Technical Research Centre of Finland - initial API and implementation\r
+ *******************************************************************************/\r
+package org.simantics.sysdyn.omsolver;\r
+\r
+import gnu.trove.list.array.TDoubleArrayList;\r
+\r
+import java.io.File;\r
+import java.io.FileInputStream;\r
+import java.io.FileNotFoundException;\r
+import java.io.FileOutputStream;\r
+import java.io.IOException;\r
+import java.lang.reflect.Field;\r
+import java.util.HashMap;\r
+\r
+import org.eclipse.core.runtime.IProgressMonitor;\r
+import org.eclipse.core.runtime.NullProgressMonitor;\r
+import org.simantics.Simantics;\r
+import org.simantics.databoard.Bindings;\r
+import org.simantics.db.ReadGraph;\r
+import org.simantics.db.Resource;\r
+import org.simantics.db.Session;\r
+import org.simantics.db.WriteGraph;\r
+import org.simantics.db.common.request.WriteRequest;\r
+import org.simantics.db.common.utils.Logger;\r
+import org.simantics.db.exception.DatabaseException;\r
+import org.simantics.db.layer0.util.Layer0Utils;\r
+import org.simantics.db.layer0.variable.Variable;\r
+import org.simantics.db.layer0.variable.Variables;\r
+import org.simantics.db.request.Read;\r
+import org.simantics.fmu.FMUControlJNI;\r
+import org.simantics.fmu.FMUJNIException;\r
+import org.simantics.modelica.IModelicaMonitor;\r
+import org.simantics.modelica.ModelicaManager;\r
+import org.simantics.modelica.SimulationLocation;\r
+import org.simantics.modeling.PartialIC;\r
+import org.simantics.sysdyn.SysdynResource;\r
+import org.simantics.sysdyn.manager.SysdynGameExperimentBase;\r
+import org.simantics.sysdyn.simulation.SimulationJob.HeadlessModelicaMonitor;\r
+import org.simantics.sysdyn.solver.ISolver;\r
+\r
+/**\r
+ * Game experiment\r
+ * @author Teemu Lempinen\r
+ *\r
+ */\r
+public class GameExperiment extends SysdynGameExperimentBase {\r
+\r
+ private ModelicaSolver solver;\r
+ public FMUControlJNI control;\r
+ private boolean loaded = false;\r
+ \r
+ private static boolean fortranLibrariesLoaded = false;\r
+ \r
+ public GameExperiment(Resource experiment, Resource model) {\r
+ super(experiment, model);\r
+ this.solver = new ModelicaSolver(this);\r
+ }\r
+ \r
+ public FMUControlJNI getFMUControl() {\r
+ return control;\r
+ }\r
+ \r
+ @Override\r
+ public void init(ReadGraph g) {\r
+ super.init(g);\r
+\r
+ if(control == null)\r
+ control = new FMUControlJNI();\r
+ \r
+ results = new TDoubleArrayList[results != null ? results.length : 0];\r
+ \r
+ }\r
+ \r
+ @Override\r
+ protected void onExperimentDisposed() {\r
+ super.onExperimentDisposed();\r
+ if(control!=null) {\r
+ try {\r
+ control.unloadFMU();\r
+ loaded = false;\r
+ } catch (FMUJNIException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ }\r
+\r
+ private boolean isValidFMU(File file) {\r
+ if(!file.exists()) return false;\r
+ if(!file.isFile()) return false;\r
+ if(file.length() == 0) return false;\r
+ return true;\r
+ }\r
+ \r
+\r
+ @Override\r
+ public synchronized void simulate(final IModelicaMonitor monitor, final IProgressMonitor progressMonitor, String modelName) throws IOException {\r
+ canceled = false;\r
+\r
+ progressMonitor.subTask("Write modelica classes");\r
+\r
+ // Write Modelica files \r
+ String modelText = getModelicaCode(monitor, true, getOpenModelicaVersion());\r
+ if(modelText == null)\r
+ return;\r
+ \r
+ omcVersion = ModelicaManager.getDefaultOMVersion();\r
+ \r
+ monitor.message("Simulate " + modelName + " using OpenModelica " + omcVersion);\r
+ \r
+ progressMonitor.worked(1);\r
+\r
+ // Write initial files and add init-parameters\r
+ progressMonitor.subTask("Write simulation files");\r
+ HashMap<String, String> inits = getExperimentParameters(monitor);\r
+\r
+\r
+ // add loadFile script to load all related functions and function libraries \r
+ String additionalScript = getAdditionalScripts();\r
+\r
+ // Create simulation files\r
+ SimulationLocation simulationLocation = createSimulationFiles(sysdynModel, modelText, inits, additionalScript, true);\r
+ progressMonitor.worked(1);\r
+\r
+ // Load precompiled fmu if structure has not changed and it has not yet been loaded\r
+ File fmu = null;\r
+ if(!sysdynModel.isStructureModified()) {\r
+ if(!simulationLocation.executableFile.isFile()) {\r
+ fmu = loadModelFmu(simulationLocation);\r
+ } else {\r
+ fmu = simulationLocation.executableFile;\r
+ }\r
+ }\r
+ // Build the model and store previous model structure and inits that affect the building\r
+ // If there is no exe file OR the model structure has not changed, no need to build\r
+ if (fmu == null && (!isValidFMU(simulationLocation.executableFile) || sysdynModel.isStructureModified())) {\r
+ progressMonitor.subTask("Build model");\r
+ buildModel(simulationLocation, monitor);\r
+ \r
+ saveModelFmu(simulationLocation);\r
+ }\r
+\r
+ progressMonitor.worked(1);\r
+\r
+ if(simulationLocation != null && !canceled) {\r
+ // Load fmu and initialize it for simulation\r
+ try {\r
+ if (!fortranLibrariesLoaded) { // Enable this when we update from OpenModelica 1.9.0beta4!\r
+ File omDir = ModelicaManager.getOMHome();\r
+ File mingw = new File(omDir, "MinGW");\r
+ File mbin = new File(mingw, "bin");\r
+ \r
+ // Add MinGW path to java.library.path. This is a bit of a hack because \r
+ // java.library.path isn't intended to be set programmatically.\r
+ String newLibPath = System.getProperty("java.library.path") + File.pathSeparator + mbin.getAbsolutePath();\r
+ System.setProperty("java.library.path", newLibPath);\r
+ Field fieldSysPath = ClassLoader.class.getDeclaredField("sys_paths");\r
+ fieldSysPath.setAccessible(true);\r
+ if (fieldSysPath != null) {\r
+ fieldSysPath.set(System.class.getClassLoader(), null);\r
+ }\r
+ \r
+ System.loadLibrary("libgfortran-3");\r
+ System.out.println("Loaded libgfortran-3.dll");\r
+ System.loadLibrary("pthreadGC2");\r
+ System.out.println("Loaded pthreadGC2.dll");\r
+ fortranLibrariesLoaded = true;\r
+ }\r
+ \r
+ control.loadFMUFile(simulationLocation.executableFile.getAbsolutePath()); // unzip and load fmu\r
+ loaded = true;\r
+ instantiate();\r
+ \r
+ } catch (FMUJNIException e) {\r
+ System.err.println("SysdynGameExperiment initialization failed:\n\t" + e.getMessage());\r
+ } catch (SecurityException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (NoSuchFieldException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (IllegalArgumentException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ } catch (IllegalAccessException e) {\r
+ // TODO Auto-generated catch block\r
+ e.printStackTrace();\r
+ }\r
+\r
+ }\r
+ process = null;\r
+ simulate(false); \r
+ }\r
+\r
+ /**\r
+ * Load fmu file from database, if it exists for the model of this experiment\r
+ * \r
+ * @param simulationLocation SimulationLocation indicating where the fmu should be loaded\r
+ * @return Loaded fmu or null if it was not loaded from database\r
+ */\r
+ private File loadModelFmu(SimulationLocation simulationLocation) {\r
+ File fmu = null;\r
+ try {\r
+ final String fmuLocation = simulationLocation.executableFile.getAbsolutePath();\r
+ fmu = session.syncRequest(new Read<File>() {\r
+ @Override\r
+ public File perform(ReadGraph graph) throws DatabaseException {\r
+ File result = null;\r
+ FileOutputStream fos;\r
+ try {\r
+ fos = new FileOutputStream(fmuLocation);\r
+ byte[] fileBArray = graph.getPossibleRelatedValue(\r
+ getModel(), SysdynResource.getInstance(graph).SysdynModel_fmuFile, Bindings.BYTE_ARRAY);\r
+ \r
+ if(fileBArray != null) {\r
+ fos.write(fileBArray);\r
+ fos.close();\r
+ result = new File(fmuLocation);\r
+ } else {\r
+ fos.close();\r
+ return null;\r
+ }\r
+ \r
+ } catch (FileNotFoundException e) {\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ return result;\r
+ }\r
+ });\r
+ } catch (DatabaseException e) {\r
+ e.printStackTrace();\r
+ }\r
+ \r
+ return fmu;\r
+ }\r
+ \r
+ /**\r
+ * Save fmu file from simulationLocation to database\r
+ * @param simulationLocation Location for finding fmu\r
+ */\r
+ private void saveModelFmu(SimulationLocation simulationLocation) {\r
+ final String fmuLocation = simulationLocation.executableFile.getAbsolutePath();\r
+ session.asyncRequest(new WriteRequest() {\r
+\r
+ @Override\r
+ public void perform(WriteGraph graph) throws DatabaseException {\r
+ File file = new File(fmuLocation);\r
+ byte[] fileBArray = new byte[(int)file.length()];\r
+ FileInputStream fis;\r
+ try {\r
+ fis = new FileInputStream(file);\r
+\r
+ fis.read(fileBArray);\r
+ graph.claimLiteral(\r
+ getModel(), \r
+ SysdynResource.getInstance(graph).SysdynModel_fmuFile, \r
+ fileBArray, Bindings.BYTE_ARRAY);\r
+ fis.close();\r
+ } catch (FileNotFoundException e) {\r
+ e.printStackTrace();\r
+ } catch (IOException e) {\r
+ e.printStackTrace();\r
+ }\r
+ }\r
+ });\r
+ }\r
+\r
+\r
+ @Override\r
+ public void rewindTo(double time) {\r
+ \r
+ if(control == null)\r
+ return;\r
+ \r
+ if(time >-0.001 && time < 0.001) {\r
+ try {\r
+ simulate(new HeadlessModelicaMonitor(), new NullProgressMonitor(), sysdynModel.getConfiguration().getLabel());\r
+ //instantiate();\r
+ } catch (IOException e) {\r
+ Logger.defaultLogError(e);\r
+ }\r
+ } else {\r
+ System.out.println("rewindTo");\r
+ }\r
+ }\r
+ \r
+ @Override\r
+ public void refresh(Session session) {\r
+ try {\r
+ control.initializeSimulation();\r
+ clearResults();\r
+ //getInitialResultValues();\r
+ \r
+ } catch (FMUJNIException e) {\r
+ System.err.println("SysdynGameExperiment instantiate failed: " + e.getMessage());\r
+ }\r
+ }\r
+ \r
+ private synchronized void instantiate() {\r
+ try {\r
+ HashMap<String, String> inits = getExperimentParameters(null);\r
+\r
+ control.setStepLength(stepLength); // FIXME: fixed step lenghth\r
+ control.setTime(startTime);\r
+ control.instantiateSimulation(); // instantiate simulation\r
+\r
+ if(!control.isInitialized()) {\r
+ control.initializeSimulation();\r
+ }\r
+\r
+ if(inits.get("variableFilter") == null || inits.get("variableFilter").equals(".*"))\r
+ subscription = control.getAllVariables();\r
+ else\r
+ subscription = control.filterVariables(inits.get("variableFilter"));\r
+ \r
+ // Initialize subscription indexes map for fast result reading in getValue()\r
+ if(subscriptionIndexes == null)\r
+ subscriptionIndexes = new HashMap<String, Integer>();\r
+ \r
+ subscriptionIndexes.clear();\r
+ for(int i = 0; i < subscription.length; i++) {\r
+ subscriptionIndexes.put(subscription[i], i);\r
+ }\r
+ \r
+ results = new TDoubleArrayList[subscription.length];\r
+\r
+ // Initialize container for current simulation results\r
+ currentValues = new double[subscription.length];\r
+ \r
+ // subscribe all variables\r
+ control.subscribe(subscription); \r
+\r
+ clearResults();\r
+ //getInitialResultValues();\r
+ \r
+ Simantics.getSession().syncRequest(new WriteRequest() {\r
+\r
+ @Override\r
+ public void perform(WriteGraph graph) throws DatabaseException {\r
+\r
+ Resource run = Layer0Utils.getPossibleChild(graph, GameExperiment.this.experiment, getIdentifier());\r
+ if(run == null) {\r
+ System.err.println("No run");\r
+ return;\r
+ }\r
+ \r
+ Variable base = Variables.getVariable(graph, run);\r
+ \r
+ SysdynResource SYSDYN = SysdynResource.getInstance(graph);\r
+ \r
+ Resource ic = graph.getPossibleObject(GameExperiment.this.experiment, SYSDYN.Experiment_ic);\r
+ if(ic == null) return;\r
+ \r
+ PartialIC data = graph.getPossibleRelatedValue(ic, SYSDYN.InitialCondition_HasInitialValues, PartialIC.BINDING);\r
+ data.apply(graph, base);\r
+ \r
+ }\r
+ \r
+ });\r
+ \r
+ } catch (FMUJNIException e) {\r
+ System.err.println("SysdynGameExperiment instantiate failed: " + e.getMessage());\r
+ } catch (DatabaseException e) {\r
+ System.err.println("SysdynGameExperiment instantiate failed: " + e.getMessage());\r
+ }\r
+ }\r
+\r
+// private synchronized void getInitialResultValues() {\r
+// try {\r
+// // Initialize results\r
+// results.clear();\r
+//\r
+// currentValues = control.getSubscribedResults(currentValues);\r
+// for(int k = 0; k < subscription.length; k++) {\r
+// results.put(subscription[k], new ArrayList<Double>());\r
+// results.get(subscription[k]).add(currentValues[k]);\r
+// }\r
+//\r
+// ((MemoryResult)getCurrentResult()).setResult(new GameResult(this.results, this.subscription));\r
+// resultsChanged(); \r
+// } catch (FMUJNIException e) {\r
+// System.err.println("SysdynGameExperiment getInitialResultValues failed: " + e.getMessage());\r
+// }\r
+// }\r
+ \r
+ @Override\r
+ public void updateSubscriptions() {\r
+ \r
+ if(!loaded) return;\r
+ \r
+ try {\r
+ if(control.isInitialized())\r
+ currentValues = control.getSubscribedResults(currentValues);\r
+ } catch (FMUJNIException e) {\r
+ e.printStackTrace();\r
+ }\r
+ super.updateSubscriptions();\r
+ }\r
+\r
+ @Override\r
+ public ISolver getSolver() {\r
+ return solver;\r
+ }\r
+ \r
+ }\r