From 549a11b3f0ee83bc60e6ca254bf2c979498e0941 Mon Sep 17 00:00:00 2001 From: lempinen Date: Thu, 10 May 2012 13:01:58 +0000 Subject: [PATCH] Improved FMU control temp file handling (refs #3398) git-svn-id: https://www.simantics.org/svn/simantics/sysdyn/trunk@24914 ac1ea38d-2e2b-0410-8846-a27921b304fc --- org.simantics.modelica/META-INF/MANIFEST.MF | 3 +- .../simantics/modelica/fmi/FMUControlJNI.java | 261 +++++++++-- .../fmi/CallFMUBeforeInitializationTests.java | 2 - .../sysdyn/ui/project/SysdynProject.java | 418 ++++++++++-------- .../sysdyn/adapter/HistoryVariable.java | 4 +- .../sysdyn/manager/SysdynExperiment.java | 29 +- .../sysdyn/manager/SysdynGameExperiment.java | 19 +- .../sysdyn/modelica/ModelicaWriter.java | 4 +- .../representation/utils/FormatUtils.java | 16 +- .../utils/RepresentationUtils.java | 21 +- 10 files changed, 513 insertions(+), 264 deletions(-) diff --git a/org.simantics.modelica/META-INF/MANIFEST.MF b/org.simantics.modelica/META-INF/MANIFEST.MF index ab9e04e4..e9bb53c4 100644 --- a/org.simantics.modelica/META-INF/MANIFEST.MF +++ b/org.simantics.modelica/META-INF/MANIFEST.MF @@ -8,7 +8,8 @@ Require-Bundle: gnu.trove2;bundle-version="2.0.4", org.eclipse.osgi;bundle-version="3.6.0", org.eclipse.core.runtime;bundle-version="3.6.0", org.simantics.history;bundle-version="1.0.0", - org.simantics.databoard;bundle-version="0.6.3" + org.simantics.databoard;bundle-version="0.6.3", + org.simantics.utils;bundle-version="1.1.0" Export-Package: org.simantics.modelica, org.simantics.modelica.data, org.simantics.modelica.fmi diff --git a/org.simantics.modelica/src/org/simantics/modelica/fmi/FMUControlJNI.java b/org.simantics.modelica/src/org/simantics/modelica/fmi/FMUControlJNI.java index 685dd59c..04a3352d 100644 --- a/org.simantics.modelica/src/org/simantics/modelica/fmi/FMUControlJNI.java +++ b/org.simantics.modelica/src/org/simantics/modelica/fmi/FMUControlJNI.java @@ -12,12 +12,19 @@ package org.simantics.modelica.fmi; import java.io.File; +import java.io.IOException; +import java.io.RandomAccessFile; +import java.nio.channels.FileChannel; +import java.nio.channels.FileLock; +import java.util.UUID; import org.eclipse.core.runtime.FileLocator; import org.eclipse.core.runtime.Platform; import org.osgi.framework.Bundle; import org.simantics.modelica.ModelicaManager; import org.simantics.modelica.ModelicaManager.OSType; +import org.simantics.utils.FileUtils; + /** * @@ -25,12 +32,17 @@ import org.simantics.modelica.ModelicaManager.OSType; * */ public class FMUControlJNI { - - public static FMUControlJNI INSTANCE = new FMUControlJNI(); + /** + * Static variables + */ private static int ERROR = 0; private static int OK = 1; - private static String UNSATISFIED_LINK = "Method not found. DLL might not be loaded properly."; + private static String UNSATISFIED_LINK = "Method not found. DLL might not be loaded properly."; + private static String TEMP_DIRECTORY; + private static String TEMP_FMU_DIRECTORY_NAME = "fmu"; + public static String TEMP_FMU_COMMON_DIRECTORY; + public static String LOCK_FILE_NAME = "fmu.lock"; /** * Static: load native libraries required for the FMU simulation to work. @@ -67,6 +79,60 @@ public class FMUControlJNI { } } + /** + * Static: initialize fmu temp folder + */ + static { + try { + // Create a temp directory marker. This shows the system temp directory. + File temp = File.createTempFile("tempMarker", null); + TEMP_DIRECTORY = temp.getParentFile().getAbsolutePath(); + // Delete the marker + temp.delete(); + + // Get common "fmu" directory in temp directory + File tempCommonDir = new File(TEMP_DIRECTORY, TEMP_FMU_DIRECTORY_NAME); + // If fmu is not a directory, create it + if(!tempCommonDir.isDirectory()) { + tempCommonDir.mkdir(); + } + TEMP_FMU_COMMON_DIRECTORY = tempCommonDir.getAbsolutePath(); + } catch (IOException e) { + e.printStackTrace(); + } + } + + + private File fmuDir; + + public String TEMP_FOLDER_1; + public String TEMP_FOLDER_2; + public String TEMP_FMU_DIRECTORY; + private String dirName; + + public FMUControlJNI() { + // Create a directory for this control + File tempDir = new File(TEMP_FMU_COMMON_DIRECTORY, UUID.randomUUID().toString()); + tempDir.mkdir(); + TEMP_FMU_DIRECTORY = tempDir.getAbsolutePath(); + + // Create two directories inside the temp directory for this control + dirName = UUID.randomUUID().toString(); + fmuDir = new File(TEMP_FMU_DIRECTORY, dirName); + fmuDir.mkdir(); + + TEMP_FOLDER_1 = fmuDir.toString(); + TEMP_FOLDER_2 = fmuDir.toString() + "_2"; + + // Lock fmu directory in temp directory + lockFMUDirectory(); + } + + public String getModelID() { + return dirName; + } + + /** * Load fmu from a given file path. Releases the (possible) previously * loaded fmu. @@ -74,19 +140,49 @@ public class FMUControlJNI { * @param path absolute file path for fmu file * @throws FMUJNIException */ + private int fmuN = 0; + private boolean fmuLoaded = false; public void loadFMUFile(String path) throws FMUJNIException { - try { - int ret = loadFMUFile_(path); + String fmuDirName; + if(fmuN % 2 == 0) { + fmuDirName = TEMP_FOLDER_1; + fmuN++; + } else { + fmuDirName = TEMP_FOLDER_2; + fmuN = 0; + } + + File tempDir = new File(fmuDirName); + if(tempDir.isDirectory()) { + try { + FileUtils.deleteAll(tempDir); + } catch (IOException e) { + throw new FMUJNIException("Could not create temp folder for fmu"); + } + tempDir.mkdir(); + } else { + tempDir.mkdir(); + } + + + try { + String tmpPath = tempDir.getAbsolutePath(); + if(!tmpPath.endsWith("\\")) + tmpPath = tmpPath + "\\"; + int ret = loadFMUFile_(getModelID(), path, tmpPath); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); - + + fmuLoaded = true; } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int loadFMUFile_(String path); + private native int loadFMUFile_(String id, String path, String toDir); /** * Set a step length for simulation @@ -97,16 +193,18 @@ public class FMUControlJNI { public void setStepLength(double step) throws FMUJNIException { try { - int ret = setStepLength_(step); + int ret = setStepLength_(getModelID(), step); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int setStepLength_(double step); + private native int setStepLength_(String id, double step); /** * Initializes a simulation. @@ -117,16 +215,18 @@ public class FMUControlJNI { public void initializeSimulation() throws FMUJNIException { try { - int ret = initializeSimulation_(); + int ret = initializeSimulation_(getModelID()); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int initializeSimulation_(); + private native int initializeSimulation_(String id); /** * Subscribe a set of variables from a loaded simulation. @@ -138,16 +238,18 @@ public class FMUControlJNI { public void subscribe(String[] variables) throws FMUJNIException { try { - int ret = subscribe_(variables, variables.length); + int ret = subscribe_(getModelID(), variables, variables.length); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int subscribe_(String[] variables, int size); + private native int subscribe_(String id, String[] variables, int size); /** @@ -161,16 +263,18 @@ public class FMUControlJNI { public void setRealValue(String name, double value) throws FMUJNIException { try { - int ret = setRealValue_(name, value); + int ret = setRealValue_(getModelID(), name, value); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int setRealValue_(String name, double value); + private native int setRealValue_(String id, String name, double value); /** * Set a new (integer) value for a variable. If the variable is a @@ -183,15 +287,17 @@ public class FMUControlJNI { public void setIntegerValue(String name, int value) throws FMUJNIException { try { - int ret = setIntegerValue_(name, value); + int ret = setIntegerValue_(getModelID(), name, value); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int setIntegerValue_(String name, int value); + private native int setIntegerValue_(String id, String name, int value); /** * Set a new (boolean) value for a variable. If the variable is a @@ -204,15 +310,17 @@ public class FMUControlJNI { public void setBooleanValue(String name, boolean value) throws FMUJNIException { try { - int ret = setBooleanValue_(name, value); + int ret = setBooleanValue_(getModelID(), name, value); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int setBooleanValue_(String name, boolean value); + private native int setBooleanValue_(String id, String name, boolean value); /** @@ -224,15 +332,17 @@ public class FMUControlJNI { public void simulateStep() throws FMUJNIException { try { - int ret = simulateStep_(); + int ret = simulateStep_(getModelID()); if(ret == ERROR) throw new FMUJNIException(getLastErrorMessage()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int simulateStep_(); + private native int simulateStep_(String id); /** * Get an array containing the current values for subscribed variables. The @@ -244,14 +354,16 @@ public class FMUControlJNI { public double[] getSubscribedResults(double[] results) throws FMUJNIException { try { - return getSubscribedResults_(results); + return getSubscribedResults_(getModelID(), results); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - - private native double[] getSubscribedResults_(double[] results); + + private native double[] getSubscribedResults_(String id, double[] results); /** * Unload FMU and the dll:s that it requires. @@ -265,15 +377,21 @@ public class FMUControlJNI { public void unloadFMU() throws FMUJNIException { try { - int ret = unloadFMU_(); - if(ret == ERROR) - throw new FMUJNIException(getLastErrorMessage()); + unlockFMUDirectory(); + if(fmuLoaded) { + int ret = unloadFMU_(getModelID()); + if(ret == ERROR) + throw new FMUJNIException(getLastErrorMessage()); + } + removeFMUDirectoryContents(); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - private native int unloadFMU_(); + private native int unloadFMU_(String id); /** * Get the current simulation time @@ -282,14 +400,16 @@ public class FMUControlJNI { public double getTime() throws FMUJNIException { try { - return getTime_(); + return getTime_(getModelID()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - - private native double getTime_(); + + private native double getTime_(String id); /** * Get all variables in a loaded model @@ -298,14 +418,16 @@ public class FMUControlJNI { public String[] getAllVariables() throws FMUJNIException { try { - return getAllVariables_(); + return getAllVariables_(getModelID()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - - private native String[] getAllVariables_(); + + private native String[] getAllVariables_(String id); /** * Get the last error message @@ -314,14 +436,16 @@ public class FMUControlJNI { public String getLastErrorMessage() throws FMUJNIException { try { - return getLastErrorMessage_(); + return getLastErrorMessage_(getModelID()); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); + } catch (Exception e) { + throw new FMUJNIException(e.getMessage()); } } - - private native String getLastErrorMessage_(); + + private native String getLastErrorMessage_(String id); /** * Get a real (double) value for variable @@ -331,7 +455,7 @@ public class FMUControlJNI { */ public double getRealValue(String name) throws FMUJNIException { try { - return getRealValue_(name); + return getRealValue_(getModelID(), name); } catch (UnsatisfiedLinkError err) { throw new FMUJNIException(UNSATISFIED_LINK); } catch (Exception e) { @@ -339,5 +463,64 @@ public class FMUControlJNI { } } - private native double getRealValue_(String name); + private native double getRealValue_(String id, String name); + + + private FileChannel channel; + private FileLock lock; + + private boolean lockFMUDirectory() { + + try { + // Get a file channel for the lock file + File lockFile = new File(TEMP_FMU_DIRECTORY, LOCK_FILE_NAME); + if(!lockFile.isFile()) + lockFile.createNewFile(); + + channel = new RandomAccessFile(lockFile, "rw").getChannel(); + + // Use the file channel to create a lock on the file. + // This method blocks until it can retrieve the lock. + lock = channel.lock(); + + // // Try acquiring the lock without blocking. This method returns + // // null or throws an exception if the file is already locked. + // try { + // lock = channel.tryLock(); + // } catch (OverlappingFileLockException e) { + // // File is already locked in this thread or virtual machine + // } + } catch (IOException e) { + return false; + } + + return true; + } + + private boolean unlockFMUDirectory() { + try { + // Release the lock + if(lock != null) + lock.release(); + + // Close the file + if(channel != null) + channel.close(); + } catch (IOException e) { + return false; + } + return true; + } + + private boolean removeFMUDirectoryContents() { + // Remove contents + try { + File tempDir = new File(TEMP_FMU_DIRECTORY); + FileUtils.deleteAll(tempDir); + tempDir.delete(); + } catch (IOException e) { + return false; + } + return true; + } } diff --git a/org.simantics.sysdyn.tests/src/org/simantics/sysdyn/tests/fmi/CallFMUBeforeInitializationTests.java b/org.simantics.sysdyn.tests/src/org/simantics/sysdyn/tests/fmi/CallFMUBeforeInitializationTests.java index 88221190..86a095c8 100644 --- a/org.simantics.sysdyn.tests/src/org/simantics/sysdyn/tests/fmi/CallFMUBeforeInitializationTests.java +++ b/org.simantics.sysdyn.tests/src/org/simantics/sysdyn/tests/fmi/CallFMUBeforeInitializationTests.java @@ -19,7 +19,6 @@ public class CallFMUBeforeInitializationTests { * Try fmu jni methods without loading an fmu. * All but unload should throw an exception. */ - /* @Test public void testBeforeLoad() { FMUControlJNI control = new FMUControlJNI(); @@ -104,7 +103,6 @@ public class CallFMUBeforeInitializationTests { } } - */ /* * Test: diff --git a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java index c7ed31f0..fe6423b0 100644 --- a/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java +++ b/org.simantics.sysdyn.ui/src/org/simantics/sysdyn/ui/project/SysdynProject.java @@ -12,6 +12,7 @@ package org.simantics.sysdyn.ui.project; import java.io.File; +import java.io.IOException; import java.util.HashMap; import org.eclipse.core.runtime.Platform; @@ -38,6 +39,7 @@ import org.simantics.db.service.LifecycleSupport; import org.simantics.db.service.VirtualGraphSupport; import org.simantics.issues.common.IssueUtils; import org.simantics.layer0.Layer0; +import org.simantics.modelica.fmi.FMUControlJNI; import org.simantics.modeling.services.CaseInsensitiveComponentNamingStrategy2; import org.simantics.modeling.services.ComponentNamingStrategy; import org.simantics.project.IProject; @@ -55,224 +57,258 @@ import org.simantics.ui.workbench.IEditorNamingService; import org.simantics.ui.workbench.action.ChooseActionRequest; import org.simantics.ui.workbench.project.UIModelManager; import org.simantics.ui.workbench.project.UIModelManagerBase; +import org.simantics.utils.FileUtils; import org.simantics.utils.datastructures.Callback; import org.simantics.utils.ui.workbench.WorkbenchUtils; public class SysdynProject extends AbstractProjectFeature { - private static final String DEFAULT_PERSPECTIVE = "org.simantics.sysdyn.ui.perspective"; + private static final String DEFAULT_PERSPECTIVE = "org.simantics.sysdyn.ui.perspective"; - class ModelManager extends UIModelManagerBase { - @Override - public void create(ProjectElementType kind, Shell parentShell, Session session, Resource container, - Callback callback, Callback errorCallback) { + class ModelManager extends UIModelManagerBase { + @Override + public void create(ProjectElementType kind, Shell parentShell, Session session, Resource container, + Callback callback, Callback errorCallback) { - if (ProjectElements.MODEL.equals(kind)) { - //FIXME: Should not be needed anymore -// request(session, container, callback, errorCallback, CREATE_MODEL); - return; - } + if (ProjectElements.MODEL.equals(kind)) { + //FIXME: Should not be needed anymore + // request(session, container, callback, errorCallback, CREATE_MODEL); + return; + } - super.create(kind, parentShell, session, container, callback, errorCallback); - } + super.create(kind, parentShell, session, container, callback, errorCallback); + } - /** - * - * - * @see org.simantics.ui.workbench.project.UIModelManager#openEditor(org.simantics.db.Session, java.lang.String) - */ - @Override - public void openEditor(Session session, String uri) throws PartInitException { - try { - Resource resource = session.syncRequest(Queries.resource(uri)); - session.syncRequest(new ChooseActionRequest(null, resource, WorkbenchUtils.getCurrentPerspectiveId())); - } catch (DatabaseException e) { - LifecycleSupport ls = session.getService(LifecycleSupport.class); - throw new PartInitException("Failed to open editor for URI '" + uri + "' with session '" + ls.getSessionReference() + "', see exception for details.", e); - } - } - } + /** + * + * + * @see org.simantics.ui.workbench.project.UIModelManager#openEditor(org.simantics.db.Session, java.lang.String) + */ + @Override + public void openEditor(Session session, String uri) throws PartInitException { + try { + Resource resource = session.syncRequest(Queries.resource(uri)); + session.syncRequest(new ChooseActionRequest(null, resource, WorkbenchUtils.getCurrentPerspectiveId())); + } catch (DatabaseException e) { + LifecycleSupport ls = session.getService(LifecycleSupport.class); + throw new PartInitException("Failed to open editor for URI '" + uri + "' with session '" + ls.getSessionReference() + "', see exception for details.", e); + } + } + } - ModelManager mm; + ModelManager mm; - @Override - public void configure() throws ProjectException { - final IProject project = getProject(); - final Session session = getSession(); + @Override + public void configure() throws ProjectException { + final IProject project = getProject(); + final Session session = getSession(); - getProjectElement().setHint(ProjectKeys.DEFAULT_PERSPECTIVE, DEFAULT_PERSPECTIVE); + getProjectElement().setHint(ProjectKeys.DEFAULT_PERSPECTIVE, DEFAULT_PERSPECTIVE); - getProjectElement().setHint(IEditorNamingService.KEY_EDITOR_NAMING_SERVICE, new SysdynEditorNamingService()); + getProjectElement().setHint(IEditorNamingService.KEY_EDITOR_NAMING_SERVICE, new SysdynEditorNamingService()); - mm = new ModelManager(); - getProjectElement().setHint(UIModelManager.KEY_MODEL_MANAGER, mm); + mm = new ModelManager(); + getProjectElement().setHint(UIModelManager.KEY_MODEL_MANAGER, mm); - // Install naming strategy for model components. - GraphChangeListenerSupport changeSupport = session.peekService(GraphChangeListenerSupport.class); - if (changeSupport != null) { - getProjectElement().setHint(ComponentNamingStrategy.PROJECT_KEY, new CaseInsensitiveComponentNamingStrategy2(changeSupport, "%s%d")); - } + // Install naming strategy for model components. + GraphChangeListenerSupport changeSupport = session.peekService(GraphChangeListenerSupport.class); + if (changeSupport != null) { + getProjectElement().setHint(ComponentNamingStrategy.PROJECT_KEY, new CaseInsensitiveComponentNamingStrategy2(changeSupport, "%s%d")); + } - try { + try { - Resource projectResource = project.get(); + Resource projectResource = project.get(); - session.registerService(RuntimeValuations.class, new RuntimeValuations() { + session.registerService(RuntimeValuations.class, new RuntimeValuations() { - @Override - public boolean supports(String valuation) { + @Override + public boolean supports(String valuation) { - IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); - IExperiment experiment = expMan.getExperiment(valuation); + IExperimentManager expMan = project.getHint(IExperimentManager.KEY_EXPERIMENT_MANAGER); + IExperiment experiment = expMan.getExperiment(valuation); - return experiment != null; + return experiment != null; - } + } - @Override - public Accessor getAccessor(String variableIdentityPrefix, String valuation, String suffix) { - return null; - } + @Override + public Accessor getAccessor(String variableIdentityPrefix, String valuation, String suffix) { + return null; + } - @Override - public TrendVariable getVariable(String variableIdentityPrefix, String valuation, String suffix) { + @Override + public TrendVariable getVariable(String variableIdentityPrefix, String valuation, String suffix) { - return null; + return null; - } + } - }); - - - - ActivationManager activationManager = session.getService(ActivationManager.class); - if (activationManager != null) { - activationManager.activate(session, projectResource); - } - - - VirtualGraphSupport support = session.getService(VirtualGraphSupport.class); - - support.getWorkspacePersistent("experiments"); - support.getWorkspacePersistent("profiles"); -// support.getWorkspacePersistent("preferences"); - support.getWorkspacePersistent("issues"); - - } catch (DatabaseException e) { - - throw new ProjectException(e); - - } - - - cleanProjectFolder(session, project.get()); - - - // Issues - try { - session.syncRequest(new ReadRequest() { - @Override - public void run(ReadGraph graph) throws DatabaseException { - onActivated(graph, getProject()); - } - }); - } catch (DatabaseException e) { - throw new ProjectException(e); - } - } - - @Override - public void deconfigure() throws ProjectException { - if (getProjectElement().getHint(UIModelManager.KEY_MODEL_MANAGER) == mm) - getProjectElement().removeHint(UIModelManager.KEY_MODEL_MANAGER); - mm = null; - - getProjectElement().removeHint(ComponentNamingStrategy.PROJECT_KEY); - } - - public void cleanProjectFolder(Session session, final Resource projectResource) throws ProjectException { - String projectName = null; - final HashMap resultPaths = new HashMap(); - try { - projectName = session.syncRequest(new Read() { - - @Override - public String perform(ReadGraph graph) throws DatabaseException { - Layer0 l0 = Layer0.getInstance(graph); - SimulationResource SIMU = SimulationResource.getInstance(graph); - SysdynResource sr = SysdynResource.getInstance(graph); - for(Resource model : graph.getObjects(projectResource, l0.ConsistsOf)) { - if(graph.isInstanceOf(model, sr.SysdynModel)){ - for(Resource experiment : graph.getObjects(model, l0.ConsistsOf)) { - if(graph.isInstanceOf(experiment, SIMU.Experiment)) { - for(Resource result : graph.getObjects(experiment, sr.Experiment_result)) { - if(!graph.isInstanceOf(result, sr.HistoryDataset)) { - String resultFile = (String)graph.getPossibleRelatedValue(result, sr.Result_resultFile); - if(result != null) resultPaths.put(resultFile, result); - } - } - } - } - } - } - return graph.getPossibleRelatedValue(projectResource, l0.HasName); - - } - }); - } catch (DatabaseException e) { - throw new ProjectException(e); - } - - if(projectName != null) { - File root = new File(Platform.getLocation().toOSString(), "www.simantics.org"); - if(!root.isDirectory()) return; - File projectRoot = new File(root, projectName); - if(!projectRoot.isDirectory()) return; - File[] files = projectRoot.listFiles(); - - for(File file : files) { - if(resultPaths.get(file.getAbsolutePath()) == null) { - file.delete(); - } else { - resultPaths.remove(file.getAbsolutePath()); - } - } - - if (!resultPaths.keySet().isEmpty()) { - session.asyncRequest(new WriteRequest() { - - @Override - public void perform(WriteGraph graph) throws DatabaseException { - Layer0 l0 = Layer0.getInstance(graph); - for(String key : resultPaths.keySet()) { - Resource result = resultPaths.get(key); - graph.deny(result, l0.PartOf); - graph.deny(result, graph.getInverse(SysdynResource.getInstance(graph).Experiment_result)); - } - } - }) ; - } - } - } - - public void onActivated(final ReadGraph graph, final IProject project) throws DatabaseException { - - GraphChangeListenerSupport changeSupport = graph.getService(GraphChangeListenerSupport.class); - changeSupport.addMetadataListener(new GenericChangeListener() { - - @Override - public void onEvent(ReadGraph graph, DependencyChanges event) throws DatabaseException { - - WriteGraph w = (WriteGraph)graph; - w.addMetadata(event); - - } - - }); - - IssueUtils.listenActiveProjectIssueSources(graph, project.get()); - - } + }); + + + + ActivationManager activationManager = session.getService(ActivationManager.class); + if (activationManager != null) { + activationManager.activate(session, projectResource); + } + + + VirtualGraphSupport support = session.getService(VirtualGraphSupport.class); + + support.getWorkspacePersistent("experiments"); + support.getWorkspacePersistent("profiles"); + // support.getWorkspacePersistent("preferences"); + support.getWorkspacePersistent("issues"); + + } catch (DatabaseException e) { + + throw new ProjectException(e); + + } + + + cleanProjectFolder(session, project.get()); + + // Clean all temporary files possibly left by previous sysdyn instances + clearFMUTempDirectory(); + + + // Issues + try { + session.syncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + onActivated(graph, getProject()); + } + }); + } catch (DatabaseException e) { + throw new ProjectException(e); + } + } + + /** + * Clears fmu temp directory. This directory hosts + * fmu files for game experiments. In normal situations + * experiments clean up their temp files, but for example + * a system crash may leave files to temp directory. + */ + private void clearFMUTempDirectory() { + // Find commone "TEMP/fmu" directory + File commonDir = new File(FMUControlJNI.TEMP_FMU_COMMON_DIRECTORY); + if(commonDir != null && commonDir.isDirectory()) { + + // List all files and directories in "TEMP/fmu" + for(File child : commonDir.listFiles()) { + if(child.isDirectory()) { + // If directory is found, try to get the lock file in it + File lock = new File(child, FMUControlJNI.LOCK_FILE_NAME); + if(!lock.isFile() || lock.delete()) { + // If lock is not found, or the lock can be delted, the directory is not locked. -> Delete the rest of the directory + try { + FileUtils.deleteAll(child); + child.delete(); + } catch (IOException e) { + + } + } + } + } + } + } + + @Override + public void deconfigure() throws ProjectException { + if (getProjectElement().getHint(UIModelManager.KEY_MODEL_MANAGER) == mm) + getProjectElement().removeHint(UIModelManager.KEY_MODEL_MANAGER); + mm = null; + + getProjectElement().removeHint(ComponentNamingStrategy.PROJECT_KEY); + } + + public void cleanProjectFolder(Session session, final Resource projectResource) throws ProjectException { + String projectName = null; + final HashMap resultPaths = new HashMap(); + try { + projectName = session.syncRequest(new Read() { + + @Override + public String perform(ReadGraph graph) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + SimulationResource SIMU = SimulationResource.getInstance(graph); + SysdynResource sr = SysdynResource.getInstance(graph); + for(Resource model : graph.getObjects(projectResource, l0.ConsistsOf)) { + if(graph.isInstanceOf(model, sr.SysdynModel)){ + for(Resource experiment : graph.getObjects(model, l0.ConsistsOf)) { + if(graph.isInstanceOf(experiment, SIMU.Experiment)) { + for(Resource result : graph.getObjects(experiment, sr.Experiment_result)) { + if(!graph.isInstanceOf(result, sr.HistoryDataset)) { + String resultFile = (String)graph.getPossibleRelatedValue(result, sr.Result_resultFile); + if(result != null) resultPaths.put(resultFile, result); + } + } + } + } + } + } + return graph.getPossibleRelatedValue(projectResource, l0.HasName); + + } + }); + } catch (DatabaseException e) { + throw new ProjectException(e); + } + + if(projectName != null) { + File root = new File(Platform.getLocation().toOSString(), "www.simantics.org"); + if(!root.isDirectory()) return; + File projectRoot = new File(root, projectName); + if(!projectRoot.isDirectory()) return; + File[] files = projectRoot.listFiles(); + + for(File file : files) { + if(resultPaths.get(file.getAbsolutePath()) == null) { + file.delete(); + } else { + resultPaths.remove(file.getAbsolutePath()); + } + } + + if (!resultPaths.keySet().isEmpty()) { + session.asyncRequest(new WriteRequest() { + + @Override + public void perform(WriteGraph graph) throws DatabaseException { + Layer0 l0 = Layer0.getInstance(graph); + for(String key : resultPaths.keySet()) { + Resource result = resultPaths.get(key); + graph.deny(result, l0.PartOf); + graph.deny(result, graph.getInverse(SysdynResource.getInstance(graph).Experiment_result)); + } + } + }) ; + } + } + } + + public void onActivated(final ReadGraph graph, final IProject project) throws DatabaseException { + + GraphChangeListenerSupport changeSupport = graph.getService(GraphChangeListenerSupport.class); + changeSupport.addMetadataListener(new GenericChangeListener() { + + @Override + public void onEvent(ReadGraph graph, DependencyChanges event) throws DatabaseException { + + WriteGraph w = (WriteGraph)graph; + w.addMetadata(event); + + } + + }); + + IssueUtils.listenActiveProjectIssueSources(graph, project.get()); + + } } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java index 199ce72e..71462cbf 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/adapter/HistoryVariable.java @@ -357,7 +357,7 @@ public class HistoryVariable extends ChildVariable implements PropertyProvider, @Override public double getParameterValue(ReadGraph graph) throws FMUJNIException, DatabaseException { if(this.experiment instanceof SysdynGameExperiment) { - FMUControlJNI control = FMUControlJNI.INSTANCE; + FMUControlJNI control = ((SysdynGameExperiment)this.experiment).getFMUControl(); RVI rvi = this.getRVI(graph); String name = rvi.toString(); if(name.length() > 0) @@ -372,7 +372,7 @@ public class HistoryVariable extends ChildVariable implements PropertyProvider, @Override public void setParameterValue(ReadGraph graph, double value) throws FMUJNIException, DatabaseException { if(this.experiment instanceof SysdynGameExperiment) { - FMUControlJNI control = FMUControlJNI.INSTANCE; + FMUControlJNI control = ((SysdynGameExperiment)this.experiment).getFMUControl(); RVI rvi = this.getRVI(graph); String name = rvi.toString(); if(name.length() > 0) diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java index 2e90860c..c82649c3 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynExperiment.java @@ -557,21 +557,28 @@ public class SysdynExperiment extends Experiment implements IDynamicExperiment { switch(state) { case DISPOSED: - System.out.println("disposed"); - session.asyncRequest(new ReadRequest() { - - @Override - public void run(ReadGraph graph) throws DatabaseException { - cancelSimulation(); - sysdynModel.removeModificationListener(modificationListener); - modificationListener = null; - toggleActivation(graph, false); - } - }); + onExperimentDisposed(); break; } } + + /** + * Actions performed when experiment is disposed + * @param graph + */ + protected void onExperimentDisposed() { + cancelSimulation(); + sysdynModel.removeModificationListener(modificationListener); + modificationListener = null; + + session.asyncRequest(new ReadRequest() { + @Override + public void run(ReadGraph graph) throws DatabaseException { + toggleActivation(graph, false); + } + }); + } /** diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java index 673bf856..cb4533a2 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/manager/SysdynGameExperiment.java @@ -67,13 +67,17 @@ public class SysdynGameExperiment extends SysdynExperiment { public void setStepLength(double stepLength) { this.stepLength = stepLength; } + + public FMUControlJNI getFMUControl() { + return control; + } @Override public void init(ReadGraph g) { super.init(g); if(control == null) - control = FMUControlJNI.INSTANCE; + control = new FMUControlJNI(); results = new HashMap>(); @@ -109,6 +113,19 @@ public class SysdynGameExperiment extends SysdynExperiment { } }); } + + @Override + protected void onExperimentDisposed() { + super.onExperimentDisposed(); + if(control!=null) { + try { + control.unloadFMU(); + } catch (FMUJNIException e) { + e.printStackTrace(); + } + } + } + @Override public synchronized void simulate(final IModelicaMonitor monitor, final IProgressMonitor progressMonitor) throws IOException { diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java index 7783dbd0..ab41ec5f 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/modelica/ModelicaWriter.java @@ -139,10 +139,10 @@ public class ModelicaWriter { if(game) { if(configuration.getModel() != null) // Parameter for model root. Values changed in FMU simulator - b.append("parameter Real time = 0;\n"); + b.append(" parameter Real time = 0;\n"); else // Continuous variable for module instances - b.append("Real time;\n"); + b.append(" Real time;\n"); } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java index 20eca950..41fd95e5 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/FormatUtils.java @@ -68,11 +68,19 @@ public class FormatUtils { return expression; if(Variability.getVariability((IndependentVariable)variable).equals(Variability.CONTINUOUS)) { - String reference = RepresentationUtils.getFirstGameVariableReference(variable, expression); + Variable reference = RepresentationUtils.getFirstGameVariableReference(variable, expression); if(reference != null) { - String condition = "if initial() or " + reference + " < 0 or " + - reference + " >= 0 then "; - String conditionEnd = " else pre(" + variable.getName() +")"; + String condition; + + if(reference.getType().equals("Boolean")) { + condition= "if initial() or " + reference.getName() + " or not " + + reference.getName() + " then ("; + } else { + condition= "if initial() or " + reference.getName() + " < 0 or " + + reference.getName() + " >= 0 then ("; + } + + String conditionEnd = ") else pre(" + variable.getName() +")"; expression = condition + expression + conditionEnd; } diff --git a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java index a0fe7fb5..dd460ae0 100644 --- a/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java +++ b/org.simantics.sysdyn/src/org/simantics/sysdyn/representation/utils/RepresentationUtils.java @@ -64,18 +64,17 @@ public class RepresentationUtils { * @param expression Expression * @return The name of the first referred game variable or null if there is no such reference */ - public static String getFirstGameVariableReference(Variable variable, String expression) { + public static Variable getFirstGameVariableReference(Variable variable, String expression) { String equation = FormatUtils.formatExpressionForModelica(variable, expression, false); ExpressionParser parser = new ExpressionParser(new StringReader(equation)); - String result = null; + Variable result = null; try { parser.expr(); if(!parser.getReferences().isEmpty()) { Set references = parser.getReferences().keySet(); // Go through each reference for(String reference : references) { - if(isGameVariable(variable, variable.getParentConfiguration(), reference)) { - result = reference; + if((result = getGameVariableReference(variable, variable.getParentConfiguration(), reference)) != null) { break; } } @@ -92,7 +91,7 @@ public class RepresentationUtils { * @param reference Reference variable name * @return true if reference is a game variable, false otherwise */ - private static boolean isGameVariable(Variable variable, Configuration configuration, String reference) { + private static Variable getGameVariableReference(Variable variable, Configuration configuration, String reference) { String r = reference.split("\\.")[0]; for(IElement element : configuration.getElements()) { @@ -101,30 +100,30 @@ public class RepresentationUtils { if(r.equals(m.getName())) { if(!reference.contains(".")) { // The reference contains only modules, implementation feature for the expression parser - return false; + return null; } Configuration moduleConfiguration = m.getType().getConfiguration(); - return isGameVariable(variable, moduleConfiguration, reference.substring(reference.indexOf(".") + 1)); + return getGameVariableReference(variable, moduleConfiguration, reference.substring(reference.indexOf(".") + 1)); } } else if(element instanceof IndependentVariable && !(element instanceof Stock)) { IndependentVariable v = (IndependentVariable)element; if(r.equals(v.getName())) { if(v.getName().equals(variable.getName())) { - return false;// Reference to self. + return null;// Reference to self. } else { if(v.getExpressions() == null || v.getExpressions().getExpressions().size() > 1) - return false; + return null; IExpression e = v.getExpressions().getExpressions().get(0); if(e instanceof ParameterExpression) - return true; + return v; } } } } - return false; + return null; } } -- 2.47.1